add links page

This commit is contained in:
Joshua Seigler 2025-06-27 14:49:07 -04:00
parent 28078ca979
commit 9620ed2247
9 changed files with 418 additions and 1 deletions

View file

@ -0,0 +1 @@
{"cachedAt":1751050127345,"type":"text","metadata":{"response":{"url":"https://links.apps.seigler.net/feed/atom?&searchtags=%24webroll","status":200,"headers":{"cache-control":"no-store, no-cache, must-revalidate, post-check=0, pre-check=0","connection":"keep-alive","content-length":"8674","content-security-policy":"upgrade-insecure-requests","content-type":"application/atom+xml; charset=utf-8","date":"Fri, 27 Jun 2025 18:48:47 GMT","expires":"Thu, 19 Nov 1981 08:52:00 GMT","last-modified":"Fri, 27 Jun 2025 18:48:47 GMT","permissions-policy":"interest-cohort=()","pragma":"no-cache","server":"nginx","set-cookie":"shaarli=b2oq0nmgum43e298gdeb06g661; domain=links.apps.seigler.net","strict-transport-security":"max-age=63072000; includeSubDomains; preload","x-content-type-options":"nosniff","x-download-options":"noopen","x-frame-options":"SAMEORIGIN","x-permitted-cross-domain-policies":"none","x-sso-wat":"You've just been SSOed","x-xss-protection":"1; mode=block"}}}}

View file

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Shaarli</title>
<subtitle>Shaared links</subtitle>
<updated>2025-06-27T14:41:37-04:00</updated>
<link rel="self" href="https://links.apps.seigler.net/feed/atom?&amp;searchtags=%24webroll" />
<link rel="search" type="application/opensearchdescription+xml" href="https://links.apps.seigler.net/open-search"
title="Shaarli search - Shaarli" />
<author>
<name>Shaarli</name>
<uri>https://links.apps.seigler.net/</uri>
</author>
<id>https://links.apps.seigler.net/</id>
<generator>Shaarli</generator>
<entry>
<title>Comic Helvetic Font | dafont.com</title>
<link href="https://www.dafont.com/comic-helvetic.font" />
<id>https://links.apps.seigler.net/shaare/WUenqw</id>
<published>2025-06-26T10:29:51-04:00</published>
<updated>2025-06-27T14:41:37-04:00</updated>
<content type="html" xml:lang="en"><![CDATA[<div class="markdown"><p>I don't understand why this feels ok but Comic Sans makes my skin crawl.</p></div>
<br>&#8212; <a href="https://links.apps.seigler.net/shaare/WUenqw" title="Permalink">Permalink</a>]]></content>
<category scheme="https://links.apps.seigler.net/?searchtags=" term="fonts" label="fonts" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="typefaces" label="typefaces" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="typography" label="typography" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="comicsans" label="comicsans" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="$webroll" label="$webroll" />
</entry>
<entry>
<title>NIKA:\git-revise\&gt;</title>
<link href="https://mystor.github.io/git-revise.html" />
<id>https://links.apps.seigler.net/shaare/-cyjHA</id>
<published>2025-06-18T12:18:36-04:00</published>
<updated>2025-06-27T13:10:02-04:00</updated>
<content type="html" xml:lang="en"><![CDATA[<div class="markdown"><p>git-revise is a history editing tool designed for the patch-stack workflow. It's fast, non-destructive, and aims to provide a familiar, powerful, and easy to use re-imagining of the patch stack workflow.</p></div>
<br>&#8212; <a href="https://links.apps.seigler.net/shaare/-cyjHA" title="Permalink">Permalink</a>]]></content>
<category scheme="https://links.apps.seigler.net/?searchtags=" term="git" label="git" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="history" label="history" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="rewriting" label="rewriting" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="fixup" label="fixup" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="$webroll" label="$webroll" />
</entry>
<entry>
<title>Markdown Code Blocks With a Title / Filename - Lusitos Tech Blog</title>
<link href="https://blog.lusito.info/markdown-code-blocks-with-a-title-filename.html" />
<id>https://links.apps.seigler.net/shaare/iRIOLg</id>
<published>2025-06-14T22:28:23-04:00</published>
<updated>2025-06-27T13:10:02-04:00</updated>
<content type="html" xml:lang="en"><![CDATA[<div class="markdown"><p>Smart alternative to immediately using some kind of markdown extension or plugin. Good perspective.</p></div>
<br>&#8212; <a href="https://links.apps.seigler.net/shaare/iRIOLg" title="Permalink">Permalink</a>]]></content>
<category scheme="https://links.apps.seigler.net/?searchtags=" term="markdown" label="Markdown" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="web-development" label="Web-Development" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="progressive-enhancement" label="Progressive-Enhancement" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="performance" label="Performance" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="$webroll" label="$webroll" />
</entry>
<entry>
<title>MidWord! The world's favorite word guessing game</title>
<link href="https://midword.com/" />
<id>https://links.apps.seigler.net/shaare/fS7Wtg</id>
<published>2025-06-14T04:28:49+00:00</published>
<updated>2025-06-27T13:10:02-04:00</updated>
<content type="html" xml:lang="en"><![CDATA[<div class="markdown"><p>Just found my new favorite long-car-ride verbal game!</p></div>
<br>&#8212; <a href="https://links.apps.seigler.net/shaare/fS7Wtg" title="Permalink">Permalink</a>]]></content>
<category scheme="https://links.apps.seigler.net/?searchtags=" term="games" label="games" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="simple" label="simple" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="elegant" label="elegant" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="language" label="language" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="$webroll" label="$webroll" />
</entry>
<entry>
<title>Verissimo Monthly - May 2025 - by Binyamin Grobman</title>
<link href="https://verissimo.substack.com/p/verissimo-monthly-may-2025" />
<id>https://links.apps.seigler.net/shaare/NWhCQg</id>
<published>2025-06-03T17:39:50+00:00</published>
<updated>2025-06-27T13:10:02-04:00</updated>
<content type="html" xml:lang="en"><![CDATA[<div class="markdown"><p>The Unreliability of LLMs &amp; What Lies Ahead</p></div>
<br>&#8212; <a href="https://links.apps.seigler.net/shaare/NWhCQg" title="Permalink">Permalink</a>]]></content>
<category scheme="https://links.apps.seigler.net/?searchtags=" term="llm" label="llm" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="hallucinations" label="hallucinations" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="software" label="software" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="reliability" label="reliability" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="$webroll" label="$webroll" />
</entry>
<entry>
<title>Keeping up appearances | deadSimpleTech</title>
<link href="https://deadsimpletech.com/blog/keeping_up_appearances" />
<id>https://links.apps.seigler.net/shaare/3e_KhA</id>
<published>2025-05-31T04:02:35+00:00</published>
<updated>2025-06-27T13:10:02-04:00</updated>
<content type="html" xml:lang="en"><![CDATA[<div class="markdown"><p>The only reason that LLMs took root in the first place was because our societies in the anglosphere have already developed cultures solely devoted to gaining status and keeping up the appearance of doing things rather than actually doing them. All other values, increasingly including even the accumulation of wealth (while this is still very much a thing that people pursue, wealth is increasingly becoming a proxy for status more than something desired in itself) are becoming subordinated to symbolic status games completely detached from anything real.</p></div>
<br>&#8212; <a href="https://links.apps.seigler.net/shaare/3e_KhA" title="Permalink">Permalink</a>]]></content>
<category scheme="https://links.apps.seigler.net/?searchtags=" term="llm" label="llm" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="strategy" label="strategy" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="status" label="status" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="career" label="career" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="advice" label="advice" />
<category scheme="https://links.apps.seigler.net/?searchtags=" term="$webroll" label="$webroll" />
</entry>
</feed>

View file

@ -0,0 +1,20 @@
import fetch from "@11ty/eleventy-fetch";
import { XMLValidator, XMLParser } from "fast-xml-parser";
const webrollSource = "https://links.apps.seigler.net/feed/atom?&searchtags=%24webroll"
const webrollText = await fetch(webrollSource, { duration: "0s", type: "text" });
const webrollValid = XMLValidator.validate(webrollText);
let webrollFeed;
if (webrollValid === true) {
webrollFeed = new XMLParser({
ignoreAttributes: false,
}).parse(webrollText).feed.entry;
} else {
throw new Error(`Invalid XML from webroll feed. Reason: ${webrollValid.err.msg}`);
}
console.log(webrollFeed);
const webrollPosts = webrollFeed.map(bookmark => {
return {
date: new Date(bookmark.published),
}
});

View file

@ -15,10 +15,12 @@ import { feedPlugin } from "@11ty/eleventy-plugin-rss";
import { execSync } from "child_process";
import eleventyAutoCacheBuster from "eleventy-auto-cache-buster";
import mdPrism from "markdown-it-prism";
import fetch from "@11ty/eleventy-fetch";
import { XMLValidator, XMLParser } from "fast-xml-parser";
dayjs.extend(utc);
export default (config) => {
export default async (config) => {
const slugify = config.getFilter("slugify");
const url = config.getFilter("url");
const mdLib = md({
@ -112,6 +114,8 @@ export default (config) => {
);
});
config.addCollection("webroll", fetchShaarliWebroll);
config.addTransform("prettier", (content, outputPath) => {
if (typeof outputPath !== "string") {
return content;
@ -184,3 +188,29 @@ export default (config) => {
},
};
};
async function fetchShaarliWebroll() {
const url = "https://links.apps.seigler.net/feed/atom?&searchtags=%24webroll";
const urlTextContent = await fetch(url, { duration: "30s", type: "text" });
const validation = XMLValidator.validate(urlTextContent);
let feedContent;
if (validation === true) {
feedContent = new XMLParser({
ignoreAttributes: false,
}).parse(urlTextContent).feed.entry;
} else {
throw new Error(`Invalid XML from webroll feed. Reason: ${validation.err.msg}`);
}
const entries = feedContent.map(entry => {
return {
url: entry.link['@_href'],
data: {
title: entry.title,
date: new Date(entry.published),
description: entry.content['#text'].split('\n<br>&#8212; <a href="https://links.apps.seigler.net/')[0],
tags: entry.category.map(category => category['@_label']).filter(category => category !== '$webroll'),
}
}
});
return entries;
}

126
package-lock.json generated
View file

@ -10,13 +10,16 @@
"license": "ISC",
"dependencies": {
"@11ty/eleventy": "^3.1.0",
"@11ty/eleventy-fetch": "^5.1.0",
"@11ty/eleventy-plugin-rss": "^2.0.4",
"@mdit/plugin-footnote": "^0.22.0",
"@mdit/plugin-spoiler": "^0.21.0",
"@types/node": "^24.0.5",
"dayjs": "^1.11.11",
"eleventy-auto-cache-buster": "^0.8.1",
"eleventy-plugin-clean": "^2.0.1",
"eleventy-plugin-toc": "^1.1.5",
"fast-xml-parser": "^5.2.5",
"markdown-it-anchor": "^9.0.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-prism": "^3.0.0",
@ -129,6 +132,26 @@
"url": "https://opencollective.com/11ty"
}
},
"node_modules/@11ty/eleventy-fetch": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@11ty/eleventy-fetch/-/eleventy-fetch-5.1.0.tgz",
"integrity": "sha512-gSmCA3olJxRwtTkXyS+KIanq1kEufCC+JsHyTa7ta5NqmeUQlWA8zEngtXrDl+ebrAvFz2bNaxLd+0ERpnnSPQ==",
"license": "MIT",
"dependencies": {
"@11ty/eleventy-utils": "^2.0.7",
"@rgrove/parse-xml": "^4.2.0",
"debug": "^4.4.0",
"flatted": "^3.3.3",
"p-queue": "6.6.2"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/11ty"
}
},
"node_modules/@11ty/eleventy-plugin-bundle": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-3.0.6.tgz",
@ -644,6 +667,15 @@
"node": ">=14"
}
},
"node_modules/@rgrove/parse-xml": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@rgrove/parse-xml/-/parse-xml-4.2.0.tgz",
"integrity": "sha512-UuBOt7BOsKVOkFXRe4Ypd/lADuNIfqJXv8GvHqtXaTYXPPKkj2nS2zPllVsrtRjcomDhIJVBnZwfmlI222WH8g==",
"license": "ISC",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@sindresorhus/slugify": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
@ -697,6 +729,15 @@
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.0.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.5.tgz",
"integrity": "sha512-CXEG9E7GCTOZIre0WdDznmnhvF7xi7AmnP/zF496trmLiqlfdtxp9nPRgLVqfmJ8jgtcKcs0EcvOu2yDZSuvTg==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.8.0"
}
},
"node_modules/a-sync-waterfall": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
@ -1491,6 +1532,12 @@
"node": ">= 8"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"license": "MIT"
},
"node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@ -1520,6 +1567,24 @@
"node": ">=8.6.0"
}
},
"node_modules/fast-xml-parser": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz",
"integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"strnum": "^2.1.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
"node_modules/fastq": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
@ -1644,6 +1709,12 @@
"node": ">=8"
}
},
"node_modules/flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"license": "ISC"
},
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@ -2585,6 +2656,15 @@
"integrity": "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==",
"license": "MIT"
},
"node_modules/p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@ -2614,6 +2694,34 @@
"node": ">=8"
}
},
"node_modules/p-queue": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
"integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^4.0.4",
"p-timeout": "^3.2.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-timeout": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
"license": "MIT",
"dependencies": {
"p-finally": "^1.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@ -3278,6 +3386,18 @@
"node": ">=0.8.0"
}
},
"node_modules/strnum": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz",
"integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT"
},
"node_modules/tinyglobby": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
@ -3379,6 +3499,12 @@
"node": ">=20.18.1"
}
},
"node_modules/undici-types": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
"license": "MIT"
},
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",

View file

@ -14,13 +14,16 @@
"license": "ISC",
"dependencies": {
"@11ty/eleventy": "^3.1.0",
"@11ty/eleventy-fetch": "^5.1.0",
"@11ty/eleventy-plugin-rss": "^2.0.4",
"@mdit/plugin-footnote": "^0.22.0",
"@mdit/plugin-spoiler": "^0.21.0",
"@types/node": "^24.0.5",
"dayjs": "^1.11.11",
"eleventy-auto-cache-buster": "^0.8.1",
"eleventy-plugin-clean": "^2.0.1",
"eleventy-plugin-toc": "^1.1.5",
"fast-xml-parser": "^5.2.5",
"markdown-it-anchor": "^9.0.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-prism": "^3.0.0",

View file

@ -12,6 +12,7 @@
<a class="{{ 'nav-active' if '/recipes' in page.url }}" href="{{ "/recipes/" | url }}">/recipes</a>
<a class="{{ 'nav-active' if '/music' in page.url }}" href="{{ "/music/" | url }}">/music</a>
<a class="{{ 'nav-active' if '/books' in page.url }}" href="{{ "/books/" | url }}">/books</a>
<a class="{{ 'nav-active' if '/links' in page.url }}" href="{{ "/links/" | url }}">/links</a>
<a class="{{ 'nav-active' if '/search' in page.url }}" href="{{ "/search/" | url }}">/search</a>
</div>
</nav>

22
site/pages/links.njk Normal file
View file

@ -0,0 +1,22 @@
---
layout: "base.njk"
title: "Links"
permalink: /links/
useTitle: true
---
<main>
<section data-pagefind-body>
<ul class="collection">
{%- for item in collections.webroll -%}
<li>
<a href="{{item.url}}">{{item.data.title}}</a>
{%- if item.data.date -%}
<aside>{{item.data.date | formatDate("MMMM DD, YYYY") }}</aside>
{%- endif -%}
<aside>Tags: {{ item.data.tags | join(", ") }}</aside>
{{item.data.description | safe}}
</li>
{%- endfor -%}
</ul>
</section>
</main>

31
types.d.ts vendored Normal file
View file

@ -0,0 +1,31 @@
declare module "@11ty/eleventy-fetch" {
type FetchType =
| "json"
| "buffer"
| "text";
type EleventyFetchOptionsBase<TType extends FetchType> = {
type: TType;
directory?: string;
concurrency?: number;
fetchOptions?: RequestInit;
dryRun?: boolean;
removeUrlQueryParams?: boolean;
verbose?: boolean;
hashLength?: number;
duration?: string;
formatUrlForDisplay?: (url: string) => string;
}
type EleventyFetch = <TReturn, TType extends FetchType = "json">(url: string, options: EleventyFetchOptionsBase<TType>) =>
Promise<
TType extends "json" ? TReturn :
TType extends "buffer" ? Buffer :
TType extends "text" ? string :
never
>;
const fetch: EleventyFetch;
export default fetch;
}