add related posts and update some styling

This commit is contained in:
2026-02-20 08:36:46 -08:00
parent c4b549bc75
commit 7d1fe776c7
7 changed files with 73 additions and 19 deletions

View File

@ -6,11 +6,50 @@ export default function(eleventyConfig) {
return Object.keys(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);
});
/* 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));
});
});
/* Return n elements from a list */
eleventyConfig.addFilter("head", (collection=[], n) => {
if(!Array.isArray(collection) || collection.length === 0) {
return [];
}
if( n < 0 ) {
return collection.slice(n);
}
return collection.slice(0, n);
});
/* For <time> elements */ /* For <time> elements */
eleventyConfig.addFilter("htmlDateString", (dateObj) => { 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) {
// 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]];
}
return shuffledArray;
});
/* Human-readable dates */ /* Human-readable dates */
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => { eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }) return DateTime.fromJSDate(dateObj, { zone: zone || "utc" })
@ -22,7 +61,7 @@ export default function(eleventyConfig) {
return tags.filter(tag => ["all", "posts", "gallery", "reference", "tagPagination"].indexOf(tag) === -1); return tags.filter(tag => ["all", "posts", "gallery", "reference", "tagPagination"].indexOf(tag) === -1);
}); });
/* What it says */ /* What it says on the tin */
eleventyConfig.addFilter("sortAlphabetically", strings => eleventyConfig.addFilter("sortAlphabetically", strings =>
(strings || []).sort((b, a) => b.localeCompare(a)) (strings || []).sort((b, a) => b.localeCompare(a))
); );

View File

@ -41,8 +41,6 @@
<main id="main"> <main id="main">
{{ content | safe }} {{ content | safe }}
<hr>
</main> </main>
{% include "footer.njk" %} {% include "footer.njk" %}

View File

@ -3,6 +3,7 @@ layout: base.njk
--- ---
{% css %}{% include "css/post.css" %}{% endcss %} {% css %}{% include "css/post.css" %}{% endcss %}
{% css %}{% include "css/highlighting.css" %}{% endcss %} {% css %}{% include "css/highlighting.css" %}{% endcss %}
{% css %}{% include "css/lists.css" %}{% endcss %}
{% js %}{% include "node_modules/@zachleat/heading-anchors/heading-anchors.js" %}{% endjs %} {% js %}{% include "node_modules/@zachleat/heading-anchors/heading-anchors.js" %}{% endjs %}
<heading-anchors content="<i class='fa-solid fa-anchor'></i>"> <heading-anchors content="<i class='fa-solid fa-anchor'></i>">
@ -43,4 +44,16 @@ layout: base.njk
{% set newerTitle = newerPost.data.title %} {% set newerTitle = newerPost.data.title %}
{% set inPost = true %} {% set inPost = true %}
{% include "pagination.njk" %} {% include "pagination.njk" %}
<hr>
{% set relevantTags = tags | removeBasicTags %}
{% 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>
{% include "postlist.njk" %}
</section>
{% endif %}
</heading-anchors> </heading-anchors>

View File

@ -49,8 +49,6 @@
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light)); --color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light)); --color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-grey: light-dark(var(--color-grey-dark), var(--color-grey-light)); --color-grey: light-dark(var(--color-grey-dark), var(--color-grey-light));
--header-offset: 3.1rem;
} }
/* Base */ /* Base */
@ -71,7 +69,7 @@ main {
width: 60vw; width: 60vw;
max-width: 1000px; max-width: 1000px;
margin: 0 auto; margin: 0 auto;
scroll-margin-top: var(--header-offset); scroll-margin-top: 7rem;
} }
@media (max-width: 1050px) { @media (max-width: 1050px) {
@ -90,7 +88,6 @@ main {
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
line-height: 1.25; line-height: 1.25;
color: var(--color-teal); color: var(--color-teal);
scroll-margin-top: var(--header-offset);
} }
h1 { h1 {
@ -99,6 +96,10 @@ h1 {
text-align: center; text-align: center;
} }
h2, h3, h4, h5, h6 {
scroll-margin-top: 5rem;
}
h2 { h2 {
margin-top: 2rem; margin-top: 2rem;
font-size: 2.2rem; font-size: 2.2rem;
@ -260,13 +261,9 @@ time {
/* Horizontal rules */ /* Horizontal rules */
hr { hr {
color: var(--color-teal); border: .25rem solid var(--color-pink);
border: .25rem solid var(--color-teal);
margin: 2rem 0; margin: 2rem 0;
} }
hr:last-child {
margin-bottom: 0;
}
/* Used on home, reference, gallery pages */ /* Used on home, reference, gallery pages */
.centered { .centered {

View File

@ -3,9 +3,10 @@ header {
position: sticky; position: sticky;
top: 0; top: 0;
background-color: var(--color-bg); background-color: var(--color-bg);
box-shadow: 0 .25rem .15rem var(--color-shadow);
padding: .75rem 0; padding: .75rem 0;
z-index: 10; z-index: 10;
border-bottom: .5rem solid var(--color-teal);
box-shadow: 0 .25rem .15rem var(--color-shadow);
} }
/* Header links, pagination links */ /* Header links, pagination links */
@ -198,6 +199,7 @@ header li {
footer { footer {
padding: 1rem 0; padding: 1rem 0;
font-size: .9rem; font-size: .9rem;
border-top: .5rem solid var(--color-pink);
} }
footer ul { footer ul {

View File

@ -72,4 +72,3 @@
left: .1rem; left: .1rem;
box-shadow: .05rem .05rem var(--color-shadow); box-shadow: .05rem .05rem var(--color-shadow);
} }

View File

@ -8,7 +8,7 @@ tags:
- software - software
--- ---
recently I wrote *several* sites using [Eleventy](https://www.11ty.dev/){target="_blank" rel="external"} (4? 5?). Including, over the past few days, this one! That's right, if you're reading this, we're now running on 11ty and hosted by [heckin.technology](https://heckin.technology/){target="_blank" rel="external"}. See ya, GitHub. Won't miss ya. recently I wrote *several* sites using [Eleventy](https://www.11ty.dev/){target="_blank" rel="external"} (4? 5?). Including, over the past few days, rewriting this one! That's right, if you're reading this, we're now running on 11ty and hosted by [heckin.technology](https://heckin.technology/){target="_blank" rel="external"}. See ya, GitHub. Won't miss ya.
I've compiled some of the things I've learned in a standalone site: [11ty Lessons](https://inherentlee.codeberg.page/lessons/){target="_blank" rel="external"}. I've compiled some of the things I've learned in a standalone site: [11ty Lessons](https://inherentlee.codeberg.page/lessons/){target="_blank" rel="external"}.
@ -26,18 +26,19 @@ while that is useful for *this* site, when building another site I wanted to see
I started by referring to [this GitHub issue about related posts](https://github.com/11ty/eleventy/discussions/2534){target="_blank rel="external"}. I had to fix a few errors that arose from the suggested code. I started by referring to [this GitHub issue about related posts](https://github.com/11ty/eleventy/discussions/2534){target="_blank rel="external"}. I had to fix a few errors that arose from the suggested code.
I also wanted to make two changes: I also wanted to make three changes:
1. I didn't want to just see posts that shared *all* tags, but rather posts that shared *any* tag 1. I didn't want to just see posts that shared *all* tags, but rather posts that shared *any* tag
1. I wanted to randomly add a few posts instead of just getting whatever was first (with a shared tag) in the post order 1. I wanted to randomly add a few posts instead of just getting whatever was first (with a shared tag) in the post order
1. I wanted to exclude the posts that I could reach with between-post pagination
### filters.js ### filters.js
after adjusting for those needs, I had the following in `filters.js`: after adjusting for those needs, I had the following in `filters.js`:
```js ```js
eleventyConfig.addNunjucksFilter("excludeFromCollection", function (collection=[], pageUrl=this.ctx.page.url) { eleventyConfig.addFilter("excludeFromCollection", function (collection=[], urls=[this.ctx.page.url]) {
return collection.filter(post => post.url !== pageUrl); return collection.filter(post => urls.indexOf(post.url) === -1);
}); });
eleventyConfig.addFilter("filterByTags", function(collection=[], ...requiredTags) { eleventyConfig.addFilter("filterByTags", function(collection=[], ...requiredTags) {
@ -67,7 +68,12 @@ I used this in my post layout. `filterTagList` comes with the base blog by defau
{% raw %} {% raw %}
```html ```html
{% set relevantTags = tags | filterTagList %} {% set relevantTags = tags | filterTagList %}
{% set postlist = collections.posts | filterByTags(relevantTags) | excludeFromCollection(page.url) | randomize | head(2) %}
{% 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 %} {% if postlist.length %}
<section class="related-posts"> <section class="related-posts">
<h2>related posts</h2> <h2>related posts</h2>