Update to Eleventy v3 (#11)

* feat: upgrade to v3; install eleventy-upgrade-help

* feat: convert all files to esm

* feat: remove decapcms

* fix: remove unused filter

* feat: remove netlify packages

* feat: update image handling

- removes old image shortcode
- update to latest 11ty image transform plugin

* feat: update colophon

* fix: pill style; global style

Fixes an issue with <img> inside <figure> not being centered

* feat: remove linting packages

* feat: update package.json scripts

* feat: remove upgrade helper plugin

* feat: add new button style, update nav

* feat: simplify `pill` class usage

* feat: fix tag list in catalogue-item.html

* feat: move games into their own section

* feat: update node version to latest LTS

* feat: move books to their own section

* feat: move fun pages into pages dir

* feat: update index and book/game templates

* feat: add watching section

* fix: update scaling values for buttons

* feat: various css updates

* feat: update now page style

* feat: cleaning up newer posts using old shortcode

also adding markdown-it-attrs to add attrs to various markdown elements!

* fix: movie data structure

* feat: update colophon

* fix: remove text-skew from post excerpt text

* feat: add support for shows in /watching

* fix: update book tags

* feat: add complete implementation of books pages

other stuff happened too

* fix: image border-radius

* feat: update game layout and content

* feat: reorganize watching section

* feat: add contact page

* feat: small page changes

* feat: add podroll page

* feat: reorganize content directories

* feat: exclude podcasts from page output

* chore: delete guestbook page

* chore: remove bracket syntax for css classes in html

* feat: create macro for tag list

* fix: colophon update

* chore: remove last.fm data

* chore: clean up 11ty config

* fix: misc permalink fixes

* feat: add update post

* fix: media meta grid on mobile

* fix: tables on mobile

* fix: add titles to icon button links

* fix: add missing divider for movies/shows

* feat: add alternate feeds

* fix: tag cleanup

* feat: homepage content update

* fix: game meta data

* fix: update post dates

* feat: add missing link to changelog
This commit is contained in:
Devin Haska 2025-01-27 18:23:38 -08:00 committed by GitHub
parent e28e804e12
commit 5f8227a46b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
282 changed files with 4577 additions and 5016 deletions

View file

@ -1,4 +1,6 @@
const postsByTag = (collection) => {
import dayjs from "dayjs";
export const postsByTag = (collection) => {
const posts = collection.getFilteredByTag("post");
const postsByTag = {};
@ -13,7 +15,22 @@ const postsByTag = (collection) => {
return postsByTag;
};
const catalogueByType = (collection) => {
export const collectionByTag = (collection, collectionName) => {
const items = collection.getFilteredByTag(collectionName);
const itemsByTag = {};
for (const item of items) {
for (const tag of item.data.tags) {
itemsByTag[tag] ??= [];
itemsByTag[tag].push(item);
}
}
return itemsByTag;
};
export const catalogueByType = (collection) => {
const allItems = collection.getFilteredByTag("catalogue");
const catalogueByType = {};
@ -28,8 +45,3 @@ const catalogueByType = (collection) => {
return catalogueByType;
};
module.exports = {
catalogueByType,
postsByTag,
};

View file

@ -1,9 +1,7 @@
const dir = {
export const dir = {
assets: "assets",
data: "_data",
includes: "_includes",
input: "src",
output: "dist",
};
module.exports = { dir };

View file

@ -0,0 +1,22 @@
export default {
light: {
primary: "188deg 84% 35%",
secondary: "8deg 84% 50%",
background: "0deg 0% 98%",
surface: "188deg 27% 94%",
border: "188deg 48% 80%",
text: "0deg 0% 4%",
fadeText: "188deg 12% 32%",
shadow: "188deg 100% 18%",
},
dark: {
primary: "188deg 100% 30%",
secondary: "8deg 84% 43%",
background: "0deg 0% 9%",
surface: "202deg 13% 14%",
border: "208deg 27% 15%",
text: "0deg 0% 98%",
fadeText: "188deg 12% 70%",
shadow: "188deg 100% 18%",
},
};

View file

@ -1,22 +0,0 @@
{
"light": {
"primary": "188deg 84% 35%",
"secondary": "8deg 84% 50%",
"background": "0deg 0% 98%",
"surface": "188deg 27% 94%",
"border": "188deg 48% 80%",
"text": "0deg 0% 4%",
"fadeText": "188deg 12% 32%",
"shadow": "188deg 100% 18%"
},
"dark": {
"primary": "188deg 100% 30%",
"secondary": "8deg 84% 43%",
"background": "0deg 0% 9%",
"surface": "202deg 13% 14%",
"border": "208deg 27% 15%",
"text": "0deg 0% 98%",
"fadeText": "188deg 12% 70%",
"shadow": "188deg 100% 18%"
}
}

View file

@ -0,0 +1,60 @@
export default {
display: {
family: "Anek Latin",
format: "truetype",
weights: {
ExtraBold: {
path: "/aneklatin/AnekLatin-ExtraBold.ttf",
"font-style": "normal",
weight: 800,
},
Bold: {
path: "/aneklatin/AnekLatin-Bold.ttf",
"font-style": "normal",
weight: 700,
},
},
},
body: {
family: "iA Writer Quattro V",
format: "woff2",
weights: {
Regular: {
path: "/quattro/iAWriterQuattroS-Regular.woff2",
"font-style": "normal",
weight: 400,
},
Italic: {
path: "/quattro/iAWriterQuattroS-Italic.woff2",
"font-style": "italic",
weight: 400,
},
Bold: {
path: "/quattro/iAWriterQuattroS-Bold.woff2",
"font-style": "normal",
weight: 650,
},
BoldItalic: {
path: "/quattro/iAWriterQuattroS-BoldItalic.woff2",
"font-style": "italic",
weight: 650,
},
},
},
monospace: {
family: "IBM Plex Mono",
format: "truetype",
weights: {
Regular: {
path: "/ibmplexmono/IBMPlexMono-Regular.ttf",
"font-style": "normal",
weight: 400,
},
Italic: {
path: "/ibmplexmono/IBMPlexMono-Italic.ttf",
"font-style": "italic",
weight: 400,
},
},
},
};

View file

@ -1,60 +0,0 @@
{
"display": {
"family": "Anek Latin",
"format": "truetype",
"weights": {
"ExtraBold": {
"path": "/aneklatin/AnekLatin-ExtraBold.ttf",
"font-style": "normal",
"weight": 800
},
"Bold": {
"path": "/aneklatin/AnekLatin-Bold.ttf",
"font-style": "normal",
"weight": 700
}
}
},
"body": {
"family": "iA Writer Quattro V",
"format": "woff2",
"weights": {
"Regular": {
"path": "/quattro/iAWriterQuattroS-Regular.woff2",
"font-style": "normal",
"weight": 400
},
"Italic": {
"path": "/quattro/iAWriterQuattroS-Italic.woff2",
"font-style": "italic",
"weight": 400
},
"Bold": {
"path": "/quattro/iAWriterQuattroS-Bold.woff2",
"font-style": "normal",
"weight": 650
},
"BoldItalic": {
"path": "/quattro/iAWriterQuattroS-BoldItalic.woff2",
"font-style": "italic",
"weight": 650
}
}
},
"monospace": {
"family": "IBM Plex Mono",
"format": "truetype",
"weights": {
"Regular": {
"path": "/ibmplexmono/IBMPlexMono-Regular.ttf",
"font-style": "normal",
"weight": 400
},
"Italic": {
"path": "/ibmplexmono/IBMPlexMono-Italic.ttf",
"font-style": "italic",
"weight": 400
}
}
}
}

View file

@ -0,0 +1,11 @@
export default {
0: 0,
0.25: 4,
0.5: 8,
1: 16,
1.5: 24,
2: 32,
3: 48,
4: 64,
5: 80,
};

View file

@ -1,11 +0,0 @@
{
"0": 0,
"0.25": 4,
"0.5": 8,
"1": 16,
"1.5": 24,
"2": 32,
"3": 48,
"4": 64,
"5": 80
}

View file

@ -1,19 +1,19 @@
const dayjs = require("dayjs");
const utc = require("dayjs/plugin/utc");
const advancedFormat = require("dayjs/plugin/advancedFormat");
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc.js";
import advancedFormat from "dayjs/plugin/advancedFormat.js";
const pluralizeBase = require("pluralize");
import pluralizeBase from "pluralize";
const keys = Object.keys;
const values = Object.values;
const entries = Object.entries;
export const keys = Object.keys;
export const values = Object.values;
export const entries = Object.entries;
dayjs.extend(utc);
dayjs.extend(advancedFormat);
const formatDate = (date, format) => dayjs.utc(date).format(format);
export const formatDate = (date, format) => dayjs.utc(date).format(format);
const organizeByDate = (collection) => {
export const organizeByDate = (collection) => {
const collectionByDate = {};
collection.forEach((item) => {
@ -29,15 +29,23 @@ const organizeByDate = (collection) => {
return collectionByDate;
};
const allTags = (collection, ignore = []) => {
const tagSet = new Set(collection.flatMap((item) => item.data.tags));
export const transformByDate = (collection) => {
const collectionByDate = {};
ignore.forEach((tag) => tagSet.delete(tag));
collection.forEach((item) => {
const year = formatDate(item.date, "YYYY");
return [...tagSet];
if (!collectionByDate[year]) {
return (collectionByDate[year] = { value: year, data: [item] });
}
collectionByDate[year].data.push(item);
});
return collectionByDate;
};
const allTagCounts = (collection, ignore = ["post"]) => {
export const allTagCounts = (collection, ignore = ["post"]) => {
if (!collection.length) {
throw new Error("Invalid collection, no items");
}
@ -62,28 +70,23 @@ const allTagCounts = (collection, ignore = ["post"]) => {
return tagArray;
};
const filter = (collection, filters = []) => {
export const filter = (collection, filters = []) => {
return collection.filter((item) => !filters.includes(item));
};
const pluralize = (string, count = 0) => {
export const pluralize = (string, count = 0) => {
return pluralizeBase(string, count);
};
const filterCatalogueTags = (tags) => {
// In the case of catalogue items, the 0-index is "catalogue"
// and the 1-index is the catalogueType. We don't need to
// show those in the front-end.
return filter(tags, [tags[0], tags[1]]);
export const limit = (collection, limit = 5) => collection.slice(0, limit);
export const filterFavourites = (collection) => {
return collection.filter(
(item) => item.data.favourite || item.data.isFavourite,
);
};
const limit = (collection, limit = 5) => collection.slice(0, limit);
const filterFavourites = (collection) => {
return collection.filter((item) => item.data.favourite);
};
const isOld = (dateArg) => {
export const isOld = (dateArg) => {
const date = dayjs(dateArg);
const now = dayjs();
@ -91,19 +94,3 @@ const isOld = (dateArg) => {
return diffInYears >= 2;
};
module.exports = {
allTagCounts,
allTags,
entries,
filter,
filterCatalogueTags,
filterFavourites,
formatDate,
isOld,
keys,
limit,
organizeByDate,
pluralize,
values,
};

View file

@ -1,8 +1,10 @@
const markdownIt = require("markdown-it");
const markdownItFootnote = require("markdown-it-footnote");
const markdownItPrism = require("markdown-it-prism");
const markdownItAbbr = require("markdown-it-abbr");
const markdownItAnchor = require("markdown-it-anchor");
import markdownIt from "markdown-it";
import markdownItFootnote from "markdown-it-footnote";
import markdownItPrism from "markdown-it-prism";
import markdownItAbbr from "markdown-it-abbr";
import markdownItAnchor from "markdown-it-anchor";
import markdownItImplicitFigures from "markdown-it-image-figures";
import markdownItAttrs from "markdown-it-attrs";
const markdown = markdownIt({
html: true,
@ -13,9 +15,13 @@ const markdown = markdownIt({
.use(markdownItFootnote)
.use(markdownItAbbr)
.use(markdownItAnchor)
.use(markdownItImplicitFigures, {
figcaption: true,
})
.use(markdownItPrism, {
defaultLanguage: "plaintext",
});
})
.use(markdownItAttrs);
markdown.renderer.rules.footnote_block_open = (_tokens, _idx, options) => {
return (
@ -27,4 +33,4 @@ markdown.renderer.rules.footnote_block_open = (_tokens, _idx, options) => {
);
};
module.exports = markdown;
export default markdown;

View file

@ -1,76 +0,0 @@
const Image = require("@11ty/eleventy-img");
const stringifyAttributes = (attributeMap) => {
return Object.entries(attributeMap)
.map(([attribute, value]) => {
if (typeof value === "undefined") return "";
return `${attribute}="${value}"`;
})
.join(" ");
};
const imageShortcode = async (
src,
alt = "",
caption = "",
className = undefined,
placeholder = "",
widths = [400, 800, 1280],
formats = ["webp", "jpeg"],
sizes = "100vw",
) => {
if (!src) {
return `<div class="image-placeholder">${placeholder}</div>`;
}
const metadata = await Image(src, {
widths: [...widths, null],
formats: [...formats, null],
outputDir: "dist/assets/images",
urlPath: "/assets/images",
sharpOptions: {
animated: true,
},
cacheOptions: {
duration: "7d",
},
});
const lowsrc = metadata.jpeg[metadata.jpeg.length - 1];
const imageSources = Object.values(metadata)
.map((imageFormat) => {
return ` <source type="${imageFormat[0].sourceType}" srcset="${imageFormat
.map((entry) => entry.srcset)
.join(", ")}" sizes="${sizes}">`;
})
.join("\n");
const imageAttributes = stringifyAttributes({
src: lowsrc.url,
width: lowsrc.width,
height: lowsrc.height,
alt,
loading: "lazy",
decoding: "async",
});
const imageElement = caption
? `<figure class="[ flow flex-col items-center justify-center ${className ? ` ${className} ` : ""}]">
<picture class="flex items-center justify-center">
${imageSources}
<img
${imageAttributes}>
</picture>
<figcaption>${caption}</figcaption>
</figure>`
: `<picture class="[ flex-col items-center justify-center ${className ? ` ${className} ` : ""}]">
${imageSources}
<img
${imageAttributes}>
</picture>`;
return imageElement;
};
module.exports = imageShortcode;

View file

@ -12,4 +12,4 @@ const liteYoutube = (id, label) => {
</div>`;
};
module.exports = liteYoutube;
export default liteYoutube;

View file

@ -1,6 +1,6 @@
const htmlmin = require("html-minifier-terser");
import htmlmin from "html-minifier-terser";
module.exports = (eleventyConfig) => {
export default function (eleventyConfig) {
eleventyConfig.addTransform("html-minify", (content, path) => {
if (path && path.endsWith(".html")) {
return htmlmin.minify(content, {
@ -17,4 +17,4 @@ module.exports = (eleventyConfig) => {
}
return content;
});
};
}