From 60855a0f3a7c13c2f22e07a0ae15657e57197cfe Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 16 Jul 2026 22:11:02 +0200 Subject: [PATCH] feat(website): group changelog patches by minor release Keep each patch dated and directly linkable while reducing top-level changelog noise. --- packages/website/src/routes/changelog.tsx | 94 ++++++++++++++++++----- packages/website/src/styles.css | 37 ++++++++- 2 files changed, 109 insertions(+), 22 deletions(-) diff --git a/packages/website/src/routes/changelog.tsx b/packages/website/src/routes/changelog.tsx index bbfb19a52..feeee8768 100644 --- a/packages/website/src/routes/changelog.tsx +++ b/packages/website/src/routes/changelog.tsx @@ -1,5 +1,5 @@ import { createFileRoute } from "@tanstack/react-router"; -import ReactMarkdown from "react-markdown"; +import ReactMarkdown, { type Components } from "react-markdown"; import changelogMarkdown from "../../../../CHANGELOG.md?raw"; import { SiteShell } from "~/components/site-shell"; import { pageMeta } from "~/meta"; @@ -10,7 +10,13 @@ interface ChangelogRelease { markdown: string; } +interface ChangelogReleaseGroup { + version: string; + releases: ChangelogRelease[]; +} + const releaseHeadingPattern = /^## (.+?) - (\d{4}-\d{2}-\d{2})$/; +const patchMarkdownComponents: Components = { h3: "h4" }; export const Route = createFileRoute("/changelog")({ head: () => @@ -64,28 +70,76 @@ function parseChangelog(markdown: string): ChangelogRelease[] { const changelogReleases = parseChangelog(changelogMarkdown); -function Release({ release }: { release: ChangelogRelease }) { +function minorVersion(version: string): string { + return version.split(".").slice(0, 2).join("."); +} + +function groupChangelogReleases(releases: ChangelogRelease[]): ChangelogReleaseGroup[] { + const groups: ChangelogReleaseGroup[] = []; + + for (const release of releases) { + const version = minorVersion(release.version); + const currentGroup = groups.at(-1); + if (currentGroup?.version === version) { + currentGroup.releases.push(release); + } else { + groups.push({ version, releases: [release] }); + } + } + + return groups; +} + +const changelogReleaseGroups = groupChangelogReleases(changelogReleases); + +function HeadingAnchor({ version }: { version: string }) { + const anchor = `release-${version}`; + + return ( + + + + ); +} + +function PatchRelease({ release }: { release: ChangelogRelease }) { const anchor = `release-${release.version}`; return ( -
- -
- - - -

- Paseo {release.version} -

+
+
+ +

{release.version}

+
- {release.markdown} + {release.markdown} +
+
+ ); +} + +function Release({ group }: { group: ChangelogReleaseGroup }) { + const anchor = `release-${group.version}`; + + return ( +
+
+ +

+ Paseo {group.version} +

+
+
+ {group.releases.map((release) => ( + + ))}
); @@ -96,8 +150,8 @@ function Changelog() {

Changelog

- {changelogReleases.map((release) => ( - + {changelogReleaseGroups.map((group) => ( + ))}
diff --git a/packages/website/src/styles.css b/packages/website/src/styles.css index d53719d6d..0f779936c 100644 --- a/packages/website/src/styles.css +++ b/packages/website/src/styles.css @@ -176,6 +176,7 @@ } .changelog-release-heading:hover .changelog-heading-anchor, +.changelog-patch-heading:hover .changelog-heading-anchor, .changelog-heading-anchor:focus { opacity: 1; } @@ -184,13 +185,44 @@ color: var(--color-foreground); } +.changelog-patches { + display: grid; + gap: 2.5rem; +} + +.changelog-patch + .changelog-patch { + border-top: 1px solid var(--color-border); + padding-top: 2.5rem; +} + +.changelog-patch-heading { + position: relative; + display: flex; + align-items: baseline; + gap: 0.625rem; + scroll-margin-top: 1.5rem; + margin-bottom: 1.25rem; +} + +.changelog-patch-title { + color: var(--color-foreground); + font-size: 1rem; + font-weight: 500; + line-height: 1.4; +} + +.changelog-patch-heading .changelog-release-date { + margin-bottom: 0; +} + .changelog-release-notes { color: color-mix(in srgb, var(--color-foreground) 76%, transparent); font-size: 0.9375rem; line-height: 1.7; } -.changelog-release-notes h3 { +.changelog-release-notes h3, +.changelog-release-notes h4 { margin-top: 1.75rem; margin-bottom: 0.625rem; color: var(--color-muted-foreground); @@ -199,7 +231,8 @@ line-height: 1.4; } -.changelog-release-notes h3:first-child { +.changelog-release-notes h3:first-child, +.changelog-release-notes h4:first-child { margin-top: 0; }