diff options
Diffstat (limited to 'src/templates.ts')
-rw-r--r-- | src/templates.ts | 290 |
1 files changed, 0 insertions, 290 deletions
diff --git a/src/templates.ts b/src/templates.ts deleted file mode 100644 index 8099065..0000000 --- a/src/templates.ts +++ /dev/null @@ -1,290 +0,0 @@ -import * as fs from "node:fs/promises"; -import * as cheerio from "cheerio"; -import { matter } from "toml-matter"; -import { Marked } from "marked"; -import { PurgeCSS } from "purgecss"; -import log from "loglevel"; - -import config from "./config"; -import { getPost, readPosts, type Post } from "./posts"; - -const css = await Bun.file("templates/style.css").text(); - -const marked = new Marked(); -marked.use({ - gfm: true, -}); - -const purgeCSS = new PurgeCSS(); - -function addMenu( - parent: cheerio.Cheerio<cheerio.AnyNode>, - child: cheerio.Cheerio<cheerio.AnyNode>, -) { - parent.empty(); - for (const link of config.menus.main) { - parent.append(child.clone().attr("href", link.url).text(link.name)); - } -} - -export async function layout( - html: string, - pageTitle: string, -): Promise<cheerio.CheerioAPI> { - const ccss = ( - await purgeCSS.purge({ - content: [ - { - raw: html, - extension: ".html", - }, - ], - css: [{ raw: css }], - }) - )[0].css; - const $ = cheerio.load(html); - $("html").attr("lang", config.default_language); - $("head > link[rel=alternate]").attr("title", config.title); - addMenu($("nav"), $("nav a")); - $(".title").text(config.title); - $("title").text(pageTitle); - $(".p-name").text(pageTitle); - $("head").children("style").text(ccss); - return $; -} - -async function render404Page(): Promise<string> { - const $ = await layout( - await fs.readFile("templates/404.html", "utf-8"), - "404 Not Found", - ); - return $.html(); -} - -async function renderHomepage(posts: Array<Post>): Promise<string> { - const file = matter(await fs.readFile("content/_index.md", "utf-8")); - const $ = await layout( - await fs.readFile("templates/homepage.html", "utf-8"), - config.title, - ); - - $("body").addClass("h-card"); - $(".title").addClass("p-name").addClass("u-url"); - $("#content").html(await marked.parse(file.content)); - const $feed = $(".h-feed"); - const $entry = $(".h-entry").remove(); - - for (const post of posts) { - const $post = $entry.clone(); - $post.find(".p-name").text(post.title); - $post.find(".u-url").attr("href", post.url); - $post - .find(".dt-published") - .attr("datetime", post.date.toISOString().replace(/\.\d{3}/, "")) - .text(post.date.toISOString().slice(0, 10)); - $post.appendTo($feed); - } - - $(".u-email").attr("href", `mailto:${config.email}`).text(config.email); - const $elsewhere = $(".elsewhere"); - const $linkRelMe = $elsewhere.find(".u-url[rel=me]").parentsUntil("ul"); - $linkRelMe.remove(); - for (const link of config.menus.me) { - const $link = $linkRelMe.clone(); - $link.find("a").attr("href", link.url).text(link.name); - $link.appendTo($elsewhere); - } - return $.html(); -} - -async function renderPost(file: Post, content: string) { - const $ = await layout( - await fs.readFile("templates/post.html", "utf-8"), - file.title, - ); - - $(".title").addClass("h-card p-author").attr("rel", "author"); - $(".h-entry .dt-published") - .attr("datetime", file.date.toISOString().replace(/\.\d{3}/, "")) - .text(file.date.toISOString().slice(0, 10)); - $(".h-entry .e-content").html(content); - const categories = $(".h-entry .p-categories"); - const cat = categories.find(".p-category").parentsUntil(categories); - cat.remove(); - for (const tag of file.taxonomies["tags"].sort()) { - categories.append( - cat - .clone() - .find(".p-category") - .attr("href", `/tags/${tag}/`) - .text(`#${tag}`) - .parent(), - ); - } - - return $.html(); -} - -async function renderListPage(tag: string, posts: Post[]) { - const $ = await layout( - await fs.readFile("templates/list.html", "utf-8"), - tag || config.title, - ); - const $feed = $(".h-feed"); - const $tpl = $(".h-entry").remove(); - $(".title").addClass("p-author h-card").attr("rel", "author"); - if (tag === "") { - $(".filter").remove(); - } else { - $(".filter").find("h3").text(`#${tag}`); - } - - for (const post of posts) { - const $post = $tpl.clone(); - $post.find(".p-name").text(post.title); - $post.find(".u-url").attr("href", post.url); - $post - .find(".dt-published") - .attr("datetime", post.date.toISOString().replace(/\.\d{3}/, "")) - .text(post.date.toISOString().slice(0, 10)); - $post.appendTo($feed); - } - return $.html(); -} - -async function renderTags(tags: string[]) { - const $ = await layout( - await fs.readFile("templates/tags.html", "utf-8"), - config.title, - ); - const $tags = $(".tags"); - const $tpl = $(".h-feed"); - $tpl.remove(); - for (const tag of tags) { - const $tag = $tpl.clone(); - $tag.find("a").attr("href", `/tags/${tag}/`).text(`#${tag}`); - $tag.appendTo($tags); - } - return $.html(); -} - -const makeTagURI = (specific: string) => - `tag:${config.original_domain},${config.domain_start_date}:${specific}`; - -async function renderFeed(title: string, posts: Post[], tag?: string) { - const $ = cheerio.load(await fs.readFile("templates/feed.xml", "utf-8"), { - xml: true, - }); - const $feed = $("feed"); - $feed.children("title").text(title); - $feed.children("link").attr("href", config.base_url); - $feed.children("id").text(makeTagURI(tag || "feed")); - $feed - .children("updated") - .text(posts[0].date.toISOString().replace(/\.\d{3}/, "")); - - const $tpl = $("feed > entry").remove(); - for (const post of posts) { - const $post = $tpl.clone(); - $post.children("title").text(post.title); - $post - .children("link") - .attr("href", new URL(post.url, config.base_url).href); - $post.children("id").text(makeTagURI(post.basename)); - $post - .children("updated") - .text(post.date.toISOString().replace(/\.\d{3}/, "")); - $post.find("author > name").text(config.title); - $post.children("summary").text(post.description || ""); - const content = marked.parse((await getPost(post.input)).content); - $post.children("content").html(await content); - $post.appendTo($feed); - } - - return $.xml(); -} - -async function renderFeedStyles() { - const $ = cheerio.load( - await fs.readFile("templates/feed-styles.xsl", "utf-8"), - { - xml: true, - }, - ); - $("style").text(css); - return $.xml(); -} - -export default async function generateSite() { - const tasks = []; - const { posts, tags } = await readPosts("content", "post", "public"); - await fs.mkdir("public/post", { recursive: true }); - for (const post of posts) { - const content = await marked.parse((await getPost(post.input)).content); - await fs.mkdir(`public/post/${post.basename}`, { recursive: true }); - tasks.push(async () => { - log.debug(`Rendering post ${post.basename} to ${post.output}`); - return fs.writeFile(post.output, await renderPost(post, content)); - }); - } - await fs.mkdir("public/tags", { recursive: true }); - tasks.push(async () => { - log.debug("Rendering tags page to public/tags/index.html"); - return fs.writeFile( - "public/tags/index.html", - await renderTags([...tags].sort()), - ); - }); - for (const tag of tags) { - log.debug(`Processing tag ${tag}`); - const matchingPosts = posts.filter((p) => - p.taxonomies["tags"].includes(tag), - ); - await fs.mkdir(`public/tags/${tag}`, { recursive: true }); - tasks.push(async () => { - log.debug(`Rendering tag ${tag} to public/tags/${tag}/index.html`); - return fs.writeFile( - `public/tags/${tag}/index.html`, - await renderListPage(tag, matchingPosts), - ); - }); - - tasks.push(async () => { - log.debug(`Rendering tag ${tag} feed to public/tags/${tag}/atom.xml`); - return fs.writeFile( - `public/tags/${tag}/atom.xml`, - await renderFeed(`${config.title} - ${tag}`, matchingPosts, tag), - ); - }); - } - tasks.push(async () => { - log.debug("Rendering posts page to public/post/index.html"); - return fs.writeFile( - "public/post/index.html", - await renderListPage("", posts), - ); - }); - tasks.push(async () => { - log.debug("Rendering site feed to public/atom.xml"); - return fs.writeFile( - "public/atom.xml", - await renderFeed(config.title, posts), - ); - }); - tasks.push(async () => { - log.debug("Rendering feed styles to public/feed-styles.xsl"); - return fs.writeFile("public/feed-styles.xsl", await renderFeedStyles()); - }); - tasks.push(async () => { - log.debug("Rendering homepage to public/index.html"); - return fs.writeFile( - "public/index.html", - await renderHomepage(posts.slice(0, 3)), - ); - }); - tasks.push(async () => { - log.debug("Rendering 404 page to public/404.html"); - return fs.writeFile("public/404.html", await render404Page()); - }); - return Promise.all(tasks.map((f) => f())); -} |