karbe/src/app/layout.tsx
Claude Integration c69c355f90 feat(plugin): theme-aquarelle + hero variant (Phase 2.4 partie 1/2)
Registry : ajoute 2 plugins :
- theme-aquarelle (carnet naturaliste XIXᵉ, mutual exclusion avec theme-guyane)
- image-gallery-aquarelle-seed (14 aquarelles → MinIO + Media carbets démo)

Hooks :
- theme-guyane et theme-aquarelle se désactivent mutuellement au toggle ON
  via disableOtherTheme()

CSS (globals.css) :
- body[data-theme=aquarelle] : background papier teinté #faf5e9 + texture
  grain papier inline SVG + radial gradients ocres/canopy délavés
- Surcharges automatiques des borders zinc/gray vers sépia délavé

Layout :
- PT_Serif (au lieu de Cormorant) en theme aquarelle, plus dense et encrée
- data-theme = aquarelle prioritaire sur guyane si les deux sont enabled
  (défensif — le hook garantit normalement la mutual exclusion)

Hero :
- 2 versions dans le composant : guyane (existant, SVG CarbetRiver) et
  aquarelle (image MinIO 01-hero-fleuve-maroni.jpg en fond, voile crème,
  texte sépia, CTAs carrés sans rounded, hairlines, ornement de planche)
- Branchement via getActiveTheme()
- aquarelleUrl() helper qui construit l'URL MinIO publique

Partie 2/2 (PR ultérieure) : upload des 14 images dans MinIO + hook
image-gallery-aquarelle-seed + variantes aquarelle des autres composants
(CarbetCard, ExperiencesSection, HowItWorksSection, CESection, Footer).
2026-05-31 12:15:07 +00:00

111 lines
3.7 KiB
TypeScript

import type { Metadata } from "next";
import { Geist, Geist_Mono, Cormorant_Garamond, PT_Serif } from "next/font/google";
import "./globals.css";
import { PluginProvider } from "@/lib/plugins/client";
import { getEnabledPluginKeys, syncPluginsFromRegistry } from "@/lib/plugins/server";
import { SeasonBanner } from "@/components/SeasonBanner";
import { LocaleProvider } from "@/lib/i18n/client";
import { dict, getLocale } from "@/lib/i18n/server";
// Le layout interroge la DB Plugin à chaque request → rendu dynamique forcé.
// Sans ça, le layout (et donc data-theme + enabledKeys passés au client) est
// statiquement rendu au build et ne reflète plus l'état actuel des toggles.
export const dynamic = "force-dynamic";
export const revalidate = 0;
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
// Cormorant Garamond : typographie display pour le theme Guyane (gated par
// le plugin `theme-guyane`). Sert pour `font-serif`.
const cormorant = Cormorant_Garamond({
variable: "--font-serif",
subsets: ["latin"],
weight: ["400", "500", "600"],
display: "swap",
});
// PT Serif : typographie display pour le theme Aquarelle (carnet naturaliste).
// Plus dense, plus encrée, parfaite pour les planches d'illustration.
const ptSerif = PT_Serif({
variable: "--font-serif-aquarelle",
subsets: ["latin"],
weight: ["400", "700"],
display: "swap",
});
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000";
export const metadata: Metadata = {
metadataBase: new URL(siteUrl),
title: {
default: "Karbé — carbets fluviaux de Guyane",
template: "%s | Karbé",
},
description:
"Karbé, la marketplace de location de carbets fluviaux de Guyane.",
openGraph: {
type: "website",
siteName: "Karbé",
locale: "fr_FR",
title: "Karbé — carbets fluviaux de Guyane",
description:
"La marketplace pour louer des carbets fluviaux le long des fleuves de Guyane.",
},
};
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
// Plugins Karbé : sync registry → DB puis charge la liste activée pour le client.
// En cas d'erreur DB (build statique sans DB par ex.), on retombe en mode "aucun
// plugin activé" pour ne pas casser le rendu.
let enabledKeys: string[] = [];
try {
await syncPluginsFromRegistry();
enabledKeys = await getEnabledPluginKeys();
} catch {
enabledKeys = [];
}
// Aquarelle > Guyane si les deux activés (mutual exclusion garantie par
// le hook plugin, mais on est défensif au cas où).
const themeAquarelle = enabledKeys.includes("theme-aquarelle");
const themeGuyane = !themeAquarelle && enabledKeys.includes("theme-guyane");
const dataTheme = themeAquarelle ? "aquarelle" : themeGuyane ? "guyane" : undefined;
// En thème aquarelle, on substitue la variable --font-serif par PT Serif
// (au lieu de Cormorant) pour coller à l'esthétique carnet.
const serifVariable = themeAquarelle ? ptSerif.variable : cormorant.variable;
const locale = await getLocale();
const messages = await dict(locale);
return (
<html
lang={locale}
className={`${geistSans.variable} ${geistMono.variable} ${serifVariable} h-full antialiased`}
>
<body
data-theme={dataTheme}
className="min-h-full flex flex-col font-sans"
>
<PluginProvider enabledKeys={enabledKeys}>
<LocaleProvider locale={locale} messages={messages}>
<SeasonBanner />
{children}
</LocaleProvider>
</PluginProvider>
</body>
</html>
);
}