diff --git a/website/astro.config.mjs b/website/astro.config.mjs index c2343e6820..b264877680 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -53,6 +53,8 @@ export default defineConfig({ '/solutions/per-tenant-db': '/', '/solutions/user-session-store': '/', '/solutions/workflows': '/', + // Changelog list view merged into the blog index + '/changelog': '/blog', }, prefetch: { prefetchAll: true, diff --git a/website/src/components/BlogArticle.astro b/website/src/components/BlogArticle.astro new file mode 100644 index 0000000000..5cb2456e3c --- /dev/null +++ b/website/src/components/BlogArticle.astro @@ -0,0 +1,250 @@ +--- +import { getCollection, render } from 'astro:content'; +import { getPostImage } from '@/lib/postImage'; +import { ArticleSocials } from '@/components/ArticleSocials'; +import { Prose } from '@/components/Prose'; +import { formatTimestamp } from '@/lib/formatDate'; +import { CATEGORIES } from '@/lib/article'; +import { Icon, faArrowLeft, faArrowRight } from '@rivet-gg/icons'; +import * as mdxComponents from '@/components/mdx'; + +interface Props { + // biome-ignore lint/suspicious/noExplicitAny: content collection entry + entry: any; + image?: { src: string; width: number; height: number } | null; + section: 'blog' | 'changelog'; +} + +const { entry, image, section } = Astro.props; +const { Content } = await render(entry); + +const { title, description } = entry.data as unknown as { title: string; description: string }; + +// "Read next" pulls from the same section the reader is currently in. +const readNextBase = section === 'changelog' ? '/changelog/' : '/blog/'; +const allPosts = await getCollection('posts'); +const otherArticles = allPosts + .filter( + (p) => + p.id !== entry.id && + !p.data.unpublished && + (section === 'changelog' ? p.data.category === 'changelog' : p.data.category !== 'changelog'), + ) + .sort((a, b) => b.data.published.getTime() - a.data.published.getTime()) + .slice(0, 3) + .map((post) => { + const data = post.data as unknown as { title: string }; + return { + slug: post.id.replace(/\/page$/, ''), + title: data.title, + category: { ...CATEGORIES[post.data.category], id: post.data.category }, + published: post.data.published, + image: getPostImage(post), + }; + }); +--- + +
+
+
+ + + + Blog + + + +
+ +

+ {title} +

+ {description && ( +

+ {description} +

+ )} +
+ + {image && ( + {title} + )} + + + + + +
+ +
+
+ + + {otherArticles.length > 0 && ( + + )} +
+
+ + diff --git a/website/src/pages/blog/[...slug].astro b/website/src/pages/blog/[...slug].astro index 7dcc81b83f..325c570154 100644 --- a/website/src/pages/blog/[...slug].astro +++ b/website/src/pages/blog/[...slug].astro @@ -1,15 +1,9 @@ --- -import { getCollection, render } from 'astro:content'; +import { getCollection } from 'astro:content'; import BlogLayout from '@/layouts/BlogLayout.astro'; +import BlogArticle from '@/components/BlogArticle.astro'; import { getPostImage } from '@/lib/postImage'; -import { ArticleSocials } from '@/components/ArticleSocials'; -import { DocsTableOfContents } from '@/components/DocsTableOfContents'; -import { Prose } from '@/components/Prose'; -import { formatTimestamp } from '@/lib/formatDate'; import { AUTHORS, CATEGORIES } from '@/lib/article'; -import { AuthorAvatar } from '@/components/AuthorAvatar'; -import { Icon, faBluesky, faCalendarDay, faChevronRight, faGithub, faXTwitter } from '@rivet-gg/icons'; -import * as mdxComponents from '@/components/mdx'; type AuthorInfo = { name: string; @@ -34,44 +28,12 @@ export async function getStaticPaths() { } const { entry, image } = Astro.props; -const { Content, headings } = await render(entry); const slug = entry.id.replace(/\/page$/, ''); const author = AUTHORS[entry.data.author] as AuthorInfo; const category = { ...CATEGORIES[entry.data.category], id: entry.data.category }; - const { title, description } = entry.data as unknown as { title: string; description: string }; -// Build table of contents -const tableOfContents = headings - .filter((h) => h.depth === 2 || h.depth === 3) - .reduce((acc, h) => { - if (h.depth === 2) { - acc.push({ title: h.text, id: h.slug, children: [] }); - } else if (acc.length > 0) { - acc[acc.length - 1].children.push({ title: h.text, id: h.slug, children: [] }); - } - return acc; - }, [] as any[]); - -// Load other articles -const allPosts = await getCollection('posts'); -const filteredOtherPosts = allPosts - .filter((p) => p.id !== entry.id && !p.data.unpublished) - .sort((a, b) => b.data.published.getTime() - a.data.published.getTime()) - .slice(0, 3); - -const otherArticles = filteredOtherPosts.map((post) => { - const slugValue = post.id.replace(/\/page$/, ''); - const cat = { ...CATEGORIES[post.data.category], id: post.data.category }; - return { - slug: slugValue, - title: (post.data as unknown as { title: string }).title, - category: cat, - published: post.data.published, - }; -}); - // BreadcrumbList schema const breadcrumbSchema = { "@context": "https://schema.org", @@ -97,112 +59,5 @@ const breadcrumbSchema = { category={category.name} >