Compare commits

...

93 Commits

Author SHA1 Message Date
e80f340642 remove site folder
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-21 16:35:18 -07:00
4b43f76ac4 add ai declaration meta values 2026-05-21 16:33:50 -07:00
54b63df970 drone file
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-15 09:23:58 -07:00
b40f41a5f7 add submodule 2026-05-15 09:23:40 -07:00
1cf7b8560e build 2026-05-14 09:32:29 -07:00
ba5b01d084 improve copyright 2026-05-14 09:30:54 -07:00
feaaeb30b7 build 2026-05-14 09:24:37 -07:00
4af8d68ac9 add all years in footer 2026-05-14 09:19:20 -07:00
c51e5b502a gram reformat 2026-05-14 09:19:05 -07:00
6585b8e74d fix time zone issue 2026-05-14 09:18:15 -07:00
22d4c48b46 core css draft 2026-05-14 09:02:08 -07:00
18989f817f build 2026-05-14 08:57:06 -07:00
5dfaac6820 tweak sizing/margins of modal images 2026-05-14 08:56:32 -07:00
814d4efe8b build 2026-05-14 08:51:09 -07:00
0b0822d21b reorder contact page 2026-05-14 08:50:30 -07:00
f1c073535d build 2026-05-14 08:46:01 -07:00
4f0a0f3969 move tabindex setting to modal controls 2026-05-14 08:45:31 -07:00
c4b7faca88 build 2026-05-13 20:50:51 -07:00
68487ad342 tweak alpha value of close button 2026-05-13 20:50:25 -07:00
2b90da7572 build 2026-05-13 20:47:18 -07:00
58be723eef pointer for clickable images 2026-05-13 20:46:48 -07:00
72c5904c27 build 2026-05-13 20:44:22 -07:00
e615e6a91f image modals for posts 2026-05-13 20:42:31 -07:00
a56ca4c03e remove pdf link 2026-05-07 14:30:54 -07:00
9a483ad27c build 2026-05-06 11:04:35 -07:00
63e225aebc fedilearns 2026-05-06 11:04:05 -07:00
60c07e629b update fedilearns url 2026-05-05 17:27:08 -07:00
ff1fa0a966 build 2026-05-05 13:32:00 -07:00
64007ea884 add fedilearns to resume 2026-05-05 13:00:41 -07:00
1108f38939 explicit favicon setting 2026-05-05 12:57:21 -07:00
cddc20ad3d build 2026-05-04 15:39:47 -07:00
3a9095c4e8 couple small fixes: home title attr, add mising tag, move post topics up in postlist 2026-05-04 11:48:19 -07:00
914243feb9 move anchor links to aria-labelledby model 2026-05-04 08:35:44 -07:00
3f9e6727de fix page title in metadata 2026-05-04 08:21:35 -07:00
f980c8c682 switch order of heading and image 2026-05-03 21:20:24 -07:00
8104cd4520 update signal link 2026-04-21 14:31:42 -07:00
4f38bbfc82 build last 4 commits 2026-04-09 07:41:16 -07:00
56736453fe resume wording 2026-04-09 07:40:47 -07:00
c04993c983 mobile margins 2026-04-09 07:40:38 -07:00
ed3a845a55 small colophon edits 2026-04-09 07:38:06 -07:00
c8ce389065 spell things right omg 2026-04-09 07:34:56 -07:00
c95b3c080a testimonial from mari 2026-04-07 15:37:23 -07:00
c559aa9154 add testimonial 2026-04-07 10:00:40 -07:00
a14753e656 build 2026-04-06 13:27:56 -07:00
82db8f8758 beall testimonial 2026-04-06 13:27:21 -07:00
d434da450f wording 2026-04-06 13:24:22 -07:00
913f8469f3 build 2026-04-06 10:27:00 -07:00
4f12d9c5ac change how resume page is handled and add some testimonials 2026-04-06 10:26:22 -07:00
e14261bf4d fix weird spaces 2026-03-27 12:35:25 -07:00
073ad660e4 ok finishing up the blur stuff and also building 2026-03-27 12:33:35 -07:00
c6dcdacbec further reorder art shows page 2026-03-27 12:25:26 -07:00
8ab1cb687b blur adulty matieral 2026-03-27 12:23:26 -07:00
ac1903c5a1 reorder art shows page 2026-03-27 12:23:04 -07:00
bf677c3cdf add line to remove structural tags 2026-03-27 11:54:48 -07:00
8adb83d8a8 rel external for accessible image modals 2026-03-25 13:03:30 -07:00
0439f0478d build prev 2026-03-25 13:00:47 -07:00
ebe2490fd3 accessible image modals crosses fingers 2026-03-25 13:00:13 -07:00
409ca37f74 wording tweak 2026-03-25 12:50:36 -07:00
e129b26e63 build 2026-03-24 10:38:18 -07:00
dc49b1cad5 update contact page 2026-03-24 10:37:53 -07:00
21e3dca187 build last two commits 2026-03-24 10:11:20 -07:00
ff9eb09838 update headers to use code blocks again now that i fixed that 2026-03-24 10:10:57 -07:00
ce6aa0fb00 tweak heading anchor styling 2026-03-24 10:10:16 -07:00
f89f135f9b build prev and add draft handling 2026-03-24 09:58:14 -07:00
422a0e45e8 format on save plus: 1) update spoonfairies URL 2) remove 11ty Lessons link 2026-03-24 09:50:14 -07:00
191ee1a355 make code blocks responsive to containing block font size 2026-03-23 15:32:27 -07:00
43ccb40e0b update resume page with gryphon's roost 2026-03-19 15:03:42 -07:00
b5aff7207e sitemap styling 2026-03-18 11:11:11 -07:00
aa9951e68d build 2026-03-12 11:52:52 -07:00
35519d9d4b remove anchor from related posts section 2026-03-12 11:52:24 -07:00
43ae5c489e rename script 2026-03-07 10:31:53 -08:00
b51e953a1b fix date zone 2026-03-02 07:49:22 -08:00
0e14d3ca72 build prev 2026-03-01 14:41:07 -08:00
50d4b61037 jesus h christ 2026-03-01 14:40:42 -08:00
73a0278392 update resume with freelance work 2026-02-25 18:10:11 -08:00
b241cc14af move 11ty lessons on resume page 2026-02-25 14:37:31 -08:00
98c00bb1fd robots txt 2026-02-25 14:25:33 -08:00
bfefa33f13 exclude tag redirect pages from sitemap 2026-02-21 13:11:30 -08:00
89ff36afc7 build prev 2026-02-21 13:09:59 -08:00
afbf693d3b redirects for the old tag urls 2026-02-21 13:09:15 -08:00
a3ba14abd2 build prev 2026-02-21 12:23:40 -08:00
e45e9b0f7a remove anchors from related posts 2026-02-21 12:23:05 -08:00
3e61e004f4 add space above footer 2026-02-20 19:22:14 -08:00
58a412f002 build now 2026-02-20 14:35:54 -08:00
64db3a2446 FAVICON 2026-02-20 14:35:32 -08:00
a03a1b6c52 update beall greenhouses url 2026-02-20 14:12:22 -08:00
7f5dc28cad remove excess note 2026-02-20 13:15:09 -08:00
7e95d9ff16 build prev 2026-02-20 12:24:10 -08:00
6e3bfd9a08 fix some accessibilty issues 2026-02-20 12:23:36 -08:00
ae056c75bd built with last change 2026-02-20 12:01:30 -08:00
5c786b15d2 remove redundant text 2026-02-20 11:59:29 -08:00
2c3711fe1e woops 2026-02-20 11:57:19 -08:00
f18e2f2078 woops i forgot the lang attribute lmao 2026-02-20 11:53:41 -08:00
509 changed files with 1446 additions and 379293 deletions

25
.drone.yml Normal file
View File

@ -0,0 +1,25 @@
kind: pipeline
type: docker
name: default
steps:
- name: build
image: node:current
environment:
REPOSITORY: leecat.art-site
GIT_USER: inherentlee
GIT_TOKEN:
from_secret: GIT_TOKEN
commands:
- git config credential.helper '!f() { echo username=$GIT_USER; echo "password=$GIT_TOKEN"; };f'
- git submodule update --remote --init --merge
- npm install
- npm run build
- apt-get update && apt-get install -y rsync
- rsync -uavh _site/ $REPOSITORY --delete --exclude .git
- cd $REPOSITORY
- git checkout main
- git config --global --add safe.directory /drone/src/$REPOSITORY
- git add -A
- git commit -m "drone build $(TZ=':America/Los_Angeles' date)"
- git push

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "leecat.art-site"]
path = leecat.art-site
url = https://heckin.technology/inherentlee/leecat.art-site.git

View File

@ -2,4 +2,14 @@
Lee Cattarin's personal website, v2. Built on Eleventy.
Not live yet.
## Pulling from git repo with NPM
Apparently this works differently in WSL vs Linux? Fuck me, I guess.
### WSL2
> "@zachleat/heading-anchors": "https://github.com/lee0c/heading-anchors/tarball/main",
### Linux
> "@zachleat/heading-anchors": "github:lee0c/heading-anchors"

View File

@ -1,73 +1,92 @@
import { DateTime } from "luxon";
export default function(eleventyConfig) {
export default function (eleventyConfig) {
// Return the keys used in an object
eleventyConfig.addFilter("getKeys", target => {
eleventyConfig.addFilter("getKeys", (target) => {
return Object.keys(target);
});
/* Exclude all posts with given URLs from a collection list */
eleventyConfig.addFilter("excludeFromCollection", function (collection=[], urls=[this.ctx.page.url]) {
return collection.filter(post => urls.indexOf(post.url) === -1);
});
eleventyConfig.addFilter(
"excludeFromCollection",
function (collection = [], urls = [this.ctx.page.url]) {
return collection.filter((post) => urls.indexOf(post.url) === -1);
},
);
/* Filter a collection by a set of tags, returning any that share one or more tags */
eleventyConfig.addFilter("filterByTags", function(collection=[], ...requiredTags) {
return collection.filter(post => {
return requiredTags.flat().some(tag => post.data.tags.includes(tag));
});
});
eleventyConfig.addFilter(
"filterByTags",
function (collection = [], ...requiredTags) {
return collection.filter((post) => {
return requiredTags.flat().some((tag) => post.data.tags.includes(tag));
});
},
);
/* Return n elements from a list */
eleventyConfig.addFilter("head", (collection=[], n) => {
if(!Array.isArray(collection) || collection.length === 0) {
eleventyConfig.addFilter("head", (collection = [], n) => {
if (!Array.isArray(collection) || collection.length === 0) {
return [];
}
if( n < 0 ) {
if (n < 0) {
return collection.slice(n);
}
return collection.slice(0, n);
});
/* For <time> elements */
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat('yyyy-LL-dd');
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat("yyyy-LL-dd");
});
/* What it says on the tin */
eleventyConfig.addFilter("randomize", function(array) {
eleventyConfig.addFilter("randomize", function (array) {
// Create a copy of the array to avoid modifying the original
let shuffledArray = array.slice();
// Fisher-Yates shuffle algorithm
for (let i = shuffledArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [
shuffledArray[j],
shuffledArray[i],
];
}
return shuffledArray;
});
/* Human-readable dates */
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" })
.toLocaleString(DateTime.DATE_FULL);
eleventyConfig.addFilter("readableDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toLocaleString(
DateTime.DATE_FULL,
);
});
/* Filter out structural tags */
eleventyConfig.addFilter("removeBasicTags", (tags) => {
return tags.filter(tag => ["all", "posts", "gallery", "reference", "tagPagination"].indexOf(tag) === -1);
return tags.filter(
(tag) =>
[
"all",
"posts",
"gallery",
"reference",
"tagPagination",
"blur",
].indexOf(tag) === -1,
);
});
/* What it says on the tin */
eleventyConfig.addFilter("sortAlphabetically", strings =>
(strings || []).sort((b, a) => b.localeCompare(a))
eleventyConfig.addFilter("sortAlphabetically", (strings) =>
(strings || []).sort((b, a) => b.localeCompare(a)),
);
/* Remove year from image filenames for OG metadata file path */
eleventyConfig.addFilter("toOgFilename", (filename) => {
return filename.split("/")[1];
});
};
}

View File

@ -1,7 +1,7 @@
<footer>
<ul>
<li>
<a href="/colophon" title="colophon" aria-label="colophon"
<a href="/colophon/"
{% if page.url == "/colophon/" %}aria-current="page"{% endif %}>
colophon
</a>
@ -9,9 +9,9 @@
<li>
<a href="/" title="go home"
aria-label="go home | {{ metadata.title }} from {{ metadata.author }} in 2026"
aria-label="go home | {{ metadata.title }} from {{ metadata.author }}, copyright 2022-2026"
{% if page.url == "/" %}aria-current="page"{% endif %}>
{{ metadata.title }} from {{ metadata.author }} in 2026</a>
{{ metadata.title }} from {{ metadata.author }}, © 2022-2026</a>
</li>
<li>

View File

@ -0,0 +1,39 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
{% set pageTitle %}{{ title }} | {{ metadata.title }}{% endset %}
<title>{{ pageTitle }}</title>
<meta name="description" content="{{ description or metadata.description }}">
<link rel="alternate" href="/feed.xml" type="application/atom+xml" title="{{ metadata.title }}">
<meta property="og:title" content="{{ pageTitle }}" />
<meta property="og:type" content="website" />
<meta property="og:description" content="{{ description or metadata.description }}" />
<meta property="og:site_name" content="{{ metadata.title }}" />
{% if image %}
<meta property="og:image" content="/img/{{ image.src | toOgFilename }}" />
<meta property="og:image:alt" content="{{ image.alt }}" />
{% endif %}
<meta name="generator" content="{{ eleventy.generator }}">
<meta itemprop="ai-content-declaration:version" content="1.0.0">
<meta itemprop="ai-content-declaration:level" content="none">
{# Fonts #}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Mono:ital,wght@0,200..800;1,200..800&family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
{# Icons #}
<script src="https://kit.fontawesome.com/884dded219.js" crossorigin="anonymous"></script>
{# Styles #}
<style>{% include "css/main.css" %}</style>
<style>{% include "css/nav.css" %}</style>
<style>{% include "css/print.css" %}</style>
<style>{% getBundle "css" %}</style>
<script type="module">{% getBundle "js" %}</script>

View File

@ -1,6 +1,6 @@
<header>
<a href="#main" id="skip" title="skip to main content" aria-label="skip to main content">
<a href="#main" id="skip" title="skip to main content">
<i class="fa-solid fa-forward" aria-hidden="true"></i> skip
</a>
@ -9,8 +9,7 @@
{% for entry in collections.all | eleventyNavigation %}
<li>
<a href="{{ entry.url }}" title="{{ entry.data.label }}"
{% if entry.url == page.url %}aria-current="page"{% endif %}
aria-label="{{ entry.data.label }}">
{% if entry.url == page.url %}aria-current="page"{% endif %}>
<i class="{{ entry.data.icon }}" aria-hidden="true"></i>
<span class="menu-text">{{ entry.title }}</span>
</a>

View File

@ -1,49 +1,17 @@
<!doctype html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<html lang="en">
<head>
{% include "head-content.njk" %}
</head>
<body>
{% include "header.njk" %}
{% set pageTitle %}{{ title }} | {{ metadata.title }}{% endset %}
<title>{{ pageTitle }}</title>
<meta name="description" content="{{ description or metadata.description }}">
<link rel="alternate" href="/feed.xml" type="application/atom+xml" title="{{ metadata.title }}">
<main id="main">
{{ content | safe }}
</main>
<meta property="og:title" content="{{ title or metadata.title }}" />
<meta property="og:type" content="website" />
<meta property="og:description" content="{{ description or metadata.description }}" />
<meta property="og:site_name" content="{{ metadata.title }}" />
{% if image %}
<meta property="og:image" content="/img/{{ image.src | toOgFilename }}" />
<meta property="og:image:alt" content="{{ image.alt }}" />
{% endif %}
{% include "footer.njk" %}
<meta name="generator" content="{{ eleventy.generator }}">
{# Fonts #}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Mono:ital,wght@0,200..800;1,200..800&family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
{# Icons #}
<script src="https://kit.fontawesome.com/884dded219.js" crossorigin="anonymous"></script>
{# Styles #}
<style>{% include "css/main.css" %}</style>
<style>{% include "css/nav.css" %}</style>
<style>{% include "css/print.css" %}</style>
<style>{% getBundle "css" %}</style>
<script type="module">{% getBundle "js" %}</script>
</head>
<body>
{% include "header.njk" %}
<main id="main">
{{ content | safe }}
</main>
{% include "footer.njk" %}
<!-- This page `{{ page.url }}` was built on {% currentBuildDate %} -->
<body>
<!-- This page `{{ page.url }}` was built on {% currentBuildDate %} -->
</body>
</html>

View File

@ -4,7 +4,9 @@ layout: base.njk
{% css %}{% include "css/post.css" %}{% endcss %}
{% css %}{% include "css/highlighting.css" %}{% endcss %}
{% css %}{% include "css/lists.css" %}{% endcss %}
{% css %}{% include "css/modal.css" %}{% endcss %}
{% js %}{% include "node_modules/@zachleat/heading-anchors/heading-anchors.js" %}{% endjs %}
{% js %}{% include "js/modal.js" %}{% endjs %}
<heading-anchors content="<i class='fa-solid fa-anchor'></i>">
<article>
@ -30,7 +32,11 @@ layout: base.njk
</div>
{% if image %}
<img src="/img/{{ image.src }}" alt="{{ image.alt }}">
<dialog closedby="any" aria-label="image modal" tabindex="-1">
<button class="close-dialog" autofocus aria-label="close the image modal">&times;</button>
<img class="modal-img" src="/img/{{ image.src }}" alt="{{ image.alt }}">
</dialog>
<img class="hero" src="/img/{{ image.src }}" alt="{{ image.alt }}">
{% endif %}
{{ content | safe }}
@ -51,7 +57,7 @@ layout: base.njk
{% set postlist = collections.posts | filterByTags(relevantTags) | excludeFromCollection([page.url, olderHref, newerHref]) | randomize | head(3) %}
{% if postlist.length %}
<section class="related-posts">
<h2>related posts</h2>
<h2 data-ha-exclude>related posts</h2>
{% include "postlist.njk" %}
</section>
{% endif %}

View File

@ -1,6 +0,0 @@
---
layout: base.njk
---
{% css %}{% include "css/resume.css" %}{% endcss %}
{{ content | safe }}

View File

@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
{% include "head-content.njk" %}
<meta http-equiv="refresh" content="0; url=/tags/{{ tag }}">
</head>
<body>
{% include "header.njk" %}
<main id="main">
<h1>{{ title }}</h1>
{{ content | safe }}
</main>
{% include "footer.njk" %}
<!-- This page `{{ page.url }}` was built on {% currentBuildDate %} -->
<body>
</html>

View File

@ -1,16 +1,17 @@
<ol id="postlist">
{% for post in postlist %}
<li class="post">
<li class="post">
<a class="postlink" href="{{ post.url }}">
<h2 data-ha-exclude>{{ post.data.title }} {% if "blur" in post.data.tags %}(mature){% endif %}</h2>
{% if post.data.image %}
<img src="/img/{{ post.data.image.src }}" alt="{{ post.data.image.alt }}">
{% endif %}
<h2>{{ post.data.title }}</h2>
<ul class="postlist-tags">
{% for tag in post.data.tags | removeBasicTags %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
<img src="/img/{{ post.data.image.src }}" alt="{{ post.data.image.alt }}"
{% if "blur" in post.data.tags %}class="blur"{% endif %}>
{% endif %}
</a>
</li>
{% endfor %}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,436 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title>hello hello</title>
<subtitle>Lee Cattarin... on the internet!</subtitle>
<link href="https://leecat.art/feed.xml" rel="self" />
<link href="https://leecat.art/" />
<updated>2026-02-19T00:00:00Z</updated>
<id>https://leecat.art/</id>
<author>
<name>Lee Cattarin</name>
<email>lee.cattarin@gmail.com</email>
</author>
<entry>
<title>eleventy lessons</title>
<link href="https://leecat.art/eleventy-lessons/" />
<updated>2026-02-19T00:00:00Z</updated>
<id>https://leecat.art/eleventy-lessons/</id>
<content type="html">&lt;p&gt;recently I wrote &lt;em&gt;several&lt;/em&gt; sites using &lt;a href=&quot;https://www.11ty.dev/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Eleventy&lt;/a&gt; (4? 5?). Including, over the past few days, rewriting this one! That&#39;s right, if you&#39;re reading this, we&#39;re now running on 11ty and hosted by &lt;a href=&quot;https://heckin.technology/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;heckin.technology&lt;/a&gt;. See ya, GitHub. Won&#39;t miss ya.&lt;/p&gt;
&lt;p&gt;I&#39;ve compiled some of the things I&#39;ve learned in a standalone site: &lt;a href=&quot;https://inherentlee.codeberg.page/lessons/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;11ty Lessons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;however, since I don&#39;t know how much I&#39;ll focus on that specific site - it is mostly a sample - I am re-publishing the most useful information here. I&#39;ll skip the intro to Markdown content. I&#39;m also going to update them where I&#39;ve learned more or to better match what&#39;s represented on this site.&lt;/p&gt;
&lt;p&gt;this will comprise of 4 parts: &lt;a href=&quot;https://leecat.art/eleventy-lessons/#related-posts&quot;&gt;related posts&lt;/a&gt;, &lt;a href=&quot;https://leecat.art/eleventy-lessons/#featured-images&quot;&gt;featured images&lt;/a&gt;, &lt;a href=&quot;https://leecat.art/eleventy-lessons/#pagination&quot;&gt;pagination&lt;/a&gt;, and &lt;a href=&quot;https://leecat.art/eleventy-lessons/#tag-image-preview&quot;&gt;tag image preview&lt;/a&gt;. Feel free to jump ahead, as none depend on the others.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;related-posts&quot;&gt;related posts&lt;/h2&gt;
&lt;p&gt;by default, the &lt;a href=&quot;https://leecat.art/eleventy-lessons/github.com/11ty/eleventy-base-blog&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Eleventy base blog&lt;/a&gt; comes with pagination between posts. Post 2 can take you to posts 1 and 3, etc.&lt;/p&gt;
&lt;p&gt;while that is useful for &lt;em&gt;this&lt;/em&gt; site, when building another site I wanted to see a couple randomly-suggested posts that shared 1 or more tags.&lt;/p&gt;
&lt;p&gt;I started by referring to &lt;a href=&quot;https://github.com/11ty/eleventy/discussions/2534&quot; target=&quot;_blank rel=external&amp;quot;&quot;&gt;this GitHub issue about related posts&lt;/a&gt;. I had to fix a few errors that arose from the suggested code.&lt;/p&gt;
&lt;p&gt;I also wanted to make three changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I didn&#39;t want to just see posts that shared &lt;em&gt;all&lt;/em&gt; tags, but rather posts that shared &lt;em&gt;any&lt;/em&gt; tag&lt;/li&gt;
&lt;li&gt;I wanted to randomly add a few posts instead of just getting whatever was first (with a shared tag) in the post order&lt;/li&gt;
&lt;li&gt;I wanted to exclude the posts that I could reach with between-post pagination&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;filters-js&quot;&gt;filters.js&lt;/h3&gt;
&lt;p&gt;after adjusting for those needs, I had the following in &lt;code&gt;filters.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;excludeFromCollection&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;collection&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; urls&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; urls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;filterByTags&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;collection&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;requiredTags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; requiredTags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;randomize&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Create a copy of the array to avoid modifying the original&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; shuffledArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Fisher-Yates shuffle algorithm&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; shuffledArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;shuffledArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shuffledArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;shuffledArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shuffledArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; shuffledArray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;post-njk&quot;&gt;post.njk&lt;/h3&gt;
&lt;p&gt;I used this in my post layout. &lt;code&gt;filterTagList&lt;/code&gt; comes with the base blog by default, and removes the tags &amp;quot;posts&amp;quot; and &amp;quot;all.&amp;quot; &lt;code&gt;head&lt;/code&gt; also comes with the base blog. &lt;code&gt;postlist.njk&lt;/code&gt; is my modified-from-the-base-blog post layout.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;{% set relevantTags = tags | filterTagList %}
{% set olderPost = collections.posts | getPreviousCollectionItem %}
{% set newerPost = collections.posts | getNextCollectionItem %}
{% set urlsToExclude = [page.url, olderPost.url, newerPost.url]}
{% set postlist = collections.posts | filterByTags(relevantTags) | excludeFromCollection(urlsToExclude) | randomize | head(3) %}
{% if postlist.length %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;related-posts&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;related posts&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% include &quot;postlist.njk&quot; %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and that sorts related posts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;featured-images&quot;&gt;featured images&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;this one&#39;s been edited from the lessons site. I&#39;ve learned a bit more about 11ty images and feel more comfortable with my build now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;images in 11ty use the &lt;a href=&quot;https://www.11ty.dev/docs/plugins/image/#eleventy-transform&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Image Transform Plugin&lt;/a&gt;. I found it hard to find anything to reference while building this - a lot of sites in the template gallery are either text-heavy or not using the plugin - so I&#39;m reproducing what I&#39;ve got here for reference.&lt;/p&gt;
&lt;h3 id=&quot;file-structure&quot;&gt;file structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;content/
|--img/
| |--sample-0.jpg
| |--sample-1.jpg
| `--etc
|--posts/
| |--lesson-0-front-matter-and-urls.md
| |--lesson-1-headings-paragraphs-and-horizontal-lines.md
| `--etc
`--etc
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;front-matter&quot;&gt;front matter&lt;/h3&gt;
&lt;p&gt;for any given post, my front matter references the image in this manner:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
image:
src: sample-0.jpg
alt: moss on a fencepost
---
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;image-html-transform&quot;&gt;image HTML transform&lt;/h3&gt;
&lt;p&gt;As mentioned, there&#39;s a plugin for images. If you started with the base blog, in &lt;code&gt;eleventy.config.js&lt;/code&gt;, you&#39;ll probably find a chunk of code similar to this already in place:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;eleventyImageTransformPlugin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;formats&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;widths&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;640&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;failOnError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;htmlOptions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;imgAttributes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// e.g. &amp;lt;img loading decoding&gt; assigned on the HTML tag will override these values.&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lazy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;decoding&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;async&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;sharpOptions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;animated&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;setting &lt;code&gt;formats&lt;/code&gt; to &amp;quot;auto&amp;quot; helps - use whatever type of image you want, get that type out. The default settings that came with the Eleventy base blog didn&#39;t set a &lt;code&gt;width&lt;/code&gt;, which I wanted (by default, images off my camera - like the hellebore featured image for this post - are almost 5k pixels wide). I also found it helpful to set &lt;code&gt;failOnError&lt;/code&gt; to true for a little more feedback.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: It sure seems like Eleventy will fail your image processing if there&#39;s no alt text. While admirable, it would be nice if I could find any documentation for this!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;passthrough-copy&quot;&gt;passthrough copy&lt;/h3&gt;
&lt;p&gt;as I worked through this, I thought I needed a passthrough copy for a while. You don&#39;t - just let the plugin do its thing.&lt;/p&gt;
&lt;h3 id=&quot;templating&quot;&gt;templating&lt;/h3&gt;
&lt;p&gt;I needed images to show up in 3 places:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the lists of posts on the home page, I wanted each post to show its featured image&lt;/li&gt;
&lt;li&gt;In the &amp;quot;related posts&amp;quot; section on each individual post, I wanted each related post to show its featured image&lt;/li&gt;
&lt;li&gt;And of course, I wanted the post to show its own featured image&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;home-page-and-related-posts&quot;&gt;home page and related posts&lt;/h3&gt;
&lt;p&gt;both of these sections use the same template, which in my setup is called &lt;code&gt;postlist.njk&lt;/code&gt;. Within the relevant links, I added the following:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;{% if post.data.image.src %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/{{ post.data.image.src }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ post.data.image.alt }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% else %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;missing-image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;post-body&quot;&gt;post body&lt;/h3&gt;
&lt;p&gt;the post body looks similar:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;{% if image.src %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;featured-img&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/posts/img/{{ image.src }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ image.alt }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;together, that sets up featured images for posts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pagination&quot;&gt;pagination&lt;/h2&gt;
&lt;h3 id=&quot;simple-pagination&quot;&gt;simple pagination&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.11ty.dev/docs/pagination/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Post pagination in Eleventy is pretty straightforward&lt;/a&gt;, mostly requiring some specific front matter.&lt;/p&gt;
&lt;p&gt;The home page pagination I have set up here looks like the following (in &lt;code&gt;index.njk&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
pagination:
data: collections.posts
size: 13
alias: posts
reverse: true
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;6 posts per page, paginate data from &lt;code&gt;collections.posts&lt;/code&gt; which we&#39;ll call just &lt;code&gt;posts&lt;/code&gt; for short, and do it in reverse (aka, most recent posts show first).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.11ty.dev/docs/pagination/nav&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;You&#39;ll also likely want previous and next buttons&lt;/a&gt;. I did. Here&#39;s what I have...&lt;/p&gt;
&lt;h4 id=&quot;pagination-njk&quot;&gt;pagination.njk&lt;/h4&gt;
&lt;p&gt;There&#39;s two components to this, the bigger one being this &lt;code&gt;pagination.njk&lt;/code&gt; template. Look, I like my little icons, ok? It takes an &lt;code&gt;olderHref&lt;/code&gt; and a &lt;code&gt;newerHref&lt;/code&gt;, and optionally an &lt;code&gt;olderTitle&lt;/code&gt; and &lt;code&gt;newerTitle&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;{% if olderHref or newerHref %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;pagination&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;pagination {% if inPost %}post-pagination{% endif %}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% if olderHref %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;older&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ olderHref }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;i&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fa-solid fa-hand-point-left&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{{ olderTitle or &quot;older&quot; }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}
{% if newerHref %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;newer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ newerHref }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{{ newerTitle or &quot;newer&quot; }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;i&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fa-solid fa-hand-point-right&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-hidden&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;calling-the-template&quot;&gt;calling the template&lt;/h4&gt;
&lt;p&gt;From &lt;code&gt;index.njk&lt;/code&gt; we can &lt;code&gt;include &amp;quot;pagination.njk&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{# idk why these are backwards either #}
{% set newerHref = pagination.href.previous %}
{% set olderHref = pagination.href.next %}
{% include &amp;quot;pagination.njk&amp;quot; %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yup. The order of previous vs. next is totally unintuitive to me, too.&lt;/p&gt;
&lt;h3 id=&quot;complex-pagination&quot;&gt;complex pagination&lt;/h3&gt;
&lt;p&gt;however, there&#39;s a catch. &lt;a href=&quot;https://www.11ty.dev/docs/quicktips/tag-pages/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Tag pages are &lt;em&gt;created&lt;/em&gt; via pagination&lt;/a&gt;! It&#39;s a lot harder to paginate those - you can&#39;t just use the front matter to set it up.&lt;/p&gt;
&lt;p&gt;I untangled &lt;a href=&quot;https://github.com/11ty/eleventy/issues/332#issuecomment-445236776&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;this GitHub issue about double-layered pagination&lt;/a&gt; and came to the following solution...&lt;/p&gt;
&lt;h4 id=&quot;eleventy-config-js&quot;&gt;eleventy.config.js&lt;/h4&gt;
&lt;p&gt;in &lt;code&gt;eleventy.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// note that this uses the lodash.chunk method, so youll have to import that&lt;/span&gt;
eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tagPagination&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Get unique list of tags&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; tagSet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAllSorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tags &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Get each item that matches the tag&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; paginationSize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; tagMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; tagArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;tagSet&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; tagName &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; tagArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; tagItems &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFilteredByTag&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tagName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pagedItems &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tagItems&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; paginationSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pageNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pagedItems&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; pageNumber &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; pageNumber&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
tagMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;tagName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tagName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;pageNumber&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pageNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;pageSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pagedItems&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;pageData&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pagedItems&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pageNumber&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tagMap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;tag-pages-njk&quot;&gt;tag-pages.njk&lt;/h4&gt;
&lt;p&gt;in my &lt;code&gt;tag-pages.njk&lt;/code&gt; file (or whatever you use to template out your tag pages):&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;---
pagination:
data: collections.tagPagination
size: 1
alias: tag
eleventyComputed:
permalink: /tags/{{ tag.tagName | slugify }}/% if tag.pageNumber %{{ tag.pageNumber + 1 }}/% endif %
title: &quot;Posts tagged {{ tag.tagName }}&quot;
eleventyExcludeFromCollections: true
---
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Posts tagged “{{ tag.tagName }}”&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% set postlist = tag.pageData %}
{% include &quot;postlist.njk&quot; %}
{# idk why these are backwards either #}
{% if tag.pageNumber &gt; 0 %}
{% set newerHref = pagination.href.previous %}
{% endif %}
{% if tag.pageNumber &amp;lt; tag.pageSize - 1 %}
{% set olderHref = pagination.href.next %}
{% endif %}
{% include &quot;pagination.njk&quot; %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;note the pagination checking &lt;code&gt;tag.pageNumber&lt;/code&gt; against &lt;code&gt;tag.PageSize&lt;/code&gt; - the &lt;a href=&quot;https://github.com/11ty/eleventy/issues/332#issuecomment-445236776&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;original suggested solution&lt;/a&gt; in the GitHub post creates an issue where the pagination loops through &lt;em&gt;all&lt;/em&gt; of the tag pages bit-by-bit. This sorts that - hat tip to &lt;a href=&quot;https://github.com/11ty/eleventy/issues/332#issuecomment-1248185406&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;TheReyzar who mentioned the issue and showed part of their solution&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;filters-js-again&quot;&gt;filters.js (again)&lt;/h4&gt;
&lt;p&gt;finally, in my &lt;code&gt;filters.js&lt;/code&gt; file, I add the &lt;code&gt;tagPagination&lt;/code&gt; tag to the tags that get filtered using &lt;code&gt;filterTagList&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;filterTagList&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;filterTagList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tags &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;all&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;posts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tagPagination&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;tag-image-preview&quot;&gt;tag image preview&lt;/h2&gt;
&lt;p&gt;today I tackled making the tag page more visually interesting.&lt;/p&gt;
&lt;h3 id=&quot;preview-the-first-featured-image&quot;&gt;preview the first featured image&lt;/h3&gt;
&lt;p&gt;first, I worked on previewing the first featured image. The focus here is on digging into &lt;code&gt;collections[tag]&lt;/code&gt; (reversed!) to get to the data of the first post.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;taglist&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% for tag in collections | getKeys | filterTagList | sortAlphabetically %}
{% set tagUrl %}/tags/{{ tag | slugify }}/{% endset %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ tagUrl }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;taglist-link&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% set tagRecent = collections[tag] | reverse %}
{% if tagRecent[0].data.image.src %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/posts/img/{{ tagRecent[0].data.image.src }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ tagRecent[0].data.image.alt }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% else %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;missing-image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-tag&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ tag }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% set numPosts = collections[tag].length %}
({{ numPosts }} post{% if numPosts &gt; 1 %}s{% endif %})
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endfor %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;preview-a-collage-of-recent-featured-images&quot;&gt;preview a collage of recent featured images&lt;/h3&gt;
&lt;p&gt;I found that having just the first featured image made the tag page hard to differentiate from any of the pages listing individual posts, so from there I moved to showing 4 images (or empty rectangles where there weren&#39;t four to show).&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;taglist&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% for tag in collections | getKeys | filterTagList | sortAlphabetically %}
{% set tagUrl %}/tags/{{ tag | slugify }}/{% endset %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ tagUrl }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;taglist-link&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;tag-imgs&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% set tagRecent = collections[tag] | reverse %}
{% for i in range(0, 4) %}
{% if tagRecent[i].data.image.src %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/posts/img/{{ tagRecent[i].data.image.src }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ tagRecent[i].data.image.alt }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% else %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;missing-image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endif %}
{% endfor %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-tag&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ tag }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% set numPosts = collections[tag].length %}
({{ numPosts }} post{% if numPosts &gt; 1 %}s{% endif %})
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{% endfor %}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with a bit of &lt;code&gt;display: grid&lt;/code&gt;, we&#39;re good to go, right?&lt;/p&gt;
&lt;h4 id=&quot;handling-multiple-aspect-ratios&quot;&gt;handling multiple aspect ratios&lt;/h4&gt;
&lt;p&gt;this had worked so far because the photos on the lessons site are from my camera in landscape mode, producing neat, identical 3:2 aspect ratios. Let&#39;s throw a wrench in that and introduce a portrait-mode photo.&lt;/p&gt;
&lt;p&gt;thankfully, the CSS property &lt;code&gt;aspect-ratio&lt;/code&gt; makes this pretty straightforward, and &lt;code&gt;object-fit&lt;/code&gt; finishes the job.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.taglist-link img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3 / 2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;object-fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I also set the &lt;code&gt;missing-img&lt;/code&gt; &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s to have the same aspect ratio.)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There&#39;s the good stuff from &lt;a href=&quot;https://inherentlee.codeberg.page/lessons/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;11ty Lessons&lt;/a&gt;. Hope you enjoyed.&lt;/p&gt;
</content>
</entry>
<entry>
<title>crow</title>
<link href="https://leecat.art/crow/" />
<updated>2026-02-09T00:00:00Z</updated>
<id>https://leecat.art/crow/</id>
<content type="html"></content>
</entry>
<entry>
<title>screen reader optimizations</title>
<link href="https://leecat.art/screen-reader-optimizations/" />
<updated>2026-02-06T00:00:00Z</updated>
<id>https://leecat.art/screen-reader-optimizations/</id>
<content type="html">&lt;h2 id=&quot;context&quot;&gt;context&lt;/h2&gt;
&lt;p&gt;recently, I&#39;ve been working on a &lt;a href=&quot;https://inherentlee.codeberg.page/spoonfairies/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;website for a project called spoonfairies&lt;/a&gt;. On the providers page, we list a series of names along with their pronouns, location, and services offered. Visually, it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://leecat.art/img/spoonfairies-provider.png&quot; alt=&quot;A provider listing from spoonfairies. On the top row of text, it shows the provider&#39;s name in large purple text, then their pronouns in slightly opaque white and slightly smaller font, then aligned on the right, a map pin emoji and their general location in standard size white text. On the second row of text, it lists a few services the provider offers, comma separated.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;147&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;pronouns&quot;&gt;pronouns&lt;/h2&gt;
&lt;p&gt;at first, all three pieces of information in the top row had no extra styling - it was just a line of text with the same color and size throughout. The location bit also didn&#39;t exist yet, so we&#39;re going to briefly ignore it. Screenreader testing (with NVDA, specifically) informed me that, when reading through a long list of providers, parentheses become &lt;em&gt;very&lt;/em&gt; irritating. Imagine hearing the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lorem Ipsum left parentheses she slash her right parentheses web accessiblity webdev. Dolor Sit left parentheses they slash them right parentheses housecleaning. Amet Consectetur left parentheses he slash him right parentheses webdev spreadsheets software.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;...ad nauseam. Kinda irritating.&lt;/p&gt;
&lt;h3 id=&quot;the-fix&quot;&gt;the fix&lt;/h3&gt;
&lt;p&gt;put the pronouns in a span that provides special styling, and use &lt;code&gt;::before&lt;/code&gt; and &lt;code&gt;::after&lt;/code&gt; to apply parentheses.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/providers/lorem-ipsum&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
Lorem Ipsum
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;pronouns&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;she/her&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.pronouns::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;(&quot;&lt;/span&gt; / &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.pronouns::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;)&quot;&lt;/span&gt; / &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;the slash is the magic there.&lt;/strong&gt; The string before the slash indicates the visual content, and the string after the slash is the alternative text content. I went happily on my way.&lt;/p&gt;
&lt;p&gt;plus, this is neat - now I can style the pronouns separately. Let&#39;s make them the standard text color rather than the link color, and a bit smaller, and a smidge opaque... nice.&lt;/p&gt;
&lt;h2 id=&quot;location&quot;&gt;location&lt;/h2&gt;
&lt;p&gt;ooh, time to implement locations! I did my same ol&#39; trick.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/providers/lorem-ipsum&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
Lorem Ipsum
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;pronouns&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;she/her&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Tacoma&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.location::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;📍&quot;&lt;/span&gt; / &lt;span class=&quot;token string&quot;&gt;&quot;is based out of&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I even added actual alternative text rather than an empty string to provide some context. Pronouns, I figured, could exist without much context, as it&#39;s pretty common for them to follow directly after names in introductions, but location isn&#39;t as much of a given.&lt;/p&gt;
&lt;p&gt;again, style em up nice, more of a standard text look, right-aligned. Cool.&lt;/p&gt;
&lt;h2 id=&quot;a-bigger-problem-than-parentheses&quot;&gt;a bigger problem than parentheses&lt;/h2&gt;
&lt;p&gt;...then I did some screen reader testing. Which I should have done directly after the pronouns bit. Turns out, I wasn&#39;t thrilled with what the &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;s did.&lt;/p&gt;
&lt;p&gt;at least with fairly default settings in NVDA, the &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;s broke up the way the link was read out. Suddenly, I was getting:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;visited link Lorem Ipsum visited link she slash her visited link Tacoma&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;this is all one link, mind you. The &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag isn&#39;t broken into three links. But the &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;s apparently break up the screen reader output anyway (in NVDA, that&#39;s a continual caveat).&lt;/p&gt;
&lt;p&gt;ooookay... what next?&lt;/p&gt;
&lt;h3 id=&quot;total-overhaul&quot;&gt;total overhaul&lt;/h3&gt;
&lt;p&gt;I moved away from my &lt;code&gt;content&lt;/code&gt; approach entirely (well, I kept it around as a failsafe, but it&#39;s not running the show now). Instead, I switched over to an &lt;code&gt;aria-label&lt;/code&gt; for the whole link.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/providers/lorem-ipsum&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Lorem Ipsum she/her is based out of Tacoma&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
Lorem Ipsum
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;pronouns&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;she/her&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Tacoma&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(technically, all this is templated to hell and back. I would hope that&#39;s obvious given I&#39;m talking about &lt;em&gt;lists&lt;/em&gt; of these entries.)&lt;/p&gt;
&lt;p&gt;now, after more screen reader testing, it reads out smoothly. The &lt;code&gt;aria-label&lt;/code&gt; precludes the actual link text and cleanly says what needs to be said, with nothing breaking up the text and the whole thing easily recognized as one link. &lt;em&gt;And&lt;/em&gt; I&#39;ve got my fancy styling. Sweet.&lt;/p&gt;
</content>
</entry>
<entry>
<title>charlie the alpaca handspun</title>
<link href="https://leecat.art/charlie-the-alpaca-handspun/" />
<updated>2026-02-05T00:00:00Z</updated>
<id>https://leecat.art/charlie-the-alpaca-handspun/</id>
<content type="html">&lt;p&gt;Fiber from Circle R Ranch. 100% alpaca, from Charlie the alpaca.&lt;/p&gt;
</content>
</entry>
<entry>
<title>ruby the alpaca handspun</title>
<link href="https://leecat.art/ruby-the-alpaca-handspun/" />
<updated>2026-01-27T00:00:00Z</updated>
<id>https://leecat.art/ruby-the-alpaca-handspun/</id>
<content type="html">&lt;p&gt;Fiber from Circle R Ranch. 100% alpaca, from Ruby the alpaca.&lt;/p&gt;
</content>
</entry>
<entry>
<title>hand-dyed gold handspun</title>
<link href="https://leecat.art/hand-dyed-gold-handspun/" />
<updated>2026-01-24T00:00:00Z</updated>
<id>https://leecat.art/hand-dyed-gold-handspun/</id>
<content type="html">&lt;p&gt;Fiber from &lt;a href=&quot;https://paradisefibers.com&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Paradise Fibers&lt;/a&gt;. 70% merino/30% nylon. Hand-dyed by me.&lt;/p&gt;
</content>
</entry>
<entry>
<title>spinner&#39;s dream handspun</title>
<link href="https://leecat.art/spinners-dream-handspun/" />
<updated>2026-01-18T00:00:00Z</updated>
<id>https://leecat.art/spinners-dream-handspun/</id>
<content type="html">&lt;p&gt;Fiber from &lt;a href=&quot;https://paradisefibers.com&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Paradise Fibers&lt;/a&gt;. 40% merino/20% alpaca/20% camel/20% mulberry silk. Scrumptiously soft.&lt;/p&gt;
</content>
</entry>
<entry>
<title>rambouillet handspun</title>
<link href="https://leecat.art/rambouillet-handspun/" />
<updated>2026-01-18T00:00:00Z</updated>
<id>https://leecat.art/rambouillet-handspun/</id>
<content type="html">&lt;p&gt;Fiber from &lt;a href=&quot;https://woolgatherings.com&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Woolgatherings&lt;/a&gt;. 100% rambouillet. Hand-dyed!&lt;/p&gt;
</content>
</entry>
<entry>
<title>fire &amp; ice handspun</title>
<link href="https://leecat.art/fire-and-ice-handspun/" />
<updated>2026-01-18T00:00:00Z</updated>
<id>https://leecat.art/fire-and-ice-handspun/</id>
<content type="html">&lt;p&gt;Fiber from &lt;a href=&quot;https://www.etsy.com/shop/JakiraFarms&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Jakira Farms&lt;/a&gt; in Fire &amp;amp; Ice colorway. 100% merino.&lt;/p&gt;
</content>
</entry>
<entry>
<title>dyeing fiber</title>
<link href="https://leecat.art/dyeing-fiber/" />
<updated>2026-01-18T00:00:00Z</updated>
<id>https://leecat.art/dyeing-fiber/</id>
<content type="html">&lt;p&gt;hand-dyed with acid dyes&lt;/p&gt;
</content>
</entry>
</feed>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More