diff --git a/docs/public/Geist-Regular.ttf b/docs/public/Geist-Regular.ttf new file mode 100644 index 0000000..07f9e4f Binary files /dev/null and b/docs/public/Geist-Regular.ttf differ diff --git a/docs/src/app/cdp-mode/page.mdx b/docs/src/app/cdp-mode/page.mdx index 9c5242a..7edec00 100644 --- a/docs/src/app/cdp-mode/page.mdx +++ b/docs/src/app/cdp-mode/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "CDP Mode" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("cdp-mode") # CDP Mode diff --git a/docs/src/app/changelog/page.mdx b/docs/src/app/changelog/page.mdx index 5134fab..d5d8e54 100644 --- a/docs/src/app/changelog/page.mdx +++ b/docs/src/app/changelog/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Changelog" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("changelog") # Changelog diff --git a/docs/src/app/commands/page.mdx b/docs/src/app/commands/page.mdx index 82ed5f4..5e9e793 100644 --- a/docs/src/app/commands/page.mdx +++ b/docs/src/app/commands/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Commands" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("commands") # Commands diff --git a/docs/src/app/configuration/page.mdx b/docs/src/app/configuration/page.mdx index a82c36b..ff93d10 100644 --- a/docs/src/app/configuration/page.mdx +++ b/docs/src/app/configuration/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Configuration" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("configuration") # Configuration diff --git a/docs/src/app/diffing/page.mdx b/docs/src/app/diffing/page.mdx index f6fcda9..871b512 100644 --- a/docs/src/app/diffing/page.mdx +++ b/docs/src/app/diffing/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Diffing" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("diffing") import { DiffDemo } from "@/components/diff-demo" diff --git a/docs/src/app/installation/page.mdx b/docs/src/app/installation/page.mdx index fe0fbb9..f203965 100644 --- a/docs/src/app/installation/page.mdx +++ b/docs/src/app/installation/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Installation" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("installation") # Installation diff --git a/docs/src/app/ios/page.mdx b/docs/src/app/ios/page.mdx index 82e6b1d..1a40cab 100644 --- a/docs/src/app/ios/page.mdx +++ b/docs/src/app/ios/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "iOS Simulator" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("ios") # iOS Simulator diff --git a/docs/src/app/layout.tsx b/docs/src/app/layout.tsx index 4d451a4..ec09015 100644 --- a/docs/src/app/layout.tsx +++ b/docs/src/app/layout.tsx @@ -21,8 +21,27 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "agent-browser", + metadataBase: new URL("https://agent-browser.dev"), + title: { + default: "agent-browser | Headless Browser Automation for AI", + template: "%s | agent-browser", + }, description: "Headless browser automation CLI for AI agents", + openGraph: { + type: "website", + locale: "en_US", + url: "https://agent-browser.dev", + siteName: "agent-browser", + title: "agent-browser | Headless Browser Automation for AI", + description: "Headless browser automation CLI for AI agents", + images: [{ url: "/og", width: 1200, height: 630, alt: "agent-browser" }], + }, + twitter: { + card: "summary_large_image", + title: "agent-browser | Headless Browser Automation for AI", + description: "Headless browser automation CLI for AI agents", + images: ["/og"], + }, }; export default async function RootLayout({ diff --git a/docs/src/app/og/[...slug]/route.tsx b/docs/src/app/og/[...slug]/route.tsx new file mode 100644 index 0000000..50ce10c --- /dev/null +++ b/docs/src/app/og/[...slug]/route.tsx @@ -0,0 +1,16 @@ +import { NextResponse } from "next/server"; +import { getPageTitle, renderOgImage } from "../og-image"; + +export async function GET( + _request: Request, + { params }: { params: Promise<{ slug: string[] }> }, +) { + const { slug } = await params; + const title = getPageTitle(slug.join("/")); + + if (!title) { + return NextResponse.json({ error: "Not found" }, { status: 404 }); + } + + return renderOgImage(title); +} diff --git a/docs/src/app/og/og-image.tsx b/docs/src/app/og/og-image.tsx new file mode 100644 index 0000000..dde4dde --- /dev/null +++ b/docs/src/app/og/og-image.tsx @@ -0,0 +1,104 @@ +import { ImageResponse } from "next/og"; +import { readFile } from "node:fs/promises"; +import { join } from "node:path"; + +export { getPageTitle } from "@/lib/page-titles"; + +let fontCache: { geistRegular: Buffer } | null = null; + +async function loadFonts() { + if (fontCache) return fontCache; + const geistRegular = await readFile( + join(process.cwd(), "public/Geist-Regular.ttf"), + ); + fontCache = { geistRegular }; + return fontCache; +} + +export async function renderOgImage(title: string) { + const { geistRegular } = await loadFonts(); + + return new ImageResponse( +
+
+ + + + + / + + + agent-browser + +
+ +
+ {title.split("\n").map((line, i) => ( + + {line} + + ))} +
+
, + { + width: 1200, + height: 630, + fonts: [ + { + name: "Geist", + data: geistRegular.buffer as ArrayBuffer, + style: "normal", + weight: 400, + }, + ], + }, + ); +} diff --git a/docs/src/app/og/route.tsx b/docs/src/app/og/route.tsx new file mode 100644 index 0000000..e37a195 --- /dev/null +++ b/docs/src/app/og/route.tsx @@ -0,0 +1,6 @@ +import { getPageTitle, renderOgImage } from "./og-image"; + +export async function GET() { + const title = getPageTitle("")!; + return renderOgImage(title); +} diff --git a/docs/src/app/page.mdx b/docs/src/app/page.mdx index 962c6d2..4ba14a6 100644 --- a/docs/src/app/page.mdx +++ b/docs/src/app/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "agent-browser" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("") # agent-browser diff --git a/docs/src/app/profiler/page.mdx b/docs/src/app/profiler/page.mdx index f964376..95108f5 100644 --- a/docs/src/app/profiler/page.mdx +++ b/docs/src/app/profiler/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Profiler" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("profiler") # Profiler diff --git a/docs/src/app/quick-start/page.mdx b/docs/src/app/quick-start/page.mdx index 81881d2..3346321 100644 --- a/docs/src/app/quick-start/page.mdx +++ b/docs/src/app/quick-start/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Quick Start" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("quick-start") # Quick Start diff --git a/docs/src/app/selectors/page.mdx b/docs/src/app/selectors/page.mdx index 1ab7013..03d76a5 100644 --- a/docs/src/app/selectors/page.mdx +++ b/docs/src/app/selectors/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Selectors" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("selectors") # Selectors diff --git a/docs/src/app/sessions/page.mdx b/docs/src/app/sessions/page.mdx index b73182e..bf234c2 100644 --- a/docs/src/app/sessions/page.mdx +++ b/docs/src/app/sessions/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Sessions" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("sessions") # Sessions diff --git a/docs/src/app/snapshots/page.mdx b/docs/src/app/snapshots/page.mdx index 43471ee..a5a9f05 100644 --- a/docs/src/app/snapshots/page.mdx +++ b/docs/src/app/snapshots/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Snapshots" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("snapshots") # Snapshots diff --git a/docs/src/app/streaming/page.mdx b/docs/src/app/streaming/page.mdx index 15af7b9..d0c32a6 100644 --- a/docs/src/app/streaming/page.mdx +++ b/docs/src/app/streaming/page.mdx @@ -1,4 +1,6 @@ -export const metadata = { title: "Streaming" } +import { pageMetadata } from "@/lib/page-metadata" + +export const metadata = pageMetadata("streaming") # Streaming diff --git a/docs/src/lib/page-metadata.ts b/docs/src/lib/page-metadata.ts new file mode 100644 index 0000000..2246af4 --- /dev/null +++ b/docs/src/lib/page-metadata.ts @@ -0,0 +1,39 @@ +import type { Metadata } from "next"; +import { PAGE_TITLES } from "./page-titles"; + +const DESCRIPTION = + "Headless browser automation CLI for AI agents"; + +export function pageMetadata(slug: string): Metadata { + const title = PAGE_TITLES[slug]; + if (!title) return {}; + + const displayTitle = title.replace(/\n/g, " "); + const fullTitle = `${displayTitle} | agent-browser`; + const ogImageUrl = slug ? `/og/${slug}` : "/og"; + + return { + title: displayTitle, + openGraph: { + type: "website", + locale: "en_US", + siteName: "agent-browser", + title: fullTitle, + description: DESCRIPTION, + images: [ + { + url: ogImageUrl, + width: 1200, + height: 630, + alt: `${displayTitle} - agent-browser`, + }, + ], + }, + twitter: { + card: "summary_large_image", + title: fullTitle, + description: DESCRIPTION, + images: [ogImageUrl], + }, + }; +} diff --git a/docs/src/lib/page-titles.ts b/docs/src/lib/page-titles.ts new file mode 100644 index 0000000..a43ff5e --- /dev/null +++ b/docs/src/lib/page-titles.ts @@ -0,0 +1,20 @@ +export const PAGE_TITLES: Record = { + "": "Headless Browser\nAutomation for AI", + installation: "Installation", + "quick-start": "Quick Start", + commands: "Commands", + configuration: "Configuration", + selectors: "Selectors", + snapshots: "Snapshots", + sessions: "Sessions", + diffing: "Diffing", + "cdp-mode": "CDP Mode", + streaming: "Streaming", + profiler: "Profiler", + ios: "iOS Simulator", + changelog: "Changelog", +}; + +export function getPageTitle(slug: string): string | null { + return slug in PAGE_TITLES ? PAGE_TITLES[slug]! : null; +}