Apr 3, 2018

Creating a Jekyll Blog with Bootstrap 4 and Sass - Part 3

In Part 2 we added some basic structure to our blog along with a few navigation links. In part 3, we’ll add some posts and figure out how we can dispay and paginate our posts from the main page of the blog.

I’d encourage you to follow along, but if you want to skip directly to the code, it’s available on GitHub at: https://github.com/riebeekn/jekyll-bootstrap-4-starter.

What we’ll build

At the end of this post, our site will look like:

Getting started

If you followed along with part 2 just continue on with the code you created in part 2. If not and you’d rather jump right into part 3, you can use a clone of part 2 as a starting point.

Clone the Repo

If grabbing the code from GitHub instead of continuing along from part 2, the first step is to clone the repo.

Terminal
git clone -b part-02 https://github.com/riebeekn/jekyll-bootstrap-4-starter.git
cd jekyll-bootstrap-4-starter

What we’re starting with

OK, you’ve either gotten the code from GitHub or are using the existing code you created in Part 2, let’s see where we’re starting from.

Terminal
jekyll serve --livereload

If you navigate to http://localhost:4000/ you’ll see where we left off last time.

Let’s start things off by adding posts to our index.html page.

Adding posts to the index page

Creating a posts include file

We’ll create an include file that will list all the posts on our blog. You could add this directly to index.html but I feel it’s a little cleaner including it in a seperate file… so let’s do just that!

Terminal
touch _includes/posts.html
/_includes/posts.html
<section id="posts" class="py-5">
  <div class="container">
    <div class="row">
      <div class="col">
        {% for post in site.posts %}
          <div>
            <h2><a href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a></h2>
            <p class="text-info lead">
              {{ post.date | date: "%b %-d, %Y" }}
            </p>

            <p>
              {% if post.summary %}
                {{ post.summary }}
              {% else %}
                {{ post.excerpt }}
              {% endif %}
            </p>
          </div>
        {% endfor %}
      </div>
    </div>
  </div>
</section>

Nothing too crazy here, just basic HTML and Bootstrap, along with a bit of Jekyll functionality. We’re iterating over all our (soon to be created) posts and displaying the post title; the date of the post; and a small summary (if we’ve included one in our post) or excerpt of the post.

Now we need to create the code required for the individual posts.

Adding a layout file for a post

We’ll want a seperate layout file for a post.

Terminal
touch _layouts/post.html
/_layout/post.html
<!DOCTYPE html>
<html lang="en">
  {% include head.html %}
  <body>
    {% include header.html %}
    {% include banner.html %}
    {% include post.html %}
    {% include footer.html %}
  </body>
</html>

Very similar to our default.html layout, but instead of just rendering our content via the {{ content }} tag, we’re linking to a post.html include.

Let’s create the include file next.

Adding an include file for a post

Terminal
touch _includes/post.html
/_includes/post.html
<div id="post" class="container pt-3">
  <div class="row">
    <div class="col">
      <p class="lead text-info">
        {{ page.date | date: "%b %-d, %Y" }}
      </p>
      <h1>{{ page.title }}</h1>
      <article>
        {{ content }}
      </article>
    </div>
  </div>
</div>

Within our post.html include we create a simple header with the date and title of the post (accessed via page.date, and page.title), followed by the content of the post which we enclose in a article tag. Pretty straight forward.

Displaying posts from the Index page

Finally we need to hook all this up to our index.html page, so update ‘index.html’ as below.

/index.html
---
layout: default
---

{% include posts.html %}

Since we have no posts, we’re not going to see any changes at the moment… let’s create some test data next.

Creating some test data

We’re going to need some content to display in order to ensure our post functionality is working, so let’s create a few posts that we can use for the purpose of testing.

Terminal
mkdir _posts
touch _posts/2018-01-01-a-sample-post.md
/_posts/2018-01-01-a-sample-post.md
---
layout: post
title: A Sample Post
summary: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Unde, dolore.
---

## Lorem
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Unde, dolore.

## More Lorem
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit, ipsam nam sit in omnis id. Ut molestiae non velit inventore quas, laborum dolorum maiores beatae animi aspernatur reprehenderit accusantium nostrum?

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit, ipsam nam sit in omnis id. Ut molestiae non velit inventore quas, laborum dolorum maiores beatae animi aspernatur reprehenderit accusantium nostrum?

All we’ve done is create a sample post with some generic Lorem ipsum content, notice we’re using the post as opposed to the default layout.

We’ll want a few sample posts, so let’s duplicate our sample post a few times, just altering the date in the title.

Terminal
cp _posts/2018-01-01-a-sample-post.md _posts/2018-01-15-a-sample-post.md
cp _posts/2018-01-01-a-sample-post.md _posts/2018-02-01-a-sample-post.md
cp _posts/2018-01-01-a-sample-post.md _posts/2018-03-01-a-sample-post.md

And with all that out of the way, we finally have some posts showing up:

Styling posts

Let’s add a little bit of styling to improve the way the links look when a user selects them.

Terminal
touch css/custom/includes/_posts.scss
/css/custom/includes/_posts.scss
#posts {
  a {
    text-decoration: none;
    &:hover {
      color: $info;
    }
  }
}

We’re just removing the underline when a user hovers over a post title, and we’re also changing the color of a hovered over link. We’ll need to import the style in main.scss.

/css/main.scss
---
---

@import 'bootstrap/bootstrap';
@import 'custom/includes/header';
@import 'custom/includes/banner';
@import 'custom/includes/social_links';
@import 'custom/includes/posts';

Adding pagination

With only 4 posts it’s not really an issue, but eventually our index page is going to become unwieldy as it fills up with posts. Luckily it is very easy to add pagination to a Jekyll site.

Update our config

The first step is to update _config.yml. Add the following to the config file.

/_config.yml
# plugins
plugins: [jekyll-paginate]
paginate: 3

All this does is indicate we want to use the Jekyll paginate plugin with a pagination setting of 3, meaning we’ll have 3 posts displayed per page.

We need to restart the Jekyll server for the configuration settings to take affect.

Terminal
jekyll serve --livereload

Update the posts include file

Now to make use of pagination, we just need to make a very small change to posts.html.

/_includes/posts.html
<!-- replace site.posts with paginator.posts -->
<!-- {% for post in site.posts %} -->
{% for post in paginator.posts %}

We now have only 3 posts showing up.

Fanatastic, but how do we get at our 4th post? We need to add a pagination include.

Terminal
touch _includes/pagination.html
/_includes/pagination.html
<div id="pager" class="container">
  <div class="row">
    <div class="col text-center">
      {% if paginator.previous_page %}
        {% if paginator.page == 2 %}
          <a class="btn btn-primary" href="{{ site.baseurl }}/">&larr;&nbsp;Newer posts</a>
        {% else %}
          <a class="btn btn-primary" href="{{ site.baseurl }}/page{{paginator.previous_page}}/">&larr;&nbsp;Newer posts</a>
        {% endif %}
      {% else %}
        <a class="disabled btn btn-primary">&larr;&nbsp;Newer posts</a>
      {% endif %}

      {% if paginator.next_page %}
        <a class="btn btn-primary" href="{{ site.baseurl }}/page{{paginator.next_page}}/">Older posts&nbsp;&rarr;</a>
      {% else %}
        <a class="disabled btn btn-primary">Older posts&nbsp;&rarr;</a>
      {% endif %}
    </div>
  </div>
</div>

Nothing too crazy here, we are doing some checks to see if we have next and previous pages, and if so we show some previous / next buttons. In the previous page section i.e. {% if paginator.previous_page %} we have special logic to handle the navigation back from the 2nd page; in this case we want to go back to our naked index page, i.e. localhost:4000/ instead of localhost:4000/page1/.

In order for the pager to show up, we need to add it to index.html.

/index.html
---
layout: default
---

{% include posts.html %}
{% include pagination.html %}

And with that we have a pager.

The text on our disabled button is not fanatastic, let’s fix that up with some styling.

Terminal
touch css/custom/includes/_pagination.scss
/css/custom/includes/_pagination.scss
#pager {
  a.btn.disabled {
    color: $info;
  }
}
/css/main.scss
---
---

@import 'bootstrap/bootstrap';
@import 'custom/includes/header';
@import 'custom/includes/banner';
@import 'custom/includes/social_links';
@import 'custom/includes/posts';
@import 'custom/includes/pagination'

With that we’re finished!

Summary

We’ve added some posts to our main page and also implemented pagination. Next time, we’ll concentrate on the styling of individual posts… and eventually we’ll get around to implementing our about, and archive pages.

Thanks for reading and I hope you enjoyed the post!



Comment on this post!