Skip to content

Commit 1e2acf3

Browse files
Copilotbenkutil
andauthored
feat: Tufte 11ty theme (#94)
* Initial plan * Add Tufte 11ty theme integration with CSS and fonts Co-authored-by: benkutil <228373+benkutil@users.noreply.github.com> * Fix HTML syntax errors in shortcode templates Co-authored-by: benkutil <228373+benkutil@users.noreply.github.com> * Fix Cloudflare build by specifying Node 18 in .nvmrc Co-authored-by: benkutil <228373+benkutil@users.noreply.github.com> * Update Node version to 20 to fix undici dependency issue Co-authored-by: benkutil <228373+benkutil@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: benkutil <228373+benkutil@users.noreply.github.com>
1 parent b1b5e0d commit 1e2acf3

29 files changed

Lines changed: 2096 additions & 7 deletions

.eleventy.js

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ const pluginRss = require("@11ty/eleventy-plugin-rss");
44
const Image = require("@11ty/eleventy-img");
55
const htmlmin = require("html-minifier");
66
const outdent = require("outdent");
7+
const pluginNavigation = require("@11ty/eleventy-navigation");
8+
const pluginSyntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
9+
const markdownItAnchor = require("markdown-it-anchor");
10+
const markdownItAttrs = require("markdown-it-attrs");
11+
const pluginTOC = require("eleventy-plugin-toc");
12+
const pluginFilters = require("./_config/filters.js");
13+
const pluginShortCodes = require("./_config/shortcode.js");
714

815
/** Maps a config of attribute-value pairs to an HTML string
916
* representing those same attribute-value pairs.
@@ -83,14 +90,61 @@ const imageShortcode = async (
8390
module.exports = function (eleventyConfig) {
8491
// 11ty plugins
8592
eleventyConfig.addPlugin(pluginRss);
86-
eleventyConfig.addPlugin(Webmentions, {
87-
domain: "benkutil.com",
88-
token: process.env.WEBMENTIONS_TOKEN
93+
94+
// Only add Webmentions if token is provided
95+
if (process.env.WEBMENTIONS_TOKEN) {
96+
eleventyConfig.addPlugin(Webmentions, {
97+
domain: "benkutil.com",
98+
token: process.env.WEBMENTIONS_TOKEN
99+
});
100+
}
101+
102+
eleventyConfig.addPlugin(pluginNavigation);
103+
eleventyConfig.addPlugin(pluginSyntaxHighlight, {
104+
preAttributes: { tabindex: 0 }
105+
});
106+
eleventyConfig.addPlugin(pluginTOC, {
107+
tags: ['h2', 'h3', 'h4', 'h5'],
108+
ul: true,
109+
flat: false,
110+
wrapper: 'div'
89111
});
90112

113+
// Add Tufte filters and shortcodes
114+
eleventyConfig.addPlugin(pluginFilters);
115+
eleventyConfig.addPlugin(pluginShortCodes);
116+
91117
// 11ty shortcodes
92118
eleventyConfig.addShortcode('image', imageShortcode);
93119

120+
// Configure markdown-it
121+
const markdownIt = require("markdown-it");
122+
let options = {
123+
html: true,
124+
breaks: true,
125+
linkify: true,
126+
typographer: true,
127+
};
128+
let markdownLib = markdownIt(options).use(markdownItAttrs);
129+
eleventyConfig.setLibrary("md", markdownLib);
130+
131+
eleventyConfig.amendLibrary("md", mdLib => {
132+
mdLib.use(markdownItAnchor, {
133+
permalink: markdownItAnchor.permalink.ariaHidden({
134+
placement: "after",
135+
class: "header-anchor",
136+
symbol: "",
137+
ariaHidden: false,
138+
}),
139+
level: [1,2,3,4],
140+
slugify: eleventyConfig.getFilter("slugify")
141+
});
142+
});
143+
144+
// Pass through Tufte CSS and fonts
145+
eleventyConfig.addPassthroughCopy("src/css");
146+
eleventyConfig.addPassthroughCopy("src/et-book");
147+
94148
// run these configs in production only
95149
if (process.env.ELEVENTY_ENV === 'production') {
96150
eleventyConfig.addTransform("htmlmin", function (content, outputPath) {

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
20

Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ Personal website using [11ty](https://11ty.dev) and [Cloudflare Pages](https://p
44
## Setup
55
### Environment variables
66
- `ELEVENTY_ENV` is either `production` or `preview`. Defaults to not set.
7-
- In Cloudflare Pages, set `NODE_VERSION` to desired nodejs version. Currently set to `16.18` to match GitHub Codespace version.
7+
- Node version is set to `20` via `.nvmrc` file for compatibility with 11ty and dependencies.

_config/filters.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const { DateTime } = require("luxon");
2+
3+
module.exports = function(eleventyConfig) {
4+
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
5+
// Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens
6+
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(format || "dd LLLL yyyy");
7+
});
8+
9+
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
10+
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
11+
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat('yyyy-LL-dd');
12+
});
13+
14+
// Get the first `n` elements of a collection.
15+
eleventyConfig.addFilter("head", (array, n) => {
16+
if (!Array.isArray(array) || array.length === 0) {
17+
return [];
18+
}
19+
if (n < 0) {
20+
return array.slice(n);
21+
}
22+
23+
return array.slice(0, n);
24+
});
25+
26+
// Return the smallest number argument
27+
eleventyConfig.addFilter("min", (...numbers) => {
28+
return Math.min.apply(null, numbers);
29+
});
30+
31+
// Return the keys used in an object
32+
eleventyConfig.addFilter("getKeys", target => {
33+
return Object.keys(target);
34+
});
35+
36+
eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
37+
return (tags || []).filter(tag => ["all", "posts"].indexOf(tag) === -1);
38+
});
39+
40+
};

_config/shortcode.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module.exports = function(eleventyConfig) {
2+
eleventyConfig.addShortcode("notes",(id,content) =>`<label for="${id}" class="margin-toggle">&#8853;</label><input type="checkbox" id="${id}" class="margin-toggle"/><span class="marginnote">${content}</span>`);
3+
4+
eleventyConfig.addShortcode("notesimage",(id,image,alt,content) =>`<label for="${id}" class="margin-toggle">&#8853;</label><input type="checkbox" id="${id}" class="margin-toggle"/><span class="marginnote"><img src="${image}" alt="${alt}"/>${content}</span>`);
5+
6+
eleventyConfig.addShortcode("fullimage",(image,alt) =>`<figure class="fullwidth"><img src="${image}" width="100%" alt="${alt}"/></figure>`);
7+
8+
eleventyConfig.addShortcode("videos",(video,title) =>`<figure class="iframe-wrapper"><iframe width="100%" height="auto" src="${video}" title="${title}" frameborder="0" allowfullscreen></iframe></figure>`);
9+
10+
eleventyConfig.addShortcode("sidenote",(id,title,sidenote,content) =>`<span class="newthought">${title}<label for="sn-${id}" class="margin-toggle sidenote-number"></label></span><input type="checkbox" id="sn-${id}" class="margin-toggle"/><span class="sidenote"><a href="#sn-${id}" class="no-deco"><em>${sidenote}</em></a></span>, ${content}`);
11+
12+
eleventyConfig.addShortcode("sidenoteinternal",(id,title,sidenote,content) =>`<span class="newthought" id="sn-${id}" >${title}<label for="sn-${id}" class="margin-toggle sidenote-number"></label></span><input type="checkbox" class="margin-toggle"/><span class="sidenote"><a href="#sn-${id}" class="no-deco"><em>${sidenote}</em></a></span>, ${content}`);
13+
14+
eleventyConfig.addShortcode("sidenoteexternal",(id,title,sidenote,content,content_link,url) =>`<span class="newthought">${title}<label for="sn-${id}" class="margin-toggle sidenote-number"></label></span><input type="checkbox" id="sn-${id}" class="margin-toggle"/><span class="sidenote"><em>${sidenote}</em> <a href="${url}">${content_link}</a></span>, ${content} `);
15+
16+
eleventyConfig.addShortcode("epigraph",(content,footer) =>`<div class="epigraph"><blockquote><p>${content}</p><footer>${footer}</footer></blockquote></div>`);
17+
18+
eleventyConfig.addShortcode("blockquote",(content,footer) =>`<blockquote><p>${content}</p><footer>${footer}</footer></blockquote>`);
19+
20+
eleventyConfig.addShortcode("epigraphlink",(content,footer,info,url) =>`<div class="epigraph"><blockquote><p>${content}</p><footer>${footer} <a href="${url}">${info}</a></footer></blockquote></div>`);
21+
22+
eleventyConfig.addShortcode("blockquotelink",(content,footer,info,url) =>`<blockquote><p>${content}</p><footer>${footer} <a href="${url}">${info}</a></footer></blockquote>`);
23+
};

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@
2222
"devDependencies": {
2323
"@11ty/eleventy": "^2.0.0-beta.3",
2424
"@11ty/eleventy-img": "^3.0.0",
25+
"@11ty/eleventy-navigation": "^0.3.5",
2526
"@11ty/eleventy-plugin-rss": "^1.2.0",
27+
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
2628
"eleventy-plugin-webmentions": "^2.0.0",
2729
"html-minifier": "^4.0.0",
30+
"luxon": "^3.5.0",
31+
"markdown-it-anchor": "^9.2.0",
32+
"markdown-it-attrs": "^4.3.1",
2833
"outdent": "^0.8.0"
2934
},
3035
"dependencies": {
3136
"@11ty/eleventy-upgrade-help": "^2.0.5",
32-
"dotenv": "^16.0.3"
37+
"dotenv": "^16.0.3",
38+
"eleventy-plugin-toc": "^1.1.5"
3339
}
3440
}

src/_includes/layouts/base.njk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<link rel="webmention" href="https://webmention.io/benkutil.com/webmention" />
1818
<link rel="pingback" href="https://webmention.io/benkutil.com/xmlrpc" />
1919

20+
<!-- Tufte CSS -->
21+
<link rel="stylesheet" href="/css/tufte.css">
22+
2023
<style type="text/css">
2124
html { margin: 0; padding: 0; text-align: center; }
2225
body {

src/_includes/layouts/content.njk

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22
layout: layouts/base.njk
33
templateClass: tmpl-content
44
---
5-
{{ content | safe }}
6-
{%- set currentPostMentions = webmentions | webmentionsForPage -%}
5+
{{ content | safe }}

0 commit comments

Comments
 (0)