feat: add published status to changelog entries
This commit is contained in:
parent
1261e663e1
commit
585e28d49b
|
|
@ -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 };
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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<Metadata> {
|
||||
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<Metadata> {
|
|||
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
|
||||
</Link>
|
||||
|
||||
<ReleaseArticle variant="detail">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<ReleaseMeta release={release} />
|
||||
<CopyMarkdownButton
|
||||
description={release.description}
|
||||
changes={release.changes}
|
||||
/>
|
||||
<ReleaseArticle variant="detail">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<ReleaseMeta release={release} />
|
||||
<CopyMarkdownButton
|
||||
description={release.description}
|
||||
changes={release.changes}
|
||||
/>
|
||||
</div>
|
||||
<ReleaseTitle as="h1">{release.title}</ReleaseTitle>
|
||||
{release.description && (
|
||||
<ReleaseDescription>{release.description}</ReleaseDescription>
|
||||
)}
|
||||
</div>
|
||||
<ReleaseTitle as="h1">{release.title}</ReleaseTitle>
|
||||
{release.description && (
|
||||
<ReleaseDescription>{release.description}</ReleaseDescription>
|
||||
)}
|
||||
</div>
|
||||
<ReleaseChanges release={release} />
|
||||
</ReleaseArticle>
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export function ReleaseChanges({ release }: { release: Release }) {
|
|||
{orderedTypes.map((type) => (
|
||||
<div key={type} className="flex flex-col gap-1.5">
|
||||
<h3 className="text-base font-semibold text-foreground">
|
||||
{getSectionTitle(type)}:
|
||||
{getSectionTitle({ type })}:
|
||||
</h3>
|
||||
<ul className="list-disc pl-5 space-y-1.5">
|
||||
{grouped[type].map((change) => (
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const knownSectionTitles: Record<string, string> = {
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue