import type { CSSProperties } from 'react' import { ImageResponse } from 'next/og' import type { NextRequest } from 'next/server' export const runtime = 'edge' const TITLE_FONT_SIZE = { large: 64, medium: 56, small: 48, } as const const FONT_CACHE_REVALIDATE_SECONDS = 60 * 60 * 24 * 30 const OG_CONTAINER_STYLE = { height: '100%', width: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', padding: '56px 64px', background: '#121212', fontFamily: 'Geist', } satisfies CSSProperties const OG_TITLE_STYLE = { fontWeight: 500, color: '#fafafa', lineHeight: 1.2, letterSpacing: '-0.02em', } satisfies CSSProperties const OG_FOOTER_STYLE = { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', } satisfies CSSProperties const OG_DOMAIN_STYLE = { fontSize: 20, fontWeight: 400, color: '#71717a', } satisfies CSSProperties function getTitleFontSize(title: string): number { if (title.length > 45) return TITLE_FONT_SIZE.small if (title.length > 30) return TITLE_FONT_SIZE.medium return TITLE_FONT_SIZE.large } function getTitleStyle(title: string): CSSProperties { return { ...OG_TITLE_STYLE, fontSize: getTitleFontSize(title), } } /** * Loads a Google Font dynamically by fetching the CSS and extracting the font URL. */ async function loadGoogleFont(font: string, weights: string, text: string): Promise { const url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weights}&text=${encodeURIComponent(text)}` const cssResponse = await fetch(url, { next: { revalidate: FONT_CACHE_REVALIDATE_SECONDS }, }) if (!cssResponse.ok) { throw new Error(`Failed to load font CSS: ${cssResponse.status} ${cssResponse.statusText}`) } const css = await cssResponse.text() const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/) if (resource) { const response = await fetch(resource[1], { next: { revalidate: FONT_CACHE_REVALIDATE_SECONDS }, }) if (response.ok) { return await response.arrayBuffer() } } throw new Error('Failed to load font data') } /** * Sim logo with icon and "Sim" text for OG image. */ function SimLogoFull() { return ( {/* Green icon - top left shape with cutout */} {/* Green icon - bottom right square */} {/* "Sim" text - white for dark background */} ) } /** * Generates dynamic Open Graph images for documentation pages. * Style matches Cursor docs: dark background, title at top, logo bottom-left, domain bottom-right. */ export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url) const title = searchParams.get('title') || 'Documentation' const allText = `${title}docs.sim.ai` const fontData = await loadGoogleFont('Geist', '400;500;600', allText) return new ImageResponse(
{/* Title at top */} {title} {/* Footer: icon left, domain right */}
docs.sim.ai
, { width: 1200, height: 630, fonts: [ { name: 'Geist', data: fontData, style: 'normal', }, ], } ) }