Preface
Goal: Add indicator, and putting all pagination part together.
1: Source
I respect copyright. Most of the code below, especially middle pagination, copied and pasted from:
The rest is my modification.
2: Prepare
Config
Pagination can be set in config.toml
-
- config.toml
- gitlab.com/…/config.toml
Paginate = 7
Layout: List
The complete file is here below:
-
- themes/tutor-05/layouts/archives/list.html
- gitlab.com/…/layouts/archives/list.html.
{{ define "main" }}
<main role="main"
class="container-fluid m-3 m-sm-0 p-3
bg-light rounded border border-dark shadow-hover">
<header>
<h4>{{ .Title | default .Site.Title }}</h4>
</header>
<article>
{{ .Content }}
</article>
{{ $paginator := .Paginate (where .Site.Pages "Type" "post") }}
{{ partial "pagination-indicator.html" (dict "p" $paginator "s" .Scratch) }}
<section id="archive">
<div class="post-list">
{{ range $paginator.Pages }}
{{ partial "summary-blog-list.html" . }}
{{ end }}
</div>
</section>
</main>
{{ end }}
Partial: Minimal Pagination Code
You should have this minimal code, before you begin.
- themes/tutor-05/layouts/partials/pagination-indicator.html : gitlab.com/…/partials/pagination-indicator.html.
<nav aria-label="Page navigation">
{{ $s := .s }}
{{ $p := .p }}
{{ if gt $p.TotalPages 1 }}
<ul class="pagination justify-content-center">
...
</ul>
{{ end }}
</nav>
Dictionary
In order to pass variable from list layout to pagination partial, we utilize dictionary: (dict “p” $paginator).
- themes/tutor-05/layouts/archives/list.html.
{{ partial "pagination-indicator.html" (dict "p" $paginator "s" .Scratch) }}
And later call it here:
- themes/tutor-05/layouts/partials/pagination-indicator.html.
{{ $s := .s }}
{{ $p := .p }}
3: 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.
- themes/tutor-05/layouts/partials/pagination-indicator.html : gitlab.com/…/partials/pagination-indicator.html.
<nav aria-label="Page navigation">
{{ $s := .s }}
{{ $p := .p }}
{{ if gt $p.TotalPages 1 }}
<ul class="pagination justify-content-center">
<!-- Variable Initialization. -->
<!-- Previous Page. -->
<!-- First Page. -->
<!-- Early (More Pages) Indicator. -->
{{- range $p.Pagers -}}
{{ $s.Set "page_number_flag" false }}
<!-- Complex page numbers. -->
{{ if gt $p.TotalPages $max_links }}
<!-- Lower limit pages. -->
<!-- Upper limit pages. -->
<!-- Middle pages. -->
<!-- Simple page numbers. -->
{{ else }}
...
{{ end }}
<!-- Show Pager. -->
{{- if eq ($s.Get "page_number_flag") true -}}
...
{{- end -}}
{{ end }}
<!-- Late (More Pages) Indicator. -->
<!-- Last Page. -->
<!-- Next Page. -->
</ul>
{{ end }}
</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).
4: Variables: Initialization
Consider refresh our memory, about our variables initialization.
<nav aria-label="Page navigation">
{{ $s := .s }}
{{ $p := .p }}
{{ if gt $p.TotalPages 1 }}
<ul class="pagination justify-content-center">
<!-- Page numbers. -->
{{- $pagenumber := $p.PageNumber -}}
<!-- Number of links either side of the current page. -->
{{ $adjacent_links := 2 }}
<!-- $max_links = ($adjacent_links * 2) + 1 -->
{{ $max_links := (add (mul $adjacent_links 2) 1) }}
<!-- $lower_limit = 1 + $adjacent_links -->
{{ $lower_limit := (add 1 $adjacent_links) }}
<!-- $upper_limit = $paginator.TotalPages - $adjacent_links -->
{{ $upper_limit := (sub $p.TotalPages $adjacent_links) }}
</ul>
{{ end }}
</nav>
5: Navigation: Previous and Next
It is similar to our simple pagination. Except that, now we use dictionary.
Navigation: Previous
<!-- Previous Page. -->
{{ if $p.HasPrev }}
<li class="page-item blog_previous">
<a class="page-link" href="{{ $p.Prev.URL }}" rel="prev">«</a>
</li>
{{ else }}
<li class="page-item blog_previous disabled">
<span class="page-link">«</span>
</li>
{{ end }}
Navigation: Next
<!-- Next Page. -->
{{ if $p.HasNext }}
<li class="page-item blog_next">
<a class="page-link" href="{{ $p.Next.URL }}" rel="next">»</a>
</li>
{{ else }}
<li class="page-item blog_next disabled">
<span class="page-link">»</span>
</li>
{{ end }}
6: 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 gt $p.TotalPages $max_links }}
<!-- First Page. -->
{{ if gt (sub $p.PageNumber $adjacent_links) 1 }}
<li class="page-item first">
<a class="page-link" href="{{ $p.First.URL }}">1</a>
</li>
{{ end }}
{{ end }}
Navigation: Last
This will not be shown, if it is already be shown middle pagination.
{{ if gt $p.TotalPages $max_links }}
<!-- Last Page. -->
{{ if lt (add $p.PageNumber $adjacent_links) $p.TotalPages }}
<li class="page-item last">
<a class="page-link" href="{{ $p.Last.URL }}">{{ $p.TotalPages }}</a>
</li>
{{ end }}
{{ end }}
7: Indicator: Left and Right
This will only be shown, if necessary.
Indicator: Left
{{ if gt $p.TotalPages $max_links }}
<!-- Early (More Pages) Indicator. -->
{{ if gt (sub $p.PageNumber $adjacent_links) 2 }}
<li class="pages-indicator first disabled">
<span class="page-link">...</span>
</li>
{{ end }}
{{ end }}
Indicator: Right
{{ if gt $p.TotalPages $max_links }}
<!-- Late (More Pages) Indicator. -->
{{ if lt (add $p.PageNumber $adjacent_links) (sub $p.TotalPages 1) }}
<li class="pages-indicator last disabled">
<span class="page-link">...</span>
</li>
{{ end }}
{{ end }}
8: Combined Code
It is about the right time to put all the code together.
- themes/tutor-05/layouts/partials/pagination-indicator.html : gitlab.com/…/partials/pagination-indicator.html.
<nav aria-label="Page navigation">
{{ $s := .s }}
{{ $p := .p }}
{{ if gt $p.TotalPages 1 }}
<ul class="pagination justify-content-center">
<!-- Page numbers. -->
{{- $pagenumber := $p.PageNumber -}}
<!-- Number of links either side of the current page. -->
{{ $adjacent_links := 2 }}
<!-- $max_links = ($adjacent_links * 2) + 1 -->
{{ $max_links := (add (mul $adjacent_links 2) 1) }}
<!-- $lower_limit = 1 + $adjacent_links -->
{{ $lower_limit := (add 1 $adjacent_links) }}
<!-- $upper_limit = $paginator.TotalPages - $adjacent_links -->
{{ $upper_limit := (sub $p.TotalPages $adjacent_links) }}
<!-- Previous Page. -->
{{ if $p.HasPrev }}
<li class="page-item blog_previous">
<a class="page-link" href="{{ $p.Prev.URL }}" rel="prev">«</a>
</li>
{{ else }}
<li class="page-item blog_previous disabled">
<span class="page-link">«</span>
</li>
{{ end }}
{{ if gt $p.TotalPages $max_links }}
<!-- First Page. -->
{{ if gt (sub $p.PageNumber $adjacent_links) 1 }}
<li class="page-item first">
<a class="page-link" href="{{ $p.First.URL }}">1</a>
</li>
{{ end }}
<!-- Early (More Pages) Indicator. -->
{{ if gt (sub $p.PageNumber $adjacent_links) 2 }}
<li class="pages-indicator first disabled">
<span class="page-link">...</span>
</li>
{{ end }}
{{ end }}
{{- range $p.Pagers -}}
{{ $s.Set "page_number_flag" false }}
<!-- Complex page numbers. -->
{{ if gt $p.TotalPages $max_links }}
<!-- Lower limit pages. -->
<!-- If the user is on a page which is in the lower limit. -->
{{ if le $p.PageNumber $lower_limit }}
<!-- If the current loop page is less than max_links. -->
{{ if le .PageNumber $max_links }}
{{ $s.Set "page_number_flag" true }}
{{ end }}
<!-- Upper limit pages. -->
<!-- If the user is on a page which is in the upper limit. -->
{{ else if ge $p.PageNumber $upper_limit }}
<!-- If the current loop page is greater than total pages minus $max_links -->
{{ if gt .PageNumber (sub .TotalPages $max_links) }}
{{ $s.Set "page_number_flag" true }}
{{ end }}
<!-- Middle pages. -->
{{ else }}
{{ if and ( ge .PageNumber (sub $p.PageNumber $adjacent_links) ) ( le .PageNumber (add $p.PageNumber $adjacent_links) ) }}
{{ $s.Set "page_number_flag" true }}
{{ end }}
{{ end }}
<!-- Simple page numbers. -->
{{ else }}
{{ $s.Set "page_number_flag" true }}
{{ end }}
{{- if eq ($s.Get "page_number_flag") true -}}
<li class="page-item{{ if eq $pagenumber .PageNumber }} active{{ end }}">
{{ if not (eq $pagenumber .PageNumber) }}
<a href="{{ .URL }}" class="page-link">{{ .PageNumber }}</a>
{{ else }}
<span class="page-link page-item">{{ .PageNumber }}</span>
{{ end }}
</li>
{{- end -}}
{{ end }}
{{ if gt $p.TotalPages $max_links }}
<!-- Late (More Pages) Indicator. -->
{{ if lt (add $p.PageNumber $adjacent_links) (sub $p.TotalPages 1) }}
<li class="pages-indicator last disabled">
<span class="page-link">...</span>
</li>
{{ end }}
<!-- Last Page. -->
{{ if lt (add $p.PageNumber $adjacent_links) $p.TotalPages }}
<li class="page-item last">
<a class="page-link" href="{{ $p.Last.URL }}">{{ $p.TotalPages }}</a>
</li>
{{ end }}
{{ end }}
<!-- Next Page. -->
{{ if $p.HasNext }}
<li class="page-item blog_next">
<a class="page-link" href="{{ $p.Next.URL }}" rel="next">»</a>
</li>
{{ else }}
<li class="page-item blog_next disabled">
<span class="page-link">»</span>
</li>
{{ end }}
</ul>
{{ end }}
</nav>
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.
-
- themes/tutor-05/sass/css/_pagination.scss
- gitlab.com/…/sass/_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
-
- themes/tutor-05/sass/css/main.scss
- gitlab.com/…/sass/main.scss.
@import
// taken from bootstrap
"sticky-footer-navbar",
"blog",
"bootstrap-custom",
// variables
"bootstrap/functions",
"variables",
"bootstrap/variables",
"bootstrap/mixins/breakpoints",
// custom
"layout",
"decoration",
"list",
"pagination"
;
SASS: Bootstrap Grid Breakpoint Variables.
Bootstrap 4 grid breakpoints are defined as below.
- themes/tutor-05/sass/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 ?
There are, some interesting topic about Pagination in Hugo. Consider continue reading [ Hugo - Pagination - Responsive ].
Thank you for reading.