import type { Metadata } from "next"; import { Nunito, Pixelify_Sans } from "next/font/google"; import { headers } from "next/headers"; import Script from "next/script"; import { NextIntlClientProvider } from "next-intl"; import { getLocale, getMessages } from "next-intl/server"; import type { ReactNode } from "react"; import { Toaster } from "sonner"; import { PwaRegister } from "@/components/pwa-register"; import { SmoothScroll } from "@/components/smooth-scroll"; import { ThemeVars } from "@/components/theme-vars"; import { enforceSiteAccess } from "@/lib/access-guard"; import { resolveHotelName } from "@/lib/hotel-name"; import { siteSettings } from "@/lib/services/site-settings"; import "./globals.css"; const nunito = Nunito({ subsets: ["latin"], weight: ["400", "600", "700", "800"], variable: "--font-nunito", display: "swap", }); const pixelify = Pixelify_Sans({ subsets: ["latin"], weight: ["400", "700"], variable: "--font-pixel", display: "swap", }); // The root layout reads runtime data (locale cookie, request headers via // enforceSiteAccess, DB-backed site settings) to render the element, // which cannot be wrapped in . Child pages inherit this opt-out, // so leaf pages that only access cached/DB data stay instant. // export const instant = false; export async function generateMetadata(): Promise { const appUrl = process.env.APP_URL ?? "http://localhost:3000"; const hotel = await resolveHotelName(); const customFavicon = await siteSettings.get("cms_favicon"); const faviconUrl = customFavicon ?? "/favicon.svg"; const icons = [ { rel: "icon", url: faviconUrl }, { rel: "shortcut icon", url: faviconUrl }, ]; return { title: { default: `${hotel} - Hotel`, template: `%s · ${hotel}` }, description: `${hotel} — a Habbo retro hotel. Hang out, collect furni and meet friends.`, metadataBase: new URL(appUrl), alternates: { canonical: appUrl }, icons, openGraph: { title: `${hotel} - Hotel`, description: `${hotel} — a Habbo retro hotel. Hang out, collect furni and meet friends.`, type: "website", siteName: hotel, }, twitter: { card: "summary_large_image", title: `${hotel} - Hotel` }, }; } export default async function RootLayout({ children, }: { children: ReactNode; }) { await enforceSiteAccess(); const locale = await getLocale(); const messages = await getMessages(); const defaultDark = await siteSettings.getBool("default_dark", false); const nitroUrl = await siteSettings.get("nitro_client_url", ""); const nonce = (await headers()).get("x-nonce") ?? undefined; return (