From 530900c9aca6aba06c5322040e5d4590263c4123 Mon Sep 17 00:00:00 2001 From: Maximilian Kaske <56969857+mxkaske@users.noreply.github.com> Date: Wed, 4 Oct 2023 22:48:45 +0200 Subject: [PATCH] feat: add changelog (#359) --- apps/web/contentlayer.config.ts | 3 +- .../public/assets/changelog/status-widget.png | Bin 0 -> 20900 bytes .../src/app/(content)/blog/[slug]/page.tsx | 76 ++++++++++ apps/web/src/app/(content)/blog/page.tsx | 24 ++++ apps/web/src/app/(content)/changelog/page.tsx | 53 +++++++ .../src/app/{blog => (content)}/layout.tsx | 0 apps/web/src/app/blog/[slug]/page.tsx | 130 ------------------ apps/web/src/app/blog/page.tsx | 45 ------ apps/web/src/components/content/article.tsx | 62 +++++++++ apps/web/src/components/content/thumbnail.tsx | 24 ++++ .../components/layout/marketing-footer.tsx | 10 +- .../components/layout/marketing-header.tsx | 26 ++-- .../src/components/layout/marketing-menu.tsx | 66 +++++++++ .../src/content/changelog/status-widget.mdx | 15 ++ .../src/contentlayer/documents/changelog.ts | 29 ++++ apps/web/src/middleware.ts | 1 + 16 files changed, 374 insertions(+), 190 deletions(-) create mode 100644 apps/web/public/assets/changelog/status-widget.png create mode 100644 apps/web/src/app/(content)/blog/[slug]/page.tsx create mode 100644 apps/web/src/app/(content)/blog/page.tsx create mode 100644 apps/web/src/app/(content)/changelog/page.tsx rename apps/web/src/app/{blog => (content)}/layout.tsx (100%) delete mode 100644 apps/web/src/app/blog/[slug]/page.tsx delete mode 100644 apps/web/src/app/blog/page.tsx create mode 100644 apps/web/src/components/content/article.tsx create mode 100644 apps/web/src/components/content/thumbnail.tsx create mode 100644 apps/web/src/components/layout/marketing-menu.tsx create mode 100644 apps/web/src/content/changelog/status-widget.mdx create mode 100644 apps/web/src/contentlayer/documents/changelog.ts diff --git a/apps/web/contentlayer.config.ts b/apps/web/contentlayer.config.ts index e34c9ee2..f1f46879 100644 --- a/apps/web/contentlayer.config.ts +++ b/apps/web/contentlayer.config.ts @@ -2,6 +2,7 @@ import { makeSource } from "contentlayer/source-files"; import rehypeSlug from "rehype-slug"; import remarkGfm from "remark-gfm"; +import { Changelog } from "./src/contentlayer/documents/changelog"; import { LegalPost } from "./src/contentlayer/documents/legal"; import { Post } from "./src/contentlayer/documents/post"; import autolinkHeadings from "./src/contentlayer/plugins/autolink-headings"; @@ -9,7 +10,7 @@ import prettyCode from "./src/contentlayer/plugins/pretty-code"; export default makeSource({ contentDirPath: "src/content/", - documentTypes: [Post, LegalPost], + documentTypes: [Post, LegalPost, Changelog], mdx: { remarkPlugins: [remarkGfm], rehypePlugins: [rehypeSlug, prettyCode, autolinkHeadings], diff --git a/apps/web/public/assets/changelog/status-widget.png b/apps/web/public/assets/changelog/status-widget.png new file mode 100644 index 0000000000000000000000000000000000000000..d0f37f2c28c049f92d48e5835a8eb6b970b187d9 GIT binary patch literal 20900 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 literal 0 HcmV?d00001 diff --git a/apps/web/src/app/(content)/blog/[slug]/page.tsx b/apps/web/src/app/(content)/blog/[slug]/page.tsx new file mode 100644 index 00000000..7a40b42e --- /dev/null +++ b/apps/web/src/app/(content)/blog/[slug]/page.tsx @@ -0,0 +1,76 @@ +import type { Metadata } from "next"; +import { notFound } from "next/navigation"; +import { allPosts } from "contentlayer/generated"; + +import { + defaultMetadata, + ogMetadata, + twitterMetadata, +} from "@/app/shared-metadata"; +import { Article } from "@/components/content/article"; +import { Shell } from "@/components/dashboard/shell"; +import { BackButton } from "@/components/layout/back-button"; + +export const dynamic = "force-static"; + +export async function generateStaticParams() { + return allPosts.map((post) => ({ + slug: post.slug, + })); +} + +export async function generateMetadata({ + params, +}: { + params: { slug: string }; +}): Promise { + const post = allPosts.find((post) => post.slug === params.slug); + if (!post) { + return; + } + const { title, publishedAt: publishedTime, description, slug, image } = post; + + return { + ...defaultMetadata, + title, + description, + openGraph: { + ...ogMetadata, + title, + description, + type: "article", + publishedTime, + url: `https://www.openstatus.dev/blog/${slug}`, + images: [ + { + url: `https://openstatus.dev/api/og/post?title=${title}&description=${description}&image=${image}`, + }, + ], + }, + twitter: { + ...twitterMetadata, + title, + description, + images: [ + `https://openstatus.dev/api/og/post?title=${title}&description=${description}&image=${image}`, + ], + }, + }; +} + +export default function PostPage({ params }: { params: { slug: string } }) { + const post = allPosts.find((post) => post.slug === params.slug); + + if (!post) { + notFound(); + } + + return ( + <> + + +
+ + + ); +} diff --git a/apps/web/src/app/(content)/blog/page.tsx b/apps/web/src/app/(content)/blog/page.tsx new file mode 100644 index 00000000..325c4cf7 --- /dev/null +++ b/apps/web/src/app/(content)/blog/page.tsx @@ -0,0 +1,24 @@ +import { allPosts } from "contentlayer/generated"; + +import { Thumbnail } from "@/components/content/thumbnail"; +import { Shell } from "@/components/dashboard/shell"; + +export default async function Post() { + const posts = allPosts.sort( + (a, b) => + new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime(), + ); + + return ( + +
+

Blog

+
+ {posts.map((post) => ( + + ))} +
+
+
+ ); +} diff --git a/apps/web/src/app/(content)/changelog/page.tsx b/apps/web/src/app/(content)/changelog/page.tsx new file mode 100644 index 00000000..af1edf23 --- /dev/null +++ b/apps/web/src/app/(content)/changelog/page.tsx @@ -0,0 +1,53 @@ +import Image from "next/image"; +import { allChangelogs } from "contentlayer/generated"; + +import { Mdx } from "@/components/content/mdx"; +import { Shell } from "@/components/dashboard/shell"; +import { formatDate } from "@/lib/utils"; + +export default async function Post() { + const posts = allChangelogs.sort( + (a, b) => + new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime(), + ); + + return ( + +
+
+
+
+

Changelog

+

+ All the latest features, fixes and work to OpenStatus. +

+
+
+ {posts.map((post) => ( +
+ +
+ {post.title} +
+

+ {post.title} +

+
+ +
+
+ ))} +
+ + ); +} diff --git a/apps/web/src/app/blog/layout.tsx b/apps/web/src/app/(content)/layout.tsx similarity index 100% rename from apps/web/src/app/blog/layout.tsx rename to apps/web/src/app/(content)/layout.tsx diff --git a/apps/web/src/app/blog/[slug]/page.tsx b/apps/web/src/app/blog/[slug]/page.tsx deleted file mode 100644 index e508f0ed..00000000 --- a/apps/web/src/app/blog/[slug]/page.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import { notFound } from "next/navigation"; -import { allPosts } from "contentlayer/generated"; - -import { Avatar, AvatarFallback, AvatarImage } from "@openstatus/ui"; - -import { - defaultMetadata, - ogMetadata, - twitterMetadata, -} from "@/app/shared-metadata"; -import { Mdx } from "@/components/content/mdx"; -import { Shell } from "@/components/dashboard/shell"; -import { BackButton } from "@/components/layout/back-button"; -import { formatDate } from "@/lib/utils"; - -export const dynamic = "force-static"; - -export async function generateStaticParams() { - return allPosts.map((post) => ({ - slug: post.slug, - })); -} - -export async function generateMetadata({ - params, -}: { - params: { slug: string }; -}): Promise { - const post = allPosts.find((post) => post.slug === params.slug); - if (!post) { - return; - } - const { title, publishedAt: publishedTime, description, slug, image } = post; - - return { - ...defaultMetadata, - title, - description, - openGraph: { - ...ogMetadata, - title, - description, - type: "article", - publishedTime, - url: `https://www.openstatus.dev/blog/${slug}`, - images: [ - { - url: `https://openstatus.dev/api/og/post?title=${title}&description=${description}&image=${image}`, - }, - ], - }, - twitter: { - ...twitterMetadata, - title, - description, - images: [ - `https://openstatus.dev/api/og/post?title=${title}&description=${description}&image=${image}`, - ], - }, - }; -} - -export default function PostPage({ params }: { params: { slug: string } }) { - const post = allPosts.find((post) => post.slug === params.slug); - - if (!post) { - notFound(); - } - - const getNameInitials = (name: string) => { - const individualNames = name.split(" "); - return ( - individualNames[0][0] + individualNames[individualNames.length - 1][0] - ); - }; - - return ( - <> - - -
-
-

{post.title}

-
- {/* {post.title} */} - {/* HOTFIX: plain `img` */} - {post.title} -
-
- - - - {getNameInitials(post.author.name)} - - -
- - {post.author.name} - -

- {formatDate(new Date(post.publishedAt))} - • - {post.readingTime} -

-
-
-
-
- -
-
-
- - ); -} diff --git a/apps/web/src/app/blog/page.tsx b/apps/web/src/app/blog/page.tsx deleted file mode 100644 index e9e29b7f..00000000 --- a/apps/web/src/app/blog/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import Link from "next/link"; -import { allPosts } from "contentlayer/generated"; - -import { Shell } from "@/components/dashboard/shell"; -import { formatDate } from "@/lib/utils"; - -export default async function Post() { - const posts = allPosts.sort( - (a, b) => - new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime(), - ); - - return ( - -
-

Blog

-
- {posts.map((post) => ( -
- -
-

- {post.title} -

-

{post.description}

-

- {post.author.name} - - • - - {formatDate(new Date(post.publishedAt))} - - • - - {post.readingTime} -

-
- -
- ))} -
-
-
- ); -} diff --git a/apps/web/src/components/content/article.tsx b/apps/web/src/components/content/article.tsx new file mode 100644 index 00000000..b1cb68a0 --- /dev/null +++ b/apps/web/src/components/content/article.tsx @@ -0,0 +1,62 @@ +import Image from "next/image"; +import Link from "next/link"; +import type { Post } from "contentlayer/generated"; + +import { Avatar, AvatarFallback, AvatarImage } from "@openstatus/ui"; + +import { Mdx } from "@/components/content/mdx"; +import { formatDate } from "@/lib/utils"; + +export function Article({ post }: { post: Post }) { + const getNameInitials = (name: string) => { + const individualNames = name.split(" "); + return ( + individualNames[0][0] + individualNames[individualNames.length - 1][0] + ); + }; + + return ( +
+
+

{post.title}

+
+ {post.title} + {/* HOTFIX: plain `img` */} + {/* {post.title} */} +
+
+ + + {getNameInitials(post.author.name)} + +
+ + {post.author.name} + +

+ {formatDate(new Date(post.publishedAt))} + • + {post.readingTime} +

+
+
+
+
+ +
+
+ ); +} diff --git a/apps/web/src/components/content/thumbnail.tsx b/apps/web/src/components/content/thumbnail.tsx new file mode 100644 index 00000000..ab275aba --- /dev/null +++ b/apps/web/src/components/content/thumbnail.tsx @@ -0,0 +1,24 @@ +import Link from "next/link"; +import type { Post } from "contentlayer/generated"; + +import { formatDate } from "@/lib/utils"; + +export function Thumbnail({ post }: { post: Post }) { + return ( +
+ +
+

{post.title}

+

{post.description}

+

+ {post.author.name} + • + {formatDate(new Date(post.publishedAt))} + • + {post.readingTime} +

+
+ +
+ ); +} diff --git a/apps/web/src/components/layout/marketing-footer.tsx b/apps/web/src/components/layout/marketing-footer.tsx index 8bc6f368..ebe4d29d 100644 --- a/apps/web/src/components/layout/marketing-footer.tsx +++ b/apps/web/src/components/layout/marketing-footer.tsx @@ -14,23 +14,23 @@ export function MarketingFooter({ className }: Props) {