import lume from "lume/mod.ts"; import jsx from "lume/plugins/jsx.ts"; import nav from "lume/plugins/nav.ts"; import sass from "lume/plugins/sass.ts"; import feed from "lume/plugins/feed.ts"; import code_highlight from "lume/plugins/code_highlight.ts"; import toc from "lume-markdown-plugins/toc.ts"; import footnotes from "lume-markdown-plugins/footnotes.ts"; import lang_typescript from "npm:highlight.js/lib/languages/typescript"; import lang_javascript from "npm:highlight.js/lib/languages/javascript"; import lang_bash from "npm:highlight.js/lib/languages/bash"; import { deflateSync } from "node:zlib"; const textEncoder = new TextEncoder(); const site = lume({ src: "./src", location: new URL("https://www.fosterhangdaan.com/"), }); site.ignore("README.md", "README.org", "LICENSE.txt", "LICENSE.md"); site.copy("static", "."); site.copy([ ".avif", ".jpeg", ".jpg", ".png", ".webp", ]); site.use(jsx()); site.use(nav()); site.use(sass()); site.use(feed({ query: "type=post", output: [ "/blog/feed.rss", "/blog/feed.json", ], info: { authorName: "=site.author.name", authorUrl: "=site.author.url", description: "A strange place where I write something other than code.", lang: "en", published: new Date(), title: "Foster Hangdaan's Blog", }, items: { authorName: "=author.name", authorUrl: "=author.url", description: "=description", published: "=date", title: "=title", updated: "=updated", }, })); site.use(code_highlight({ languages: { typescript: lang_typescript, javascript: lang_javascript, bash: lang_bash, }, options: { noHighlightRe: /^no-highlight$/i, languageDetectRe: /\blanguage-([\w-]+)\b/i, classPrefix: "hljs-", cssSelector: "pre code", }, })); site.use(toc({ slugify: { separator: "-", lowercase: true, }, })); site.use(footnotes()); site.process([".html"], (pages) => { pages.forEach((page) => { if (page.document) { // NOTE: This is a hack to append a class to JS doctrings so that we // can style them. If only the Hightlight.js plugin could be configured // to do this instead. for ( const codeCommentElement of page.document.getElementsByClassName( "hljs-comment", ) ) { const docStringRegex = /^\/\*\*.*\*\/$/gsm; const matchResult = codeCommentElement.textContent?.match( docStringRegex, ); if (matchResult) { codeCommentElement.classList.add("docstring"); } } /** * Convert Plantuml code to images using Kroki. */ const diagrams = page.document.getElementsByClassName( "language-plantuml", ); if (diagrams.length > 0) { for (const diagram of diagrams) { if (diagram.textContent && diagram.parentElement) { const encoded = textEncoder.encode(diagram.textContent); const compressed = deflateSync(encoded); const result = compressed.toString("base64url"); const img = page.document.createElement("img"); const url = new URL( `https://kroki.fosterhangdaan.com/plantuml/svg/${result}`, ); img.setAttribute("src", url.toString()); diagram.parentElement.replaceWith(img); } } } } }); }); export default site;