| 1 | const markdownIt = require("markdown-it"); |
| 2 | const { feedPlugin } = require("@11ty/eleventy-plugin-rss"); |
| 3 | |
| 4 | module.exports = function (eleventyConfig) { |
| 5 | // RSS feed of the blog, generated at build time. |
| 6 | eleventyConfig.addPlugin(feedPlugin, { |
| 7 | type: "rss", |
| 8 | outputPath: "/feed.xml", |
| 9 | collection: { name: "blog", limit: 0 }, |
| 10 | metadata: { |
| 11 | language: "en", |
| 12 | title: "Paul Campbell", |
| 13 | subtitle: "Writing from Paul Campbell.", |
| 14 | base: "https://paulca.com/", |
| 15 | author: { name: "Paul Campbell", email: "paul@rslw.com" }, |
| 16 | }, |
| 17 | }); |
| 18 | // Renders a front-matter string (e.g. a ledger prompt) as inline Markdown: |
| 19 | // links and `code` work, raw HTML stays escaped, no <p> wrapper. |
| 20 | const mdInline = markdownIt({ html: false }); |
| 21 | eleventyConfig.addFilter("mdInline", (s) => mdInline.renderInline(s || "")); |
| 22 | // Archives and site furniture, copied to the output byte-for-byte. |
| 23 | eleventyConfig.addPassthroughCopy("src/posts"); |
| 24 | eleventyConfig.addPassthroughCopy("src/microblog"); |
| 25 | eleventyConfig.addPassthroughCopy("src/assets"); |
| 26 | eleventyConfig.addPassthroughCopy("src/activity_pub"); |
| 27 | eleventyConfig.addPassthroughCopy("src/icon.png"); |
| 28 | eleventyConfig.addPassthroughCopy("src/icon.svg"); |
| 29 | eleventyConfig.addPassthroughCopy("src/CNAME"); |
| 30 | eleventyConfig.addPassthroughCopy("src/.nojekyll"); |
| 31 | |
| 32 | // "July 25, 2026" |
| 33 | eleventyConfig.addFilter("longDate", (d) => |
| 34 | new Date(d).toLocaleDateString("en-US", { |
| 35 | year: "numeric", |
| 36 | month: "long", |
| 37 | day: "numeric", |
| 38 | timeZone: "UTC", |
| 39 | }) |
| 40 | ); |
| 41 | |
| 42 | // "July 2026" |
| 43 | eleventyConfig.addFilter("monthYear", (d) => |
| 44 | new Date(d).toLocaleDateString("en-US", { |
| 45 | year: "numeric", |
| 46 | month: "long", |
| 47 | timeZone: "UTC", |
| 48 | }) |
| 49 | ); |
| 50 | |
| 51 | // Sum a numeric front-matter field across the ledger collection. |
| 52 | eleventyConfig.addFilter("total", (entries, key) => |
| 53 | entries.reduce((sum, e) => sum + (e.data[key] ?? 0), 0) |
| 54 | ); |
| 55 | |
| 56 | // FAQ entries, ordered by their two-digit filename prefix. |
| 57 | eleventyConfig.addCollection("faq", (api) => |
| 58 | api |
| 59 | .getFilteredByGlob("src/faq/*.md") |
| 60 | .sort((a, b) => a.inputPath.localeCompare(b.inputPath)) |
| 61 | ); |
| 62 | |
| 63 | eleventyConfig.addGlobalData("buildDate", () => new Date()); |
| 64 | |
| 65 | return { |
| 66 | // Only .njk and .md are processed as templates; the archived .html files |
| 67 | // under src/posts/ and src/microblog/ go through passthrough copy only. |
| 68 | templateFormats: ["njk", "md"], |
| 69 | markdownTemplateEngine: "njk", |
| 70 | htmlTemplateEngine: "njk", |
| 71 | dir: { |
| 72 | input: "src", |
| 73 | output: "docs", |
| 74 | }, |
| 75 | }; |
| 76 | }; |
| 77 | |