diff --git a/config/filters/collection.js b/config/filters/collection.js new file mode 100644 index 0000000..783e43b --- /dev/null +++ b/config/filters/collection.js @@ -0,0 +1,28 @@ +import date from "./date.js"; + +const filterFavourites = (collection) => { + return collection.filter( + (item) => item.data.favourite || item.data.isFavourite, + ); +}; + +const organizeByYear = (collection) => { + const collectionByYear = {}; + + collection.forEach((item) => { + const year = date.formatDate(item.date, "YYYY"); + + if (!collectionByYear[year]) { + return (collectionByYear[year] = [item]); + } + + collectionByYear[year].push(item); + }); + + return collectionByYear; +}; + +export default { + filterFavourites, + organizeByYear, +}; diff --git a/config/filters/date.js b/config/filters/date.js new file mode 100644 index 0000000..8bcf6a8 --- /dev/null +++ b/config/filters/date.js @@ -0,0 +1,14 @@ +import dayjs from "dayjs"; +import utc from "dayjs/plugin/utc.js"; +import advancedFormat from "dayjs/plugin/advancedFormat.js"; + +dayjs.extend(utc); +dayjs.extend(advancedFormat); + +const formatDate = (date, format) => dayjs.utc(date).format(format); +const formatAsUTCString = (date) => new Date(date).toUTCString(); + +export default { + formatDate, + formatAsUTCString, +}; diff --git a/config/filters/feed.js b/config/filters/feed.js new file mode 100644 index 0000000..d478b06 --- /dev/null +++ b/config/filters/feed.js @@ -0,0 +1,31 @@ +import { JSDOM } from "jsdom"; + +// From coryd.dev +// https://www.coryd.dev/posts/2025/generating-absolute-urls-in-my-rss-feeds/ +const convertRelativeLinks = (htmlContent, url) => { + if (!htmlContent || !url) return htmlContent; + + const dom = new JSDOM(htmlContent); + const document = dom.window.document; + + document.querySelectorAll("a[href]").forEach((link) => { + let href = link.getAttribute("href"); + + if (href.startsWith("#")) { + link.remove(); + return; + } + + if (!href.startsWith("http://") && !href.startsWith("https://")) + link.setAttribute( + "href", + `${url.replace(/\/$/, "")}/${href.replace(/^\/+/, "")}`, + ); + }); + + return document.body.innerHTML; +}; + +export default { + convertRelativeLinks, +}; diff --git a/config/filters/general.js b/config/filters/general.js new file mode 100644 index 0000000..5bc3e51 --- /dev/null +++ b/config/filters/general.js @@ -0,0 +1,20 @@ +import pluralizeBase from "pluralize"; + +const filter = (collection, filters = []) => { + return collection.filter((item) => !filters.includes(item)); +}; + +const keys = Object.keys; + +const limit = (collection, limit = 5) => collection.slice(0, limit); + +const pluralize = (string, count = 0) => { + return pluralizeBase(string, count); +}; + +export default { + filter, + keys, + limit, + pluralize, +}; diff --git a/config/filters/index.js b/config/filters/index.js index 0e16303..c1f2b3b 100644 --- a/config/filters/index.js +++ b/config/filters/index.js @@ -1,132 +1,15 @@ -import dayjs from "dayjs"; -import utc from "dayjs/plugin/utc.js"; -import advancedFormat from "dayjs/plugin/advancedFormat.js"; +import collection from "./collection.js"; +import date from "./date.js"; +import feed from "./feed.js"; +import general from "./general.js"; +import postcss from "./postcss/index.js"; +import tag from "./tag.js"; -import pluralizeBase from "pluralize"; - -import { JSDOM } from "jsdom"; - -export const keys = Object.keys; -export const values = Object.values; -export const entries = Object.entries; - -dayjs.extend(utc); -dayjs.extend(advancedFormat); - -export const formatDate = (date, format) => dayjs.utc(date).format(format); -export const formatAsUTCString = (date) => new Date(date).toUTCString(); - -export const organizeByDate = (collection) => { - const collectionByDate = {}; - - collection.forEach((item) => { - const year = formatDate(item.date, "YYYY"); - - if (!collectionByDate[year]) { - return (collectionByDate[year] = [item]); - } - - collectionByDate[year].push(item); - }); - - return collectionByDate; -}; - -export const transformByDate = (collection) => { - const collectionByDate = {}; - - collection.forEach((item) => { - const year = formatDate(item.date, "YYYY"); - - if (!collectionByDate[year]) { - return (collectionByDate[year] = { value: year, data: [item] }); - } - - collectionByDate[year].data.push(item); - }); - - return collectionByDate; -}; - -export const allTagCounts = (collection, ignore = ["post"]) => { - if (!collection.length) { - throw new Error("Invalid collection, no items"); - } - - const tagCounts = new Map(); - - for (const item of collection) { - const tags = item.data.tags; - - tags?.forEach((tag) => tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1)); - } - - ignore.forEach((tag) => tagCounts.delete(tag)); - - const tagArray = Array.from(tagCounts.entries()) - .map(([tag, count]) => ({ - tag, - count, - })) - .sort((a, b) => b.count - a.count); - - return tagArray; -}; - -export const filter = (collection, filters = []) => { - return collection.filter((item) => !filters.includes(item)); -}; - -export const pluralize = (string, count = 0) => { - return pluralizeBase(string, count); -}; - -export const limit = (collection, limit = 5) => collection.slice(0, limit); - -export const filterFavourites = (collection) => { - return collection.filter( - (item) => item.data.favourite || item.data.isFavourite, - ); -}; - -export const filterByTags = (collection, tags = []) => { - return collection.filter( - (item) => - item.data.tags && !item.data.tags.every((tag) => tags.includes(tag)), - ); -}; - -export const isOld = (dateArg) => { - const date = dayjs(dateArg); - const now = dayjs(); - - const diffInYears = now.diff(date, "years"); - - return diffInYears >= 2; -}; - -// From coryd.dev -// https://www.coryd.dev/posts/2025/generating-absolute-urls-in-my-rss-feeds/ -export const convertRelativeLinks = (htmlContent, url) => { - if (!htmlContent || !url) return htmlContent; - - const dom = new JSDOM(htmlContent); - const document = dom.window.document; - - document.querySelectorAll("a[href]").forEach((link) => { - let href = link.getAttribute("href"); - - if (href.startsWith("#")) { - link.remove(); - return; - } - - if (!href.startsWith("http://") && !href.startsWith("https://")) - link.setAttribute( - "href", - `${url.replace(/\/$/, "")}/${href.replace(/^\/+/, "")}`, - ); - }); - - return document.body.innerHTML; +export default { + ...collection, + ...date, + ...feed, + ...general, + ...postcss, + ...tag, }; diff --git a/config/filters/postcss/index.js b/config/filters/postcss/index.js new file mode 100644 index 0000000..92051d3 --- /dev/null +++ b/config/filters/postcss/index.js @@ -0,0 +1,5 @@ +import postcss from "./postcss.js"; + +export default { + ...postcss, +}; diff --git a/config/filters/postcss/postcss.js b/config/filters/postcss/postcss.js index d622b43..0fc1a6f 100644 --- a/config/filters/postcss/postcss.js +++ b/config/filters/postcss/postcss.js @@ -4,7 +4,7 @@ * --- * https://github.com/philhawksworth/eleventyone/blob/master/src/site/css/styles.11ty.js */ -import postcss from "postcss"; +import { default as postcssBase } from "postcss"; import postcssImport from "postcss-import"; import postcssImportExtGlob from "postcss-import-ext-glob"; import autoprefixer from "autoprefixer"; @@ -15,9 +15,9 @@ import fontFamily from "./utils/font-family.js"; import fontVariables from "./utils/font-variables.js"; import spacing from "./utils/spacing.js"; -const postCss = async (rawCss) => { +const postcss = async (rawCss) => { const css = `${rawCss}${fontFamily}${fontVariables}${colors}${spacing}`; - return await postcss([ + return await postcssBase([ postcssImportExtGlob, postcssImport, autoprefixer, @@ -27,4 +27,6 @@ const postCss = async (rawCss) => { .then((result) => result.css); }; -export default postCss; +export default { + postcss, +}; diff --git a/config/filters/tag.js b/config/filters/tag.js new file mode 100644 index 0000000..d92dee2 --- /dev/null +++ b/config/filters/tag.js @@ -0,0 +1,36 @@ +const allTagCounts = (collection, ignore = ["post"]) => { + if (!collection.length) { + throw new Error("Invalid collection, no items"); + } + + const tagCounts = new Map(); + + for (const item of collection) { + const tags = item.data.tags; + + tags?.forEach((tag) => tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1)); + } + + ignore.forEach((tag) => tagCounts.delete(tag)); + + const tagArray = Array.from(tagCounts.entries()) + .map(([tag, count]) => ({ + tag, + count, + })) + .sort((a, b) => b.count - a.count); + + return tagArray; +}; + +const filterByTags = (collection, tags = []) => { + return collection.filter( + (item) => + item.data.tags && !item.data.tags.every((tag) => tags.includes(tag)), + ); +}; + +export default { + allTagCounts, + filterByTags, +}; diff --git a/eleventy.config.js b/eleventy.config.js index 94dd9ba..74e91f5 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,27 +1,10 @@ -import util from "util"; import pluginRss from "@11ty/eleventy-plugin-rss"; import pluginNoRobots from "eleventy-plugin-no-robots"; import { eleventyImageTransformPlugin } from "@11ty/eleventy-img"; import { collectionByTag, postsByTag } from "./config/collections/index.js"; -import { - allTagCounts, - convertRelativeLinks, - entries, - filter, - filterByTags, - filterFavourites, - formatDate, - formatAsUTCString, - isOld, - keys, - limit, - organizeByDate, - pluralize, - values, -} from "./config/filters/index.js"; -import postcss from "./config/filters/postcss/postcss.js"; +import filters from "./config/filters/index.js"; import markdown from "./config/plugins/markdown.js"; import liteYoutube from "./config/shortcodes/youtube.js"; @@ -32,7 +15,6 @@ export default function (eleventyConfig) { eleventyConfig.addWatchTarget("./src/css"); // --------------------- Plugins --------------------- - eleventyConfig.addPlugin(pluginRss); eleventyConfig.addPlugin(pluginNoRobots); // --------------------- Custom Collections ----------------------- @@ -51,22 +33,9 @@ export default function (eleventyConfig) { ); // --------------------- Custom Filters ----------------------- - eleventyConfig.addFilter("allTagCounts", allTagCounts); - eleventyConfig.addFilter("convertRelativeLinks", convertRelativeLinks); - eleventyConfig.addFilter("entries", entries); - eleventyConfig.addFilter("filter", filter); - eleventyConfig.addFilter("filterFavourites", filterFavourites); - eleventyConfig.addFilter("filterByTags", filterByTags); - eleventyConfig.addFilter("formatDate", formatDate); - eleventyConfig.addFilter("formatAsUTCString", formatAsUTCString); - eleventyConfig.addFilter("isOld", isOld); - eleventyConfig.addFilter("keys", keys); - eleventyConfig.addFilter("limit", limit); - eleventyConfig.addFilter("organizeByDate", organizeByDate); - eleventyConfig.addFilter("values", values); - eleventyConfig.addFilter("pluralize", pluralize); - - eleventyConfig.addFilter("postcss", postcss); + Object.keys(filters).forEach((filterName) => { + eleventyConfig.addFilter(filterName, filters[filterName]); + }); // --------------------- Custom Transforms ----------------------- eleventyConfig.addPlugin(htmlConfigTransform); @@ -101,7 +70,6 @@ export default function (eleventyConfig) { ["src/assets/fonts/", "src/assets/images"].forEach((path) => eleventyConfig.addPassthroughCopy(path), ); - eleventyConfig.addPassthroughCopy("_redirects"); // --------------------- Markdown ----------------------- eleventyConfig.setLibrary("md", markdown); @@ -109,10 +77,6 @@ export default function (eleventyConfig) { // --------------------- Shortcodes ----------------------- eleventyConfig.addShortcode("youtube", liteYoutube); - eleventyConfig.addFilter("console", function (value) { - return util.inspect(value); - }); - return { // Optional (default is set): If your site deploys to a subdirectory, change `pathPrefix`, for example with with GitHub pages pathPrefix: "/", diff --git a/src/pages/posts.html b/src/pages/posts.html index 0c47611..7ac6146 100644 --- a/src/pages/posts.html +++ b/src/pages/posts.html @@ -8,7 +8,7 @@ description: Read all of my posts.
Browse all of my posts, or narrow things down via tags.
-{% set itemsByYear = collections.post | reverse | organizeByDate %} +{% set itemsByYear = collections.post | reverse | organizeByYear %} {% set years = itemsByYear | keys | sort("desc") %}All posts tagged with "{{ tag }}", or go back to all tags.
-{% set itemsByYear = collections.postsByTag[tag] | reverse | organizeByDate %} +{% set itemsByYear = collections.postsByTag[tag] | reverse | organizeByYear %} {% set years = itemsByYear | keys | sort("desc") %}