Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
74bc722
Update landing page for blog
carlagn Mar 4, 2026
a73dc20
Update pagination and blog grid
carlagn Mar 4, 2026
0a77c16
Update filters for blog
carlagn Mar 9, 2026
5b84c27
Update blog landing iso string
carlagn Mar 9, 2026
915de0a
Updayte blog format date
carlagn Mar 9, 2026
cf1c961
Add blogpost
carlagn Mar 4, 2026
51ff112
Update share section for blogpost
carlagn Mar 5, 2026
ec04156
Fix discarded authorSrc
carlagn Mar 5, 2026
e794a73
Add functioning newsletter
carlagn Mar 6, 2026
a2f9d71
Update newsletter component
carlagn Mar 6, 2026
242210e
Update sharesocials export
carlagn Mar 9, 2026
d6492f9
Update tags field
carlagn Mar 9, 2026
72f59f3
Update possible undefined
carlagn Mar 9, 2026
86d9797
Update page
carlagn Mar 9, 2026
873eb4b
Update blog slug tags format
carlagn Mar 9, 2026
fff0a63
Update z index of blog post
carlagn Mar 9, 2026
79b497a
Update formatdate for blogpost
carlagn Mar 9, 2026
93e2a1c
Update gap of toc and content
carlagn Mar 9, 2026
0706148
Update filtered items
carlagn Mar 9, 2026
05449db
Fix bg-blog
carlagn Mar 9, 2026
a3f0f82
Update quotes
carlagn Mar 9, 2026
9439796
Update global.css
carlagn Mar 9, 2026
f69ae5e
Remove route for static eclipse site
carlagn Mar 9, 2026
cda85ef
Merge branch 'main' into feat/DR-7521-blog-post
mhartington Mar 10, 2026
d1bc428
Merge branch 'main' into feat/DR-7521-blog-post
mhartington Mar 10, 2026
96affdc
chore(blog): update post page
mhartington Mar 11, 2026
f7d52c7
Merge branch 'main' into feat/DR-7521-blog-post
mhartington Mar 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/blog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@fumadocs/cli": "catalog:",
"@prisma/eclipse": "workspace:^",
"@prisma-docs/ui": "workspace:*",
"cors": "^2.8.6",
"fumadocs-core": "catalog:",
"fumadocs-mdx": "catalog:",
"fumadocs-openapi": "catalog:",
Expand Down
Binary file added apps/blog/public/authors/aidan-mcalister.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/alberto-perdomo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/alex-emerich.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/alex-ruheni.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/andrew-carlson.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/ankur-datta.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/charly-poly.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/daniel-norman.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/dave-feldman.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions apps/blog/public/authors/default.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/dennis-walsh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/etel-sverdlov.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/herve-labas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/james-ritchie.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/jan-piotrowski.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/jillian-winter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/johannes-schickling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/jon-harrell.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/josh-mcleod.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/justin-ellingwood.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/mahmoud-abdelwahab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/marc-hess.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/michelle-greer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/blog/public/authors/mike-hartington.png
Binary file added apps/blog/public/authors/nikolas-burk.png
Binary file added apps/blog/public/authors/nitin-gupta.png
Binary file added apps/blog/public/authors/petra-donka.png
Binary file added apps/blog/public/authors/ryan-chenkie.png
Binary file added apps/blog/public/authors/sam-bhatti.png
Binary file added apps/blog/public/authors/shane-neubauer.png
Binary file added apps/blog/public/authors/sonia-lomo.png
Binary file added apps/blog/public/authors/spiros-martzoukos.png
Binary file added apps/blog/public/authors/stephen-king.png
Binary file added apps/blog/public/authors/tasin-ishmam.png
Binary file added apps/blog/public/authors/tim-griesser.png
Binary file added apps/blog/public/authors/tim-suchanek.png
Binary file added apps/blog/public/authors/tyler-benfield.png
Binary file added apps/blog/public/authors/uri-goldshtein.png
Binary file added apps/blog/public/authors/vladi-stevanovic.png
Binary file added apps/blog/public/authors/will-madden.png
184 changes: 85 additions & 99 deletions apps/blog/src/app/(blog)/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { notFound } from 'next/navigation';
import Link from 'next/link';
import { InlineTOC } from 'fumadocs-ui/components/inline-toc';
import { getMDXComponents } from '@/mdx-components';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import { blog } from '@/lib/source';
import Image from 'next/image';
import { withBlogBasePathForImageSrc } from '@/lib/url';
import { formatTag, formatDate } from "@/lib/format";
import { notFound } from "next/navigation";
import { getMDXComponents } from "@/mdx-components";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { blog } from "@/lib/source";
import {
Badge,
InlineTOC,
Separator,
} from "@prisma/eclipse";

import { FooterNewsletterForm } from "@prisma-docs/ui/components/newsletter";
import { BlogShare } from "@/components/BlogShare";
import { AuthorAvatarGroup } from "@/components/AuthorAvatarGroup";
import { withBlogBasePath } from "@/lib/url";
import Link from "next/link";

interface TOCItem {
title: string;
url: string;
depth: number;
items?: TOCItem[];
}

export default async function Page(props: {
params: Promise<{ slug: string }>;
}) {
Expand All @@ -14,106 +30,76 @@ export default async function Page(props: {

if (!page) notFound();
const MDX = page.data.body;
const formatDate = (value: unknown) => {
const date =
value instanceof Date ? value : new Date((value as string) ?? '');
if (Number.isNaN(date.getTime())) return '';
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
};
const getHeroImageSrc = () => {
const data = page.data as any;
const rel =
(data.heroImagePath as string | undefined) ??
(data.metaImagePath as string | undefined);
if (rel) {
if (rel.startsWith('/')) return rel;
const base = page.url.startsWith('/') ? page.url : `/${page.url}`;
const baseClean = base.endsWith('/') ? base.slice(0, -1) : base;
const relClean = rel.replace(/^\.\//, '').replace(/^\/+/, '');
return `${baseClean}/${relClean}`;
}
const absolute =
(data.heroImageUrl as string | undefined) ??
(data.metaImageUrl as string | undefined);
return absolute ?? null;
};
const heroSrc = getHeroImageSrc();

const newsletterApiUrl = withBlogBasePath("/api/newsletter");
return (
<>
{/* Hero image */}
{heroSrc ? (
<div className="w-full">
<div className="relative w-full aspect-video">
<Image
src={withBlogBasePathForImageSrc(heroSrc)}
alt={(page.data as any).heroImageAlt ?? page.data.title}
fill
priority
className="object-cover"
sizes="100vw"
<div className="w-full px-4 z-1 mx-auto md:grid md:grid-cols-[1fr_180px] mt-4 md:mt-22 gap-12 max-w-257">
<div className="post-contents w-full">
{/* Title + meta */}
<header className="w-full relative">
<Link
href="/"
className="text-fd-primary hover:underline text-sm absolute -top-8"
>
← Back to Blog
</Link>
<h1 className="mt-3 mb-8 font-bold max-md:text-3xl md:text-5xl stretch-display font-display text-foreground-neutral">
{page.data.title}
</h1>
<div className="text-sm flex gap-2 items-center text-foreground-neutral mb-4">
<AuthorAvatarGroup authors={page.data.authors} />
{page.data.date ? (
<>
<Separator orientation="vertical" className="h-4" />
<span className="text-foreground-neutral-weak">
{formatDate(new Date(page.data.date).toISOString())}
</span>
</>
) : null}
</div>
{page.data.tags && page.data.tags.length > 0 && (
<div className="filter-badge flex gap-2">
{page.data?.tags?.map((tag) => (
<Badge
key={tag}
color="neutral"
label={formatTag(tag)}
className="border capitalize border-stroke-neutral-strong bg-transparent text-foreground-neutral-weak"
/>
))}
</div>
)}
</header>

{/* Body */}
<article className="w-full flex flex-col pb-8 mt-12">
<div className="prose min-w-0 [&_figure]:w-full [&_figure]:md:max-w-140 [&_figure]:lg:max-w-200">
<MDX
components={getMDXComponents({
a: createRelativeLink(blog, page),
})}
/>
</div>
</div>
) : null}
</article>
<Separator className="my-12" />

{/* Title + meta */}
<header className="w-full max-w-350 mx-auto px-4 md:px-8 py-10">
<Link href="/" className="text-fd-primary hover:underline text-sm">
← Back to Blog
</Link>
<h1 className="mt-3 mb-3 text-3xl md:text-4xl font-bold">
{page.data.title}
</h1>
{page.data.description ? (
<p className="text-fd-muted-foreground mb-3">{page.data.description}</p>
) : null}
<p className="text-sm text-fd-muted-foreground">
{page.data.authors?.length ? page.data.authors.join(', ') : null}
{page.data.date ? (
<>
{' • '}
<span>{formatDate(page.data.date)}</span>
</>
) : null}
</p>
</header>
{/* Share Container */}
<BlogShare desc={page.data.metaDescription as string} />

{/* Body */}
<article className="w-full max-w-350 mx-auto flex flex-col px-4 md:px-8 pb-12">
<div className="prose min-w-0">
<InlineTOC items={page.data.toc} />
<MDX
components={getMDXComponents({
a: createRelativeLink(blog, page)
})}
/>
{/* Newsletter CTA */}
<div className="w-full px-8 py-12 shadow-box-low newsletter-bg rounded-square border border-background-neutral flex max-sm:flex-col wrap items-start gap-4 sm:items-center justify-between my-12">
<FooterNewsletterForm apiUrl={newsletterApiUrl} />
</div>
</article>

{/* Newsletter CTA */}
<div className="w-full max-w-350 mx-auto px-4 md:px-8 pb-16">
<div className="rounded-2xl border border-fd-primary/20 bg-fd-secondary p-6 md:p-8">
<h4 className="text-2xl font-semibold mb-2">
Don’t miss the next post!
</h4>
<p className="text-fd-muted mb-4">
Sign up for the Prisma Newsletter to stay up to date with the latest
releases and posts.
</p>
<Link
href="https://www.prisma.io/newsletter"
className="inline-flex items-center px-4 py-2 rounded-md bg-fd-primary text-white hover:opacity-90 transition"
>
Sign up
</Link>
</div>
<div className="max-md:hidden toc">
<div className="sticky top-24 [&_a[data-state=inactive]]:text-foreground-neutral-weak! [&_a[data-state=active]]:text-foreground-neutral!">
<span className="text-shadow-foreground-neutral-reverse font-semibold text-md mb-4 mt-0 block">
On this page
</span>
<InlineTOC items={page.data.toc as TOCItem[]} className="px-0" />
</div>
</div>
</>
</div>
);
}

Expand Down
11 changes: 9 additions & 2 deletions apps/blog/src/app/(blog)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Suspense } from "react";
import { blog } from "@/lib/source";
import { BlogGrid } from "@/components/BlogGrid";
import { Avatar, Badge, Card } from "@prisma/eclipse";
import { getCardImageSrc } from "@/lib/source";
import { getAuthorProfiles } from "@/lib/authors";
export default function BlogHome() {
const posts = blog.getPages().sort((a, b) => {
const aTime =
Expand All @@ -21,6 +21,14 @@ export default function BlogHome() {
const authors = Array.isArray(data?.authors) ? data?.authors : [];
return authors.length > 0 ? authors[0] : null;
};

const getPrimaryAuthorImage = (post: (typeof posts)[number]) => {
const data = post.data as any;
const authors = Array.isArray(data?.authors) ? data?.authors : [];
const profiles = getAuthorProfiles(authors);
const firstWithImage = profiles.find((profile) => profile.imageSrc);
return firstWithImage?.imageSrc ?? null;
};
const items = posts.map((post) => {
const data = post.data as any;

Expand All @@ -45,7 +53,6 @@ export default function BlogHome() {
description:
(data.description as string) || (data.metaDescription as string) || "",
author: getPrimaryAuthor(post),
authorSrc: null,
imageSrc: getCardImageSrc(post),
imageAlt: (data.heroImageAlt as string) ?? (data.title as string),
seriesTitle: data.series?.title ?? null,
Expand Down
Loading
Loading