Skip to content

Commit 28ecbf1

Browse files
committed
[Docs Site] Release notes PoC
1 parent 0feed50 commit 28ecbf1

File tree

12 files changed

+259
-15
lines changed

12 files changed

+259
-15
lines changed

src/components/overrides/PageTitle.astro

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ const summary = Astro.props.entry.data.summary;
2121
2222
const slug = Astro.props.entry.slug;
2323
24-
const showBreadcrumbs = !["products"].includes(slug);
25-
2624
const breadcrumbProps: Record<string, any> = {
2725
crumbs: [
2826
{
@@ -73,10 +71,11 @@ for (let i = 0; i < segments.length; i++) {
7371
// Currently the officially sanctioned way to alter behaviour on specific routes
7472
// https://starlight.astro.build/guides/overriding-components/#only-override-on-specific-pages
7573
const hideTitle = Astro.props.hideTitle;
74+
const hideBreadcrumbs = Astro.props.hideBreadcrumbs;
7675
---
7776

7877
{
79-
showBreadcrumbs && (
78+
!hideBreadcrumbs && (
8079
<Breadcrumbs {...breadcrumbProps}>
8180
<svg
8281
slot="separator"

src/components/overrides/Sidebar.astro

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,21 @@ async function handleLink(link: Link): Promise<Link> {
157157
return link;
158158
}
159159
160-
filtered.entries = await Promise.all(
161-
filtered.entries.map((entry) => {
162-
if (entry.type === "group") {
163-
return handleGroup(entry);
164-
} else {
165-
return handleLink(entry);
166-
}
167-
}),
168-
);
160+
if (currentSection !== "release-notes") {
161+
filtered.entries = await Promise.all(
162+
filtered.entries.map((entry) => {
163+
if (entry.type === "group") {
164+
return handleGroup(entry);
165+
} else {
166+
return handleLink(entry);
167+
}
168+
}),
169+
);
169170
170-
filtered.entries = filtered.entries.sort(sortGroup);
171+
filtered.entries = filtered.entries.sort(sortGroup);
171172
172-
filtered.entries[0].label = "Overview";
173+
filtered.entries[0].label = "Overview";
174+
}
173175
174176
const lookupProductTitle = async (slug: string) => {
175177
const segments = slug.split("/");
@@ -183,6 +185,10 @@ const lookupProductTitle = async (slug: string) => {
183185
return `${entryData?.data?.title} (Learning Paths)`;
184186
}
185187
188+
if (product === "release-notes") {
189+
return "Release notes";
190+
}
191+
186192
const entryData = await getEntry("products", product);
187193
188194
return entryData?.data?.product?.title ?? "Unknown";

src/components/overrides/SocialIcons.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ const links = Object.entries({
2727

2828
<style>
2929
:root {
30-
--sl-icon-color: var(--sl-color-text);
30+
.social-icons {
31+
--sl-icon-color: var(--sl-color-text);
32+
}
3133
}
3234
</style>

src/content/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
learningPathsSchema,
1313
videosSchema,
1414
workersAiSchema,
15+
releaseNotesSchema,
1516
} from "~/schemas";
1617

1718
const partialSchema = z.object({
@@ -74,4 +75,7 @@ export const collections = {
7475
schema: appsSchema,
7576
type: "data",
7677
}),
78+
"release-notes": defineCollection({
79+
schema: releaseNotesSchema,
80+
}),
7781
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: Other stuff
3+
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent non arcu tortor. Duis fringilla nibh vitae lorem viverra tincidunt. Nullam nec maximus nulla, sed euismod sapien. Fusce venenatis ipsum non orci tincidunt aliquam.
4+
products:
5+
- Access
6+
- WARP
7+
tags: feature
8+
---
9+
10+
import { Details } from "~/components";
11+
12+
<Details header="Open me!">
13+
Etiam varius fermentum ex, a gravida ligula tincidunt nec. Cras a vehicula metus. Praesent ut fermentum justo, eget tincidunt leo. Ut lobortis aliquet tortor et viverra.
14+
</Details>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Stuff and things
3+
description: Donec faucibus nunc vel fermentum porttitor. Etiam ac lorem dui. Duis facilisis facilisis sem, vel malesuada ipsum feugiat in.
4+
products:
5+
- Workers
6+
- KV
7+
tags: changed
8+
---
9+
10+
## Foo
11+
12+
Aenean lectus sapien, sollicitudin eget condimentum quis, vehicula sed risus. Maecenas consectetur nisi nec nisi sagittis lacinia.
13+
14+
## Bar
15+
16+
:::note
17+
Phasellus non sagittis urna.
18+
:::
19+
20+
Suspendisse vitae congue massa, sed tempus felis. Cras erat nisl, vulputate scelerisque urna pretium, eleifend euismod arcu.

src/icons/release-notes.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
3+
import type { GetStaticPaths } from "astro";
4+
import { getCollection } from "astro:content";
5+
import { format } from "date-fns";
6+
7+
export const getStaticPaths = (async () => {
8+
const notes = await getCollection("release-notes");
9+
10+
return notes.map((note) => {
11+
return {
12+
params: {
13+
slug: note.slug,
14+
},
15+
props: {
16+
note,
17+
},
18+
};
19+
});
20+
}) satisfies GetStaticPaths;
21+
22+
const notes = await getCollection("release-notes");
23+
24+
const months = Object.entries(
25+
Object.groupBy(notes, (note) => note.id.split("/").slice(0, 2).join("/")),
26+
);
27+
28+
const sidebar = [
29+
{
30+
label: "release-notes",
31+
items: [
32+
{
33+
label: "Latest releases",
34+
link: "/release-notes/",
35+
},
36+
...months.map(([date, entries]) => {
37+
return {
38+
label: format(date, "MMMM yyyy"),
39+
items: entries
40+
?.sort()
41+
.reverse()
42+
.map((entry) => {
43+
const date = entry.id.split("/").slice(0, 3).join("/");
44+
const formatted = format(date, "MMMM dd");
45+
46+
return {
47+
label: `${formatted} - ${entry.data.title}`,
48+
link: `/release-notes/${entry.slug}/`,
49+
};
50+
}),
51+
};
52+
}),
53+
],
54+
},
55+
];
56+
57+
const { note } = Astro.props;
58+
59+
const { Content, headings } = await note.render();
60+
---
61+
62+
<StarlightPage
63+
frontmatter={{
64+
title: note.data.title,
65+
}}
66+
sidebar={sidebar}
67+
headings={headings}
68+
hideBreadcrumbs={true}
69+
>
70+
<Content />
71+
</StarlightPage>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
3+
import { getCollection } from "astro:content";
4+
import { LinkButton, Steps } from "~/components";
5+
import { format } from "date-fns";
6+
7+
const notes = await getCollection("release-notes");
8+
9+
const months = Object.entries(
10+
Object.groupBy(notes, (note) => note.id.split("/").slice(0, 2).join("/")),
11+
);
12+
13+
const days = Object.entries(
14+
Object.groupBy(notes, (note) => note.id.split("/").slice(0, 3).join("/")),
15+
);
16+
17+
const sidebar = [
18+
{
19+
label: "release-notes",
20+
items: [
21+
{
22+
label: "Latest releases",
23+
link: "/release-notes/",
24+
},
25+
...months.map(([date, entries]) => {
26+
return {
27+
label: format(date, "MMMM yyyy"),
28+
items: entries
29+
?.sort()
30+
.reverse()
31+
.map((entry) => {
32+
const date = entry.id.split("/").slice(0, 3).join("/");
33+
const formatted = format(date, "MMMM dd");
34+
35+
return {
36+
label: `${formatted} - ${entry.data.title}`,
37+
link: `/release-notes/${entry.slug}/`,
38+
};
39+
}),
40+
};
41+
})
42+
]
43+
},
44+
];
45+
---
46+
47+
<StarlightPage
48+
frontmatter={{ title: "Release notes", tableOfContents: false }}
49+
sidebar={sidebar}
50+
hideBreadcrumbs={true}
51+
>
52+
<LinkButton href="/release-notes/rss.xml" icon="rss" style={{ padding: "0.4375rem 1.125rem" }}>RSS</LinkButton>
53+
<div class="grid grid-cols-[10%_90%]">
54+
{
55+
days.sort().reverse().map(([date, entries]) => {
56+
const formatted = format(date, "MMMM dd");
57+
58+
return (
59+
<div class="!mt-0">
60+
<p class="text-xs">{formatted}</p>
61+
</div>
62+
<Steps>
63+
<ol class="!mt-0">
64+
{
65+
entries?.map((entry) => (
66+
<li>
67+
<a href={`/release-notes/${entry.slug}/`}>
68+
<strong>
69+
{entry.data.title}
70+
</strong>
71+
</a>
72+
<p>{entry.data.description}</p>
73+
<div class="flex gap-2 items-center">
74+
<span class="ml-1 bg-orange-200 text-orange-900 rounded-full px-2 py-0.5 text-xs">
75+
{entry.data.tags}
76+
</span>
77+
<p class="text-xs">{entry.data.products.join(", ")}</p>
78+
</div>
79+
</li>
80+
))
81+
}
82+
</ol>
83+
</Steps>
84+
)
85+
})
86+
}
87+
</div>
88+
</StarlightPage>
89+
90+
<style>
91+
.sl-steps > li::before {
92+
content: "";
93+
}
94+
</style>

src/pages/release-notes/rss.xml.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import rss from "@astrojs/rss";
2+
import { getCollection } from "astro:content";
3+
import type { APIRoute } from "astro";
4+
5+
export const GET: APIRoute = async () => {
6+
const notes = await getCollection("release-notes");
7+
8+
return rss({
9+
title: "Release notes",
10+
description: `Cloudflare release notes`,
11+
site: "https://developers.cloudflare.com",
12+
trailingSlash: false,
13+
items: notes.map((entry) => {
14+
const date = new Date(entry.id.split("/").slice(0, 3).join("/"));
15+
16+
return {
17+
title: entry.data.title,
18+
description: entry.data.description,
19+
pubDate: date,
20+
link: `/release-notes/${entry.slug}/`,
21+
};
22+
}),
23+
});
24+
};

0 commit comments

Comments
 (0)