Zine

Frequent Use Cases

About

This page collects common use cases that people will encounter while creating a Zine site.

As time passes new use cases will emerge as common enough to be listed here, so you might want to check back from time to time when wondering how to implement something in Zine.

Table of Contents

RSS feed

Zine doesn’t have direct knowledge of RSS feeds but by combining a handful of its features you can add support for the most syndication formats commonly used.

In this example we’ll assume that we want to generate an RSS feed for a blog.

1. Define an alternative for the post listing page

Your blog should have a page that lists all posts. We’ll generate the RSS feed as an alternative version of it.

If you think about it, this is the semantically correct thing to do, since an RSS feed is an alternative version of a page that lists your posts.

posts.smd (in the frontmatter)

---
.alternatives = [{
  .name = "rss",
  .type = "application/rss+xml",
  .layout = "rss.xml",
  .output = "index.xml",
}],
---

2. Create the XML layout

SuperHTML doesn’t support XML officially yet, but there is enough support to generate correct feeds.

This is a RSS2.0 example but you can also do the same with Atom, if you prefer.

rss.xml

<rss version="2.0">
 <channel>
  <title>My blog</title>
  <link>https://site.com/</link>
  <description>Recent content</description>
  <generator>Zine -- https://zine-ssg.io</generator>
  <language>en-us</language>
  <lastBuildDate :text="$build.generated.formatHTTP()"></lastBuildDate>
  <ctx :loop="$page.subpages()">
   <item>
    <title :text="$loop.it.title"></title>
    <link :text="$site.host_url.addPath($loop.it.link())"></link>
    <pubDate :text="$loop.it.date.formatHTTP()"></pubDate>
    <guid :text="$site.host_url.addPath($loop.it.link())"></guid>
   </item>
  </ctx>
 </channel>
</rss>

Warning

Zine at the moment is not able to render pages loaded via Scripty, which means that currently you can’t embed full articles in your RSS feed.

This limitation will be lifted in the future.

3. Link to your RSS feed

In SuperMD

Same page:

[Follow my RSS feed]($link.alternative('rss'))

Different page (see the reference docs for more variations):

[Follow my RSS feed]($link.page('other/page').alternative('rss'))

In SuperHTML

<ctx alt="$page.alternative('rss')">
  <a href="$ctx.alt.link()" type="$ctx.alt.type">
    RSS feed
  </a>
</ctx>

Advanced Prev/Next Page

It’s trivial to add prev/next navigation to a page, but what if you would like for that logic to cross site section boundaries?

More concretely, consider the following setup:

content
├── archive
│   ├── 2024
│   │   ├── first.smd
│   │   └── index.smd
│   ├── 2025
│   │   ├── index.smd
│   │   └── second.smd
│   └── index.smd
└── index.smd

In this example archive is a section that in turn contains two other sections: 2024 and 2025.

Let’s say that you want posts in each year’s archive to link to their next and previous post but also across years.

In the example above this would mean that:

  • 2024/first.smd would have 2025/second.smd at its next page
  • 2025/second.smd would have 2024/first.smd as its previous page

Here’s how you can express this in SuperHTML:


<ctx :if="$page.prevPage?()">
  <div>
    Prev:
    <a href="$if.link()" :html="$if.title"></a>
  </div>
</ctx>
<ctx :if="$page.hasPrev().not()">
  <ctx :if="$page.parentSection().prevPage?()">
    <ctx :if="$if.subpages().first?()">
      Prev:
      <a href="$if.link()" :html="$if.title"></a>
    </ctx>
  </ctx>
</ctx>
<ctx :if="$page.nextPage?()">
  <div>
    Next:
    <a href="$if.link()" :html="$if.title"></a>
  </div>
</ctx>
<ctx :if="$page.hasNext().not()">
  <ctx :if="$page.parentSection().nextPage?()">
    <ctx :if="$if.subpages().last?()">
      Next:
      <a href="$if.link()" :html="$if.title"></a>
    </ctx>
  </ctx>
</ctx>

This logic can be roughly summed up as: if there’s no {prev, next} page go up one level (parentSection()), go to the {prev, next} section, and then navigate down (subpages()) to the {first, last} page contained.