]> Witch of Git - web/blog/blob - .eleventy.js
Template improvements
[web/blog] / .eleventy.js
1 const pluginRss = require("@11ty/eleventy-plugin-rss");
2 const pluginSyntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
3 const Nunjucks = require("nunjucks");
4 const nunjucksDate = require("nunjucks-date");
5 const md = require("markdown-it")();
6
7 module.exports = (eleventyConfig) => {
8 eleventyConfig.addNunjucksFilter('date', nunjucksDate);
9 eleventyConfig.addPlugin(pluginRss);
10 eleventyConfig.addPlugin(pluginSyntaxHighlight);
11
12 eleventyConfig.addPassthroughCopy("img");
13 eleventyConfig.addPassthroughCopy("static");
14
15 eleventyConfig.addNunjucksShortcode("youtube", youtubeShortcode);
16 eleventyConfig.addPairedNunjucksShortcode("tweet", tweetShortcode);
17 eleventyConfig.addPairedShortcode("aside", asideShortcode);
18 eleventyConfig.addPairedShortcode("figure", figureShortcode);
19
20 eleventyConfig.addFilter("markdown", value => md.renderInline(value));
21 eleventyConfig.addFilter("groupby", groupbyFilter);
22
23 eleventyConfig.addCollection("years", collection => {
24 const posts = collection.getFilteredByTag("posts");
25 const items = groupby(posts, item => item.date.getFullYear());
26 return items.reduce((obj, [k, v]) => (obj[k] = v, obj), {});
27 });
28
29 return {
30 markdownTemplateEngine: "njk",
31 };
32 };
33
34 function access(item, path) {
35 const segments = path.split(".");
36 for (const seg of segments) {
37 if (item === undefined) { return null; }
38 if (seg.endsWith("()")) {
39 const method = item[seg.slice(0, -2)];
40 if (method === undefined) { return null; }
41 item = method.bind(item)();
42 } else {
43 item = item[seg];
44 }
45 }
46 return item;
47 }
48
49 function groupby(items, keyFn) {
50 const results = [];
51 for (const item of items) {
52 const key = keyFn(item);
53 if (results.length == 0 || key != results[results.length-1][0]) {
54 results.push([key, [item]]);
55 } else {
56 results[results.length-1][1].push(item);
57 }
58 }
59 return results;
60 }
61
62 function groupbyFilter(items, path) {
63 return groupby(items, item => access(item, path));
64 }
65
66 function youtubeShortcode(items, inWidth = 560, inHeight = 315) {
67 const width = items.width || inWidth;
68 const height = items.height || inHeight;
69 const allow = items.allow || "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
70 const border = items.border || "0";
71 const video = items.video || items;
72 if (!video) {
73 throw "Required argument 'video'.";
74 }
75 const src = "https://www.youtube.com/embed/" + video;
76 return `<div class="row flex-center">
77 <iframe width="${width}" height="${height}" src="${src}"
78 frameborder="${border}" allow="${allow}" allowfullscreen></iframe>
79 </div>`;
80 }
81
82 function tweetShortcode(content, items) {
83 // @TODO: Handle parsing date
84 return `<div class="row flex-center">
85 <blockquote class="twitter-tweet">
86 <p lang="en" dir="ltr">${content}</p> &mdash; ${items.name} (@${items.at})
87 <a href="${items.link}">${items.date}</a>
88 </blockquote>
89 <script async src="https://platform.twitter.com/widgets.js" charset="utf-8">
90 </script>
91 </div>`;
92 }
93
94 function asideShortcode(content, style='') {
95 const html = md.render(content);
96 if (style) {
97 return `<aside class="${style}">${html}</aside>`;
98 } else {
99 return `<aside>${html}</aside>`;
100 }
101 }
102
103 function figureShortcode(content, { src, alt }) {
104 const captionHtml = md.render(content);
105 return `<figure class="col hcenter">
106 <img src="${src}" alt="${alt}">
107 <figcaption>${captionHtml}</figcaption>
108 </figure>`;
109 }