From 585e28d49b853155c34a3eba03388722e2049cb7 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Sun, 29 Mar 2026 14:10:57 +0200 Subject: [PATCH] feat: add published status to changelog entries --- apps/web/content-collections.ts | 6 ++- apps/web/content/changelog/0.1.0.md | 1 + apps/web/content/changelog/0.2.0.md | 1 + apps/web/content/changelog/0.3.0.md | 1 + apps/web/src/app/changelog/[version]/page.tsx | 37 +++++++++---------- .../components/copy-markdown-button.tsx | 2 +- .../src/app/changelog/components/release.tsx | 2 +- apps/web/src/app/changelog/utils.ts | 20 +++++++--- 8 files changed, 41 insertions(+), 29 deletions(-) diff --git a/apps/web/content-collections.ts b/apps/web/content-collections.ts index b9904bf6..bde2ba94 100644 --- a/apps/web/content-collections.ts +++ b/apps/web/content-collections.ts @@ -9,6 +9,7 @@ const changelog = defineCollection({ content: z.string(), version: z.string(), date: z.string(), + published: z.boolean().default(true), title: z.string(), description: z.string().optional(), changes: z.array( @@ -20,10 +21,11 @@ const changelog = defineCollection({ }), transform: async (doc, { collection }) => { const allDocs = await collection.documents(); - const sorted = [...allDocs].sort((a, b) => + const publishedDocs = allDocs.filter((entry) => entry.published !== false); + const sorted = [...publishedDocs].sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true }), ); - const isLatest = sorted[0]?.version === doc.version; + const isLatest = doc.published !== false && sorted[0]?.version === doc.version; return { ...doc, isLatest }; }, }); diff --git a/apps/web/content/changelog/0.1.0.md b/apps/web/content/changelog/0.1.0.md index 9f71ab68..f2000c76 100644 --- a/apps/web/content/changelog/0.1.0.md +++ b/apps/web/content/changelog/0.1.0.md @@ -1,6 +1,7 @@ --- version: "0.1.0" date: "2026-02-23" +published: true title: "Editor foundation" description: "This first release focuses on making editing faster, clearer, and more reliable for day-to-day use." changes: diff --git a/apps/web/content/changelog/0.2.0.md b/apps/web/content/changelog/0.2.0.md index 04c81839..18c8c48c 100644 --- a/apps/web/content/changelog/0.2.0.md +++ b/apps/web/content/changelog/0.2.0.md @@ -1,6 +1,7 @@ --- version: "0.2.0" date: "2026-03-01" +published: true title: "Motion & effects" description: "This release adds the foundation for motion and effects, alongside many improvements & fixes." changes: diff --git a/apps/web/content/changelog/0.3.0.md b/apps/web/content/changelog/0.3.0.md index cbd2037a..42c7c9a7 100644 --- a/apps/web/content/changelog/0.3.0.md +++ b/apps/web/content/changelog/0.3.0.md @@ -1,6 +1,7 @@ --- version: "0.3.0" date: "2026-03-04" +published: false title: "Brand & polish" description: "This release adds a brand page with downloadable assets, alongside a few fixes and improvements." changes: diff --git a/apps/web/src/app/changelog/[version]/page.tsx b/apps/web/src/app/changelog/[version]/page.tsx index a3647fbd..522f454a 100644 --- a/apps/web/src/app/changelog/[version]/page.tsx +++ b/apps/web/src/app/changelog/[version]/page.tsx @@ -2,9 +2,8 @@ import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { BasePage } from "@/app/base-page"; -import { allChangelogs } from "content-collections"; import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; -import { getSortedReleases } from "../utils"; +import { getReleaseByVersion, getSortedReleases } from "../utils"; import { ReleaseArticle, ReleaseMeta, @@ -17,12 +16,12 @@ import { CopyMarkdownButton } from "../components/copy-markdown-button"; type Props = { params: Promise<{ version: string }> }; export async function generateStaticParams() { - return allChangelogs.map((r) => ({ version: r.version })); + return getSortedReleases().map((release) => ({ version: release.version })); } export async function generateMetadata({ params }: Props): Promise { const { version } = await params; - const release = allChangelogs.find((r) => r.version === version); + const release = getReleaseByVersion({ version }); if (!release) return {}; return { title: `${release.title} (${release.version}) - OpenCut Changelog`, @@ -33,10 +32,8 @@ export async function generateMetadata({ params }: Props): Promise { export default async function ReleaseDetailPage({ params }: Props) { const { version } = await params; const releases = getSortedReleases(); - const index = releases.findIndex((r) => r.version === version); - + const index = releases.findIndex((entry) => entry.version === version); if (index === -1) notFound(); - const release = releases[index]; const newer = index > 0 ? releases[index - 1] : null; const older = index < releases.length - 1 ? releases[index + 1] : null; @@ -52,20 +49,20 @@ export default async function ReleaseDetailPage({ params }: Props) { All releases - -
-
- - + +
+
+ + +
+ {release.title} + {release.description && ( + {release.description} + )}
- {release.title} - {release.description && ( - {release.description} - )} -
diff --git a/apps/web/src/app/changelog/components/copy-markdown-button.tsx b/apps/web/src/app/changelog/components/copy-markdown-button.tsx index edb920f5..7ea18b2a 100644 --- a/apps/web/src/app/changelog/components/copy-markdown-button.tsx +++ b/apps/web/src/app/changelog/components/copy-markdown-button.tsx @@ -23,7 +23,7 @@ function buildMarkdown({ const { grouped, orderedTypes } = groupAndOrderChanges({ changes }); for (const type of orderedTypes) { - lines.push(`## ${getSectionTitle(type)}`); + lines.push(`## ${getSectionTitle({ type })}`); for (const change of grouped[type]) { lines.push(`- ${change.text}`); } diff --git a/apps/web/src/app/changelog/components/release.tsx b/apps/web/src/app/changelog/components/release.tsx index 2226c321..10dcf561 100644 --- a/apps/web/src/app/changelog/components/release.tsx +++ b/apps/web/src/app/changelog/components/release.tsx @@ -87,7 +87,7 @@ export function ReleaseChanges({ release }: { release: Release }) { {orderedTypes.map((type) => (

- {getSectionTitle(type)}: + {getSectionTitle({ type })}:

    {grouped[type].map((change) => ( diff --git a/apps/web/src/app/changelog/utils.ts b/apps/web/src/app/changelog/utils.ts index d3405631..3f38ab6b 100644 --- a/apps/web/src/app/changelog/utils.ts +++ b/apps/web/src/app/changelog/utils.ts @@ -12,7 +12,7 @@ const knownSectionTitles: Record = { breaking: "Breaking Changes", }; -export function getSectionTitle(type: string): string { +export function getSectionTitle({ type }: { type: string }): string { return ( knownSectionTitles[type] ?? type.charAt(0).toUpperCase() + type.slice(1) ); @@ -36,8 +36,18 @@ export function groupAndOrderChanges({ changes }: { changes: Change[] }) { return { grouped, orderedTypes }; } -export function getSortedReleases() { - return [...allChangelogs].sort((a, b) => - b.version.localeCompare(a.version, undefined, { numeric: true }), - ); +function isPublishedRelease({ published }: Release) { + return published !== false; +} + +export function getSortedReleases() { + return allChangelogs + .filter(isPublishedRelease) + .sort((a, b) => + b.version.localeCompare(a.version, undefined, { numeric: true }), + ); +} + +export function getReleaseByVersion({ version }: { version: string }) { + return getSortedReleases().find((release) => release.version === version); }