mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-07-14 18:15:56 -04:00
feat(docs): replace default Fumadocs OG image with custom branded template
Swap the generic `fumadocs-ui/og/takumi` default for a hand-crafted OG image using the Sofa cinema theme — dark background, amber accent, DM Serif Display title, DM Sans body, and a radial gradient — matching the app's visual identity. - Load DM Sans (400/500) and DM Serif Display (400) at runtime from Google Fonts via old Safari UA to get TrueType URLs - Render header with Sofa logo SVG + "Sofa Docs" label, centered title/description block, and an amber accent bar - Scale title font size based on length (68px → 56px for longer strings) - Define theme constants (BG, FG, PRIMARY, MUTED) from the app's oklch palette
This commit is contained in:
@@ -1,10 +1,42 @@
|
||||
import { ImageResponse } from "@takumi-rs/image-response";
|
||||
import { generate as DefaultImage } from "fumadocs-ui/og/takumi";
|
||||
import { notFound } from "next/navigation";
|
||||
import { getPageImage, source } from "@/lib/source";
|
||||
|
||||
export const revalidate = false;
|
||||
|
||||
async function loadFont(family: string, weight: number): Promise<ArrayBuffer> {
|
||||
const params = new URLSearchParams({
|
||||
family: `${family}:wght@${weight}`,
|
||||
display: "swap",
|
||||
});
|
||||
const css = await fetch(`https://fonts.googleapis.com/css2?${params}`, {
|
||||
headers: {
|
||||
// Old user-agent to get TrueType format (not woff2)
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1",
|
||||
},
|
||||
}).then((res) => res.text());
|
||||
|
||||
const url = css.match(/src: url\((.+?)\)/)?.[1];
|
||||
if (!url) throw new Error(`Could not load font: ${family} ${weight}`);
|
||||
return fetch(url).then((res) => res.arrayBuffer());
|
||||
}
|
||||
|
||||
const fonts = Promise.all([
|
||||
loadFont("DM Sans", 400),
|
||||
loadFont("DM Sans", 500),
|
||||
loadFont("DM Serif Display", 400),
|
||||
]);
|
||||
|
||||
// oklch(0.13 0.006 55) → background
|
||||
const BG = "#090706";
|
||||
// oklch(0.93 0.015 80) → foreground
|
||||
const FG = "#ede7dd";
|
||||
// oklch(0.8 0.14 65) → primary / amber accent
|
||||
const PRIMARY = "#fba952";
|
||||
// oklch(0.63 0.02 80) → muted foreground
|
||||
const MUTED = "#90887c";
|
||||
|
||||
export async function GET(
|
||||
_req: Request,
|
||||
{ params }: RouteContext<"/og/docs/[...slug]">,
|
||||
@@ -13,16 +45,97 @@ export async function GET(
|
||||
const page = source.getPage(slug.slice(0, -1));
|
||||
if (!page) notFound();
|
||||
|
||||
const [dmSans, dmSansMedium, dmSerif] = await fonts;
|
||||
const { title, description } = page.data;
|
||||
|
||||
return new ImageResponse(
|
||||
<DefaultImage
|
||||
title={page.data.title}
|
||||
description={page.data.description}
|
||||
site="My App"
|
||||
/>,
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
padding: "60px 80px",
|
||||
backgroundColor: BG,
|
||||
backgroundImage: `radial-gradient(ellipse at 80% 0%, rgba(180, 140, 50, 0.07) 0%, transparent 50%)`,
|
||||
fontFamily: "DM Sans",
|
||||
color: FG,
|
||||
border: `1px solid rgba(236, 231, 223, 0.08)`,
|
||||
}}
|
||||
>
|
||||
{/* Header */}
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
|
||||
<svg width="28" height="28" viewBox="0 0 24 24">
|
||||
<title>Sofa Logo</title>
|
||||
<path
|
||||
fill={PRIMARY}
|
||||
d="M7 12v1h10v-1a3 3 0 0 1 2.993-3a4.6 4.6 0 0 0-.07-.78a4 4 0 0 0-3.143-3.143C16.394 5 15.93 5 15 5H9c-.93 0-1.394 0-1.78.077A4 4 0 0 0 4.077 8.22a4.6 4.6 0 0 0-.07.78A3 3 0 0 1 7 12"
|
||||
/>
|
||||
<path
|
||||
fill={PRIMARY}
|
||||
d="M18.444 18H5.556a3.6 3.6 0 0 1-.806-.092V19a.75.75 0 0 1-1.5 0v-1.849A3.55 3.55 0 0 1 2 14.444V12a2 2 0 1 1 4 0v1.2a.8.8 0 0 0 .8.8h10.4a.8.8 0 0 0 .8-.8V12a2 2 0 1 1 4 0v2.444a3.55 3.55 0 0 1-1.25 2.707V19a.75.75 0 0 1-1.5 0v-1.092a3.6 3.6 0 0 1-.806.092"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "20px",
|
||||
fontWeight: 500,
|
||||
color: PRIMARY,
|
||||
letterSpacing: "0.02em",
|
||||
}}
|
||||
>
|
||||
Sofa
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Title + description */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontFamily: "DM Serif Display",
|
||||
fontSize: title.length > 30 ? 56 : 68,
|
||||
fontWeight: 400,
|
||||
lineHeight: 1.1,
|
||||
color: FG,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
{description ? (
|
||||
<div style={{ fontSize: "24px", lineHeight: 1.5, color: MUTED }}>
|
||||
{description}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{/* Accent bar */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
width: "120px",
|
||||
height: "3px",
|
||||
borderRadius: "2px",
|
||||
background: PRIMARY,
|
||||
}}
|
||||
/>
|
||||
</div>,
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
format: "webp",
|
||||
fonts: [
|
||||
{ name: "DM Sans", data: dmSans, weight: 400 as const },
|
||||
{ name: "DM Sans", data: dmSansMedium, weight: 500 as const },
|
||||
{ name: "DM Serif Display", data: dmSerif, weight: 400 as const },
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user