Topic Pages with Eleventy’s WebC

OK, first a little bit of story time, before I dive into some code: When I started this personal website, I thought of it as a mix of notebook, portfolio, and tech playground. That has changed over the last two years, since I am keeping a daily diary with detailed notes aside from this website. This routine has helped me a ton to realize what I am actually passionate about and I would like this website to reflect that.

That being said, I am not a fan of blasting out every little thing I do and put it on this website. I sometimes enjoy consuming that sort of content from people I admire, but thinking about producing the same makes me deeply anxious. No, that’s what my note-taking routine is for! But I would like this website to become a curated digest of my daily notes that circle around a set of interests that do not change much anymore.

You want my view on film, what has shaped my personal relationship with the medium? Sure, just head over to https://stephanmax.com/film/. Well, that’s an outright lie, as the linked page has little more to offer than a short intro sentence and a list of my notes, bookmarks and subscribed feeds, but I hope you get what I am aiming for: My personal wiki page of topics that I am interested in.

Now, how to create these pages with Eleventy and its WebC template language? I found some aspects of the process to be non-trivial, so let’s walk through them.

Eleventy’s Collections and Tags

Eleventy supports grouping content as collections by using the tags key in the front matter. Great, I have been using tags that coincide with my top-level interests (think film, running, Cologne, game development, etc.) anyway, just not the collections they construct behind the scenes.

That means all I need to do as a first step is create a template that paginates over my tag collections and displays all my notes, bookmarks, and feeds for the respective tag. The Eleventy docs got you covered: Quick Tip: Zero Maintenance Tag Pages for your Blog. If that’s all you want and you are using one of the template languages the quick tip covers, you’re good.

Dynamic Permalinks and WebC

I am using WebC, though, and had no idea how to customize my permalinks. I didn’t find any documentation on it, only found other people with the same problem on GitHub.

Luckily, that pointed me into the right direction and I found a solution on GitHub under Dynamic Permalinks Silently Ignored. The trick is to use JavaScript object front matter.

 ---js 
{
  pagination: { 
    data: "collections", 
    size: 1,
    alias: "tag" 
  }, 
  permalink: ({ tag }) => `/${tag.replaceAll(" ", "-").toLowerCase()}/` 
} 
---

Dynamic Data and WebC

Now that the permalinks are correct and dynamically created, I also wanted to have more dynamic data. A dynamic title, at the minimum. The permalink attribute of the JavaScript object front matter seems to be the only one that accepts a function, though. So I had to move my front matter data into a directory data file and use eleventyComputed for title.

module.exports = {
  layout: "page",
  pagination: { 
    data: "collections",
    size: 1,
    alias: "tag",
  }, 
  permalink: ({ tag }) => `/${tag.replaceAll(" ", "-").toLowerCase()}/`,
  eleventyComputed: {
    title: (data) => data.tag
  }
}

That is not a very elaborate title and you could just use the data value tag for this. But if you want to create anything else for the title or use a layout template (like my page layout) that expects a title, that’s how you can achieve it.

Filtering Collections

The only problem left is that not all my collections are supposed to be turned into topic pages; there is an all collection provided by Eleventy, a collection for all my notes, etc. The quick tip from above covers some basic filtering/excluding, but I rather wanted to explicitly decide which tag to turn into a topic page.

Thankfully, the pagination object takes a before method with first and second argument being the pagination and full data, respectively. That allowed me to only create a topic page if the topic is listed in a global data file interests.json.

module.exports = {
  layout: "page",
  pagination: { 
    data: "collections",
    size: 1,
    alias: "tag",
    before: (pagination, { interests }) => {
      return pagination.filter(tag => !!interests[tag]);
    }
  }, 
  permalink: ({ tag }) => `/${tag.replaceAll(" ", "-").toLowerCase()}/`,
  eleventyComputed: {
    title: (data) => data.tag
  }
}

You can find the full code on Sourcehut.