cmc/cleberg.net

My personal web garden & blog.

clone: git clone https://gitbay.org/cmc/cleberg.net.git

42bf4bae9d582abd56758c1fcc7741419161fe7e

unsigned

author: Christian Cleberg <hello@cleberg.net> · 2026-08-11T18:51:10Z

Route blog posts through post.html

The reply-by-email and Bubbles lines were emitted from base.html behind a test
on the page's URL, because org-ssg had no way for a page to pick a layout. It
does now, so they live in a post.html that extends the shared one — the same
split weblorg has between theme/templates/base.html and post.html — selected by
a [[pages]] rule for blog/.

All 169 posts carry the footer; /blog/ itself does not, being a generated
listing rather than a post.
 content/org-ssg.toml        |  6 ++++++
 content/templates/base.html |  8 ++------
 content/templates/post.html | 11 +++++++++++
 3 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/content/org-ssg.toml b/content/org-ssg.toml
index 4edb039..ffbd179 100644
--- a/content/org-ssg.toml
+++ b/content/org-ssg.toml
@@ -34,6 +34,12 @@ pages = ["blog/index.html", "garden/index.html", "salary/index.org"]
 [templates]
 dir = "templates"
 
+# Blog posts render through post.html — the shared layout plus a reply footer — the way
+# weblorg routes them through theme/templates/post.html. Everything else uses base.html.
+[[pages]]
+match = "blog"
+template = "post.html"
+
 [highlight]
 theme = "InspiredGitHub"
 
diff --git a/content/templates/base.html b/content/templates/base.html
index c012e65..6345700 100644
--- a/content/templates/base.html
+++ b/content/templates/base.html
@@ -57,13 +57,9 @@
 {%- if page.tags %}
 <p>{% for tag in page.tags %}<a href="{{ root }}tags/{{ tag }}.html">#{{ tag }}</a> {% endfor %}</p>
 {%- endif %}
+{#- Blog posts add a reply footer inside this block; see post.html, which the
+    [[pages]] rule in org-ssg.toml selects for everything under blog/. #}
 <div>{% block content %}{{ body | safe }}{% endblock %}</div>
-{#- Blog posts carry a reply footer; other pages do not. org-ssg has no per-page
-    template selection, so the page's own URL is what tells them apart. #}
-{%- if page.url is startingwith("blog/") %}
-<div><a href="mailto:hello@cleberg.net">Reply via email &rarr;</a></div>
-<div><i>...or, comment on this post on <a href="https://bubbles.town/source/cleberg.net">Bubbles</a>!</i></div>
-{%- endif %}
 </article>
 {% endblock %}
 </main>
diff --git a/content/templates/post.html b/content/templates/post.html
new file mode 100644
index 0000000..e35ad64
--- /dev/null
+++ b/content/templates/post.html
@@ -0,0 +1,11 @@
+{# A blog post, mirroring theme/templates/post.html. Everything but the reply footer is
+   the shared layout, so this extends it rather than restating it.
+
+   Selected by the [[pages]] rule for blog/ in org-ssg.toml; a post that wants a different
+   layout says so with #+TEMPLATE:. #}
+{% extends "base.html" %}
+{% block content %}
+{{ body | safe }}
+<div><a href="mailto:hello@cleberg.net">Reply via email &rarr;</a></div>
+<div><i>...or, comment on this post on <a href="https://bubbles.town/source/cleberg.net">Bubbles</a>!</i></div>
+{% endblock %}