Set up RSS/Atom/JSON feeds for blog
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import pugPlugin from "@11ty/eleventy-plugin-pug";
|
||||
import rssPlugin from "@11ty/eleventy-plugin-rss";
|
||||
import brokenLinksPlugin from "eleventy-plugin-broken-links";
|
||||
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
|
||||
import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";
|
||||
@@ -10,6 +11,7 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.setInputDirectory("src")
|
||||
eleventyConfig.addPlugin(brokenLinksPlugin);
|
||||
eleventyConfig.addPlugin(pugPlugin);
|
||||
eleventyConfig.addPlugin(rssPlugin);
|
||||
eleventyConfig.addPlugin(syntaxHighlight);
|
||||
eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
|
||||
htmlOptions: {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"@11ty/eleventy": "^3.0.0",
|
||||
"@11ty/eleventy-img": "^6.0.1",
|
||||
"@11ty/eleventy-plugin-pug": "^1.0.0",
|
||||
"@11ty/eleventy-plugin-rss": "^2.0.3",
|
||||
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
|
||||
"eleventy-plugin-broken-links": "^2.2.1",
|
||||
"opml": "^0.5.7"
|
||||
|
||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@@ -17,6 +17,9 @@ importers:
|
||||
'@11ty/eleventy-plugin-pug':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
'@11ty/eleventy-plugin-rss':
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.3
|
||||
'@11ty/eleventy-plugin-syntaxhighlight':
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
@@ -60,6 +63,9 @@ packages:
|
||||
resolution: {integrity: sha512-7o9SQqbHfiIctfvWpbP6tibzM1R5YnC97yrMn8r8nPGA3umGbbSMUFr9sx4lepLbfzqd21svhq9X3SJRhj4xpg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@11ty/eleventy-plugin-rss@2.0.3':
|
||||
resolution: {integrity: sha512-ubK97uahCLpKhORLfblgxLcoaNqTcKde1cH8CeRKNTFoUuuDSEjWZtodV9fKrg+uOp5X74dO43z1/io6hhs5Bw==}
|
||||
|
||||
'@11ty/eleventy-plugin-syntaxhighlight@5.0.0':
|
||||
resolution: {integrity: sha512-y9BUmP1GofmbJgxM1+ky/UpFCpD8JSOeLeKItUs0WApgnrHk9haHziW7lS86lbArX5SiCVo4zTTw9x53gvRCaA==}
|
||||
|
||||
@@ -1469,6 +1475,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@11ty/eleventy-plugin-rss@2.0.3':
|
||||
dependencies:
|
||||
'@11ty/eleventy-utils': 2.0.1
|
||||
'@11ty/posthtml-urls': 1.0.1
|
||||
debug: 4.4.0
|
||||
posthtml: 0.16.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@11ty/eleventy-plugin-syntaxhighlight@5.0.0':
|
||||
dependencies:
|
||||
prismjs: 1.30.0
|
||||
|
||||
47
src/blog/feeds/atom.xml.njk
Normal file
47
src/blog/feeds/atom.xml.njk
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
permalink: /blog/atom.xml
|
||||
eleventyExcludeFromCollections: true
|
||||
metadata:
|
||||
title: "Garrett's Blog"
|
||||
description: "Write-ups and musings by Garrett Mills, often technical, sometimes not."
|
||||
language: en
|
||||
base: "https://garrettmills.dev"
|
||||
author:
|
||||
name: "Garrett Mills"
|
||||
email: "shout@garrettmills.dev"
|
||||
---
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml-stylesheet href="http://localhost:8080/blog/feed.xsl" type="text/xsl"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<id>{{ metadata.base }}/#about</id>
|
||||
<title>{{ metadata.title }}</title>
|
||||
<updated>{{ collections.blog | getNewestCollectionItemDate | dateToRfc3339 }}</updated>
|
||||
<author>
|
||||
<name>{{ metadata.author.name }}</name>
|
||||
<email>{{ metadata.author.email }}</email>
|
||||
<uri>{{ metadata.base }}/#about</uri>
|
||||
</author>
|
||||
<link rel="alternate" href="{{ metadata.base }}/blog"/>
|
||||
<link rel="self" href="{{ metadata.base }}/blog/atom.xml"/>
|
||||
<subtitle>{{ metadata.description }}</subtitle>
|
||||
<logo>{{ metadata.base }}/assets/favicon/apple-touch-icon.png</logo>
|
||||
<icon>{{ metadata.base }}/assets/favicon/favicon.ico</icon>
|
||||
<rights>Copyright (c) 2025 Garrett Mills. See website for licensing details.</rights>
|
||||
<category term="Technology"/>
|
||||
<category term="Software Development"/>
|
||||
{%- for post in collections.blog %}
|
||||
{%- set absolutePostUrl = post.url | htmlBaseUrl(metadata.base) %}
|
||||
<entry>
|
||||
<title type="html"><![CDATA[{{ post.data.title }}]]></title>
|
||||
<id>{{ absolutePostUrl }}</id>
|
||||
<link href="{{ absolutePostUrl }}"/>
|
||||
<updated>{{ post.date | dateToRfc3339 }}</updated>
|
||||
<author>
|
||||
<name>{{ metadata.author.name }}</name>
|
||||
<email>{{ metadata.author.email }}</email>
|
||||
<uri>{{ metadata.base }}/#about</uri>
|
||||
</author>
|
||||
<content type="html">{{ post.content | renderTransforms(post.data.page, metadata.base) }}</content>
|
||||
</entry>
|
||||
{%- endfor %}
|
||||
</feed>
|
||||
45
src/blog/feeds/json.json.njk
Normal file
45
src/blog/feeds/json.json.njk
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
permalink: /blog/json.json
|
||||
eleventyExcludeFromCollections: true
|
||||
metadata:
|
||||
title: "Garrett's Blog"
|
||||
description: "Write-ups and musings by Garrett Mills, often technical, sometimes not."
|
||||
language: en
|
||||
base: "https://garrettmills.dev"
|
||||
author:
|
||||
name: "Garrett Mills"
|
||||
email: "shout@garrettmills.dev"
|
||||
---
|
||||
{
|
||||
"version": "https://jsonfeed.org/version/1.1",
|
||||
"title": "{{ metadata.title }}",
|
||||
"language": "{{ metadata.language }}",
|
||||
"home_page_url": "{{ metadata.base | addPathPrefixToFullUrl }}",
|
||||
"feed_url": "{{ permalink | htmlBaseUrl(metadata.base) }}",
|
||||
"description": "{{ metadata.description }}",
|
||||
"icon": "{{ metadata.base }}/assets/favicon/apple-touch-icon.png",
|
||||
"authors": [
|
||||
{
|
||||
"name": "{{ metadata.author.name }}",
|
||||
"url": "{{ metadata.base }}/#about"
|
||||
}
|
||||
],
|
||||
"items": [
|
||||
{%- for post in collections.blog %}
|
||||
{%- 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 }}",
|
||||
"date_modified": "{{ post.date | dateToRfc3339 }}",
|
||||
"author": {
|
||||
"name": "{{ metadata.author.name }}",
|
||||
"url": "{{ metadata.base }}/#about"
|
||||
}
|
||||
}
|
||||
{% if not loop.last %},{% endif %}
|
||||
{%- endfor %}
|
||||
]
|
||||
}
|
||||
119
src/blog/feeds/obsidian.xsl.njk
Normal file
119
src/blog/feeds/obsidian.xsl.njk
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
permalink: /blog/feed.xsl
|
||||
---
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
|
||||
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
|
||||
<xsl:template match="/">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<head>
|
||||
<title><xsl:value-of select="/rss/channel/title"/>
|
||||
<xsl:value-of select="/atom:feed/atom:title"/> | Web Feed</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
||||
<style type="text/css">
|
||||
{% include "../../assets/css/normalize.css" %}
|
||||
{% include "../../assets/css/prism-cb.css" %}
|
||||
{% include "../../assets/css/obsidian.css" %}
|
||||
body {
|
||||
--background: #111;
|
||||
--background-2: #252525;
|
||||
--background-3: #444;
|
||||
--color: #fffbe3;
|
||||
--color-2: #d0c895;
|
||||
|
||||
background: var(--background);
|
||||
color: var(--color);
|
||||
font-family: "Reckless", serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
max-width: 800px;
|
||||
width: calc(100% - 40px);
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
margin-bottom: 100px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<header class="hero">glm.</header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{{ metadata.base }}/">Return to Main Site</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="content-wrapper">
|
||||
<blockquote style="font-size: 1.3rem">
|
||||
<p>
|
||||
<strong>This is a web feed,</strong> also known as an RSS feed. <strong>Subscribe</strong> by copying the URL from the address bar into your newsreader.
|
||||
Visit <a href="https://aboutfeeds.com">About Feeds</a> to get started with newsreaders and subscribing. It’s free.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<header class="py-5">
|
||||
<h1 class="border-0">
|
||||
<!-- https://commons.wikimedia.org/wiki/File:Feed-icon.svg -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="vertical-align: text-bottom; width: 1.2em; height: 1.2em; margin-right: 10px;" class="pr-1" id="RSSicon" viewBox="0 0 256 256">
|
||||
<defs>
|
||||
<linearGradient x1="0.085" y1="0.085" x2="0.915" y2="0.915" id="RSSg">
|
||||
<stop offset="0.0" stop-color="#E3702D"/><stop offset="0.1071" stop-color="#EA7D31"/>
|
||||
<stop offset="0.3503" stop-color="#F69537"/><stop offset="0.5" stop-color="#FB9E3A"/>
|
||||
<stop offset="0.7016" stop-color="#EA7C31"/><stop offset="0.8866" stop-color="#DE642B"/>
|
||||
<stop offset="1.0" stop-color="#D95B29"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="256" height="256" rx="55" ry="55" x="0" y="0" fill="#CC5D15"/>
|
||||
<rect width="246" height="246" rx="50" ry="50" x="5" y="5" fill="#F49C52"/>
|
||||
<rect width="236" height="236" rx="47" ry="47" x="10" y="10" fill="url(#RSSg)"/>
|
||||
<circle cx="68" cy="189" r="24" fill="#FFF"/>
|
||||
<path d="M160 213h-34a82 82 0 0 0 -82 -82v-34a116 116 0 0 1 116 116z" fill="#FFF"/>
|
||||
<path d="M184 213A140 140 0 0 0 44 73 V 38a175 175 0 0 1 175 175z" fill="#FFF"/>
|
||||
</svg>
|
||||
<xsl:value-of select="/rss/channel/title"/>
|
||||
<xsl:value-of select="/atom:feed/atom:title"/>
|
||||
</h1>
|
||||
<p><xsl:value-of select="/rss/channel/description"/>
|
||||
<xsl:value-of select="/atom:feed/atom:subtitle"/></p>
|
||||
</header>
|
||||
<h2>Web Feed Items</h2>
|
||||
<ul class="plain">
|
||||
<xsl:for-each select="/rss/channel/item">
|
||||
<li>
|
||||
<div class="secondary"><xsl:value-of select="substring(pubDate, 5, 12)"/></div>
|
||||
<a target="_blank" class="title">
|
||||
<xsl:attribute name="href">
|
||||
<xsl:value-of select="link"/>
|
||||
</xsl:attribute>
|
||||
<xsl:value-of select="title"/>
|
||||
</a>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select="/atom:feed/atom:entry">
|
||||
<li>
|
||||
<div class="secondary"><xsl:value-of select="substring(atom:updated, 0, 11)"/></div>
|
||||
<a target="_blank" class="title">
|
||||
<xsl:attribute name="href">
|
||||
<xsl:value-of select="atom:link/@href"/>
|
||||
</xsl:attribute>
|
||||
<xsl:value-of select="atom:title"/>
|
||||
</a>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
47
src/blog/feeds/rss2.xml.njk
Normal file
47
src/blog/feeds/rss2.xml.njk
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
permalink: /blog/rss2.xml
|
||||
eleventyExcludeFromCollections: true
|
||||
metadata:
|
||||
title: "Garrett's Blog"
|
||||
description: "Write-ups and musings by Garrett Mills, often technical, sometimes not."
|
||||
language: en
|
||||
base: "https://garrettmills.dev"
|
||||
author:
|
||||
name: "Garrett Mills"
|
||||
email: "shout@garrettmills.dev"
|
||||
---
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml-stylesheet href="http://localhost:8080/blog/feed.xsl" type="text/xsl"?>
|
||||
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{{ metadata.title }}</title>
|
||||
<link>{{ metadata.base }}/blog</link>
|
||||
<description>{{ metadata.description }}</description>
|
||||
<lastBuildDate>{{ collections.blog | getNewestCollectionItemDate | dateToRfc822 }}</lastBuildDate>
|
||||
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
|
||||
<language>{{ metadata.language }}</language>
|
||||
<image>
|
||||
<title>{{ metadata.title }}</title>
|
||||
<url>{{ metadata.base }}/assets/favicon/apple-touch-icon.png</url>
|
||||
<link>{{ metadata.base }}/blog</link>
|
||||
</image>
|
||||
<copyright>Copyright (c) 2025 Garrett Mills. See website for licensing details.</copyright>
|
||||
<category>Technology</category>
|
||||
<category>Software Development</category>
|
||||
<atom:link href="permalink | htmlBaseUrl(metadata.base)" rel="self" type="application/rss+xml"/>
|
||||
|
||||
{%- for post in collections.blog %}
|
||||
{%- set absolutePostUrl = post.url | htmlBaseUrl(metadata.base) %}
|
||||
<item>
|
||||
<title><![CDATA[{{ post.data.title }}]]></title>
|
||||
<link>{{ absolutePostUrl }}</link>
|
||||
<guid>{{ absolutePostUrl }}</guid>
|
||||
<pubDate>{{ post.date | dateToRfc822 }}</pubDate>
|
||||
<author>{{ metadata.author.name }}</author>
|
||||
<dc:creator>{{ metadata.author.name }}</dc:creator>
|
||||
<description>{{ post.content | renderTransforms(post.data.page, metadata.base) }}</description>
|
||||
<content:encoded>{{ post.content | renderTransforms(post.data.page, metadata.base) }}</content:encoded>
|
||||
</item>
|
||||
{%- endfor %}
|
||||
</channel>
|
||||
</rss>
|
||||
Reference in New Issue
Block a user