diff --git a/_config/filters.js b/_config/filters.js index 5e03be1..df2dcd5 100644 --- a/_config/filters.js +++ b/_config/filters.js @@ -1,6 +1,14 @@ import { DateTime } from "luxon"; export default function(eleventyConfig) { + eleventyConfig.addFilter("filterByDate", (listings, date) => { + date = DateTime.fromISO(date, { zone: "utc" }); + return listings.filter((listing) => { + let postDate = DateTime.fromJSDate(listing.data.date, { zone: "utc" }); + return postDate.equals(date); + }); + }) + // Return the keys used in an object eleventyConfig.addFilter("getKeys", target => { return Object.keys(target); @@ -60,7 +68,7 @@ export default function(eleventyConfig) { /* Filter out structural tags */ eleventyConfig.addFilter("removeCoreTags", (tags) => { - return tags.filter(tag => ["all", "ads"].indexOf(tag) === -1); + return tags.filter(tag => ["all", "ads", "daily"].indexOf(tag) === -1); }); /* What it says on the tin */ diff --git a/_includes/daily-listings.njk b/_includes/daily-listings.njk new file mode 100644 index 0000000..623b76b --- /dev/null +++ b/_includes/daily-listings.njk @@ -0,0 +1,28 @@ +
+ {% for tag in collections | getKeys | removeCoreTags | sortAlphabetically %} +
+
+

{{ tag }}

+

{{ tag | getTagline }}

+
+ {% if collections[tag] | filterByDate(today) | length == 0 %} +

No listings.

+ {% endif %} + {% for listing in collections[tag] | filterByDate(today) %} +
+

{{ listing.data.title }}

+

+ + {{ listing.data.handle }} + offers: {{ listing.data.blurb }} +

+

+ listed on +

+
+ {% endfor %} +
+ {% endfor %} +
diff --git a/_includes/footer.njk b/_includes/footer.njk index fb15e4b..cce1a92 100644 --- a/_includes/footer.njk +++ b/_includes/footer.njk @@ -7,5 +7,8 @@ source code +
  • + RSS +
  • diff --git a/css/home.css b/css/listings.css similarity index 98% rename from css/home.css rename to css/listings.css index 7044bbd..b0b7803 100644 --- a/css/home.css +++ b/css/listings.css @@ -2,7 +2,7 @@ columns: 3; } -@media (max-width: 1050px) { +@media (max-width: 1200px) { #listings { columns: 2; } diff --git a/eleventy.config.js b/eleventy.config.js index 25ae0c5..37a3b9c 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,4 +1,5 @@ import { HtmlBasePlugin, IdAttributePlugin } from "@11ty/eleventy"; +import { feedPlugin } from "@11ty/eleventy-plugin-rss"; import pluginFilters from "./_config/filters.js"; @@ -31,6 +32,25 @@ export default async function(eleventyConfig) { /* `id` attributes */ eleventyConfig.addPlugin(IdAttributePlugin); + /* RSS */ + eleventyConfig.addPlugin(feedPlugin, { + type: "atom", // or "rss", "json" + outputPath: "/feed.xml", + collection: { + name: "daily", // iterate over `collections.posts` + limit: 10, // 0 means no limit + }, + metadata: { + language: "en", + title: "Fediverse Skillshare Classifieds", + subtitle: "Skillshare listings for the Fediverse", + base: "https://inherentlee.codeberg.page/", + author: { + name: "Lee Cattarin" + } + } + }); + /* Draft handling */ eleventyConfig.addPreprocessor("drafts", "*", (data, content) => { if(data.draft) { diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 3160ad2..8c5f155 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -129,6 +129,23 @@ "url": "https://opencollective.com/11ty" } }, + "node_modules/@11ty/eleventy-plugin-rss": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-rss/-/eleventy-plugin-rss-3.0.0.tgz", + "integrity": "sha512-kKW4DcR57xAyRx0e8gNhKh56ahHVEaAj8/TuXQDnw+B46ig2bWADJAlyj/GdV37IG5ja9dZ4SgKZrs/CHz6YWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@11ty/eleventy-utils": "^2.0.7", + "@11ty/posthtml-urls": "^1.0.2", + "debug": "^4.4.3", + "posthtml": "^0.16.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, "node_modules/@11ty/eleventy-utils": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-2.0.7.tgz", diff --git a/node_modules/@11ty/eleventy-plugin-rss/.eleventy.js b/node_modules/@11ty/eleventy-plugin-rss/.eleventy.js new file mode 100644 index 0000000..bfee82b --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/.eleventy.js @@ -0,0 +1,20 @@ +import rssPlugin from "./src/rssPlugin.js"; +import dateRfc3339 from "./src/dateRfc3339.js"; +import dateRfc822 from "./src/dateRfc822.js"; +import getNewestCollectionItemDate from "./src/getNewestCollectionItemDate.js"; +import virtualTemplate from "./src/virtualTemplate.js"; + +import absoluteUrl from "./src/absoluteUrl.js"; +import convertHtmlToAbsoluteUrls from "./src/htmlToAbsoluteUrls.js"; + +export default rssPlugin; + +export { + rssPlugin, + virtualTemplate as feedPlugin, + dateRfc3339 as dateToRfc3339, + dateRfc822 as dateToRfc822, + getNewestCollectionItemDate as getNewestCollectionItemDate, + absoluteUrl as absoluteUrl, + convertHtmlToAbsoluteUrls as convertHtmlToAbsoluteUrls +}; diff --git a/node_modules/@11ty/eleventy-plugin-rss/LICENSE b/node_modules/@11ty/eleventy-plugin-rss/LICENSE new file mode 100644 index 0000000..89a4362 --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Zach Leatherman @zachleat + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@11ty/eleventy-plugin-rss/README.md b/node_modules/@11ty/eleventy-plugin-rss/README.md new file mode 100644 index 0000000..c782cfc --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/README.md @@ -0,0 +1,34 @@ +

    11ty Logo

    + +# eleventy-plugin-rss đŸ•šâšĄī¸đŸŽˆđŸ€ + +A pack of [Eleventy](https://github.com/11ty/eleventy) filters for generating Atom, JSON and RSS feeds using the Nunjucks templating engine. + + +See `sample/feed.njk` for an example Atom feed template, `sample/feed.json` for an example JSON feed template, or `sample/feed-rss.njk` for an example RSS feed template. + +## [The full `eleventy-plugin-rss` documentation is on 11ty.dev](https://www.11ty.dev/docs/plugins/rss/). + +* _This is a plugin for the [Eleventy static site generator](https://www.11ty.dev/)._ +* Find more [Eleventy plugins](https://www.11ty.dev/docs/plugins/). +* Please star [Eleventy on GitHub](https://github.com/11ty/eleventy/), follow [@eleven_ty](https://twitter.com/eleven_ty) on Twitter, and support [11ty on Open Collective](https://opencollective.com/11ty) + +[![npm Version](https://img.shields.io/npm/v/@11ty/eleventy-plugin-rss.svg?style=for-the-badge)](https://www.npmjs.com/package/@11ty/eleventy-plugin-rss) [![GitHub issues](https://img.shields.io/github/issues/11ty/eleventy-plugin-rss.svg?style=for-the-badge)](https://github.com/11ty/eleventy-plugin-rss/issues) + +## Installation + +``` +npm install @11ty/eleventy-plugin-rss +``` + +_[The full `eleventy-plugin-rss` documentation is on 11ty.dev](https://www.11ty.dev/docs/plugins/rss/)._ + +## Tests + +``` +npm run test +``` + +- We use the [ava JavaScript test runner](https://github.com/avajs/ava) ([Assertions documentation](https://github.com/avajs/ava/blob/master/docs/03-assertions.md)) +- â„šī¸ To keep tests fast, thou shalt try to avoid writing files in tests. + diff --git a/node_modules/@11ty/eleventy-plugin-rss/package.json b/node_modules/@11ty/eleventy-plugin-rss/package.json new file mode 100644 index 0000000..6487694 --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/package.json @@ -0,0 +1,50 @@ +{ + "name": "@11ty/eleventy-plugin-rss", + "version": "3.0.0", + "type": "module", + "description": "Generate an Atom, RSS, or JSON feed.", + "publishConfig": { + "access": "public" + }, + "main": ".eleventy.js", + "scripts": { + "test": "npx ava", + "sample": "cd sample && npx @11ty/eleventy --config=config-sample.js --pathprefix=pathprefix", + "clean": "rm -rf sample/_site" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/11ty/eleventy-plugin-rss.git" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + }, + "keywords": [ + "eleventy", + "eleventy-plugin" + ], + "author": { + "name": "Zach Leatherman", + "email": "zachleatherman@gmail.com", + "url": "https://zachleat.com/" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/11ty/eleventy-plugin-rss/issues" + }, + "homepage": "https://www.11ty.dev/docs/plugins/rss/", + "11ty": { + "compatibility": ">=3.0.0-alpha.15" + }, + "devDependencies": { + "@11ty/eleventy": "^3.1.5", + "ava": "^6.4.1" + }, + "dependencies": { + "@11ty/eleventy-utils": "^2.0.7", + "@11ty/posthtml-urls": "^1.0.2", + "debug": "^4.4.3", + "posthtml": "^0.16.7" + } +} diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/absoluteUrl.js b/node_modules/@11ty/eleventy-plugin-rss/src/absoluteUrl.js new file mode 100644 index 0000000..83a4754 --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/absoluteUrl.js @@ -0,0 +1,13 @@ +import debugUtil from "debug"; +const debug = debugUtil("Eleventy:Rss"); + +// This is deprecated! Use the Eleventy HTML plugin instead (2.0+) +export default function(url, base) { + try { + return (new URL(url, base)).toString() + } catch(e) { + debug("Trying to convert %o to be an absolute url with base %o and failed, returning: %o (invalid url)", url, base, url) + // TODO add debug output! + return url; + } +}; diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/dateRfc3339.js b/node_modules/@11ty/eleventy-plugin-rss/src/dateRfc3339.js new file mode 100644 index 0000000..563598a --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/dateRfc3339.js @@ -0,0 +1,11 @@ +// Atom uses RFC 3339 dates +// https://tools.ietf.org/html/rfc3339#section-5.8 +export default function(dateObj) { + let s = dateObj.toISOString(); + + // remove milliseconds + let split = s.split("."); + split.pop(); + + return split.join("") + "Z"; +} diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/dateRfc822.js b/node_modules/@11ty/eleventy-plugin-rss/src/dateRfc822.js new file mode 100644 index 0000000..e2cdacf --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/dateRfc822.js @@ -0,0 +1,23 @@ +export default function pubDateRFC822(value, timeZone = undefined) { + const date = new Date(value); + const options = { + weekday: 'short', + day: '2-digit', + month: 'short', + year: 'numeric', + + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hourCycle: 'h23', + + timeZone: timeZone, + timeZoneName: 'longOffset', + }; + + const formattedDate = new Intl.DateTimeFormat('en-US', options).format(date); + const [wkd, mmm, dd, yyyy, time, z] = formattedDate.replace(/([,\s]+)/g, ' ').split(' '); + const tz = z.replace(/GMT(?\+|\-)(?\d\d):(?\d\d)/, '$$$'); + + return `${wkd}, ${dd} ${mmm} ${yyyy} ${time} ${tz}`; +} diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/getNewestCollectionItemDate.js b/node_modules/@11ty/eleventy-plugin-rss/src/getNewestCollectionItemDate.js new file mode 100644 index 0000000..05e7a8b --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/getNewestCollectionItemDate.js @@ -0,0 +1,7 @@ +export default function(collection, emptyFallbackDate) { + if( !collection || !collection.length ) { + return emptyFallbackDate || new Date(); + } + + return new Date(Math.max(...collection.map(item => {return item.date}))); +} diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/htmlToAbsoluteUrls.js b/node_modules/@11ty/eleventy-plugin-rss/src/htmlToAbsoluteUrls.js new file mode 100644 index 0000000..56004fa --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/htmlToAbsoluteUrls.js @@ -0,0 +1,21 @@ +import posthtml from 'posthtml'; +import urls from '@11ty/posthtml-urls'; +import absoluteUrl from "./absoluteUrl.js"; + +// This is deprecated! Use the Eleventy HTML plugin instead (2.0+) +export default async function(htmlContent, base, processOptions = {}) { + if( !base ) { + throw new Error( "eleventy-plugin-rss: htmlToAbsoluteUrls(absolutePostUrl) was missing the full URL base `absolutePostUrl` argument.") + } + + let options = { + eachURL: function(url) { + return absoluteUrl(url.trim(), base); + } + }; + + let modifier = posthtml().use(urls(options)); + + let result = await modifier.process(htmlContent, processOptions); + return result.html; +}; diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/rssPlugin.js b/node_modules/@11ty/eleventy-plugin-rss/src/rssPlugin.js new file mode 100644 index 0000000..c746653 --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/rssPlugin.js @@ -0,0 +1,60 @@ +import pkg from "../package.json" with {type: "json"}; + +import dateRfc3339 from "./dateRfc3339.js"; +import dateRfc822 from "./dateRfc822.js"; +import getNewestCollectionItemDate from "./getNewestCollectionItemDate.js"; + +import absoluteUrl from "./absoluteUrl.js"; +import convertHtmlToAbsoluteUrls from "./htmlToAbsoluteUrls.js"; + + +export default function eleventyRssPlugin(eleventyConfig, options = {}) { + eleventyConfig.versionCheck(pkg["11ty"].compatibility); + + // Guaranteed unique, first add wins + const pluginHtmlBase = eleventyConfig.resolvePlugin("@11ty/eleventy/html-base-plugin"); + eleventyConfig.addPlugin(pluginHtmlBase, options.htmlBasePluginOptions || {}); + + // Dates + eleventyConfig.addNunjucksFilter("getNewestCollectionItemDate", getNewestCollectionItemDate); + eleventyConfig.addNunjucksFilter("dateToRfc3339", dateRfc3339); + eleventyConfig.addNunjucksFilter("dateToRfc822", dateRfc822); + + // Deprecated in favor of the more efficient HTML plugin bundled with Eleventy + eleventyConfig.addNunjucksFilter("absoluteUrl", absoluteUrl); + + // Deprecated in favor of the more efficient HTML plugin bundled with Eleventy + eleventyConfig.addNunjucksAsyncFilter("htmlToAbsoluteUrls", (htmlContent, base, callback) => { + if(!htmlContent) { + callback(null, ""); + return; + } + + let posthtmlOptions = Object.assign({ + // default PostHTML render options + closingSingleTag: "slash" + }, options.posthtmlRenderOptions); + + convertHtmlToAbsoluteUrls(htmlContent, base, posthtmlOptions).then(html => { + callback(null, html); + }); + }); + + // These are removed, their names are incorrect! Issue #8, #21 + eleventyConfig.addNunjucksFilter("rssLastUpdatedDate", () => { + throw new Error("The `rssLastUpdatedDate` filter was removed. Use `getNewestCollectionItemDate | dateToRfc3339` (for Atom) or `getNewestCollectionItemDate | dateToRfc822` (for RSS) instead.") + }); + eleventyConfig.addNunjucksFilter("rssDate", () => { + throw new Error("The `rssDate` filter was removed. Use `dateToRfc3339` (for Atom) or `dateToRfc822` (for RSS) instead."); + }); +}; + +Object.defineProperty(eleventyRssPlugin, "eleventyPackage", { + value: pkg.name +}); + +Object.defineProperty(eleventyRssPlugin, "eleventyPluginOptions", { + value: { + unique: true + } +}); diff --git a/node_modules/@11ty/eleventy-plugin-rss/src/virtualTemplate.js b/node_modules/@11ty/eleventy-plugin-rss/src/virtualTemplate.js new file mode 100644 index 0000000..a7e8028 --- /dev/null +++ b/node_modules/@11ty/eleventy-plugin-rss/src/virtualTemplate.js @@ -0,0 +1,204 @@ +import debugUtil from "debug"; +import pkg from "../package.json" with {type: "json"}; + +import { DeepCopy } from "@11ty/eleventy-utils"; + +import rssPlugin from "./rssPlugin.js"; + +const debug = debugUtil("Eleventy:Rss:Feed"); + +function getFeedContent({ type, stylesheet, collection, script }) { + // Note: page.lang comes from the i18n plugin: https://www.11ty.dev/docs/plugins/i18n/#page.lang + + if(type === "rss") { + // Nunjucks template + return ` +${stylesheet ? `\n` : ""} + + ${script ? `` : ""} + {{ metadata.title }} + {{ metadata.base | addPathPrefixToFullUrl }} + + {{ metadata.subtitle }} + {{ metadata.language or page.lang }} + {%- if metadata.icon %}{{ metadata.icon }}{%- endif %} + {%- for post in collections.${collection.name} | reverse | eleventyFeedHead(${collection.limit}) %} + {%- set absolutePostUrl = post.url | htmlBaseUrl(metadata.base) %} + + {{ post.data.title }} + {{ absolutePostUrl }} + {%- if (post.data.summary) -%} + {{ post.data.summary }} + {{ post.content | renderTransforms(post.data.page, metadata.base) }} + {%- else -%} + {{ post.content | renderTransforms(post.data.page, metadata.base) }} + {%- endif -%} + {{ post.date | dateToRfc822 }} + {{ metadata.author.name }} + {{ absolutePostUrl }} + + {%- endfor %} + +`; + } + + if(type === "atom") { + // Nunjucks template + return ` +${stylesheet ? `\n` : ""} + ${script ? `` : ""} + {{ metadata.title }} + {{ metadata.subtitle }} + + + {{ collections['${collection.name}'] | getNewestCollectionItemDate | dateToRfc3339 }} + {{ metadata.base | addPathPrefixToFullUrl }} + {%- if metadata.icon %} + {{ metadata.icon }} + {%- endif %} + {%- if metadata.logo %} + {{ metadata.logo }} + {%- endif %} + + {{ metadata.author.name }} + {%- if metadata.author.email %} + {{ metadata.author.email }} + {%- endif %} + + {%- for post in collections['${collection.name}'] | reverse | eleventyFeedHead(${collection.limit}) %} + {%- set absolutePostUrl %}{{ post.url | htmlBaseUrl(metadata.base) }}{% endset %} + + {{ post.data.title }} + + {{ post.date | dateToRfc3339 }} + {{ absolutePostUrl }} + {%- if post.data.summary %} + {{ post.data.summary }} + {%- endif %} + {{ post.content | renderTransforms(post.data.page, metadata.base) }} + + {%- endfor %} +`; + } + + if(type === "json") { + return `{ + "version": "https://jsonfeed.org/version/1.1", + "title": "{{ metadata.title }}", + "language": "{{ metadata.language or page.lang }}", + "home_page_url": "{{ metadata.base | addPathPrefixToFullUrl }}", + "feed_url": "{{ permalink | htmlBaseUrl(metadata.base) }}", + "description": "{{ metadata.description }}", + "authors": [ + { + "name": "{{ metadata.author.name }}"{% if metadata.author.email %}, + "url": "mailto:{{ metadata.author.email }}" + {%- endif %} + } + ], + "items": [ + {%- for post in collections['${collection.name}'] | reverse | eleventyFeedHead(${collection.limit}) %} + {%- set absolutePostUrl %}{{ post.url | htmlBaseUrl(metadata.base) }}{% endset %} + { + "id": "{{ absolutePostUrl }}", + "url": "{{ absolutePostUrl }}", + "title": "{{ post.data.title }}", + "content_html": {% if post.content %}{{ post.content | renderTransforms(post.data.page, metadata.base) | dump | safe }}{% else %}""{% endif %}, + "date_published": "{{ post.date | dateToRfc3339 }}" + } + {% if not loop.last %},{% endif %} + {%- endfor %} + ] +}` + } + + throw new Error("Missing or invalid feed type. Received: " + type); +} + +export default function eleventyFeedPlugin(eleventyConfig, options = {}) { + eleventyConfig.versionCheck(pkg["11ty"].compatibility); + + // Guaranteed unique, first add wins + const pluginHtmlBase = eleventyConfig.resolvePlugin("@11ty/eleventy/html-base-plugin"); + eleventyConfig.addPlugin(pluginHtmlBase, options.htmlBasePluginOptions || {}); + + // Guaranteed unique, first add wins + eleventyConfig.addPlugin(rssPlugin, options.rssPluginOptions || {}); + + let slugifyFilter = eleventyConfig.getFilter("slugify"); + let inputPathSuffix = options?.metadata?.title ? `-${slugifyFilter(options?.metadata?.title)}` : ""; + + options = DeepCopy({ + // rss and json also supported + type: "atom", + collection: { + name: false, // required + limit: 0, // limit number of entries, 0 means no limit + }, + outputPath: "/feed.xml", + inputPath: `eleventy-plugin-feed${inputPathSuffix}-${options.type || "atom"}.njk`, // TODO make this more unique + templateData: {}, + metadata: { + title: "Blog Title", + subtitle: "This is a longer description about your blog.", + language: "", // downstream templates use `page.lang` as fallback + base: "https://example.com/", + author: { + name: "Your Name", + email: "", // Optional + } + } + }, options); + + if(!options.collection?.name) { + throw new Error("Missing `collection.name` option in feedPlugin from @11ty/eleventy-plugin-rss."); + } + if(typeof options.collection?.name !== "string") { + throw new Error("Only string is supported in `collection.name` option in feedPlugin from @11ty/eleventy-plugin-rss. Received: " + typeof options.collection?.name); + } + + let eleventyExcludeFromCollections; + let eleventyImport; + if(options.collection.name === "all") { + eleventyExcludeFromCollections = true; + eleventyImport = {}; + } else { + eleventyExcludeFromCollections = [ options.collection.name ] + eleventyImport = { + collections: [ options.collection.name ], + }; + } + + let templateData = { + ...options?.templateData || {}, + permalink: options.outputPath, + eleventyExcludeFromCollections, + eleventyImport, + layout: false, + metadata: options.metadata, + }; + + // Get the first `n` elements of a collection. + eleventyConfig.addFilter("eleventyFeedHead", function(array, n) { + if(!n || n === 0) { + return array; + } + if(n < 0) { + return array.slice(n); + } + return array.slice(0, n); + }); + + eleventyConfig.addTemplate(options.inputPath, getFeedContent(options), templateData); +}; + +Object.defineProperty(eleventyFeedPlugin, "eleventyPackage", { + value: `${pkg.name}/feed-plugin` +}); + +Object.defineProperty(eleventyFeedPlugin, "eleventyPluginOptions", { + value: { + // multiple adds of this one is OK + unique: false + } +}); diff --git a/package-lock.json b/package-lock.json index 1e10e5a..94dedcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "AGPL-3.0-only", "devDependencies": { "@11ty/eleventy": "^3.1.5", + "@11ty/eleventy-plugin-rss": "^3.0.0", "luxon": "^3.7.2" } }, @@ -138,6 +139,23 @@ "url": "https://opencollective.com/11ty" } }, + "node_modules/@11ty/eleventy-plugin-rss": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-rss/-/eleventy-plugin-rss-3.0.0.tgz", + "integrity": "sha512-kKW4DcR57xAyRx0e8gNhKh56ahHVEaAj8/TuXQDnw+B46ig2bWADJAlyj/GdV37IG5ja9dZ4SgKZrs/CHz6YWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@11ty/eleventy-utils": "^2.0.7", + "@11ty/posthtml-urls": "^1.0.2", + "debug": "^4.4.3", + "posthtml": "^0.16.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, "node_modules/@11ty/eleventy-utils": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-2.0.7.tgz", diff --git a/package.json b/package.json index 99f6519..15ca58e 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "type": "module", "devDependencies": { "@11ty/eleventy": "^3.1.5", + "@11ty/eleventy-plugin-rss": "^3.0.0", "luxon": "^3.7.2" } } diff --git a/src/ads/beauty-and-health/thegiddystitcher-sunny-garden.md b/src/ads/beauty-and-health/thegiddystitcher-sunny-garden.md new file mode 100644 index 0000000..80ee7c7 --- /dev/null +++ b/src/ads/beauty-and-health/thegiddystitcher-sunny-garden.md @@ -0,0 +1,7 @@ +--- +title: "AMA about parkrun" +handle: "@thegiddystitcher@sunny.garden" +url: "sunny.garden/@thegiddystitcher" +blurb: "Parkrun is a free weekly 5k event run by volunteers around the world. Talk to me to learn more about it, how to join, whether you're welcome at your level of fitness (yes), what it's like to volunteer. No question too anxious!" +date: 2026-05-03 +--- diff --git a/src/ads/repair-and-diy/essanay-sfba-social.md b/src/ads/repair-and-diy/essanay-sfba-social.md new file mode 100644 index 0000000..c408c89 --- /dev/null +++ b/src/ads/repair-and-diy/essanay-sfba-social.md @@ -0,0 +1,7 @@ +--- +title: "Wind-up and Acoustic Record Players" +handle: "@Essanay@sfba.social" +url: "sfba.social/@Essanay" +blurb: "Do you have an old Victrola or Edison cylinder player that doesn't work? I've fixed a bunch of them and I can help diagnose problems, and maybe even help you fix it. And if you're anywhere near me (Northern California) I could even come take a look at it. This account is for the Niles Essanay Silent FIlm Museum, in Fremont CA, where we have several restored machines on display. I can also give advice on handling of movies (on physical film) and I'm learning how to fix projectors." +date: 2026-05-03 +--- diff --git a/src/ads/mzedp-plasmatrap-com.md b/src/ads/technology/mzedp-plasmatrap-com.md similarity index 93% rename from src/ads/mzedp-plasmatrap-com.md rename to src/ads/technology/mzedp-plasmatrap-com.md index 1f6d238..acb775a 100644 --- a/src/ads/mzedp-plasmatrap-com.md +++ b/src/ads/technology/mzedp-plasmatrap-com.md @@ -3,5 +3,5 @@ title: "Renewable Energy Q&A" handle: "@mzedp@plasmatrap.com" url: "plasmatrap.com/@mzedp" blurb: "I'm an electrical engineer with a specialization in Solar energy, glad to offer guidance on solar energy/renewables/energy transition related questions." -date: 2026-05-02 +date: 2026-05-03 --- diff --git a/src/daily/2026-04-29.njk b/src/daily/2026-04-29.njk new file mode 100644 index 0000000..cea7fc4 --- /dev/null +++ b/src/daily/2026-04-29.njk @@ -0,0 +1,7 @@ +--- +title: Listings for April 29th, 2026 +--- +{% css %}{% include "css/listings.css" %}{% endcss %} + +{% set today = "2026-04-29" %} +{% include "daily-listings.njk" %} diff --git a/src/daily/2026-05-01.njk b/src/daily/2026-05-01.njk new file mode 100644 index 0000000..aeb66ee --- /dev/null +++ b/src/daily/2026-05-01.njk @@ -0,0 +1,7 @@ +--- +title: Listings for May 1st, 2026 +--- +{% css %}{% include "css/listings.css" %}{% endcss %} + +{% set today = "2026-05-01" %} +{% include "daily-listings.njk" %} diff --git a/src/daily/2026-05-02.njk b/src/daily/2026-05-02.njk new file mode 100644 index 0000000..9754859 --- /dev/null +++ b/src/daily/2026-05-02.njk @@ -0,0 +1,7 @@ +--- +title: Listings for May 2nd, 2026 +--- +{% css %}{% include "css/listings.css" %}{% endcss %} + +{% set today = "2026-05-02" %} +{% include "daily-listings.njk" %} diff --git a/src/daily/2026-05-03.njk b/src/daily/2026-05-03.njk new file mode 100644 index 0000000..7e0b9eb --- /dev/null +++ b/src/daily/2026-05-03.njk @@ -0,0 +1,7 @@ +--- +title: Listings for May 3rd, 2026 +--- +{% css %}{% include "css/listings.css" %}{% endcss %} + +{% set today = "2026-05-03" %} +{% include "daily-listings.njk" %} diff --git a/src/daily/daily.11tydata.js b/src/daily/daily.11tydata.js new file mode 100644 index 0000000..336420a --- /dev/null +++ b/src/daily/daily.11tydata.js @@ -0,0 +1,6 @@ +export default { + layout: "base.njk", + tags: [ + "daily" + ] +} diff --git a/src/index.njk b/src/index.njk index 05db413..1775d26 100644 --- a/src/index.njk +++ b/src/index.njk @@ -2,7 +2,7 @@ layout: base.njk title: Fediverse Skillshare Classifieds --- -{% css %}{% include "css/home.css" %}{% endcss %} +{% css %}{% include "css/listings.css" %}{% endcss %}