diff options
Diffstat (limited to 'src/pages/releases')
| -rw-r--r-- | src/pages/releases/[version].tsx | 100 | ||||
| -rw-r--r-- | src/pages/releases/feed.ts | 19 | ||||
| -rw-r--r-- | src/pages/releases/index.mdx | 8 | ||||
| -rw-r--r-- | src/pages/releases/index.tsx | 51 |
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 @@ | |||
| 1 | import { Page, PipelineStageError } from "corvos"; | ||
| 2 | |||
| 3 | import { strapiLoader } from "$/deps/strapi.tsx"; | ||
| 4 | import { releaseStrapiSchema } from "$/schemas/releases.ts"; | ||
| 5 | import { BaseLayout } from "$/ui/base/BaseLayout.tsx"; | ||
| 6 | import { ReleaseCard } from "$/ui/components/ReleaseCard.tsx"; | ||
| 7 | import { SiteHeader } from "$/ui/components/SiteHeader.tsx"; | ||
| 8 | import { CardList } from "$/ui/layouts/CardList.tsx"; | ||
| 9 | import { Container } from "$/ui/layouts/Container.tsx"; | ||
| 10 | import { HList } from "$/ui/layouts/HList.tsx"; | ||
| 11 | import { ActionButton } from "$/ui/objects/ActionButton.tsx"; | ||
| 12 | import { Badge } from "$/ui/objects/Badge.tsx"; | ||
| 13 | import { Body } from "$/ui/objects/Body.tsx"; | ||
| 14 | import { Divider } from "$/ui/objects/Divider.tsx"; | ||
| 15 | import { Heading } from "$/ui/objects/Heading.tsx"; | ||
| 16 | import { Icon } from "$/ui/objects/Icon.tsx"; | ||
| 17 | import site from "@/corvos.config.ts"; | ||
| 18 | |||
| 19 | export 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 | |||
| 36 | export 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 @@ | |||
| 1 | import type { FeedItem } from "corvos/plugins/feeds.ts"; | ||
| 2 | |||
| 3 | import site from "@/corvos.config.ts"; | ||
| 4 | |||
| 5 | export 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 | --- | ||
| 2 | type: "releases-index" | ||
| 3 | title: "Releases" | ||
| 4 | description: "All releases of Corvos." | ||
| 5 | --- | ||
| 6 | |||
| 7 | import { template } from "./index.tsx"; | ||
| 8 | export { 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 @@ | |||
| 1 | import { BaseLayout } from "$/ui/base/BaseLayout.tsx"; | ||
| 2 | import { ReleaseCard } from "$/ui/components/ReleaseCard.tsx"; | ||
| 3 | import { SiteHeader } from "$/ui/components/SiteHeader.tsx"; | ||
| 4 | import { CardList } from "$/ui/layouts/CardList.tsx"; | ||
| 5 | import { Container } from "$/ui/layouts/Container.tsx"; | ||
| 6 | import { ActionButton } from "$/ui/objects/ActionButton.tsx"; | ||
| 7 | import { Heading } from "$/ui/objects/Heading.tsx"; | ||
| 8 | import { Icon } from "$/ui/objects/Icon.tsx"; | ||
| 9 | import { PlaceholderBox } from "$/ui/objects/PlaceholderBox.tsx"; | ||
| 10 | import site from "@/corvos.config.ts"; | ||
| 11 | |||
| 12 | export 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 | }); | ||
