import type { Metadata, Viewport } from "next"; import { Wix_Madefor_Text, Wix_Madefor_Display } from "next/font/google"; import { Toaster } from "sonner"; import { UmamiAnalytics } from "@/components/analytics/umami"; import { umamiConfig } from "@/lib/analytics"; import { SITE_DESCRIPTION, SITE_NAME, SITE_TAGLINE, SITE_URL, absoluteUrl } from "@/lib/seo"; import "./globals.css"; // Wix Madefor — the platform typeface (body + UI) const madeforText = Wix_Madefor_Text({ subsets: ["latin"], variable: "--font-sans", display: "swap", }); // Wix Madefor Display — headlines (variable font, full weight range) const madeforDisplay = Wix_Madefor_Display({ subsets: ["latin"], variable: "--font-display", display: "swap", }); export const metadata: Metadata = { metadataBase: new URL(SITE_URL), title: { default: `${SITE_NAME} — ${SITE_TAGLINE}`, template: `%s · ${SITE_NAME}`, }, description: SITE_DESCRIPTION, applicationName: SITE_NAME, authors: [{ name: SITE_NAME, url: absoluteUrl("/") }], creator: SITE_NAME, publisher: SITE_NAME, category: "technology", keywords: [ "AI podcast generator", "podcast script generator", "AI voice over", "text to speech podcast", "podcast cover art generator", "AI podcast production", "content repurposing", "multi-voice AI audio", ], // Every route gets a self-referencing canonical; pages override this with their // own absolute URL via `pageMetadata()` so query strings never fragment a page. alternates: { canonical: absoluteUrl("/") }, openGraph: { type: "website", siteName: SITE_NAME, title: `${SITE_NAME} — ${SITE_TAGLINE}`, description: SITE_DESCRIPTION, url: absoluteUrl("/"), locale: "en_US", }, twitter: { card: "summary_large_image", title: `${SITE_NAME} — ${SITE_TAGLINE}`, description: SITE_DESCRIPTION, }, robots: { index: true, follow: true, googleBot: { index: true, follow: true, "max-image-preview": "large", "max-snippet": -1, "max-video-preview": -1, }, }, formatDetection: { telephone: false, address: false, email: false }, // Search-console ownership tokens; unset values are simply omitted. verification: { google: process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION, other: process.env.NEXT_PUBLIC_BING_SITE_VERIFICATION ? { "msvalidate.01": process.env.NEXT_PUBLIC_BING_SITE_VERIFICATION } : {}, }, }; export const viewport: Viewport = { themeColor: [ { media: "(prefers-color-scheme: light)", color: "#ffffff" }, { media: "(prefers-color-scheme: dark)", color: "#0d0d0d" }, ], colorScheme: "light dark", width: "device-width", initialScale: 1, }; export default function RootLayout({ children }: { children: React.ReactNode }) { // Absent config (the default in development) renders nothing at all. const umami = umamiConfig(); return ( {children} {umami && } ); }