import fs from 'node:fs'; import { env } from 'node:process'; import { eleventyImageTransformPlugin } from '@11ty/eleventy-img'; import { feedPlugin } from '@11ty/eleventy-plugin-rss'; import Image from '@11ty/eleventy-img'; import eleventyPluginCiu from '@alexcarpenter/eleventy-plugin-caniuse'; import eleventyPluginEmbedEverything from 'eleventy-plugin-embed-everything'; import eleventyPluginIcons from 'eleventy-plugin-icons'; import eleventyPluginLucideIcons from '@grimlink/eleventy-plugin-lucide-icons'; import eleventyPluginMetagen from 'eleventy-plugin-metagen'; import eleventyPluginNavigation from '@11ty/eleventy-navigation'; import eleventyPluginOgImage from 'eleventy-plugin-og-image'; import eleventyPluginReadingTime from '@myxotod/eleventy-plugin-readingtime'; import eleventyPluginRobotsTxt from 'eleventy-plugin-robotstxt'; import eleventyPluginSyntaxHighlight from '@11ty/eleventy-plugin-syntaxhighlight'; import markdownIt from 'markdown-it'; import markdownItAbbr from 'markdown-it-abbr'; import markdownItAnchor from 'markdown-it-anchor'; import markdownItCallouts from 'markdown-it-obsidian-callouts'; import markdownItCollapsible from 'markdown-it-collapsible'; import markdownItDeflist from 'markdown-it-deflist'; import markdownItFootnote from 'markdown-it-footnote'; import markdownItImageFigures from 'markdown-it-image-figures'; Image.concurrency = 4; const urlFormat = ({ src, width, format }) => { const baseUrl = `https://img.sebin-nyshkim.net/i`; const imgUuid = src.match(/\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.(\w{3,})/); const imgFormat = format === 'jpeg' ? 'jpg' : format; return `${baseUrl}/${imgUuid[1]}.${imgFormat}?width=${width}`; }; const MARKDOWNIT_OPTIONS = { html: true, linkify: true, typographer: true }; const ELEVENTY_IMAGE_DEFAULTS = { formats: ['webp', 'auto'], urlPath: '/img/', outputDir: './public/img/', urlFormat }; export default async function (eleventyConfig) { eleventyConfig.addPassthroughCopy('./src/css/prism.css'); eleventyConfig.addWatchTarget('./src/css/'); eleventyConfig.addPassthroughCopy('./src/fonts/'); eleventyConfig.addWatchTarget('./src/fonts/'); eleventyConfig.addCollection('posts', (collection) => process.env.ELEVENTY_PRODUCTION ? collection.getFilteredByGlob('./src/posts/*.md') : collection.getFilteredByGlob('./src/{posts,drafts}/*.md') ); eleventyConfig.setFrontMatterParsingOptions({ excerpt: (file) => { if (!file.data.tags) return; // immediately return if not a blog post with tags const separator = ''; const excerpt = file.content.substring(0, file.content.indexOf(separator)).trim(); file.excerpt = new markdownIt(MARKDOWNIT_OPTIONS).render(excerpt).trim(); } }); eleventyConfig.addPlugin(eleventyPluginCiu); eleventyConfig.addPlugin(eleventyPluginEmbedEverything); eleventyConfig.addPlugin(eleventyPluginIcons, { sources: [{ name: 'simple', path: 'node_modules/simple-icons/icons' }] }); eleventyConfig.addPlugin(eleventyPluginLucideIcons, { 'aria-hidden': 'true' }); eleventyConfig.addPlugin(eleventyPluginMetagen); eleventyConfig.addPlugin(eleventyPluginNavigation); eleventyConfig.addPlugin(eleventyPluginReadingTime); eleventyConfig.addPlugin(eleventyPluginRobotsTxt, { sitemapURL: 'https://blog.sebin-nyshkim.net/sitemap.xml', shouldBlockAIRobots: true, rules: new Map([['*', [{ allow: '/' }, { disallow: '/404.html' }, { disallow: '/og-images' }]]]) }); eleventyConfig.addPlugin(eleventyPluginSyntaxHighlight); eleventyConfig.addPlugin(eleventyPluginOgImage, { shortcodeOutput: async (ogImage) => { const host = env.ELEVENTY_PRODUCTION ? 'https://blog.sebin-nyshkim.net' : 'http://localhost:8080'; const src = await ogImage.outputUrl(); return ` `; }, satoriOptions: { width: 1200, height: 630, fonts: [ { name: 'Tilt Warp', data: fs.readFileSync('./src/fonts/tilt-warp/tilt-warp.ttf'), weight: 400, style: 'normal' } ] }, outputFileExtension: 'webp', sharpOptions: { quality: 100 } }); eleventyConfig.addPlugin(eleventyImageTransformPlugin, { ...ELEVENTY_IMAGE_DEFAULTS, extensions: 'html', widths: [640, 800, 1280, 1920, 2560, 3840, 'auto'], defaultAttributes: { loading: 'lazy', decoding: 'async', sizes: '(min-width: 1280px) 960px, (min-width: 1024px) 768px, (min-width: 640px) 640px, 480px' } }); eleventyConfig.addPlugin(feedPlugin, { type: 'atom', // or "rss", "json" outputPath: '/feed.xml', collection: { name: 'posts', // iterate over `collections.posts` limit: 0 // 0 means no limit }, metadata: { language: 'en', title: "Sebin's Blog", subtitle: 'Writing about stuff I have vague interests in and commenting on stuff I read.', base: 'https://blog.sebin-nyshkim.net/', author: { name: 'Sebin Nyshkim', email: '' // Optional } } }); eleventyConfig.setLibrary('md', markdownIt(MARKDOWNIT_OPTIONS)); eleventyConfig.amendLibrary('md', (mdLib) => mdLib .use(markdownItAbbr) .use(markdownItAnchor) .use(markdownItCallouts) .use(markdownItCollapsible) .use(markdownItDeflist) .use(markdownItFootnote) .use(markdownItImageFigures, { figcaption: true }) ); eleventyConfig.addShortcode('year', () => `${new Date().getFullYear()}`); eleventyConfig.addShortcode('bgimgset', async (src) => { const imgset = await Image(src, { ...ELEVENTY_IMAGE_DEFAULTS, widths: [1920, 2560, 3840], }); const getSets = ({ url, sourceType }, i) => `url(${url}) type('${sourceType}') ${i + 1}x`; return Object.values(imgset) .map((format) => format.map(getSets)) .flat(); }); eleventyConfig.addFilter('toDateObj', (dateString) => new Date(dateString)); eleventyConfig.addFilter('isoDate', (dateObj) => dateObj.toISOString()); eleventyConfig.addFilter('longDate', (dateObj) => dateObj.toString()); eleventyConfig.addFilter('readableDate', (dateObj) => dateObj.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }) ); eleventyConfig.addFilter('toHTML', (str) => new markdownIt(MARKDOWNIT_OPTIONS).render(str ? str : '')); eleventyConfig.addFilter('toPlain', (str) => (str ? str.replace(/<[^>]+>/g, '') : null)); } export const config = { dir: { input: 'src', output: 'public', layouts: 'layouts', includes: 'includes' } };