Lazy select-based pagination in Eleventy

I've relaunched, rebuilt and rewritten my personal blog more times than I can count and I've had a trail of posts I've never fully migrated at each turn. This weekend, while relaxing and watching movies I ported them into Eleventy and, in doing so, found that the pagination implementation I was using didn't scale well with the number of pages I added.

I quickly explored having the current page act as a floating index of sorts wherein I would cap the number of pages shown at, say, 5 and then show the previous and next two pages on either side. Limiting the rendered count in liquid.js was as simple as using the limit filter, but tracking the floating index and numbers on either side was more difficult than I would have liked.

Given that I was already iterating through all pages in my posts collection, my next thought (and the choice I ran with) was to fold all of the enumerated values into a <select> and use that to give users more control when paging. That select lives in paginator.liquid#17-28 and looks like this:

  <div class="flex flex-row items-center">
    <select
      id="pagination"
      class="block w-12 h-12 rounded-full text-white dark:text-gray-900 bg-primary-500 hover:bg-primary-500 dark:hover:bg-primary-300 mr-1 focus-visible:outline-none focus-visible:bg-primary-400 appearance-none text-center"
      style="text-align-last:center">

    </select>
    <span>
      of </span>
  </div>

When the select is changed, Javascript is executed to update the current uri to the appropriate page — that logic lives in an IIFE in base.liquid:

(function() {
    const pagination = document.getElementById('pagination');
        if (pagination) {
          pagination.addEventListener('change', (event) => {
            const page = parseInt(event.target.value)
            if (page === 1) {
              window.location.href = '/'
            } else {
              window.location.href = `/${
                event.target.value - 1
              }/`
            }
        })
    }
})()

You can see all of that rendered here.