diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 290aa7fd..d8d81c3e 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -11,9 +11,25 @@ import { UsageMonitor } from './components/UsageMonitor'; const geistSans = GeistSans; const geistMono = GeistMono; +/** + * Where this site actually serves. Load-bearing for the social preview: Next + * resolves the generated og:image against `metadataBase`, and without it the + * tag is emitted as http://localhost:3000/opengraph-image — present, plausible, + * and unfetchable by every scraper. Falls back to the real host, not localhost. + */ +const SITE_URL = process.env.NEXT_PUBLIC_APP_URL || "https://datacat.orangecat.ch"; + export const metadata: Metadata = { + metadataBase: new URL(SITE_URL), title: "Form Builder | KI-gestützter DataCat-Editor", description: "Erstellen Sie schöne, intelligente DataCate für jede Branche – nicht nur HR.", + openGraph: { + title: "DataCat — KI-gestützter Formular-Editor", + description: "Erstellen Sie schöne, intelligente Formulare für jede Branche – nicht nur HR.", + url: SITE_URL, + siteName: "DataCat", + type: "website", + }, }; export default function RootLayout({ diff --git a/frontend/src/app/opengraph-image.tsx b/frontend/src/app/opengraph-image.tsx new file mode 100644 index 00000000..dd07a1f8 --- /dev/null +++ b/frontend/src/app/opengraph-image.tsx @@ -0,0 +1,70 @@ +import { ImageResponse } from "next/og"; + +/** + * Social preview card (1200x630 — the 1.91:1 size Slack, Telegram and the + * OpenGraph scrapers crop to). DataCat shipped no og:image, so every shared + * link rendered as a blank grey rectangle. + * + * Satori cannot read CSS custom properties or Tailwind classes, so the accent + * is repeated here as a literal. It mirrors the indigo-600 used across the app. + */ + +export const runtime = "edge"; +export const alt = "DataCat — KI-gestützter Formular-Editor"; +export const size = { width: 1200, height: 630 }; +export const contentType = "image/png"; + +const INK = "#171717"; +const INDIGO = "#4F46E5"; +const MUTED = "#6B7280"; +const PAPER = "#FFFFFF"; + +export default function OGImage() { + return new ImageResponse( + ( +