Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigate through specific tag in double layered pagination #1120

Open
kaviars opened this issue Apr 25, 2020 · 7 comments
Open

Navigate through specific tag in double layered pagination #1120

kaviars opened this issue Apr 25, 2020 · 7 comments

Comments

@kaviars
Copy link

kaviars commented Apr 25, 2020

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 #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

@kaviars kaviars changed the title Navigation for double layer pagination Navigate through specific tag in double layered pagination Apr 27, 2020
@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented May 3, 2020

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.

@kaviars
Copy link
Author

kaviars commented May 4, 2020

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.

@solution-loisir
Copy link

solution-loisir commented Dec 7, 2020

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!

@solution-loisir
Copy link

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/'
    }
  ]
}

@solution-loisir
Copy link

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).

@solution-loisir
Copy link

solution-loisir commented Dec 12, 2020

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!

@AleksandrHovhannisyan
Copy link
Contributor

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants