From ba451a6b9ba283b4c519283a45aa523662854677 Mon Sep 17 00:00:00 2001 From: Kumar Damani Date: Mon, 3 Aug 2026 12:55:54 -0400 Subject: added rss2 feed --- feed.typ | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ global/common.typ | 7 ++++--- main.typ | 2 ++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 feed.typ diff --git a/feed.typ b/feed.typ new file mode 100644 index 0000000..75639e0 --- /dev/null +++ b/feed.typ @@ -0,0 +1,54 @@ +// 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). + +#import "/global/common.typ": baseurl + +#let xml-escape(s) = s.replace("&", "&").replace("<", "<").replace(">", ">") + +// ISO date ("2026-07-28") to RFC 822 ("Tue, 28 Jul 2026 00:00:00 GMT"). +#let rfc822(iso) = { + let (y, m, d) = iso.split("-").map(int) + datetime(year: y, month: m, day: d).display( + "[weekday repr:short], [day] [month repr:short] [year] 00:00:00 GMT" + ) +} + +#let feed-xml(site-info) = { + let pages = site-info.pages + let ids = pages.keys().filter(k => k.starts-with("post/")) + + let items = () + 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" + + let lines = ( + " ", + " " + xml-escape(title) + "", + " " + url + "", + " " + url + "", + ) + if "date" in p { + lines.push(" " + rfc822(p.date) + "") + } + if "description" in p { + lines.push(" " + xml-escape(p.description) + "") + } + lines.push(" ") + items.push(lines.join("\n")) + } + + ( + "", + "", + "", + " " + xml-escape(site-info.title) + "", + " " + baseurl + "/", + " Posts from " + xml-escape(site-info.title) + " (" + baseurl + ")", + items.join("\n"), + "", + "", + "", + ).join("\n") +} diff --git a/global/common.typ b/global/common.typ index f5f5c6d..d1a0aaa 100644 --- a/global/common.typ +++ b/global/common.typ @@ -10,6 +10,7 @@ #let _asset-paths = state("asset-paths", ()) #let srcurl = "https://git.kumardamani.net/kumardamani.net" +#let baseurl = "https://kumardamani.net" // Deployment info, overwritten by CI per build: // printf '{ "date": "%s", "link": "%s" }\n' \ @@ -183,6 +184,7 @@ html.link(rel: "icon", href: base + "favicon.ico") html.elem("link", attrs: (rel: "preload", href: base + "extlink.svg", "as": "image")) html.link(rel: "stylesheet", href: base + "main.css") + html.link(rel: "alternate", type: "application/rss+xml", title: site + " RSS", href: base + "feed.xml") for ss in stylesheets { html.link(rel: "stylesheet", href: base + ss) @@ -227,10 +229,9 @@ html.main(body) html.hr() html.footer({ - html.span(class: "updated")[Updated: #ci.date.] + html.span(class: "updated")[\[Updated: #ci.date.\]] html.span(class: "logs")[ - #extlink(srcurl)[site source] | - #extlink(ci.link)[logs] for nerds! + \[For nerds: #extlink(srcurl)[site source], #extlink(ci.link)[logs], #link(base + "feed.xml")[rss]\] ] }) }) diff --git a/main.typ b/main.typ index a7f470a..e74b903 100644 --- a/main.typ +++ b/main.typ @@ -4,6 +4,7 @@ #import "/global/common.typ": * #import "/site.typ": site-info +#import "/feed.typ": feed-xml #import "/index.typ" as index-page #import "/software.typ" as software-page @@ -74,6 +75,7 @@ #asset("extlink.svg", read("/global/extlink.svg", encoding: none)) #asset("favicon.ico", read("/global/favicon.ico", encoding: none)) #asset("favicon.svg", read("/global/favicon.svg", encoding: none)) +#asset("feed.xml", bytes(feed-xml(site-info))) // image assets collected from pages via the img/fig helpers #context { -- cgit v1.2.3