From c4353cfd829d30c611bb6227ea3cf86ae0369dc1 Mon Sep 17 00:00:00 2001 From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com> Date: Sat, 30 May 2026 17:30:15 +0200 Subject: [PATCH 1/2] Add docs and blog share cards --- website-next/app/blog/[...slug]/page.tsx | 27 +++- .../app/docs-og/[id]/opengraph-image.tsx | 134 ++++++++++++++++++ website-next/app/docs/[...slug]/page.tsx | 71 ++++------ website-next/app/globals.css | 1 + website-next/nginx/conf.d/default.conf | 14 ++ website-next/src/helpers/docsParams.ts | 77 ++++++++++ website-next/src/helpers/siteUrl.ts | 12 ++ website-next/src/og/fonts.ts | 31 ++++ website-next/src/og/fonts/Inter-Bold.ttf | Bin 0 -> 67988 bytes website-next/src/og/fonts/Inter-Regular.ttf | Bin 0 -> 67952 bytes website-next/src/og/fonts/LICENSE.md | 11 ++ website-next/src/theme/colors.ts | 14 ++ 12 files changed, 350 insertions(+), 42 deletions(-) create mode 100644 website-next/app/docs-og/[id]/opengraph-image.tsx create mode 100644 website-next/src/helpers/docsParams.ts create mode 100644 website-next/src/og/fonts.ts create mode 100644 website-next/src/og/fonts/Inter-Bold.ttf create mode 100644 website-next/src/og/fonts/Inter-Regular.ttf create mode 100644 website-next/src/og/fonts/LICENSE.md create mode 100644 website-next/src/theme/colors.ts diff --git a/website-next/app/blog/[...slug]/page.tsx b/website-next/app/blog/[...slug]/page.tsx index 2f002ed885e..5ed74d94137 100644 --- a/website-next/app/blog/[...slug]/page.tsx +++ b/website-next/app/blog/[...slug]/page.tsx @@ -18,6 +18,7 @@ import { findSimilarPosts, listBlogPostSummaries } from "@/src/helpers/blogPosts import { compileDoc } from "@/src/helpers/compileDoc"; import { readFrontmatter } from "@/src/helpers/readFrontmatter"; import { estimateReadingTime } from "@/src/helpers/readingTime"; +import { toAbsoluteUrl } from "@/src/helpers/siteUrl"; type BlogFrontmatter = { title?: string; @@ -67,9 +68,29 @@ export async function generateMetadata({ return {}; } const { title, description } = readFrontmatter(path.join(BLOG_ROOT, rel)); + + const stem = stemForSlug(slug); + const summary = listBlogPostSummaries().find((s) => s.stem === stem); + const featuredImageAbs = summary?.featuredImage + ? toAbsoluteUrl(summary.featuredImage) + : undefined; + const images = featuredImageAbs ? [featuredImageAbs] : undefined; + return { title, description, + openGraph: { + type: "article", + title, + description, + images, + }, + twitter: { + card: "summary_large_image", + title, + description, + images, + }, }; } @@ -93,7 +114,7 @@ export default async function BlogSlugPage({ params }: PageProps) { const readingTime = estimateReadingTime(raw).text; const summaries = listBlogPostSummaries(); - const stem = `${slug[0]}-${slug[1]}-${slug[2]}-${slug.slice(3).join("/")}`; + const stem = stemForSlug(slug); const current = summaries.find((s) => s.stem === stem); const similar = current ? findSimilarPosts(current, summaries) : []; const featuredImage = current?.featuredImage ?? null; @@ -133,6 +154,10 @@ function isPaginationSlug(slug: string[]): boolean { return slug.length === 1 && /^\d+$/.test(slug[0]); } +function stemForSlug(slug: string[]): string { + return `${slug[0]}-${slug[1]}-${slug[2]}-${slug.slice(3).join("/")}`; +} + function renderPagination(pageNum: number) { if (!Number.isInteger(pageNum) || pageNum < 2) { notFound(); diff --git a/website-next/app/docs-og/[id]/opengraph-image.tsx b/website-next/app/docs-og/[id]/opengraph-image.tsx new file mode 100644 index 00000000000..5dcefc42a9e --- /dev/null +++ b/website-next/app/docs-og/[id]/opengraph-image.tsx @@ -0,0 +1,134 @@ +import path from "node:path"; +import { ImageResponse } from "next/og"; +import { PRODUCTS } from "@/src/data/products"; +import { + CONTENT_ROOT, + decodeDocId, + encodeDocId, + listDocSlugs, + resolveFile, +} from "@/src/helpers/docsParams"; +import { readFrontmatter } from "@/src/helpers/readFrontmatter"; +import { loadInterFonts } from "@/src/og/fonts"; +import { ccAccent, ccBg, ccInk, ccSurface } from "@/src/theme/colors"; + +// TODO: Proper styling and layout of share cards + +export const dynamicParams = false; + +/** `#rrggbb` -> `rgba(r, g, b, a)`, so gradients derive from the same tokens. */ +function rgba(hex: string, alpha: number): string { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + return `rgba(${r}, ${g}, ${b}, ${alpha})`; +} + +export const alt = "ChilliCream documentation"; + +export const size = { + width: 1200, + height: 630, +}; + +export const contentType = "image/png"; + +type Params = { + id: string; +}; + +export function generateStaticParams(): Params[] { + return listDocSlugs().map((slug) => ({ id: encodeDocId(slug) })); +} + +export default async function Image({ params }: { params: Promise }) { + const { id } = await params; + const slug = decodeDocId(id); + const rel = resolveFile(slug); + const frontmatter = rel + ? readFrontmatter(path.join(CONTENT_ROOT, rel)) + : null; + + const productSlug = slug[0]; + const product = PRODUCTS.find((p) => p.slug === productSlug); + const eyebrow = product?.title ?? "ChilliCream"; + const title = frontmatter?.title ?? product?.title ?? "ChilliCream"; + + const fonts = await loadInterFonts(); + + return new ImageResponse( +
+
+ {eyebrow} +
+ +
+
+ {eyebrow} +
+
+ {title} +
+
+
, + { + ...size, + fonts, + }, + ); +} diff --git a/website-next/app/docs/[...slug]/page.tsx b/website-next/app/docs/[...slug]/page.tsx index 13b63315463..f72a4b3c4c6 100644 --- a/website-next/app/docs/[...slug]/page.tsx +++ b/website-next/app/docs/[...slug]/page.tsx @@ -1,4 +1,3 @@ -import fs from "node:fs"; import path from "node:path"; import type { Metadata } from "next"; import { notFound } from "next/navigation"; @@ -7,11 +6,16 @@ import { EditOnGitHub } from "@/src/design-system/EditOnGitHub"; import { TableOfContents } from "@/src/design-system/TableOfContents"; import { Typography } from "@/src/design-system/Typography"; import { compileDoc } from "@/src/helpers/compileDoc"; +import { + CONTENT_ROOT, + encodeDocId, + listDocSlugs, + resolveFile, +} from "@/src/helpers/docsParams"; import { getGitMetadata } from "@/src/helpers/gitMetadata"; import { githubEditUrl } from "@/src/helpers/githubEditUrl"; import { readFrontmatter } from "@/src/helpers/readFrontmatter"; - -const CONTENT_ROOT = path.join(process.cwd(), "content/docs"); +import { toAbsoluteUrl } from "@/src/helpers/siteUrl"; type Params = { slug: string[]; @@ -24,19 +28,7 @@ type PageProps = { export const dynamicParams = false; export function generateStaticParams(): Params[] { - const params = walk(CONTENT_ROOT) - .filter((f) => /\.mdx?$/.test(f)) - .map((f) => path.relative(CONTENT_ROOT, f).replace(/\.mdx?$/, "")) - .map((rel) => rel.split(path.sep)) - .map((parts) => - parts[parts.length - 1] === "index" ? parts.slice(0, -1) : parts, - ) - .filter((slug) => slug.length > 0) - .map((slug) => ({ slug })); - - // output: export requires at least one prerendered path; placeholder - // renders 404 via notFound() when no content is present. - return params.length > 0 ? params : [{ slug: ["__empty__"] }]; + return listDocSlugs().map((slug) => ({ slug })); } export async function generateMetadata({ @@ -48,9 +40,31 @@ export async function generateMetadata({ return {}; } const { title, description } = readFrontmatter(path.join(CONTENT_ROOT, rel)); + + const id = encodeDocId(slug); + const ogImage = { + url: toAbsoluteUrl(`/docs-og/${id}/opengraph-image`), + width: 1200, + height: 630, + type: "image/png", + alt: title ? `${title} documentation` : "ChilliCream documentation", + }; + return { title, description, + openGraph: { + type: "article", + title, + description, + images: [ogImage], + }, + twitter: { + card: "summary_large_image", + title, + description, + images: [ogImage], + }, }; } @@ -89,28 +103,3 @@ export default async function DocPage({ params }: PageProps) { ); } - -function resolveFile(slug: string[]): string | null { - const joined = slug.join("/"); - const candidates = [ - `${joined}.md`, - `${joined}.mdx`, - `${joined}/index.md`, - `${joined}/index.mdx`, - ]; - - for (const c of candidates) { - if (fs.existsSync(path.join(CONTENT_ROOT, c))) { - return c; - } - } - return null; -} - -function walk(dir: string): string[] { - const entries = fs.readdirSync(dir, { withFileTypes: true }); - return entries.flatMap((e) => { - const full = path.join(dir, e.name); - return e.isDirectory() ? walk(full) : [full]; - }); -} diff --git a/website-next/app/globals.css b/website-next/app/globals.css index 4c17bed0f3a..aebdaeca457 100644 --- a/website-next/app/globals.css +++ b/website-next/app/globals.css @@ -9,6 +9,7 @@ /* Disable default Tailwind colors */ --color-*: initial; + /* The cc-* colors below are mirrored in src/theme/colors.ts for the OG share cards. */ --color-cc-ink: #f5f1ea; /* Long-form body prose: lighter than `cc-ink-dim` so paragraphs stay readable. */ --color-cc-prose: rgba(245, 241, 234, 0.8); diff --git a/website-next/nginx/conf.d/default.conf b/website-next/nginx/conf.d/default.conf index 2ae1930e93e..3b08c36f2bc 100644 --- a/website-next/nginx/conf.d/default.conf +++ b/website-next/nginx/conf.d/default.conf @@ -34,6 +34,20 @@ server { try_files $uri =404; } + # Generated OG share-card images. The Next.js static export emits these as + # extension-less files (out/docs-og//opengraph-image), so without this + # block nginx would serve them as application/octet-stream (default_type) + # and social scrapers (Slack/Facebook/LinkedIn) would refuse to render them. + # Both og:image and twitter:image reference this single file. Force the PNG + # content type and match the long-cache policy used for other static images. + location ~ ^/docs-og/.+/opengraph-image$ { + default_type image/png; + add_header Cache-Control "public, max-age=31536000, immutable" always; + add_header X-Content-Type-Options "nosniff" always; + access_log off; + try_files $uri =404; + } + # HTML — always revalidate location ~* \.html$ { add_header Cache-Control "public, max-age=0, must-revalidate" always; diff --git a/website-next/src/helpers/docsParams.ts b/website-next/src/helpers/docsParams.ts new file mode 100644 index 00000000000..eb0874257f3 --- /dev/null +++ b/website-next/src/helpers/docsParams.ts @@ -0,0 +1,77 @@ +import fs from "node:fs"; +import path from "node:path"; + +/** + * Root directory that holds all docs markdown content. Shared by the docs page + * and its Open Graph image route so they enumerate the exact same slugs. + */ +export const CONTENT_ROOT = path.join(process.cwd(), "content/docs"); + +/** + * Enumerates the doc slugs (one `string[]` per route) from the markdown files + * under `CONTENT_ROOT`. `index.md(x)` files map to their parent directory. + * + * `output: export` requires at least one prerendered path, so a `__empty__` + * placeholder is returned when no content is present; the page renders a 404 + * for it via `notFound()`. + */ +export function listDocSlugs(): string[][] { + const slugs = walk(CONTENT_ROOT) + .filter((f) => /\.mdx?$/.test(f)) + .map((f) => path.relative(CONTENT_ROOT, f).replace(/\.mdx?$/, "")) + .map((rel) => rel.split(path.sep)) + .map((parts) => + parts[parts.length - 1] === "index" ? parts.slice(0, -1) : parts, + ) + .filter((slug) => slug.length > 0); + + return slugs.length > 0 ? slugs : [["__empty__"]]; +} + +/** + * Separator used to flatten a doc slug (`["foo", "bar"]`) into the single + * opaque `[id]` segment of the Open Graph image route. Catch-all segments + * cannot be followed by the `opengraph-image` file convention, so the docs + * share-card route lives under `app/docs-og/[id]` and the page metadata points + * at it. No doc slug contains this separator. + */ +const SLUG_ID_SEPARATOR = "__"; + +/** Flattens a doc slug into the opaque `[id]` segment. */ +export function encodeDocId(slug: string[]): string { + return slug.join(SLUG_ID_SEPARATOR); +} + +/** Expands an opaque `[id]` segment back into a doc slug. */ +export function decodeDocId(id: string): string[] { + return id.split(SLUG_ID_SEPARATOR); +} + +/** + * Resolves a doc slug to its markdown file path relative to `CONTENT_ROOT`, + * or `null` when no matching file exists. + */ +export function resolveFile(slug: string[]): string | null { + const joined = slug.join("/"); + const candidates = [ + `${joined}.md`, + `${joined}.mdx`, + `${joined}/index.md`, + `${joined}/index.mdx`, + ]; + + for (const c of candidates) { + if (fs.existsSync(path.join(CONTENT_ROOT, c))) { + return c; + } + } + return null; +} + +function walk(dir: string): string[] { + const entries = fs.readdirSync(dir, { withFileTypes: true }); + return entries.flatMap((e) => { + const full = path.join(dir, e.name); + return e.isDirectory() ? walk(full) : [full]; + }); +} diff --git a/website-next/src/helpers/siteUrl.ts b/website-next/src/helpers/siteUrl.ts index e1d98ba989c..cf40a19e0c7 100644 --- a/website-next/src/helpers/siteUrl.ts +++ b/website-next/src/helpers/siteUrl.ts @@ -5,3 +5,15 @@ export const SITE_URL = ( process.env.NEXT_PUBLIC_SITE_URL ?? "https://chillicream.com" ).replace(/\/+$/, ""); + +/** + * Turns a path into an absolute URL against {@link SITE_URL}. Root-relative + * paths (`/foo`) are prefixed with the site origin; values that are already + * absolute (`https://…`) or protocol-relative (`//…`) are returned unchanged. + */ +export function toAbsoluteUrl(pathOrUrl: string): string { + if (/^(https?:)?\/\//.test(pathOrUrl)) { + return pathOrUrl; + } + return `${SITE_URL}${pathOrUrl.startsWith("/") ? "" : "/"}${pathOrUrl}`; +} diff --git a/website-next/src/og/fonts.ts b/website-next/src/og/fonts.ts new file mode 100644 index 00000000000..0d0b33bd85d --- /dev/null +++ b/website-next/src/og/fonts.ts @@ -0,0 +1,31 @@ +import { readFile } from "node:fs/promises"; +import path from "node:path"; + +const FONT_DIR = path.join(process.cwd(), "src/og/fonts"); + +/** + * Shape `ImageResponse` (from `next/og`) expects for the `fonts` option. + */ +export type OgFont = { + name: string; + data: Buffer; + weight: 400 | 700; + style: "normal"; +}; + +/** + * Loads the vendored Inter TTFs (regular + bold) as raw font bytes for + * `ImageResponse`. Reading from `process.cwd()` works at build time, which is + * required for the static export (`output: "export"`). + */ +export async function loadInterFonts(): Promise { + const [regular, bold] = await Promise.all([ + readFile(path.join(FONT_DIR, "Inter-Regular.ttf")), + readFile(path.join(FONT_DIR, "Inter-Bold.ttf")), + ]); + + return [ + { name: "Inter", data: regular, weight: 400, style: "normal" }, + { name: "Inter", data: bold, weight: 700, style: "normal" }, + ]; +} diff --git a/website-next/src/og/fonts/Inter-Bold.ttf b/website-next/src/og/fonts/Inter-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..47e27502649679dd4ee4725711555531f1e868cb GIT binary patch literal 67988 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 QVib)>myw=;C^_!`0SEqS>;M1& literal 0 HcmV?d00001 diff --git a/website-next/src/og/fonts/Inter-Regular.ttf b/website-next/src/og/fonts/Inter-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1e228ab9ab1c9efb809768523af885b03f728007 GIT binary patch literal 67952 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%0Ax5=Ejs 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 literal 0 HcmV?d00001 diff --git a/website-next/src/og/fonts/LICENSE.md b/website-next/src/og/fonts/LICENSE.md new file mode 100644 index 00000000000..b9e570295da --- /dev/null +++ b/website-next/src/og/fonts/LICENSE.md @@ -0,0 +1,11 @@ +# Inter font files + +`Inter-Regular.ttf` (weight 400) and `Inter-Bold.ttf` (weight 700) are static +subsets of the [Inter](https://github.com/rsms/inter) typeface, sourced from the +[Fontsource](https://fontsource.org/fonts/inter) jsDelivr CDN +(`fonts/inter@latest/latin-{400,700}-normal.ttf`). + +Inter is licensed under the SIL Open Font License, Version 1.1 +(). These files are vendored so that +`next/og` (`ImageResponse`) can render Open Graph share cards at build time +without any network access. diff --git a/website-next/src/theme/colors.ts b/website-next/src/theme/colors.ts new file mode 100644 index 00000000000..82af6d6425c --- /dev/null +++ b/website-next/src/theme/colors.ts @@ -0,0 +1,14 @@ +// Mirror of the cc-* color tokens in app/globals.css @theme. Keep in sync — +// satori (next/og) cannot read the CSS @theme tokens at build time. + +export const ccBg = "#0b0f1a"; +export const ccInk = "#f5f1ea"; +export const ccAccent = "#5eead4"; +export const ccSurface = "#0c1322"; + +export const ccColors = { + bg: ccBg, + ink: ccInk, + accent: ccAccent, + surface: ccSurface, +} as const; From e43bb8aae1a406ced989cb88aebdc9e4a0ce6258 Mon Sep 17 00:00:00 2001 From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com> Date: Sat, 30 May 2026 17:46:04 +0200 Subject: [PATCH 2/2] Add default share card for all pages outside blog / docs --- .../app/(content)/opengraph-image.tsx | 33 +++++++ .../app/docs-og/[id]/opengraph-image.tsx | 80 +-------------- website-next/nginx/conf.d/default.conf | 26 ++--- website-next/src/og/ShareCard.tsx | 97 +++++++++++++++++++ 4 files changed, 138 insertions(+), 98 deletions(-) create mode 100644 website-next/app/(content)/opengraph-image.tsx create mode 100644 website-next/src/og/ShareCard.tsx diff --git a/website-next/app/(content)/opengraph-image.tsx b/website-next/app/(content)/opengraph-image.tsx new file mode 100644 index 00000000000..fdd0b4cc1b6 --- /dev/null +++ b/website-next/app/(content)/opengraph-image.tsx @@ -0,0 +1,33 @@ +import { ImageResponse } from "next/og"; +import { loadInterFonts } from "@/src/og/fonts"; +import { ShareCard } from "@/src/og/ShareCard"; + +// TODO: Proper styling and layout of share cards + +// Required under `output: export` for this paramless metadata route, which has +// no `generateStaticParams` to imply prerendering (unlike the per-doc card). +export const dynamic = "force-static"; + +// Mirrors the brand strings in app/layout.tsx (TITLE is the headline). +const TITLE = "ChilliCream GraphQL Platform"; + +export const alt = TITLE; + +export const size = { + width: 1200, + height: 630, +}; + +export const contentType = "image/png"; + +export default async function Image() { + const fonts = await loadInterFonts(); + + return new ImageResponse( + , + { + ...size, + fonts, + }, + ); +} diff --git a/website-next/app/docs-og/[id]/opengraph-image.tsx b/website-next/app/docs-og/[id]/opengraph-image.tsx index 5dcefc42a9e..e3c4bb42537 100644 --- a/website-next/app/docs-og/[id]/opengraph-image.tsx +++ b/website-next/app/docs-og/[id]/opengraph-image.tsx @@ -10,20 +10,12 @@ import { } from "@/src/helpers/docsParams"; import { readFrontmatter } from "@/src/helpers/readFrontmatter"; import { loadInterFonts } from "@/src/og/fonts"; -import { ccAccent, ccBg, ccInk, ccSurface } from "@/src/theme/colors"; +import { ShareCard } from "@/src/og/ShareCard"; // TODO: Proper styling and layout of share cards export const dynamicParams = false; -/** `#rrggbb` -> `rgba(r, g, b, a)`, so gradients derive from the same tokens. */ -function rgba(hex: string, alpha: number): string { - const r = parseInt(hex.slice(1, 3), 16); - const g = parseInt(hex.slice(3, 5), 16); - const b = parseInt(hex.slice(5, 7), 16); - return `rgba(${r}, ${g}, ${b}, ${alpha})`; -} - export const alt = "ChilliCream documentation"; export const size = { @@ -57,75 +49,7 @@ export default async function Image({ params }: { params: Promise }) { const fonts = await loadInterFonts(); return new ImageResponse( -
-
- {eyebrow} -
- -
-
- {eyebrow} -
-
- {title} -
-
-
, + , { ...size, fonts, diff --git a/website-next/nginx/conf.d/default.conf b/website-next/nginx/conf.d/default.conf index 3b08c36f2bc..d8713021e1b 100644 --- a/website-next/nginx/conf.d/default.conf +++ b/website-next/nginx/conf.d/default.conf @@ -9,52 +9,38 @@ server { error_page 404 /404.html; - # security headers - add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "SAMEORIGIN" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; - # redirects (managed in redirects.conf) include /etc/nginx/conf.d/redirects.conf; - # Next.js hashed build assets — immutable forever + # Next.js hashed build assets - immutable, cached forever location /_next/static/ { add_header Cache-Control "public, max-age=31536000, immutable" always; - add_header X-Content-Type-Options "nosniff" always; access_log off; try_files $uri =404; } - # static asset extensions — long cache + # Static asset files (CSS, JS, fonts, images, media) - immutable, cached forever location ~* \.(?:css|js|mjs|woff2?|ttf|otf|eot|ico|svg|png|jpe?g|gif|webp|avif|bmp|mp4|webm|ogg|mp3|wav|flac|aac|pdf)$ { add_header Cache-Control "public, max-age=31536000, immutable" always; - add_header X-Content-Type-Options "nosniff" always; access_log off; try_files $uri =404; } - # Generated OG share-card images. The Next.js static export emits these as - # extension-less files (out/docs-og//opengraph-image), so without this - # block nginx would serve them as application/octet-stream (default_type) - # and social scrapers (Slack/Facebook/LinkedIn) would refuse to render them. - # Both og:image and twitter:image reference this single file. Force the PNG - # content type and match the long-cache policy used for other static images. - location ~ ^/docs-og/.+/opengraph-image$ { + # Generated OG share-card images - immutable, cached forever + location ~ ^/(.*/)?opengraph-image(-[^/]+)?$ { default_type image/png; add_header Cache-Control "public, max-age=31536000, immutable" always; - add_header X-Content-Type-Options "nosniff" always; access_log off; try_files $uri =404; } - # HTML — always revalidate + # HTML files - always revalidate location ~* \.html$ { add_header Cache-Control "public, max-age=0, must-revalidate" always; - add_header X-Content-Type-Options "nosniff" always; try_files $uri =404; } + # Catch-all for pages/routes not matched above - always revalidate location / { add_header Cache-Control "public, max-age=0, must-revalidate" always; try_files $uri $uri.html $uri/index.html =404; diff --git a/website-next/src/og/ShareCard.tsx b/website-next/src/og/ShareCard.tsx new file mode 100644 index 00000000000..87dd076e3ff --- /dev/null +++ b/website-next/src/og/ShareCard.tsx @@ -0,0 +1,97 @@ +import { ccAccent, ccBg, ccInk, ccSurface } from "@/src/theme/colors"; + +/** `#rrggbb` -> `rgba(r, g, b, a)`, so gradients derive from the same tokens. */ +function rgba(hex: string, alpha: number): string { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + return `rgba(${r}, ${g}, ${b}, ${alpha})`; +} + +type ShareCardProps = { + /** Brand badge text in the top-right box. */ + badge: string; + /** Small uppercase accent line above the title. */ + eyebrow: string; + /** Headline, large text lower-left. */ + title: string; +}; + +/** + * The shared 1200x630 share-card layout used by both the per-doc OG image and + * the default marketing OG image. Satori (next/og) supports only flexbox and a + * subset of CSS, so this stays within those constraints. + */ +export function ShareCard({ badge, eyebrow, title }: ShareCardProps) { + return ( +
+
+ {badge} +
+ +
+
+ {eyebrow} +
+
+ {title} +
+
+
+ ); +}