Add RSS feed, add links for direct md editing on GitHub and update favicon

This commit is contained in:
thiloho
2025-04-26 22:48:37 +02:00
parent c06006d24b
commit 480ddd1e68
24 changed files with 484 additions and 23 deletions

View File

@@ -4,6 +4,8 @@ import tailwindcss from "@tailwindcss/vite";
export default defineConfig({ export default defineConfig({
site: "https://thiloho.github.io", site: "https://thiloho.github.io",
trailingSlash: "never",
prefetch: { prefetch: {
prefetchAll: true, prefetchAll: true,
}, },

250
package-lock.json generated
View File

@@ -8,8 +8,11 @@
"name": "thiloho-github-io", "name": "thiloho-github-io",
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@astrojs/rss": "4.0.11",
"@tailwindcss/vite": "4.1.4", "@tailwindcss/vite": "4.1.4",
"astro": "5.7.5", "astro": "5.7.5",
"markdown-it": "14.1.0",
"sanitize-html": "2.16.0",
"tailwindcss": "4.1.4" "tailwindcss": "4.1.4"
}, },
"devDependencies": { "devDependencies": {
@@ -71,6 +74,16 @@
"node": "^18.17.1 || ^20.3.0 || >=22.0.0" "node": "^18.17.1 || ^20.3.0 || >=22.0.0"
} }
}, },
"node_modules/@astrojs/rss": {
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.11.tgz",
"integrity": "sha512-3e3H8i6kc97KGnn9iaZBJpIkdoQi8MmR5zH5R+dWsfCM44lLTszOqy1OBfGGxDt56mpQkYVtZJWoxMyWuUZBfw==",
"license": "MIT",
"dependencies": {
"fast-xml-parser": "^4.5.0",
"kleur": "^4.1.5"
}
},
"node_modules/@astrojs/telemetry": { "node_modules/@astrojs/telemetry": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.2.1.tgz", "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.2.1.tgz",
@@ -2221,6 +2234,15 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/defu": { "node_modules/defu": {
"version": "6.1.4", "version": "6.1.4",
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
@@ -2303,6 +2325,73 @@
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/dom-serializer/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dset": { "node_modules/dset": {
"version": "3.1.4", "version": "3.1.4",
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
@@ -2428,6 +2517,24 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-xml-parser": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz",
"integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"strnum": "^1.1.1"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
"node_modules/fdir": { "node_modules/fdir": {
"version": "6.4.4", "version": "6.4.4",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
@@ -2726,6 +2833,37 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
}
},
"node_modules/htmlparser2/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/http-cache-semantics": { "node_modules/http-cache-semantics": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
@@ -2812,6 +2950,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-wsl": { "node_modules/is-wsl": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
@@ -3085,6 +3232,15 @@
"url": "https://opencollective.com/parcel" "url": "https://opencollective.com/parcel"
} }
}, },
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/lodash.castarray": { "node_modules/lodash.castarray": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
@@ -3142,6 +3298,35 @@
"source-map-js": "^1.2.0" "source-map-js": "^1.2.0"
} }
}, },
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdown-it/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/markdown-table": { "node_modules/markdown-table": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
@@ -3383,6 +3568,12 @@
"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
"license": "CC0-1.0" "license": "CC0-1.0"
}, },
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"license": "MIT"
},
"node_modules/micromark": { "node_modules/micromark": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
@@ -4149,6 +4340,12 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/parse-srcset": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
"license": "MIT"
},
"node_modules/parse5": { "node_modules/parse5": {
"version": "7.3.0", "version": "7.3.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
@@ -4293,6 +4490,15 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/radix3": { "node_modules/radix3": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz",
@@ -4591,6 +4797,32 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/sanitize-html": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.16.0.tgz",
"integrity": "sha512-0s4caLuHHaZFVxFTG74oW91+j6vW7gKbGD6CD2+miP73CE6z6YtOBN0ArtLd2UGyi4IC7K47v3ENUbQX4jV3Mg==",
"license": "MIT",
"dependencies": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
"htmlparser2": "^8.0.0",
"is-plain-object": "^5.0.0",
"parse-srcset": "^1.0.2",
"postcss": "^8.3.11"
}
},
"node_modules/sanitize-html/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sass-formatter": { "node_modules/sass-formatter": {
"version": "0.7.9", "version": "0.7.9",
"resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz", "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz",
@@ -4762,6 +4994,18 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1" "url": "https://github.com/chalk/strip-ansi?sponsor=1"
} }
}, },
"node_modules/strnum": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz",
"integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT"
},
"node_modules/suf-log": { "node_modules/suf-log": {
"version": "2.5.3", "version": "2.5.3",
"resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz",
@@ -4893,6 +5137,12 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT"
},
"node_modules/ufo": { "node_modules/ufo": {
"version": "1.6.1", "version": "1.6.1",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",

View File

@@ -10,8 +10,11 @@
"format": "prettier . --write" "format": "prettier . --write"
}, },
"dependencies": { "dependencies": {
"@astrojs/rss": "4.0.11",
"@tailwindcss/vite": "4.1.4", "@tailwindcss/vite": "4.1.4",
"astro": "5.7.5", "astro": "5.7.5",
"markdown-it": "14.1.0",
"sanitize-html": "2.16.0",
"tailwindcss": "4.1.4" "tailwindcss": "4.1.4"
}, },
"devDependencies": { "devDependencies": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="174.8" height="131.4"><svg viewBox="0 0 174.8 131.4" xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="175" height="175"><svg viewBox="0 0 175 175" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="174.8" height="131.4" fill="#e5e5e5" stroke="none" rx="20" ry="20"></rect> <rect x="0" y="0" width="175" height="175" fill="#e5e5e5" stroke="none" rx="43.75" ry="43.75"></rect>
<g transform="translate(20, 30)"> <g transform="translate(20, 52)">
<g id="SvgjsG1082" stroke-linecap="round" fill-rule="evenodd" font-size="9pt" stroke="#525252" stroke-width="0.125mm" fill="#a1a1a1" style="stroke:#525252;stroke-width:0.125mm;fill:#a1a1a1"> <g id="SvgjsG1039" stroke-linecap="round" fill-rule="evenodd" font-size="9pt" stroke="#525252" stroke-width="0.125mm" fill="#a1a1a1" style="stroke:#525252;stroke-width:0.125mm;fill:#a1a1a1">
<path d="M 92.2 71.4 L 63.1 71.4 L 63.1 67.2 L 64.4 67.2 Q 66.7 67.2 68.55 66.7 Q 70.4 66.2 71.5 64.65 A 5.045 5.045 0 0 0 72.17 63.27 Q 72.587 61.979 72.6 60.121 A 17.219 17.219 0 0 0 72.6 60 L 72.6 11 A 12.54 12.54 0 0 0 72.509 9.435 Q 72.285 7.659 71.509 6.627 A 3.715 3.715 0 0 0 71.45 6.55 Q 70.3 5.1 68.45 4.65 A 15.785 15.785 0 0 0 66.001 4.263 A 19.693 19.693 0 0 0 64.4 4.2 L 63.1 4.2 L 63.1 0 L 92.2 0 L 92.2 4.2 L 90.9 4.2 A 17.148 17.148 0 0 0 88.267 4.395 A 14.51 14.51 0 0 0 86.8 4.7 A 5.523 5.523 0 0 0 84.882 5.604 A 5.171 5.171 0 0 0 83.8 6.7 Q 82.771 8.104 82.705 10.996 A 17.684 17.684 0 0 0 82.7 11.4 L 82.7 31.6 L 115.2 31.6 L 115.2 11.4 A 14.799 14.799 0 0 0 115.113 9.734 Q 114.92 8.032 114.296 6.995 A 3.873 3.873 0 0 0 114.1 6.7 Q 113 5.2 111.15 4.7 A 14.115 14.115 0 0 0 108.926 4.296 A 18.631 18.631 0 0 0 107 4.2 L 105.7 4.2 L 105.7 0 L 134.8 0 L 134.8 4.2 L 133.5 4.2 A 17.148 17.148 0 0 0 130.867 4.395 A 14.51 14.51 0 0 0 129.4 4.7 A 5.523 5.523 0 0 0 127.482 5.604 A 5.171 5.171 0 0 0 126.4 6.7 Q 125.371 8.104 125.305 10.996 A 17.684 17.684 0 0 0 125.3 11.4 L 125.3 60.5 A 11.673 11.673 0 0 0 125.401 62.094 Q 125.512 62.894 125.743 63.543 A 4.544 4.544 0 0 0 126.45 64.85 Q 127.6 66.3 129.45 66.75 A 15.785 15.785 0 0 0 131.899 67.137 A 19.693 19.693 0 0 0 133.5 67.2 L 134.8 67.2 L 134.8 71.4 L 105.7 71.4 L 105.7 67.2 L 107 67.2 Q 109.3 67.2 111.15 66.7 Q 113 66.2 114.1 64.65 A 5.045 5.045 0 0 0 114.77 63.27 Q 115.187 61.979 115.2 60.121 A 17.219 17.219 0 0 0 115.2 60 L 115.2 36.6 L 82.7 36.6 L 82.7 60 A 14.094 14.094 0 0 0 82.787 61.621 Q 82.998 63.435 83.718 64.53 A 4.105 4.105 0 0 0 83.8 64.65 Q 84.9 66.2 86.8 66.7 A 15.233 15.233 0 0 0 89.554 67.151 A 18.189 18.189 0 0 0 90.9 67.2 L 92.2 67.2 L 92.2 71.4 Z M 44.1 71.4 L 13 71.4 L 13 67.2 L 15.3 67.2 A 18.863 18.863 0 0 0 17.664 67.058 A 15.182 15.182 0 0 0 19.35 66.75 Q 21.2 66.3 22.35 64.85 Q 23.179 63.805 23.41 62.007 A 11.832 11.832 0 0 0 23.5 60.5 L 23.5 5 L 13.9 5 Q 11.343 5 9.698 5.828 A 4.991 4.991 0 0 0 7.8 7.45 Q 6.1 9.9 5.7 13.2 L 5.2 17.5 L 0 17.5 L 0.5 0 L 56.8 0 L 57.3 17.5 L 52.1 17.5 L 51.6 13.2 A 13.62 13.62 0 0 0 50.739 9.756 A 11.607 11.607 0 0 0 49.5 7.45 Q 48.152 5.507 45.043 5.105 A 13.611 13.611 0 0 0 43.3 5 L 33.6 5 L 33.6 60 A 14.094 14.094 0 0 0 33.687 61.621 Q 33.898 63.435 34.618 64.53 A 4.105 4.105 0 0 0 34.7 64.65 Q 35.8 66.2 37.7 66.7 A 15.233 15.233 0 0 0 40.454 67.151 A 18.189 18.189 0 0 0 41.8 67.2 L 44.1 67.2 L 44.1 71.4 Z" vector-effect="non-scaling-stroke"></path> <path d="M 92.2 71.4 L 63.1 71.4 L 63.1 67.2 L 64.4 67.2 Q 66.7 67.2 68.55 66.7 Q 70.4 66.2 71.5 64.65 A 5.045 5.045 0 0 0 72.17 63.27 Q 72.587 61.979 72.6 60.121 A 17.219 17.219 0 0 0 72.6 60 L 72.6 11 A 12.54 12.54 0 0 0 72.509 9.435 Q 72.285 7.659 71.509 6.627 A 3.715 3.715 0 0 0 71.45 6.55 Q 70.3 5.1 68.45 4.65 A 15.785 15.785 0 0 0 66.001 4.263 A 19.693 19.693 0 0 0 64.4 4.2 L 63.1 4.2 L 63.1 0 L 92.2 0 L 92.2 4.2 L 90.9 4.2 A 17.148 17.148 0 0 0 88.267 4.395 A 14.51 14.51 0 0 0 86.8 4.7 A 5.523 5.523 0 0 0 84.882 5.604 A 5.171 5.171 0 0 0 83.8 6.7 Q 82.771 8.104 82.705 10.996 A 17.684 17.684 0 0 0 82.7 11.4 L 82.7 31.6 L 115.2 31.6 L 115.2 11.4 A 14.799 14.799 0 0 0 115.113 9.734 Q 114.92 8.032 114.296 6.995 A 3.873 3.873 0 0 0 114.1 6.7 Q 113 5.2 111.15 4.7 A 14.115 14.115 0 0 0 108.926 4.296 A 18.631 18.631 0 0 0 107 4.2 L 105.7 4.2 L 105.7 0 L 134.8 0 L 134.8 4.2 L 133.5 4.2 A 17.148 17.148 0 0 0 130.867 4.395 A 14.51 14.51 0 0 0 129.4 4.7 A 5.523 5.523 0 0 0 127.482 5.604 A 5.171 5.171 0 0 0 126.4 6.7 Q 125.371 8.104 125.305 10.996 A 17.684 17.684 0 0 0 125.3 11.4 L 125.3 60.5 A 11.673 11.673 0 0 0 125.401 62.094 Q 125.512 62.894 125.743 63.543 A 4.544 4.544 0 0 0 126.45 64.85 Q 127.6 66.3 129.45 66.75 A 15.785 15.785 0 0 0 131.899 67.137 A 19.693 19.693 0 0 0 133.5 67.2 L 134.8 67.2 L 134.8 71.4 L 105.7 71.4 L 105.7 67.2 L 107 67.2 Q 109.3 67.2 111.15 66.7 Q 113 66.2 114.1 64.65 A 5.045 5.045 0 0 0 114.77 63.27 Q 115.187 61.979 115.2 60.121 A 17.219 17.219 0 0 0 115.2 60 L 115.2 36.6 L 82.7 36.6 L 82.7 60 A 14.094 14.094 0 0 0 82.787 61.621 Q 82.998 63.435 83.718 64.53 A 4.105 4.105 0 0 0 83.8 64.65 Q 84.9 66.2 86.8 66.7 A 15.233 15.233 0 0 0 89.554 67.151 A 18.189 18.189 0 0 0 90.9 67.2 L 92.2 67.2 L 92.2 71.4 Z M 44.1 71.4 L 13 71.4 L 13 67.2 L 15.3 67.2 A 18.863 18.863 0 0 0 17.664 67.058 A 15.182 15.182 0 0 0 19.35 66.75 Q 21.2 66.3 22.35 64.85 Q 23.179 63.805 23.41 62.007 A 11.832 11.832 0 0 0 23.5 60.5 L 23.5 5 L 13.9 5 Q 11.343 5 9.698 5.828 A 4.991 4.991 0 0 0 7.8 7.45 Q 6.1 9.9 5.7 13.2 L 5.2 17.5 L 0 17.5 L 0.5 0 L 56.8 0 L 57.3 17.5 L 52.1 17.5 L 51.6 13.2 A 13.62 13.62 0 0 0 50.739 9.756 A 11.607 11.607 0 0 0 49.5 7.45 Q 48.152 5.507 45.043 5.105 A 13.611 13.611 0 0 0 43.3 5 L 33.6 5 L 33.6 60 A 14.094 14.094 0 0 0 33.687 61.621 Q 33.898 63.435 34.618 64.53 A 4.105 4.105 0 0 0 34.7 64.65 Q 35.8 66.2 37.7 66.7 A 15.233 15.233 0 0 0 40.454 67.151 A 18.189 18.189 0 0 0 41.8 67.2 L 44.1 67.2 L 44.1 71.4 Z" vector-effect="non-scaling-stroke"></path>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

141
public/pretty-feed-v3.xsl Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -6,7 +6,7 @@ interface Props {
const { date } = Astro.props; const { date } = Astro.props;
--- ---
<time datetime={date.toISOString()}> <time datetime={date.toISOString()} class="underline decoration-dotted">
{ {
date.toLocaleString("en-us", { date.toLocaleString("en-us", {
year: "numeric", year: "numeric",

View File

@@ -4,10 +4,10 @@ import "../styles/global.css";
interface Props { interface Props {
title: string; title: string;
metaDescription: string; description: string;
} }
const { title, metaDescription } = Astro.props; const { title, description } = Astro.props;
--- ---
<head> <head>
@@ -21,7 +21,14 @@ const { title, metaDescription } = Astro.props;
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
<title>{title}</title> <title>{title}</title>
<meta name="description" content={metaDescription} /> <meta name="description" content={description} />
<meta name="color-scheme" content="light dark" />
<link
rel="alternate"
type="application/rss+xml"
title="Your Site's Title"
href={new URL("rss.xml", Astro.site)}
/>
<ClientRouter /> <ClientRouter />
<script is:inline> <script is:inline>
const setTheme = () => { const setTheme = () => {

View File

@@ -5,9 +5,10 @@ interface Props {
title: string; title: string;
pubDate?: Date; pubDate?: Date;
modDate?: Date; modDate?: Date;
slug?: string;
} }
const { title, pubDate, modDate } = Astro.props; const { title, pubDate, modDate, slug } = Astro.props;
--- ---
<header class="bg-white dark:bg-neutral-800"> <header class="bg-white dark:bg-neutral-800">
@@ -24,6 +25,21 @@ const { title, pubDate, modDate } = Astro.props;
Last modified:{" "} Last modified:{" "}
{modDate ? <Date date={modDate} /> : <span>No modifications</span>} {modDate ? <Date date={modDate} /> : <span>No modifications</span>}
</p> </p>
<a
href={`https://github.com/thiloho/thiloho.github.io/edit/main/src/content/blog/${slug}/index.md`}
class="text-blue-800 dark:text-blue-300 inline-flex items-center gap-1 hover:no-underline"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="size-5"
>
<path d="m5.433 13.917 1.262-3.155A4 4 0 0 1 7.58 9.42l6.92-6.918a2.121 2.121 0 0 1 3 3l-6.92 6.918c-.383.383-.84.685-1.343.886l-3.154 1.262a.5.5 0 0 1-.65-.65Z" />
<path d="M3.5 5.75c0-.69.56-1.25 1.25-1.25H10A.75.75 0 0 0 10 3H4.75A2.75 2.75 0 0 0 2 5.75v9.5A2.75 2.75 0 0 0 4.75 18h9.5A2.75 2.75 0 0 0 17 15.25V10a.75.75 0 0 0-1.5 0v5.25c0 .69-.56 1.25-1.25 1.25h-9.5c-.69 0-1.25-.56-1.25-1.25v-9.5Z" />
</svg>
Edit this page
</a>
</hgroup> </hgroup>
) : ( ) : (
<h1>{title}</h1> <h1>{title}</h1>

View File

@@ -6,7 +6,7 @@ const routes = ["blog"];
<nav class="max-w-none bg-neutral-100 dark:bg-neutral-900 sticky top-0 z-10"> <nav class="max-w-none bg-neutral-100 dark:bg-neutral-900 sticky top-0 z-10">
<div <div
class="dark:text-neutral-300 flex items-center justify-between max-w-screen-lg mx-auto ps-4 pe-2" class="text-neutral-700 dark:text-neutral-300 flex items-center justify-between max-w-screen-lg mx-auto ps-4 pe-2"
> >
<a href="/" title="Home"> <a href="/" title="Home">
<Logo width={42} height={42} /> <Logo width={42} height={42} />
@@ -54,6 +54,26 @@ const routes = ["blog"];
></path> ></path>
</svg> </svg>
</button> </button>
<a
class="inline-grid place-content-center p-2 cursor-pointer border-b-2 border-transparent hover:bg-neutral-200 hover:border-neutral-400 hover:dark:bg-neutral-700 hover:dark:border-neutral-600"
title="RSS feed"
href="/rss.xml"
>
<!-- RSS -->
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="size-5"
>
<path
d="M3.75 3a.75.75 0 0 0-.75.75v.5c0 .414.336.75.75.75H4c6.075 0 11 4.925 11 11v.25c0 .414.336.75.75.75h.5a.75.75 0 0 0 .75-.75V16C17 8.82 11.18 3 4 3h-.25Z"
></path>
<path
d="M3 8.75A.75.75 0 0 1 3.75 8H4a8 8 0 0 1 8 8v.25a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1-.75-.75V16a6 6 0 0 0-6-6h-.25A.75.75 0 0 1 3 9.25v-.5ZM7 15a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z"
></path>
</svg>
</a>
</div> </div>
</div> </div>
</nav> </nav>

View File

@@ -8,7 +8,6 @@ const index = defineCollection({
const blog = defineCollection({ const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }), loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }),
schema: z.object({ schema: z.object({
id: z.number().positive(),
title: z.string(), title: z.string(),
description: z.string(), description: z.string(),
pubDate: z.coerce.date(), pubDate: z.coerce.date(),

View File

@@ -1,5 +1,4 @@
--- ---
id: 1
title: "Steps to install NixOS on a system with ext4 and LUKS" title: "Steps to install NixOS on a system with ext4 and LUKS"
description: "A guide to installing NixOS with full disk encryption using LUKS and LVM, showing the complete process from disk partitioning to system configuration" description: "A guide to installing NixOS with full disk encryption using LUKS and LVM, showing the complete process from disk partitioning to system configuration"
pubDate: "2025-01-04" pubDate: "2025-01-04"

View File

@@ -1,5 +1,4 @@
--- ---
id: 2
title: "Privacy-focused operating systems" title: "Privacy-focused operating systems"
description: "Good choices for privacy-focused operating systems for desktop and mobile phones." description: "Good choices for privacy-focused operating systems for desktop and mobile phones."
pubDate: "2025-01-16" pubDate: "2025-01-16"

View File

@@ -6,19 +6,20 @@ import Footer from "../components/Footer.astro";
interface Props { interface Props {
title: string; title: string;
metaDescription: string; description: string;
pubDate?: Date; pubDate?: Date;
modDate?: Date; modDate?: Date;
slug?: string;
} }
const { title, metaDescription, pubDate, modDate } = Astro.props; const { title, description, pubDate, modDate, slug } = Astro.props;
--- ---
<html lang="en" class="light"> <html lang="en" class="light">
<Head {title} {metaDescription} /> <Head {title} {description} />
<body class="min-h-screen flex flex-col"> <body class="min-h-screen flex flex-col">
<Nav /> <Nav />
<Header {title} {pubDate} {modDate} /> <Header {title} {pubDate} {modDate} {slug} />
<main class="flex-1 bg-white dark:bg-neutral-800"> <main class="flex-1 bg-white dark:bg-neutral-800">
<div <div
class={`relative prose prose-neutral dark:prose-invert mx-auto px-4 ${pubDate ? "pt-0" : "pt-8"} pb-16 prose-headings:scroll-mt-16 prose-h1:font-bold prose-pre:!bg-neutral-700 prose-a:text-blue-800 prose-a:dark:text-blue-300 prose-a:hover:no-underline`} class={`relative prose prose-neutral dark:prose-invert mx-auto px-4 ${pubDate ? "pt-0" : "pt-8"} pb-16 prose-headings:scroll-mt-16 prose-h1:font-bold prose-pre:!bg-neutral-700 prose-a:text-blue-800 prose-a:dark:text-blue-300 prose-a:hover:no-underline`}

View File

@@ -22,9 +22,10 @@ const { Content, headings } = await render(article);
<PageLayout <PageLayout
title={article.data.title} title={article.data.title}
metaDescription="Blog" description="Blog"
pubDate={article.data.pubDate} pubDate={article.data.pubDate}
modDate={article.data.modDate} modDate={article.data.modDate}
{slug}
> >
<details class="toc sticky top-0 z-20"> <details class="toc sticky top-0 z-20">
<summary <summary

View File

@@ -9,11 +9,11 @@ const sortedArticles = allArticles.sort((a, b) => {
}); });
--- ---
<PageLayout title="Blog" metaDescription="Blog"> <PageLayout title="Blog" description="Blog">
<ul> <ul>
{ {
sortedArticles.map((article) => ( sortedArticles.map((article) => (
<li class="gap-1"> <li class="flex gap-2">
<Date date={article.data.pubDate} /> <Date date={article.data.pubDate} />
<span>&raquo;</span> <span>&raquo;</span>
<a <a

View File

@@ -2,6 +2,6 @@
import PageLayout from "../layouts/PageLayout.astro"; import PageLayout from "../layouts/PageLayout.astro";
--- ---
<PageLayout title="Contact" metaDescription="Contact"> <PageLayout title="Contact" description="Contact">
<p>Example content</p> <p>Example content</p>
</PageLayout> </PageLayout>

View File

@@ -11,6 +11,6 @@ if (!indexContent) {
const { Content } = await render(indexContent); const { Content } = await render(indexContent);
--- ---
<PageLayout title="Thilo Hohlt" metaDescription="Thilo Hohlt"> <PageLayout title="Thilo Hohlt" description="Thilo Hohlt">
<Content /> <Content />
</PageLayout> </PageLayout>

View File

@@ -11,6 +11,6 @@ if (!legalContent) {
const { Content } = await render(legalContent); const { Content } = await render(legalContent);
--- ---
<PageLayout title="Legal Disclosure" metaDescription="Legal Disclosure"> <PageLayout title="Legal Disclosure" description="Legal Disclosure">
<Content /> <Content />
</PageLayout> </PageLayout>

23
src/pages/rss.xml.js Normal file
View File

@@ -0,0 +1,23 @@
import rss from "@astrojs/rss";
import { getCollection } from "astro:content";
import sanitizeHtml from "sanitize-html";
import MarkdownIt from "markdown-it";
const parser = new MarkdownIt();
export const GET = async (context) => {
const blog = await getCollection("blog");
return rss({
title: "Thilo Hohlts Blog",
description: "Thilo Hohlts Blog",
site: context.site,
trailingSlash: false,
stylesheet: "pretty-feed-v3.xsl",
items: blog.map((article) => ({
link: `/blog/${article.id}/`,
content: sanitizeHtml(parser.render(article.body), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
}),
...article.data,
})),
});
};