Skip to content
AstroCraft Docs
On this theme

Journal

Urbic’s journal is seven notes across three routes: the index at /blog/, a note at /blog/<slug>/, and one page per topic at /blog/topic/<topic>/. Three routes, one collection, and — importantly — one composition.

Three routes, one page

The unfiltered index and a topic page are the same page with a different note list. So the composition lives in Sections/Blog/JournalIndex.astro and both routes hand it a list. Two copies of a five-section page is how a filtered view ends up missing whatever the index gains six months later.

/blog/ sorts the collection with publishedNewestFirst and passes the whole list. /blog/topic/<topic>/ does the same, then filters by label. Its getStaticPaths builds a route only for topics that have notes — getTopics is a projection of the collection, so an empty topic page is not representable rather than merely unlikely. Three topic pages exist in the sample content.

The slug work happens in the route rather than in the helper, and that is deliberate: src/js/blog.ts is dependency-free so pnpm test can run it under plain Node, which cannot resolve the @js alias — so the helpers match topics by label and getStaticPaths applies slugify. The label rides along in props, so nothing ever has to un-slugify anything.

The filter strip’s topic chips are anchors pointing at those topic routes, not a client-side filter. Each topic is therefore shareable, crawlable, and survives a reload.

The layout toggle on the index is the opposite call: three layouts, built on radios and :has(), with no JavaScript and no URL. That asymmetry is intentional — a topic is content worth a URL, a layout preference is not.

Both rely on unlayered CSS for their hide rules. A display: none inside @layer components loses to a card’s own flex utility, because a later layer wins regardless of specificity.

A note page

src/pages/blog/[note].astro renders the entry body through NoteBody, with NoteAuthor drawing the byline from the referenced authors entry, a derived contents rail, ShareRow, and a related-notes grid.

Reading time and the related list both come from src/js/blog.ts. Drafts are dropped inside publishedNewestFirst rather than at each call site, which is what stops a draft leaking into a related grid — exactly the kind of miss that passes lint, check, build and test.

What a note must carry

heroImage and a non-empty categories array are required, where a generic starter would leave both optional. The hero image is the card photo, the post hero and the OG image at once, so a note without one is a hole in the index grid rather than merely a missing social preview. A note with no category would be a card with a blank chip that leads nowhere.

authors is a required reference into the authors collection. pubDate is required; updatedDate and draft are optional. See Content Collections for the full schema.

RSS

src/pages/rss.xml.ts generates the feed, and like robots.txt, llms.txt and the sitemap it derives its absolute URLs from site in astro.config.mjs. Setting SITE_URL once fixes all four together. See SEO.

Editing from the CMS

blog is mapped in src/admin.config.ts as Journal at /blog/, with title, pubDate, updatedDate, draft, description and heroImage filling the six editor roles. Because heroImage and categories are required in the Zod schema, the editor can never produce a note missing either — the constraint is enforced once, in src/content.config.ts, and the admin inherits it.

An entry moves through four statuses — draft, review, ready and published — and each one says whose move is next. Working with entries covers the flow, The document editor covers writing, and Details, SEO and History covers the side panels where the frontmatter fields live.

Replacing the sample notes

The seven notes are written as a real studio’s journal would be — short trade pieces about surveys, joinery and finishes — so they are useful as a shape while you replace them. Delete the folders under src/data/blog/ and write your own; the topics regenerate from whatever categories your notes carry, and the topic routes follow.

The one author entry is the studio founder. If you add more, note that authors is a reference target with no page of its own, which is why it appears in the CMS with no Preview button.

NEXT STEPServices