import type { Metadata, Viewport } from "next"; import { Manrope, Plus_Jakarta_Sans } from "next/font/google"; import "./globals.css"; import { SITE_NAME, SITE_URL } from "./lib/site"; import { buildStructuredData } from "./lib/structured-data"; // DESIGN.md names Switzer / Basier Circle; neither ships on Google Fonts. // These are the documented substitutes — Manrope for UI, Plus Jakarta Sans for // display, which holds the tight negative tracking the brand depends on. const switzer = Manrope({ variable: "--font-switzer-local", subsets: ["latin"], weight: ["400", "500", "600", "700"], display: "swap", }); const display = Plus_Jakarta_Sans({ variable: "--font-display-local", subsets: ["latin"], weight: ["500", "600"], style: ["normal", "italic"], display: "swap", }); export const metadata: Metadata = { metadataBase: new URL(SITE_URL), title: { // Under 60 characters so Google does not truncate it in the SERP, // with the primary keyword ahead of the brand name. default: "Kursverwaltung & Buchungssystem für Kursbetriebe · Kumasy", template: "%s · Kumasy", }, description: "Kumasy bündelt Kurse, Räume, Trainer, Buchungen und Zahlungen in einer Oberfläche. Deine Teilnehmer:innen buchen und bezahlen selbst — mit Stripe, Warteliste und GoBD-konformen Rechnungen.", applicationName: SITE_NAME, category: "Business Software", authors: [{ name: SITE_NAME, url: SITE_URL }], creator: SITE_NAME, publisher: SITE_NAME, alternates: { canonical: "/" }, openGraph: { type: "website", locale: "de_DE", url: SITE_URL, siteName: SITE_NAME, title: "Deine Kurse füllen und bezahlen sich von selbst.", description: "Kurse, Räume, Trainer, Buchungen und Zahlungen in einer Oberfläche. Jetzt auf die Warteliste.", }, twitter: { card: "summary_large_image", title: "Kumasy — Kursverwaltung und Buchungssystem", description: "Kurse, Räume, Trainer, Buchungen und Zahlungen in einer Oberfläche.", }, // No `icons` key: app/favicon.ico, app/icon.svg and app/apple-icon.png // are picked up by the file convention. Declaring them here as well // emitted a duplicate . manifest: "/manifest.webmanifest", formatDetection: { telephone: false, address: false, email: false }, robots: { index: true, follow: true, googleBot: { index: true, follow: true, // Let Google use full-length snippets, large image previews and // full video previews rather than its conservative defaults. "max-snippet": -1, "max-image-preview": "large", "max-video-preview": -1, }, }, }; export const viewport: Viewport = { // Matches --color-canvas (#f9fafb), the actual body background. themeColor: "#f9fafb", colorScheme: "light", }; export default function RootLayout({ children }: LayoutProps<"/">) { return (
{/* Structured data. Rendered on the server into the initial HTML, so crawlers see it without executing any JavaScript. */} Zum Hauptinhalt springen {children} ); }