eleventy
eleventy copied to clipboard
Navigate through specific tag in double layered pagination
Trying to make blog for some creative texts, that is in style of a book with visible one page at a time.
Chapters, the tagged content, generates using @zachleat code 11ty/eleventy#332 (comment).
The problem
To get the pagination navigation am using https://www.11ty.dev/docs/pagination/nav/#put-it-all-together, but this loops through all tags (f.ex., pagination.href.first leads to mysite.com/tag1/ but pagination.href.last to mysite.com/tag3/9) . How to make the navigation to loop through a certain tag?
Git repository https://github.com/ritms/11ty-simple-book
that is in style of a book with visible one page at a time
Like in print stylesheets? In that case @maxboeck blogged about a résumé builder which might serve as inspiration. It inspired Zach at least.
Navigating through tagged content is the issue.
For next item in tag list my take <li>{% if pagination.href.next and pagination.tag.tagName == pagination.tag.tagName.next %}<a href="{{ pagination.href.next }}">Next</a> {% else %}Next{% endif %}</li> iterates through all tags.
Hi @kaviars, I got in the same situation woking on multi-level pagination or as you call it, double layered pagination (I also came up with deep pagination, but you know what I mean). So I thought I'd share my solution to this particular problem here. The solution I'm presenting is based on @zachleat code seen here #332. As you experiment, using @zachleat code as is with the built in pagination navigation will encompass all of the pages which is normal behavior since it's using a pagination of size: 1. So I decided to integrate collection specific navigation as properties. It worked well for first, previous, next and last properties, but in the end I had to retort to an extra collection for page listing (I'm more than open for improvements suggestions). Here is what it looks like:
.eleventy.js
const pagedTagsCollection = require('./_src/_includes/collections/pagedTags');
module.exports = function(config) {
config.addCollection('posts', collection => collection.getFilteredByGlob('_src/posts/*.md'));
config.addCollection('pagedTags', collection => {
return pagedTagsCollection(collection);
});
config.addCollection('pagedTagsListing', collection => {
return pagedTagsCollection(collection).reduce((accumulatorObject, currentItem) => {
const tagNameProp = currentItem.tagName;
if(!accumulatorObject[tagNameProp]) accumulatorObject[tagNameProp] = [];
accumulatorObject[tagNameProp].push(currentItem);
return accumulatorObject;
}, {});
});
}
collections/pagedTags.js
const lodashChunk = require('lodash.chunk');
module.exports = collection => {
const postsCollection = collection.getFilteredByGlob('_src/posts/*.md');
let tagSet = new Set();
postsCollection.forEach(templateObjet => {
if('tags' in templateObjet.data) {
const tagsProperty = templateObjet.data.tags;
if(Array.isArray(tagsProperty)) {
tagsProperty.forEach(tag => tagSet.add(tag));
} else if(typeof tagsProperty === 'string') {
tagSet.add(tagsProperty);
}
}
});
const pagedTags = [];
let pagedCollectionMaxIndex;
[...tagSet].forEach(tag => {
const tagCollection = collection.getFilteredByTag(tag);
const pagedCollection = lodashChunk(tagCollection, 4);
pagedCollection.forEach((templateObjectsArray, index) => {
pagedCollectionMaxIndex = index;
pagedTags.push({
tagName: tag,
path: `/tags/${tag}/${index ? (index + 1) + '/' : ''}`,
pageNumber: index,
templateObjets: templateObjectsArray
});
});
});
const pagedCollectionLength = ++pagedCollectionMaxIndex;
const groupedByTagName = lodashChunk(pagedTags, pagedCollectionLength);
groupedByTagName.forEach(group => {
group.forEach((pageObject, index, source) => {
pageObject.first = source[0].path;
pageObject.last = source[source.length - 1].path;
if(source[index - 1]) pageObject.previous = source[index - 1].path;
if(source[index + 1]) pageObject.next = source[index + 1].path;
});
});
return pagedTags;
}
Using it in a template tags.njk:
---
layout: base-layout.njk
pagination:
data: collections.pagedTags
size: 1
alias: tag
addAllPagesToCollections: true
permalink: tags/{{ tag.tagName }}/{{ (tag.pageNumber + 1) + "/" if tag.pageNumber }}
eleventyComputed:
title: "{{ tag.tagName }}-page-{{ tag.pageNumber }}"
---
{% include 'partials/tags-header.njk' %}
<hr>
<main>
<section class="post-listing">
{% for post in tag.templateObjets %}
<div class="listing-card">
<h2>{{ post.data.title }} on {{ tag.tagName }}</h2>
<a href="{{ post.url }}">Read more!</a>
</div>
{% endfor %}
</section>
<nav aria-labelledby="page-navigation">
<p id="page-navigation"><big><b>Tagged page navigation</b></big></p>
<ul>
<li>{% if page.url !== tag.first %}<a href="{{ tag.first }}">First</a>{% else %}First{% endif %}</li>
<li>{% if tag.previous %}<a href="{{ tag.previous }}">Previous</a>{% else %}Previous{% endif %}</li>
{% for item in collections.pagedTagsListing[tag.tagName] %}
<li><a href="{{ item.path }}"{% if page.url == item.path %} aria-current="page"{% endif %}>Page {{ item.pageNumber + 1 }}</a></li>
{% endfor %}
<li>{% if tag.next %}<a href="{{ tag.next }}">Next</a>{% else %}Next{% endif %}</li>
<li>{% if page.url !== tag.last %}<a href="{{ tag.last }}">Last</a>{% else %}Last{% endif %}</li>
</ul>
</nav>
<a href="/">Back to Home page</a>
</main>
I also created a live demo hosted on Netlify! I will probably use this solution in production until double layered pagination becomes a feature (or if it does). I hope this answers some of your questions. Have a good day!
I forgot, this is what the data looks like:
pagedTags
[
{
tagName: 'JavaScript',
path: '/tags/JavaScript/',
pageNumber: 0,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/JavaScript/',
last: '/tags/JavaScript/3/',
next: '/tags/JavaScript/2/'
},
{
tagName: 'JavaScript',
path: '/tags/JavaScript/2/',
pageNumber: 1,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/JavaScript/',
last: '/tags/JavaScript/3/',
previous: '/tags/JavaScript/',
next: '/tags/JavaScript/3/'
},
{
tagName: 'JavaScript',
path: '/tags/JavaScript/3/',
pageNumber: 2,
templateObjets: [ [Object], [Object] ],
first: '/tags/JavaScript/',
last: '/tags/JavaScript/3/',
previous: '/tags/JavaScript/2/'
},
{
tagName: 'GO',
path: '/tags/GO/',
pageNumber: 0,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/GO/',
last: '/tags/GO/3/',
next: '/tags/GO/2/'
},
{
tagName: 'GO',
path: '/tags/GO/2/',
pageNumber: 1,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/GO/',
last: '/tags/GO/3/',
previous: '/tags/GO/',
next: '/tags/GO/3/'
},
{
tagName: 'GO',
path: '/tags/GO/3/',
pageNumber: 2,
templateObjets: [ [Object], [Object] ],
first: '/tags/GO/',
last: '/tags/GO/3/',
previous: '/tags/GO/2/'
},
{
tagName: 'Rust',
path: '/tags/Rust/',
pageNumber: 0,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/Rust/',
last: '/tags/Rust/3/',
next: '/tags/Rust/2/'
},
{
tagName: 'Rust',
path: '/tags/Rust/2/',
pageNumber: 1,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/Rust/',
last: '/tags/Rust/3/',
previous: '/tags/Rust/',
next: '/tags/Rust/3/'
},
{
tagName: 'Rust',
path: '/tags/Rust/3/',
pageNumber: 2,
templateObjets: [ [Object], [Object] ],
first: '/tags/Rust/',
last: '/tags/Rust/3/',
previous: '/tags/Rust/2/'
},
{
tagName: 'PHP',
path: '/tags/PHP/',
pageNumber: 0,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/PHP/',
last: '/tags/PHP/3/',
next: '/tags/PHP/2/'
},
{
tagName: 'PHP',
path: '/tags/PHP/2/',
pageNumber: 1,
templateObjets: [ [Object], [Object], [Object], [Object] ],
first: '/tags/PHP/',
last: '/tags/PHP/3/',
previous: '/tags/PHP/',
next: '/tags/PHP/3/'
},
{
tagName: 'PHP',
path: '/tags/PHP/3/',
pageNumber: 2,
templateObjets: [ [Object], [Object] ],
first: '/tags/PHP/',
last: '/tags/PHP/3/',
previous: '/tags/PHP/2/'
}
]
pagedTagsListing
{
JavaScript: [
{
tagName: 'JavaScript',
path: '/tags/JavaScript/',
pageNumber: 0,
templateObjets: [Array],
first: '/tags/JavaScript/',
last: '/tags/JavaScript/3/',
next: '/tags/JavaScript/2/'
},
{
tagName: 'JavaScript',
path: '/tags/JavaScript/2/',
pageNumber: 1,
templateObjets: [Array],
first: '/tags/JavaScript/',
last: '/tags/JavaScript/3/',
previous: '/tags/JavaScript/',
next: '/tags/JavaScript/3/'
},
{
tagName: 'JavaScript',
path: '/tags/JavaScript/3/',
pageNumber: 2,
templateObjets: [Array],
first: '/tags/JavaScript/',
last: '/tags/JavaScript/3/',
previous: '/tags/JavaScript/2/'
}
],
GO: [
{
tagName: 'GO',
path: '/tags/GO/',
pageNumber: 0,
templateObjets: [Array],
first: '/tags/GO/',
last: '/tags/GO/3/',
next: '/tags/GO/2/'
},
{
tagName: 'GO',
path: '/tags/GO/2/',
pageNumber: 1,
templateObjets: [Array],
first: '/tags/GO/',
last: '/tags/GO/3/',
previous: '/tags/GO/',
next: '/tags/GO/3/'
},
{
tagName: 'GO',
path: '/tags/GO/3/',
pageNumber: 2,
templateObjets: [Array],
first: '/tags/GO/',
last: '/tags/GO/3/',
previous: '/tags/GO/2/'
}
],
Rust: [
{
tagName: 'Rust',
path: '/tags/Rust/',
pageNumber: 0,
templateObjets: [Array],
first: '/tags/Rust/',
last: '/tags/Rust/3/',
next: '/tags/Rust/2/'
},
{
tagName: 'Rust',
path: '/tags/Rust/2/',
pageNumber: 1,
templateObjets: [Array],
first: '/tags/Rust/',
last: '/tags/Rust/3/',
previous: '/tags/Rust/',
next: '/tags/Rust/3/'
},
{
tagName: 'Rust',
path: '/tags/Rust/3/',
pageNumber: 2,
templateObjets: [Array],
first: '/tags/Rust/',
last: '/tags/Rust/3/',
previous: '/tags/Rust/2/'
}
],
PHP: [
{
tagName: 'PHP',
path: '/tags/PHP/',
pageNumber: 0,
templateObjets: [Array],
first: '/tags/PHP/',
last: '/tags/PHP/3/',
next: '/tags/PHP/2/'
}
]
}
As a note, I would have rather merge the two collections into one returning an object with pagedTags under a pages key. But for some reasons pagination through collections.pagedTagsObject.pages returned an error (although it works in for loops).
I just figured out a simpler way to list pages without the need of an extra collection like this:
{% for item in collections.pagedTags %}
{% if tag.tagName === item.tagName %}
<li><a href="{{ item.path }}"{% if page.url == item.path %} aria-current="page"{% endif %}>Page {{ item.pageNumber + 1 }}</a></li>
{% endif %}
{% endfor %}
That way I can implement navigation solely with pagedTags collection and get rid of pagedTagsListing altogether!
For anyone who comes across this in the future, I found this article to be really helpful in implementing double-layered pagination: https://www.webstoemp.com/blog/basic-custom-taxonomies-with-eleventy/. Works like a charm!
#3987 is the new home base for double layer pagination!