import type { Metadata } from "next"; import { Cormorant_Garamond, Inter } from "next/font/google"; import "./globals.css"; import { Header, CartDrawer } from "@/components/site-chrome"; import { Footer } from "@/components/site-footer"; import { CookieConsentBanner } from "@/components/cookie-consent"; import { FlashToast } from "@/components/flash-toast"; import { SubmitFeedback } from "@/components/submit-feedback"; import { readFlash } from "@/lib/flash"; import { getSiteUrl } from "@/lib/url"; import { getCompanyInfo } from "@/lib/company-info"; import { getSocialLinks } from "@/lib/social-links"; import { getLocale } from "@/i18n/locale"; import { getDictionary } from "@/i18n/get-dictionary"; import { I18nProvider } from "@/i18n/i18n-provider"; const cormorant = Cormorant_Garamond({ variable: "--font-cormorant", subsets: ["latin"], weight: ["400", "500", "600"], }); const inter = Inter({ variable: "--font-inter", subsets: ["latin"], }); export async function generateMetadata(): Promise { const company = await getCompanyInfo(); const title = `${company.name} | Regionaler Honig aus Altenmünster`; return { metadataBase: new URL(getSiteUrl()), title: { default: title, template: `%s | ${company.name}` }, description: company.description, openGraph: { title, description: company.description, siteName: company.name, locale: "de_DE", type: "website", }, twitter: { card: "summary_large_image", title, description: company.description }, }; } export default async function RootLayout({ children }: LayoutProps<"/">) { const locale = await getLocale(); const dict = getDictionary(locale); const [company, socialLinks, flash] = await Promise.all([getCompanyInfo(), getSocialLinks(), readFlash()]); const base = getSiteUrl(); // LocalBusiness-Schema fuer die gesamte Seite (einmal im Root-Layout statt // auf jeder Seite einzeln) — hilft insbesondere bei lokaler Google-Suche // ("Honig Altenmünster") und der Kartenanzeige. telephone ist hier bewusst // NICHT enthalten: solange niemand im Admin-Bereich (Inhalte) eine echte // Telefonnummer eingetragen hat, bliebe sonst der site-config-Platzhalter // als strukturierte Daten faelschlich indexiert. const localBusinessJsonLd = { "@context": "https://schema.org", "@type": "Store", "@id": `${base}/#business`, name: company.name, description: company.description, url: base, address: { "@type": "PostalAddress", streetAddress: company.address.street, postalCode: company.address.zip, addressLocality: company.address.city, addressCountry: "DE", }, }; // Ermoeglicht Googles Sitelinks-Suchfeld direkt in den Suchergebnissen — die // Ziel-URL entspricht der tatsaechlich vorhandenen Shop-Suche (?q=...). const websiteJsonLd = { "@context": "https://schema.org", "@type": "WebSite", name: company.name, url: base, potentialAction: { "@type": "SearchAction", target: `${base}/shop?q={search_term_string}`, "query-input": "required name=search_term_string", }, }; return ( {/* Rettungsnetz fuer den Fall, dass kein JavaScript laeuft. Hero, ScrollReveal und ProductCard starten mit opacity 0 und werden erst per motion/react eingeblendet. Weil diese Startwerte schon im server-gerenderten HTML als inline-style stehen, blieb ohne JavaScript alles unterhalb des Hero-Bildes dauerhaft unsichtbar — kein Teilausfall, sondern der komplette Seiteninhalt. Auf wabenhain.com waren das 38 Elemente. !important ist hier notwendig und nicht nachlaessig: es gibt keine andere Moeglichkeit, einen inline-style zu ueberschreiben. Die Regel zielt ausschliesslich auf [data-reveal] — Ein- und Ausblendungen in AnimatePresence (Warenkorb-Schublade, Menue, Cookie-Banner) tragen das Attribut nicht und bleiben verborgen. Deckt den Fall "JavaScript deaktiviert" ab. Laedt das Bundle dagegen und schlaegt erst spaeter fehl, greift noscript nicht — dafuer waere ein Zeitgeber noetig, der die Animation im Normalfall stoeren wuerde. */}