Duck Changelog
Releases down the timeline spine, each an article with an anchor from its version, dates printed in UTC, and the body left as prose so MDX drops in.
BlockServer safe
Preview
- @duck/glow-select and @duck/glow-color, so a rail needs no raw inputs.
- xs, icon-xs and icon-sm — the 28px scale a control rail runs on.
- curve="log" on DuckSlider, with the arrow keys fixed to match.
- A viewport, a command palette and an audio player.
- A print layer that re-asserts the light palette on paper.
0.2.0Theme reaches the components
feat- Noir, to prove the tokens are not the duck.
Installation
One command writes the section and every component it renders.
$
pnpm dlx shadcn@latest add @duck/duck-changelogThe block lands in components/blocks/duck-changelog.tsx. It builds on duck-timeline, duck-prose, duck-section-marker and holo-badge, which the CLI installs alongside it. Already installed items are skipped.
Usage
import { DuckChangelog, slugify } from "@/components/blocks/duck-changelog"A block is a starting point, not a widget. The props exist so the example renders with real content — once the file is in your project, hard-code what never changes and delete the rest.
Props
Everything not listed here is forwarded to the root element.
| Prop | Type | Default | Description |
|---|---|---|---|
| eyebrow | React.ReactNode | - | Section marker above the heading. |
| title | React.ReactNode | - | Page heading, rendered as the h1. |
| description | React.ReactNode | - | One line under it. |
| releases | DuckChangelogRelease[] | - | version, date, title, tags, highlights, body. Newest first — the first entry is the one marked latest. |
| idPrefix | string | - | Prefix for the anchors, when one page carries two changelogs. |
| locale | string | "en-GB" | Locale for the printed date. The time zone stays UTC. |
| latestLabel | string | "latest" | Badge on the newest release. |
| headingLevel | "h2" | "h3" | "h2" | Release heading level. Drop to h3 when this sits under an existing h2. |
Rules
What keeps this section from turning into noise.
- The anchor comes from the version, not from useId. The point of a changelog entry is that someone can send /changelog#1-2-0 and land on it.
- Dates print in UTC. A formatter that follows the reader's zone renders one string on the server and another in the browser — a hydration mismatch that only appears for readers a day away from you.
- Pass releases newest first. The first entry gets the lit node and the badge, and nothing else does: a list where every row is highlighted has highlighted nothing.
- The body stays prose. A release note is written, so DuckProse styles whatever the MDX pipeline hands over; highlights carries the scannable half for the readers who want four lines instead of four paragraphs.
- The block ships no client code of its own. A page of releases should be readable without JavaScript.
