From e6032149d3a3b078cda34757f4a36a2bb133a080 Mon Sep 17 00:00:00 2001 From: 37ng Date: Sat, 5 Sep 2026 11:34:14 -0700 Subject: [PATCH 1/3] feat: add 'feat' to post to decide whether it's shown in main stage --- src/content.config.ts | 22 ++-------------------- src/layouts/PostLayout.astro | 1 + src/pages/[slug].astro | 1 + src/pages/posts/[slug].astro | 30 ++++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 src/pages/posts/[slug].astro diff --git a/src/content.config.ts b/src/content.config.ts index 55de32a..a98ad52 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -9,30 +9,12 @@ const posts = defineCollection({ title: z.string(), description: z.string().optional(), date: z.string(), - /* Last substantive edit, if the post was revised after its date. Only - set this when content actually changed — not for typo fixes. */ updated: z.string().optional(), + feat: z.boolean(), // whether this is showed in main stage tags: z.array(z.string()).default([]), - /* The committed webp in src/assets — stage-width already, written by - `npm run art` from a master that never enters the repo (see - scripts/generate-art.mjs). The stage uses it as-is; the fan's card - thumbnail is derived from it at build time in index.astro. */ - heroImage: image().optional(), github: z.url().optional(), - /* This post's one custom color. It carries identity, not legibility — - the index line on the fan, the caption's hover, and the post page's - own accent. Anything that has to stay readable over the art reads - stageTone instead. */ color: z.string().optional(), - /* Whether this post's hero art is dark or light. Picks the whole set of - readable tones for that stage: caption title and body, and the header - chrome above it. A light backdrop can't use ink meant for a dark one, - and it can't recede behind the fan the same way either. - - Only consulted when the post actually has heroImage. Without one the - backdrop is PaperSheet, and index.astro derives light from that — the - default here would otherwise put white type on cream, which fails - invisibly instead of visibly. */ + heroImage: image().optional(), stageTone: z.enum(["dark", "light"]).default("dark"), }), }); diff --git a/src/layouts/PostLayout.astro b/src/layouts/PostLayout.astro index 6cae358..559fd8f 100644 --- a/src/layouts/PostLayout.astro +++ b/src/layouts/PostLayout.astro @@ -6,6 +6,7 @@ interface Props { id: string; title: string; description?: string; + feat: boolean; date: string; updated?: string; github?: string; diff --git a/src/pages/[slug].astro b/src/pages/[slug].astro index c67b931..b722b36 100644 --- a/src/pages/[slug].astro +++ b/src/pages/[slug].astro @@ -18,6 +18,7 @@ const { Content } = await render(post); id={post.id} title={post.data.title} description={post.data.description} + feat={post.data.feat} date={post.data.date} updated={post.data.updated} github={post.data.github} diff --git a/src/pages/posts/[slug].astro b/src/pages/posts/[slug].astro new file mode 100644 index 0000000..74bb34e --- /dev/null +++ b/src/pages/posts/[slug].astro @@ -0,0 +1,30 @@ +--- +import { getCollection, render } from "astro:content"; +import PostLayout from "../../layouts/PostLayout.astro"; +import { oscTriangle } from "three/tsl"; + +export async function getStaticPaths() { + const posts = await getCollection("posts"); + return posts.map((post) => ({ + params: { slug: post.id }, + props: { post }, + })); +} + +const { post } = Astro.props; +const { Content } = await render(post); +--- + + + + From 907d98c8631026f6952cf0276662b2da1c20f8a6 Mon Sep 17 00:00:00 2001 From: 37ng Date: Sat, 5 Sep 2026 12:56:32 -0700 Subject: [PATCH 2/3] fix: give feat a default, and let it pick what the homepage shows feat was required, so every post without it failed the schema and the build stopped. It now defaults to false. index.astro builds the fan and the stages from the featured posts only, so an unfinished post can sit at its own URL without appearing on the homepage. The landing stage is unchanged. Co-Authored-By: Claude Opus 5 --- src/content.config.ts | 2 +- src/content/posts/bitcoin.mdx | 1 + src/content/posts/prologue.mdx | 1 + src/pages/index.astro | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/content.config.ts b/src/content.config.ts index a98ad52..5fdc864 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -10,7 +10,7 @@ const posts = defineCollection({ description: z.string().optional(), date: z.string(), updated: z.string().optional(), - feat: z.boolean(), // whether this is showed in main stage + feat: z.boolean().default(false), // whether this is showed in main stage tags: z.array(z.string()).default([]), github: z.url().optional(), color: z.string().optional(), diff --git a/src/content/posts/bitcoin.mdx b/src/content/posts/bitcoin.mdx index 0935aeb..4449654 100644 --- a/src/content/posts/bitcoin.mdx +++ b/src/content/posts/bitcoin.mdx @@ -2,6 +2,7 @@ title: "Bitcoin, and then miners" description: "Pools, farms and miners" date: "2026-07-28" +feat: true tags: ["bitcoin", "crypto", "cryptocurrency"] heroImage: "../../assets/bitcoin-bg.webp" color: "#F7941D" diff --git a/src/content/posts/prologue.mdx b/src/content/posts/prologue.mdx index 2e3747a..4a183e9 100644 --- a/src/content/posts/prologue.mdx +++ b/src/content/posts/prologue.mdx @@ -2,6 +2,7 @@ title: "prologue" description: "A playground where I throw in as much fun as I can." date: "2026-08-28" +feat: true tags: [] color: "#d72d1a" stageTone: "light" diff --git a/src/pages/index.astro b/src/pages/index.astro index 758e1e1..5c5a3c7 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -33,8 +33,9 @@ async function cardSrc(image: ImageMetadata | undefined) { // stage caption numbers itself off the same positions and the two indexes have // to agree. const posts = await getSortedPosts(); +const featured = posts.filter((post) => post.data.feat); const unordered = await Promise.all( - posts.map(async (post) => ({ + featured.map(async (post) => ({ id: post.id, title: post.data.title, description: post.data.description, From 9a7a5fc022e269a946ffb93c1c16636e167f07d8 Mon Sep 17 00:00:00 2001 From: 37ng Date: Sat, 5 Sep 2026 13:06:43 -0700 Subject: [PATCH 3/3] fix: drop the stale posts/[slug].astro route PR #31 moved this route to the pages root, but a later merge brought the old copy back. It still read post.data.heroImage, which no longer exists after the rename to stageImage, so the build failed. It also carried a stray three/tsl import. Co-Authored-By: Claude Opus 5 --- src/pages/posts/[slug].astro | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 src/pages/posts/[slug].astro diff --git a/src/pages/posts/[slug].astro b/src/pages/posts/[slug].astro deleted file mode 100644 index 74bb34e..0000000 --- a/src/pages/posts/[slug].astro +++ /dev/null @@ -1,30 +0,0 @@ ---- -import { getCollection, render } from "astro:content"; -import PostLayout from "../../layouts/PostLayout.astro"; -import { oscTriangle } from "three/tsl"; - -export async function getStaticPaths() { - const posts = await getCollection("posts"); - return posts.map((post) => ({ - params: { slug: post.id }, - props: { post }, - })); -} - -const { post } = Astro.props; -const { Content } = await render(post); ---- - - - -