aboutsummaryrefslogtreecommitdiff
path: root/feed.typ
diff options
context:
space:
mode:
authorKumar Damani <me@kumardamani.net>2026-08-03 17:23:49 +0000
committerKumar Damani <me@kumardamani.net>2026-08-03 17:23:49 +0000
commit84aff405b134337ad335453f339f46bd86e7bf27 (patch)
tree4557e915ae1e2656e2c6967f46fa457a98c31fee /feed.typ
parentba451a6b9ba283b4c519283a45aa523662854677 (diff)
added atom feed
Diffstat (limited to 'feed.typ')
-rw-r--r--feed.typ63
1 files changed, 57 insertions, 6 deletions
diff --git a/feed.typ b/feed.typ
index 75639e0..3a5fd21 100644
--- a/feed.typ
+++ b/feed.typ
@@ -1,5 +1,6 @@
-// RSS 2.0 feed for the blog posts, emitted as feed.xml by main.typ.
-// Items are built from the metadata in site-info.pages (newest first).
+// RSS 2.0 and Atom feeds for the blog posts, emitted as feed.xml and
+// atom.xml by main.typ. Entries are built from the metadata in
+// site-info.pages (newest first).
#import "/global/common.typ": baseurl
@@ -13,16 +14,25 @@
)
}
-#let feed-xml(site-info) = {
+// ISO date ("2026-07-28") to RFC 3339 ("2026-07-28T00:00:00Z").
+#let rfc3339(iso) = iso + "T00:00:00Z"
+
+#let _entries(site-info, item-fn) = {
let pages = site-info.pages
let ids = pages.keys().filter(k => k.starts-with("post/"))
- let items = ()
+ let entries = ()
for id in ids {
let p = pages.at(id)
let title = if "long-title" in p { p.long-title } else { p.title }
let url = baseurl + "/" + id + ".html"
+ entries.push(item-fn(title, url, p))
+ }
+ entries
+}
+#let feed-xml(site-info) = {
+ let items = _entries(site-info, (title, url, p) => {
let lines = (
" <item>",
" <title>" + xml-escape(title) + "</title>",
@@ -36,8 +46,8 @@
lines.push(" <description>" + xml-escape(p.description) + "</description>")
}
lines.push(" </item>")
- items.push(lines.join("\n"))
- }
+ lines.join("\n")
+ })
(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
@@ -52,3 +62,44 @@
"",
).join("\n")
}
+
+// Atom (RFC 4287) feed, emitted as atom.xml by main.typ.
+#let atom-xml(site-info) = {
+ let entries = _entries(site-info, (title, url, p) => {
+ let lines = (
+ " <entry>",
+ " <title>" + xml-escape(title) + "</title>",
+ " <link href=\"" + url + "\"/>",
+ " <id>" + url + "</id>",
+ )
+ if "date" in p {
+ lines.push(" <updated>" + rfc3339(p.date) + "</updated>")
+ }
+ if "description" in p {
+ lines.push(" <summary>" + xml-escape(p.description) + "</summary>")
+ }
+ lines.push(" </entry>")
+ lines.join("\n")
+ })
+
+ // newest post first, so its date is the feed's last-update time
+ let updated = rfc3339(site-info.pages.at(
+ site-info.pages.keys().filter(k => k.starts-with("post/")).first()
+ ).date)
+
+ (
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">",
+ " <title>" + xml-escape(site-info.title) + "</title>",
+ " <link href=\"" + baseurl + "/\"/>",
+ " <link rel=\"self\" href=\"" + baseurl + "/atom.xml\"/>",
+ " <id>" + baseurl + "/</id>",
+ " <updated>" + updated + "</updated>",
+ " <author>",
+ " <name>Kumar</name>",
+ " </author>",
+ entries.join("\n"),
+ "</feed>",
+ "",
+ ).join("\n")
+}