summaryrefslogtreecommitdiffstats
path: root/src/pages/releases
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/releases')
-rw-r--r--src/pages/releases/[version].tsx100
-rw-r--r--src/pages/releases/feed.ts19
-rw-r--r--src/pages/releases/index.mdx8
-rw-r--r--src/pages/releases/index.tsx51
4 files changed, 178 insertions, 0 deletions
diff --git a/src/pages/releases/[version].tsx b/src/pages/releases/[version].tsx
new file mode 100644
index 0000000..84d807a
--- /dev/null
+++ b/src/pages/releases/[version].tsx
@@ -0,0 +1,100 @@
1import { Page, PipelineStageError } from "corvos";
2
3import { strapiLoader } from "$/deps/strapi.tsx";
4import { releaseStrapiSchema } from "$/schemas/releases.ts";
5import { BaseLayout } from "$/ui/base/BaseLayout.tsx";
6import { ReleaseCard } from "$/ui/components/ReleaseCard.tsx";
7import { SiteHeader } from "$/ui/components/SiteHeader.tsx";
8import { CardList } from "$/ui/layouts/CardList.tsx";
9import { Container } from "$/ui/layouts/Container.tsx";
10import { HList } from "$/ui/layouts/HList.tsx";
11import { ActionButton } from "$/ui/objects/ActionButton.tsx";
12import { Badge } from "$/ui/objects/Badge.tsx";
13import { Body } from "$/ui/objects/Body.tsx";
14import { Divider } from "$/ui/objects/Divider.tsx";
15import { Heading } from "$/ui/objects/Heading.tsx";
16import { Icon } from "$/ui/objects/Icon.tsx";
17import site from "@/corvos.config.ts";
18
19export const pages = site.$.pageGenerator(async function* () {
20 for await (const item of strapiLoader.loadCollection("corvos-releases", releaseStrapiSchema, {
21 "populate[0]": "files",
22 "sort[0]": "date:desc",
23 })) {
24 if (item instanceof PipelineStageError) {
25 yield item;
26 } else {
27 yield new Page(".strapi", item.notes ?? [], {
28 ...item,
29 title: `Corvos ${item.version}`,
30 type: "release" as const,
31 });
32 }
33 }
34});
35
36export const template = site.$.template({ type: "release" }, (page, pages) => {
37 const query = site.$.query(pages);
38
39 const feed = query.type(".rss").match({ type: "releases" }).one();
40
41 const prev = query.type(".html").match({ type: "release" }).prev(page);
42 const next = query.type(".html").match({ type: "release" }).next(page);
43
44 return (
45 <BaseLayout page={page}>
46 <SiteHeader
47 mode="compact"
48 url={page.url}
49 end={
50 <div class="l-media__block">
51 <ActionButton
52 align-block
53 class="u-mbs-0"
54 href={feed.url}
55 icon={<Icon icon="rss-simple" variant="bold" />}
56 level="quiet"
57 pill
58 title="RSS Feed"
59 />
60 </div>
61 }
62 >
63 <div class="l-media__block l-media__block--main">
64 <Heading class="u-mbs-0 u-elp">{page.data.title}</Heading>
65 </div>
66 </SiteHeader>
67
68 <Container as="main" class="u-mbs-neutralize h-entry" fixed="150" pad-block pad-inline>
69 <HList aria-label="Categories">
70 <li>
71 <Badge as="strong" pill selected>
72 <time class="dt-published" datetime={page.data.date.toISOString()}>
73 {page.data.date.toLocaleDateString(undefined, {
74 day: "numeric",
75 month: "short",
76 year: "numeric",
77 })}
78 </time>
79 </Badge>
80 </li>
81 </HList>
82
83 <Heading as="h1" class="u-mbs-200 p-name" display highlight level="xxl">
84 {page.data.title}
85 </Heading>
86
87 <Body class="e-content">{{ __html: page.content }}</Body>
88 </Container>
89
90 <Divider level="faint" />
91
92 <Container as="footer" class="u-mbs-neutralize" fixed="150" pad-block pad-inline>
93 <CardList layout="grid">
94 {prev && <ReleaseCard heading-level="h2" page={prev} list />}
95 {next && <ReleaseCard heading-level="h2" page={next} list />}
96 </CardList>
97 </Container>
98 </BaseLayout>
99 );
100});
diff --git a/src/pages/releases/feed.ts b/src/pages/releases/feed.ts
new file mode 100644
index 0000000..b430ca5
--- /dev/null
+++ b/src/pages/releases/feed.ts
@@ -0,0 +1,19 @@
1import type { FeedItem } from "corvos/plugins/feeds.ts";
2
3import site from "@/corvos.config.ts";
4
5export const feeds = site.$.feedGenerator(function* (pages) {
6 const items = site.$.query(pages)
7 .match({ type: "release" })
8 .many()
9 .take(20)
10 .map(
11 (page): FeedItem => ({
12 title: page.data.title,
13 url: page.url,
14 content: page.content,
15 updated: page.data.date,
16 }),
17 );
18 yield { type: "releases", title: `Releases`, url: "/releases/", items };
19});
diff --git a/src/pages/releases/index.mdx b/src/pages/releases/index.mdx
new file mode 100644
index 0000000..6519c76
--- /dev/null
+++ b/src/pages/releases/index.mdx
@@ -0,0 +1,8 @@
1---
2type: "releases-index"
3title: "Releases"
4description: "All releases of Corvos."
5---
6
7import { template } from "./index.tsx";
8export { template };
diff --git a/src/pages/releases/index.tsx b/src/pages/releases/index.tsx
new file mode 100644
index 0000000..132eee7
--- /dev/null
+++ b/src/pages/releases/index.tsx
@@ -0,0 +1,51 @@
1import { BaseLayout } from "$/ui/base/BaseLayout.tsx";
2import { ReleaseCard } from "$/ui/components/ReleaseCard.tsx";
3import { SiteHeader } from "$/ui/components/SiteHeader.tsx";
4import { CardList } from "$/ui/layouts/CardList.tsx";
5import { Container } from "$/ui/layouts/Container.tsx";
6import { ActionButton } from "$/ui/objects/ActionButton.tsx";
7import { Heading } from "$/ui/objects/Heading.tsx";
8import { Icon } from "$/ui/objects/Icon.tsx";
9import { PlaceholderBox } from "$/ui/objects/PlaceholderBox.tsx";
10import site from "@/corvos.config.ts";
11
12export const template = site.$.template({ type: "releases-index" }, (page, pages) => {
13 const query = site.$.query(pages);
14 const items = query.type(".html").match({ type: "release" }).many().toArray();
15 const feed = query.type(".rss").match({ type: "releases" }).one();
16
17 return (
18 <BaseLayout page={page}>
19 <SiteHeader
20 url={page.url}
21 end={
22 <div class="l-media__block">
23 <ActionButton
24 align-block
25 class="u-mbs-0"
26 href={feed.url}
27 icon={<Icon icon="rss-simple" variant="bold" />}
28 level="quiet"
29 pill
30 title="RSS Feed"
31 />
32 </div>
33 }
34 sm={
35 <div class="l-media__block l-media__block--main">
36 <Heading class="u-mbs-0 u-elp">{page.data.title}</Heading>
37 </div>
38 }
39 ></SiteHeader>
40
41 <Container as="main" fixed pad-block pad-inline>
42 <CardList keyboard-nav>
43 {items.map((item) => (
44 <ReleaseCard page={item} heading-level="h2" list />
45 ))}
46 {!items.length && <PlaceholderBox as="em">Nothing there yet</PlaceholderBox>}
47 </CardList>
48 </Container>
49 </BaseLayout>
50 );
51});