const Image = require("@11ty/eleventy-img"); const path = require("path"); const markdownItKatex = require("@vscode/markdown-it-katex").default; function imageShortcode(src, alt, sizes = "100vw") { const inputPath = path.join("img", src); const options = { widths: [480, 800, 1200], formats: ["avif", "webp", "jpeg"], outputDir: "_site/img", urlPath: "/img/", filenameFormat: function (id, src, width, format) { const name = path.basename(src, path.extname(src)); return `${name}-${width}.${format}`; }, }; Image(inputPath, options); const metadata = Image.statsSync(inputPath, options); return Image.generateHTML(metadata, { alt, sizes, loading: "lazy", decoding: "async", }); } function heroImageShortcode(src, alt) { const inputPath = path.join("img", src); const options = { widths: [800, 1200, 1600], formats: ["avif", "webp", "jpeg"], outputDir: "_site/img", urlPath: "/img/", filenameFormat: function (id, src, width, format) { const name = path.basename(src, path.extname(src)); return `${name}-${width}.${format}`; }, }; Image(inputPath, options); const metadata = Image.statsSync(inputPath, options); return Image.generateHTML(metadata, { alt, sizes: "(max-width: 960px) 100vw, 960px", loading: "eager", decoding: "async", }); } module.exports = function (eleventyConfig) { eleventyConfig.addPassthroughCopy("css"); eleventyConfig.addPassthroughCopy("img"); eleventyConfig.addPassthroughCopy("favicon.svg"); // KaTeX: render $$...$$ at build time into static markup. Ship katex.min.css // plus its fonts/ as a sibling so the stylesheet's url(fonts/...) resolves. eleventyConfig.addPassthroughCopy({ "node_modules/katex/dist/katex.min.css": "css/katex.min.css", "node_modules/katex/dist/fonts": "css/fonts", }); eleventyConfig.amendLibrary("md", (md) => { md.use(markdownItKatex, { throwOnError: false, errorColor: "#cc0000" }); }); eleventyConfig.addShortcode("image", imageShortcode); eleventyConfig.addShortcode("heroImage", heroImageShortcode); // A "column" is anything tagged `column`, wherever it lives on disk // (some columns are authored under Notes/). Newest first. eleventyConfig.addCollection("columns", function (collectionApi) { return collectionApi .getFilteredByTag("column") .sort((a, b) => b.date - a.date); }); // The subject tags actually in use across columns — everything except the // `column` type marker and Eleventy's reserved `all`. Sorted for stable order. eleventyConfig.addCollection("subjects", function (collectionApi) { const reserved = new Set(["all", "column"]); const subjects = new Set(); for (const item of collectionApi.getFilteredByTag("column")) { for (const tag of item.data.tags || []) { if (!reserved.has(tag)) subjects.add(tag); } } return [...subjects].sort(); }); eleventyConfig.addFilter("inlineMarkdown", function (text) { return text.replace(/~~(.+?)~~/g, "$1"); }); eleventyConfig.addFilter("stripMarkdown", function (text) { return text.replace(/~~(.+?)~~/g, "$1"); }); eleventyConfig.addFilter("year", function (date) { return new Date(date).getFullYear(); }); eleventyConfig.addFilter("isoDate", function (date) { return new Date(date).toISOString().split("T")[0]; }); eleventyConfig.addFilter("readableDate", function (date) { return new Date(date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric", }); }); return { dir: { input: ".", includes: "_includes", output: "_site", }, markdownTemplateEngine: "njk", htmlTemplateEngine: "njk", }; };