www/eleventy.config.js

258 lines
8.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { DateTime } = require('luxon')
const fs = require('fs').promises
const path = require('path')
const pluginRss = require('@11ty/eleventy-plugin-rss')
const pluginSyntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight')
const pluginNavigation = require('@11ty/eleventy-navigation')
const markdownIt = require('markdown-it')
const markdownItAnchor = require('markdown-it-anchor')
const createHash = require('crypto').createHash
const pluginImage = require('@11ty/eleventy-img')
// Widths in pixels of responsive images to be generated
const IMAGE_SIZES = [300, 600, 900, 1200]
const dirs ={
input: '_src',
includes: '_includes',
data: '_data',
output: '_site',
}
module.exports = (eleventyConfig) => {
eleventyConfig.setServerOptions({
liveReload: false,
})
// Add plugins
eleventyConfig.addPlugin(pluginRss)
eleventyConfig.addPlugin(pluginSyntaxHighlight)
eleventyConfig.addPlugin(pluginNavigation)
// https://www.11ty.dev/docs/data-deep-merge/
eleventyConfig.setDataDeepMerge(true)
// Alias `layout: post` to `layout: layouts/post.njk`
eleventyConfig.addLayoutAlias('post', 'layouts/post.njk')
eleventyConfig.addFilter('readableDate', dateObj =>
DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat('dd LLL yyyy')
)
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
eleventyConfig.addFilter('htmlDateString', (dateObj) =>
DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat('yyyy-LL-dd')
)
// Get the first `n` elements of a collection.
eleventyConfig.addFilter('head', (array, n) =>
(n<0)? array.slice(n): array.slice(0, n)
)
// Sanitize out apostrophes
eleventyConfig.addFilter('noApostrophes', (str) =>
str.replace(/['"]+/g,'')
)
// Return the smallest number argument
eleventyConfig.addFilter('min', (...numbers) =>
Math.min.apply(null, numbers)
)
eleventyConfig.addFilter('toFixed', (num,digits) =>
num? num.toFixed(digits) : ''
)
eleventyConfig.addFilter('srintegrity', async (asset,bits=256) =>
`sha${String(bits)}-` +
createHash(`sha${String(bits)}`)
.update(await fs.readFile(`${dirs.input}${asset}`))
.digest('base64')
)
eleventyConfig.addFilter('filterCatList', cats =>
// should match the list in categories.njk
(cats || []).filter(cat => ['all','nav','post','posts'].indexOf(cat) === -1)
)
eleventyConfig.addFilter('filterTagList', tags =>
// should match the list in tags.njk
(tags || []).filter(tag => ['all','nav','post','posts'].indexOf(tag) === -1)
)
eleventyConfig.addFilter('dimsToVol', (dims) => { return {
in3: Object.values(dims.in).reduce((a,c) => a*c, 1)
} } )
// Create an array of all tags
eleventyConfig.addCollection('tagList', function(collection) {
let tagSet = new Set()
collection.getAll().forEach(item => {
(item.data.tags || []).forEach(tag => tagSet.add(tag))
});
return [...tagSet];
})
// Markdown "md" filter for nunjucks
// https://github.com/11ty/eleventy/issues/658#issuecomment-599173643
const mdFilter = new markdownIt({html:true})
eleventyConfig.addPairedShortcode('md', (content) =>
mdFilter.render(content) )
// Override Browsersync defaults (used only with --serve)
eleventyConfig.setBrowserSyncConfig({
callbacks: {
ready: function(err, browserSync) {
const content_404 = fs.readFileSync('_site/404.html')
browserSync.addMiddleware('*', (req, res) => {
// Provides the 404 content without redirect.
res.writeHead(404, {
'Content-Type': 'text/html; charset=UTF-8' })
res.write(content_404)
res.end()
});
},
},
ui: false,
ghostMode: false,
})
eleventyConfig.addPassthroughCopy('_src/assets/fonts')
eleventyConfig.addPassthroughCopy('_src/assets/base.css')
eleventyConfig.addPassthroughCopy('_src/assets/shop.css')
eleventyConfig.addPassthroughCopy('_src/assets/site.webmanifest')
eleventyConfig.addPassthroughCopy('_src/assets/scripts')
// Optimized images
// https://www.11ty.dev/docs/plugins/image/#make-your-own-markup
eleventyConfig.addShortcode('image', async (src, alt) => {
const metadata = await pluginImage(`./_src${src}`, {
widths: [...IMAGE_SIZES, 'auto'],
formats: ['auto', 'webp', 'avif'],
// https://www.11ty.dev/docs/plugins/image/#custom-filenames
filenameFormat: (id, src, width, format) =>
`${path.basename(src,path.extname(src))}-${width}w.${format}`,
// https://alexpeterhall.com/blog/2021/04/05/responsive-images-eleventy/#eleventy-configuration
urlPath: path.dirname(src),
outputDir: `_site/${path.dirname(src)}`,
})
const lowsrc = metadata.webp[0]
const highsrc = metadata.webp[metadata.webp.length - 1]
return `<a href="${src}"><picture>${Object.values(metadata).map(imageFormat =>
`\t<source type="${imageFormat[0].sourceType}" srcset="${imageFormat.map(entry => entry.srcset).join(', ')}" sizes="${IMAGE_SIZES.reverse().reduce((str,size) =>
`(max-width:${size}px) ${size}px, ${str}`,'100vw')}">`).join('')}<img src="${lowsrc.url}" width="${highsrc.width}" height="${highsrc.height}" alt="${alt}" decoding="async"></picture></a>`
})
// Video embed
eleventyConfig.addShortcode('vid', (src, autoplay=false) =>
`<video controls ${(autoplay)?'autoplay':''}width="100%"><source src="${src}" type="video/${src.split('.').pop()}">Embedded videos are not supported in this browser.</video>`
)
eleventyConfig.addShortcode('vidraw', (src) =>
`<video width="100%"><source src="${src}">Embedded videos are not supported in this browser.</video>`
)
// YouTube
eleventyConfig.addShortcode('yt', (shortcode) =>
`<iframe width="100%" height="500vh" src="https://www.youtube.com/embed/${shortcode}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`
)
// Audio embed
eleventyConfig.addShortcode('audio', (src, fmt) =>
`<audio controls><source src="${src}" type="audio/${fmt}">Embedded audio is not supported in this browser.</audio>`
)
// iFrame
eleventyConfig.addShortcode('iframe', (url, height) =>
`<iframe width="100%" height="${height}" src="${url}"</iframe>`
)
// Customize Markdown library and settings:
eleventyConfig.setLibrary("md", markdownIt({
html: true,
breaks: true,
linkify: true,
}).use(markdownItAnchor, {
permalink: markdownItAnchor.permalink.headerLink(),
level: [2, 3, 4, 5, 6],
slugify: eleventyConfig.getFilter('slugify'),
tabIndex: false,
}))
// Products and categories collections
eleventyConfig.addCollection('products', async (ca) =>
ca.getFilteredByTag('product')
)
eleventyConfig.addCollection('featured', async (ca) =>
ca.getFilteredByTags('product', 'featured')
)
eleventyConfig.addCollection('computers', async (ca) =>
ca.getFilteredByTags('product', 'computer')
)
eleventyConfig.addCollection('desktops', async (ca) =>
ca.getFilteredByTags('product', 'computer', 'desktop')
)
eleventyConfig.addCollection('laptops', async (ca) =>
ca.getFilteredByTags('product', 'computer', 'laptop')
)
eleventyConfig.addCollection('all-in-ones', async (ca) =>
ca.getFilteredByTags('product', 'computer', 'all-in-one')
)
eleventyConfig.addCollection('phones', async (ca) =>
ca.getFilteredByTags('product', 'phone')
)
eleventyConfig.addCollection('routers', async (ca) =>
ca.getFilteredByTags('product', 'router')
)
eleventyConfig.addCollection('accessories', async (ca) =>
ca.getFilteredByTags('product', 'accessory')
)
return {
// Control which files Eleventy will process
// e.g.: *.md, *.njk, *.html, *.liquid
templateFormats: [
'md',
'txt',
'njk',
'html',
'liquid',
'pdf',
'png',
'webp',
'jpg',
'svg',
'ico',
'gif',
'mp4',
],
// -----------------------------------------------------------------
// If your site deploys to a subdirectory, change `pathPrefix`.
// Dont worry about leading and trailing slashes, we normalize these.
// If you dont have a subdirectory, use '' or '/' (they do the same thing)
// This is only used for link URLs (it does not affect your file structure)
// Best paired with the `url` filter: https://www.11ty.dev/docs/filters/url/
// You can also pass this in on the command line using `--pathprefix`
// Optional (default is shown)
pathPrefix: '/',
// -----------------------------------------------------------------
// Pre-process *.md files with: (default: `liquid`)
markdownTemplateEngine: 'njk',
// Pre-process *.html files with: (default: `liquid`)
htmlTemplateEngine: 'njk',
// Opt-out of pre-processing global data JSON files: (default: `liquid`)
dataTemplateEngine: false,
// Set at top
dir: dirs,
}
}