Preface
Goal: Add indicator, and putting all pagination part together.
Preview
This is what we want to achieve in this tutorial.
More Recent Code
I have made a better code with Bulma
utilizing site.pagination.permalink
which you can examine at:
1: Prepare
Artefact that we need.
Source
I respect copyright. Most of the code below, especially middle pagination, ported from Hugo Chroma to Jekyll Liquid:
The rest is my custom modification.
Includes: Pagination: Combined
Create an empty artefact, to combine adjacent and indicator. Source code used in this tutorial, is available at this repository:
- /_includes/pagination/04-indicator.html : gitlab.com/…/partials/pagination-indicator.html.
You should have this minimal code, before you begin.
{% capture spaceless %}
...
{% endcapture %}
<nav aria-label="Page navigation">
{% if total_pages > 1 %}
<ul class="pagination justify-content-center">
...
</ul>
{% endif %}
</nav>
Pages: Blog List
Set this blog list page:
- /pages/index.html : github.com/…/pages/index.html.
{% include pagination/04-indicator.html %}
We will achieve this with Jekyll code.
2: Preview: General
Structure
This consist of at least seven parts:
-
Previous Page: «
-
First Page: always 1
-
Left Indicator
-
Middle Pagination: Glenn McComb
-
Right Indicator
-
Last Page: always the same number
-
Next Page: »
We will not discuss about Middle Pagination, as it has already been discussed in previous article.
HTML Preview
The HTML that we want to achieve is similar as below.
<ul class="pagination justify-content-center">
<li class="page-item blog_previous">...</li>
<li class="page-item first">...</li>
<li class="pages-indicator first disabled">...</li>
<li class="page-item">...</li>
<li class="page-item">...</li>
<li class="page-item active ">...</li>
<li class="page-item">...</li>
<li class="page-item">...</li>
<li class="pages-indicator last disabled">...</li>
<li class="page-item last">...</li>
<li class="page-item blog_next">...</li>
</ul>
Small Preview
This is the complete version.
Wide Preview
Wide version, in responsive context, is slightly different.
We will use responsive CSS later to achieve this effect.
Partial: Pagination Code Skeleton
As usual, the skeleton, to show the complexity.
- /_includes/pagination/04-indicator.html : gitlab.com/…/partials/pagination/04-indicator.html.
<nav aria-label="Page navigation">
{% capture spaceless %}
<!-- Variable Initialization. -->
{% endcapture %}
{% if total_pages > 1 %}
<ul class="pagination justify-content-center">
<!-- Previous Page. -->
<!-- First Page. -->
<!-- Early (More Pages) Indicator. -->
{% for page in (1..total_pages) %}
<!-- Flag Calculation -->
{% assign page_current_flag = false %}
{% if total_pages > link_max %}
<!-- Complex page numbers. -->
<!-- Lower limit pages. -->
<!-- Upper limit pages. -->
<!-- Middle pages. -->
{% else %}
<!-- Simple page numbers. -->
{% endif %}
{% if page_current_flag == true %}
<!-- Show Pager. -->
{% endif %}
{% endfor %}
<!-- Late (More Pages) Indicator. -->
<!-- Last Page. -->
<!-- Next Page. -->
</ul>
{% endif %}
</nav>
Each Pagination
Consider again, have a look at the animation above, frame by frame.
We have from first page (1), to last page (10).
3: Variables: Initialization
Consider refresh our memory, about our variables initialization.
{% capture spaceless %}
{% comment %}
Pagination links
* https://glennmccomb.com/articles/how-to-build-custom-hugo-pagination/
{% endcomment %}
{% if page.paginate_root == nil %}
{% assign paginate_root = "/" %}
{% else %}
{% assign paginate_root = page.paginate_root %}
{% endif %}
{% assign total_pages = paginator.total_pages %}
{% assign page_current = paginator.page %}
{% assign link_offset = 2 %}
{% assign link_max = link_offset | times: 2 | plus: 1 %}
{% assign limit_lower = link_offset | plus: 1 %}
{% assign limit_upper = total_pages | minus: link_offset %}
{% assign min_lower = link_max %}
{% assign max_upper = total_pages | minus: link_max %}
{% assign lower_offset = page_current | minus: link_offset %}
{% assign upper_offset = page_current | plus: link_offset %}
{% assign lower_indicator = 2 %}
{% assign upper_indicator = total_pages | minus: 1 %}
{% endcapture %}
4: Navigation: Previous and Next
It is similar to our simple pagination. Except that, now we use dictionary.
Navigation: Previous
<!-- Previous Page. -->
{% if paginator.previous_page %}
<li class="page-item blog_previous">
<a class="page-link"
href="{{ site.baseurl }}{{ paginator.previous_page_path }}"
rel="prev">«</a>
</li>
{% else %}
<li class="page-item blog_previous disabled">
<span class="page-link">«</span>
</li>
{% endif %}
Navigation: Next
<!-- Next Page. -->
{% if paginator.next_page %}
<li class="page-item blog_next">
<a class="page-link"
href="{{ site.baseurl }}{{ paginator.next_page_path }}"
rel="next">»</a>
</li>
{% else %}
<li class="page-item blog_next disabled">
<span class="page-link">»</span>
</li>
{% endif %}
5: Navigation: First and Last
It is different to our simple pagination. Although it is based on the same logic.
Navigation: First
This will not be shown, if it is already be shown middle pagination.
{% if total_pages > link_max %}
<!-- First Page. -->
{% if lower_offset > 1 %}
<li class="page-item first">
<a class="page-link"
href="{{ site.baseurl }}{{ page.paginate_root }}">1</a>
</li>
{% endif %}
{% endif %}
Navigation: Last
This will not be shown, if it is already be shown middle pagination.
{% if total_pages > link_max %}
<!-- Last Page. -->
{% if upper_offset < total_pages %}
<li class="page-item last">
<a class="page-link"
href="{{ site.paginate_path | relative_url | replace: ':num', total_pages }}"
>{{ total_pages }}</a>
</li>
{% endif %}
{% endif %}
6: Indicator: Left and Right
This will only be shown, if necessary.
Indicator: Left
{% if total_pages > link_max %}
<!-- Early (More Pages) Indicator. -->
{% if lower_offset > lower_indicator %}
<li class="pages-indicator first disabled">
<span class="page-link">...</span>
</li>
{% endif %}
{% endif %}
Indicator: Right
{% if total_pages > link_max %}
<!-- Late (More Pages) Indicator. -->
{% if upper_offset < upper_indicator %}
<li class="pages-indicator last disabled">
<span class="page-link">...</span>
</li>
{% endif %}
{% endif %}
8: Combined Code
It is about the right time to put all the code together.
- /_includes/pagination/04-indicator.html : gitlab.com/…/partials/pagination/04-indicator.html.
{% capture spaceless %}
{% comment %}
Pagination links
* https://glennmccomb.com/articles/how-to-build-custom-hugo-pagination/
{% endcomment %}
{% if page.paginate_root == nil %}
{% assign paginate_root = "/" %}
{% else %}
{% assign paginate_root = page.paginate_root %}
{% endif %}
{% assign total_pages = paginator.total_pages %}
{% assign page_current = paginator.page %}
{% assign link_offset = 2 %}
{% assign link_max = link_offset | times: 2 | plus: 1 %}
{% assign limit_lower = link_offset | plus: 1 %}
{% assign limit_upper = total_pages | minus: link_offset %}
{% assign min_lower = link_max %}
{% assign max_upper = total_pages | minus: link_max %}
{% assign lower_offset = page_current | minus: link_offset %}
{% assign upper_offset = page_current | plus: link_offset %}
{% assign lower_indicator = 2 %}
{% assign upper_indicator = total_pages | minus: 1 %}
{% endcapture %}
<nav aria-label="Page navigation">
{% if total_pages > 1 %}
<ul class="pagination justify-content-center">
<!-- Previous Page. -->
{% if paginator.previous_page %}
<li class="page-item blog_previous">
<a class="page-link"
href="{{ site.baseurl }}{{ paginator.previous_page_path }}"
rel="prev">«</a>
</li>
{% else %}
<li class="page-item blog_previous disabled">
<span class="page-link">«</span>
</li>
{% endif %}
{% if total_pages > link_max %}
<!-- First Page. -->
{% if lower_offset > 1 %}
<li class="page-item first">
<a class="page-link"
href="{{ site.baseurl }}{{ page.paginate_root }}">1</a>
</li>
{% endif %}
<!-- Early (More Pages) Indicator. -->
{% if lower_offset > lower_indicator %}
<li class="pages-indicator first disabled">
<span class="page-link">...</span>
</li>
{% endif %}
{% endif %}
<!-- Page numbers. -->
{% for page in (1..total_pages) %}
{% capture spaceless %}
{% assign page_current_flag = false %}
{% if total_pages > link_max %}
{% if page_current <= limit_lower %}
{% if page <= min_lower %}
{% assign page_current_flag = true %}
{% endif %}
{% elsif page_current >= limit_upper %}
{% if page > max_upper %}
{% assign page_current_flag = true %}
{% endif %}
{% else %}
{% if (page >= lower_offset) and (page <= upper_offset) %}
{% assign page_current_flag = true %}
{% endif %}
{% endif %}
{% else %}
{% assign page_current_flag = true %}
{% endif %}
{% endcapture %}
<!-- Show Pager. -->
{% if page_current_flag == true %}
<li class="page-item {% if page == page_current %} active{% endif %}">
{% if page == page_current %}
<span class="page-link">
{{ page }}
</span>
{% elsif page == 1 %}
<a class="page-link"
href="{{ site.baseurl }}{{ paginate_root }}"
>1</a>
{% else %}
<a class="page-link"
href="{{ site.paginate_path | relative_url | replace: ':num', page }}"
>{{ page }}
</a>
{% endif %}
</li>
{% endif %}
{% endfor %}
{% if total_pages > link_max %}
<!-- Late (More Pages) Indicator. -->
{% if upper_offset < upper_indicator %}
<li class="pages-indicator last disabled">
<span class="page-link">...</span>
</li>
{% endif %}
<!-- Last Page. -->
{% if upper_offset < total_pages %}
<li class="page-item last">
<a class="page-link"
href="{{ site.paginate_path | relative_url | replace: ':num', total_pages }}"
>{{ total_pages }}</a>
</li>
{% endif %}
{% endif %}
<!-- Next Page. -->
{% if paginator.next_page %}
<li class="page-item blog_next">
<a class="page-link"
href="{{ site.baseurl }}{{ paginator.next_page_path }}"
rel="next">»</a>
</li>
{% else %}
<li class="page-item blog_next disabled">
<span class="page-link">»</span>
</li>
{% endif %}
</ul>
{% endif %}
</nav>
Pretty long code, sure.
9: Responsive: Simple
Before we continue to the next pagination article about responsive, consider having this very simple example using bootstrap.
This will show the word previous and next for medium page.
SASS: Custom Pagination
I’m using Bootstrap 4 grid breakpoints.
-
- _sass/themes/oriclone/_pagination.scss
- gitlab.com/…/_pagination.scss.
@include media-breakpoint-up(md) {
.blog_previous {
span.page-link:after,
a.page-link:after {
content: " previous"
}
}
.blog_next {
span.page-link:before,
a.page-link:before {
content: "next "
}
}
}
SASS: Main
-
- _sass/themes/oriclone/main.scss
- gitlab.com/…/main.scss.
@import
// variables
"vendors/bootstrap/functions",
"variables",
"vendors/bootstrap/variables",
"vendors/bootstrap/mixins/breakpoints",
"vendors/bootstrap/mixins/image",
"vendors/bootstrap/mixins/gradients",
"vendors/bootstrap/mixins/transition",
"vendors/bootstrap/mixins/box-shadow",
// taken from bootstrap
"sticky-footer-navbar",
"bootstrap-custom",
// custom: general
"layout",
"decoration",
"stripes",
"list",
"pagination",
// custom: post
"post-navigation",
"post-calendar",
"post-header",
"post-content",
"post-code",
"post-highlight-jekyll"
;
SASS: Bootstrap Grid Breakpoint Variables.
Bootstrap 4 grid breakpoints are defined as below.
- _sass/vendors/bootstrap/_variables.scss
// Grid breakpoints
//
// Define the minimum dimensions at which your layout will change,
// adapting to different screen sizes, for use in media queries.
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
) !default;
What is Next ?
Consider continue reading [ Jekyll Pagination - Responsive ].
Thank you for reading.