Layout and components
The layout a split history renders in, and the two MDC components its pages are made of.
The changelog type writes ordinary Markdown pages whose bodies are two MDC
components, rendered inside a layout of its own. All three are documented because
they are part of the public surface — a consumer can override any of them — not
because a page has to be written by hand.
The changelog layout
Bound by the split granularity only; a flat
changelog is an ordinary docs page and renders in the docs chrome.
It differs from docs in two ways, and both follow from what the pages are. The
sidebar is the release list rather than a prose tree — same navigation, same
collection, because a generated section is an ordinary collection and its pages
are the releases. And the reading column is capped at a measure: a release
note is prose, and prose set across the full window is unreadable. The contents
column stays, listing the groups.
Replace it with a file of your own at the same path:
app/layouts/changelog.vue
ChangelogReleases
The overview's timeline: every release, newest first, filterable by what changed. Written onto the section's index page.
| Prop | Type | Notes |
|---|---|---|
releases | array | Each with version, date, to and its groups |
The history opens on four figures — releases, changes, kinds of change, and the day the last one shipped — each a number with a small labelled line under it, as on the landing page — but laid out as a four-column grid across the full width rather than a wrapping row, so they read as the header of the list under them instead of as a caption with a hole beside it. The kinds are counted over the names the file used, so it is the file's own vocabulary being counted; the date is the only one that is not a count, and it is dropped rather than dashed where the file dates nothing. It answers what a list of rows cannot, which is how much there is. The figures count what is shown, so a filtered page's numbers are about the filtered page, with the total kept beside the first one.
The label carries the accent, not the figure: --primary is the one colour a
consuming site sets to make the theme its own, and two short labelled lines are
where it costs nothing.
Below them every release is one line in columns — version, badge, what it
carried, date — so the versions sit line under line and the summaries start at the same
x. Under sm the summary drops to a second line; nothing scrolls sideways. The
current release says it is current with a badge beside the version — a badge is
about the version, so it sits with it — in a fixed track that exists whether or
not a row fills it, so the releases without one start their summary exactly where
the one with it does. The date sits at the far end beside the arrow: it is the
field a reader scans down rather than reads across.
Filtering animates on both sides — the chips that appear above the list and the
rows that move below it, at the same timings, so the two read as one gesture. Rows
fade and settle over 200 ms, a leaving row is taken
out of the flow so the ones under it close the gap while it goes, and the
browser's own FLIP moves the survivors. It is a TransitionGroup, not a motion
library — a fade and a nudge are not worth a runtime dependency in every site that
extends the layer — and every part of it is off under prefers-reduced-motion. A row names the three largest
groups and counts the rest: "Features 2 · Bug Fixes 2 · Documentation 1 · and 9
more". Three, by count rather than by the order the file wrote them, because
release-please's section order is fixed and means nothing. Nothing is dropped
silently, and a filtered row names what it was filtered by first.
The tone is not in the history. It stays where it distinguishes rather than decorates: the filter menu, and the label a release page heads each group with.
A mark in front of a name is drawn away wherever a name is shown — the ⚠
release-please prefixes its breaking block with, an emoji a hand-kept changelog
opens a section with. Leading only, so C++ Support survives. The stored name
stays whole: the filter matches on it, the anchor is slugified from it, and the
props carry it, which is why the mark is dropped in the drawing rather than in the
parser. See changelogLabel.
A release's groups carry a name and a count only — the entries are not
here, because each release has a page of its own and repeating its bullets would
put the whole history twice into the search index, llms-full.txt and the feed.
The filter chips are built from the names the file itself used. With nothing selected the page shows everything, which is also what the server renders: a filter is a reader's choice, so the page has to be complete before anyone makes one — otherwise the crawler and the reader whose hydration has not landed are each shown a filtered changelog nobody asked for.
ChangelogGroup
One group of one release — "Features", "Bug Fixes", whatever the file said.
| Prop | Type | Notes |
|---|---|---|
name | string | The file's own heading, verbatim |
count | number | How many entries the group lists |
The entries arrive in the slot, as the Markdown they were written as — so the
search indexes them, llms-full.txt carries them and the copy control hands a
model prose rather than a component call. Only the name and the count, which the
badge and the filters need as data, travel as props.
The name is a label, not a headline: set small, upper-case and in the group's
own tone, above a list that closes up under it. As a 20-pixel heading it claimed
the weight of a chapter for a word naming four bullet points, and six of them read
as six sections rather than as one release. It is still an <h2> — the outline,
the contents column and the anchor are unchanged, and only its setting says what
it is worth.
The colour is a hint and never a meaning: a name the hint list does not know
still gets a stable colour of its own, which is what makes the same kind of change
scannable down a page of forty releases in any language. The label takes the
tone's text pair rather than the dot fill, because a run of words and a
six-pixel dot do not clear contrast at the same lightness.
The entries' own markers stay grey. The colour is already stated in the label
directly above them; repeated on every line it stops being a signal. They are set
from duxt.css, not from this component, because they arrive as Markdown through
the slot.
Overriding one
Same as any other component the layer ships: a file at the same path in the consuming site wins.
app/components/content/ChangelogGroup.vue
The props above are the contract, and so is the layout's name. A rename here is a breaking change of the layer.
What a release page shows besides its groups
Nothing in the body. The day a release was cut and the diff it was cut from
travel as date and compare in the page's frontmatter, and are drawn where the
site already answers where a page came from: the provenance block under the
contents column, above "Edit this page".
The release date replaces the last-commit line rather than joining it — every release of a changelog lives in one file, so its last commit dates all of them the same day, which is at best the newest one's.
A release page therefore reads like every other Markdown page on the site, which is the point: a release note is prose, not a dashboard.
No heading of its own
Neither component opens on an <h1>. The docs shell draws the header —
breadcrumb, title, the copy control beside it — for every generated page whose
body opens on no heading, and a release page wants exactly that: a title and a
trail like any written page.