diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index 9fc1e7c3b..93b09e200 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -243,6 +243,8 @@ export async function generateMetadata(props: { const baseUrl = 'https://docs.sim.ai' const fullUrl = `${baseUrl}${page.url}` + const ogImageUrl = `${baseUrl}/api/og?title=${encodeURIComponent(page.data.title)}&category=DOCUMENTATION` + return { title: page.data.title, description: @@ -272,12 +274,23 @@ export async function generateMetadata(props: { alternateLocale: ['en', 'es', 'fr', 'de', 'ja', 'zh'] .filter((lang) => lang !== params.lang) .map((lang) => (lang === 'en' ? 'en_US' : `${lang}_${lang.toUpperCase()}`)), + images: [ + { + url: ogImageUrl, + width: 1200, + height: 630, + alt: page.data.title, + }, + ], }, twitter: { - card: 'summary', + card: 'summary_large_image', title: page.data.title, description: page.data.description || 'Sim visual workflow builder for AI applications documentation', + images: [ogImageUrl], + creator: '@simdotai', + site: '@simdotai', }, robots: { index: true, diff --git a/apps/docs/app/api/og/route.tsx b/apps/docs/app/api/og/route.tsx new file mode 100644 index 000000000..63ca67c61 --- /dev/null +++ b/apps/docs/app/api/og/route.tsx @@ -0,0 +1,146 @@ +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 + +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 +} + +/** + * Loads a Google Font dynamically by fetching the CSS and extracting the font URL. + */ +async function loadGoogleFont(font: string, text: string): Promise { + const url = `https://fonts.googleapis.com/css2?family=${font}:wght@500;600&text=${encodeURIComponent(text)}` + const css = await (await fetch(url)).text() + const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/) + + if (resource) { + const response = await fetch(resource[1]) + if (response.status === 200) { + return await response.arrayBuffer() + } + } + + throw new Error('Failed to load font data') +} + +/** + * Generates dynamic Open Graph images for documentation pages. + */ +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url) + const title = searchParams.get('title') || 'Documentation' + const category = searchParams.get('category') || 'DOCUMENTATION' + + const baseUrl = new URL(request.url).origin + const backgroundImageUrl = `${baseUrl}/static/og-background.png` + + // Load Inter font dynamically from Google Fonts + const allText = `${title}${category}docs.sim.ai` + const fontData = await loadGoogleFont('Inter', allText) + + return new ImageResponse( +
+ {/* Background texture */} + + + {/* Content */} +
+ {/* Logo */} + sim + + {/* Category + Title */} +
+ + {category} + + + {title} + +
+ + {/* Footer */} + + docs.sim.ai + +
+
, + { + width: 1200, + height: 630, + fonts: [ + { + name: 'Inter', + data: fontData, + style: 'normal', + }, + ], + } + ) +} diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index 807868d78..7f982a048 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -56,6 +56,14 @@ export const metadata = { title: 'Sim Documentation - Visual Workflow Builder for AI Applications', description: 'Comprehensive documentation for Sim - the visual workflow builder for AI applications. Create powerful AI agents, automation workflows, and data processing pipelines.', + images: [ + { + url: 'https://docs.sim.ai/api/og?title=Sim%20Documentation&category=DOCUMENTATION', + width: 1200, + height: 630, + alt: 'Sim Documentation', + }, + ], }, twitter: { card: 'summary_large_image', @@ -64,7 +72,7 @@ export const metadata = { 'Comprehensive documentation for Sim - the visual workflow builder for AI applications.', creator: '@simdotai', site: '@simdotai', - images: ['/og-image.png'], + images: ['https://docs.sim.ai/api/og?title=Sim%20Documentation&category=DOCUMENTATION'], }, robots: { index: true, diff --git a/apps/docs/public/static/og-background.png b/apps/docs/public/static/og-background.png new file mode 100644 index 000000000..173d38076 Binary files /dev/null and b/apps/docs/public/static/og-background.png differ