M2: content collections — case studies, blog, RSS, tags, sitemap

Projects + blog as schema-validated content collections; structured case
studies (problem/design/outcome), blog with tag pages, reading time, RSS
feed (drafts excluded), sitemap, and Shiki dual-theme code highlighting.
This commit is contained in:
2026-06-17 16:56:46 +10:00
parent 720d579386
commit 22f482d89a
26 changed files with 1139 additions and 105 deletions
+52
View File
@@ -0,0 +1,52 @@
---
import Layout from "../../layouts/Layout.astro";
import Section from "../../components/Section.astro";
import PostList from "../../components/PostList.astro";
import { getPosts, allTags } from "../../lib/blog";
const posts = await getPosts();
const tags = allTags(posts);
---
<Layout title="Blog" path="/blog" description="Notes on platform engineering, edge Kubernetes, GPUs and homelab infrastructure.">
<Section id="blog" eyebrow="Writing" index="*" title="Notes from the platform.">
<p class="lead blog__intro" data-reveal>
Lessons from edge Kubernetes, GPUs, and running infrastructure like it matters.
</p>
{tags.length > 0 && (
<nav class="blog__tags" aria-label="Filter by tag" data-reveal>
<span class="mono blog__tags-label">tags:</span>
{tags.map((t) => (
<a class="tag blog__tag" href={`/blog/tags/${t}`}>{t}</a>
))}
</nav>
)}
<PostList posts={posts} />
</Section>
</Layout>
<style>
.blog__intro {
max-width: 50ch;
margin-bottom: var(--space-5);
}
.blog__tags {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
margin-bottom: var(--space-6);
}
.blog__tags-label {
font-size: var(--step--1);
color: var(--text-faint);
margin-right: 0.25rem;
}
.blog__tag:hover {
border-color: var(--accent-line);
color: var(--text);
text-decoration: none;
}
</style>