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.

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.