// app.jsx — NOVA Résidence website root // French real estate landing site for selling T2 apartments in Orange. const { useState, useEffect, useMemo, useRef, createContext, useContext } = React; // ────────────────────────────────────────────────────────────────────────── // TWEAKS // ────────────────────────────────────────────────────────────────────────── const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": "signature", "headingFont": "Cormorant Garamond", "bodyFont": "Inter Tight", "density": "regular", "lotsView": "grid", "showPlaceholderLabels": true }/*EDITMODE-END*/; const PALETTES = { signature: { // NOVA brand palette — anthracite + champagne gold (from logo) name: "Signature NOVA", bg: "#F5F2EC", // warm cream bg2: "#EBE6DA", // deeper cream surface: "#FBF9F4", // lightest ink: "#1F2A33", // anthracite (logo) ink2: "#48535C", // muted anthracite muted: "#8A8E92", // logo subtitle gray accent: "#C5A572", // champagne gold (logo) accentDark: "#9D8051", deep: "#1F2A33", // anthracite (deep sections) line: "#D9D3C5", }, clair: { name: "Clair & Or", bg: "#FBF9F4", bg2: "#F1ECDF", surface: "#FFFFFF", ink: "#1F2A33", ink2: "#48535C", muted: "#969A9F", accent: "#B89764", accentDark: "#876A3F", deep: "#1F2A33", line: "#E5DFCF", }, nuit: { name: "Anthracite", bg: "#1A2229", bg2: "#222B33", surface: "#1F2832", ink: "#F5F2EC", ink2: "#C9CDD1", muted: "#8A8E92", accent: "#C5A572", accentDark: "#A38450", deep: "#F5F2EC", line: "#2D3842", }, }; // ────────────────────────────────────────────────────────────────────────── // LOTS DATA — placeholder, all T2 at Résidence NOVA Orange // ────────────────────────────────────────────────────────────────────────── // 8 lots T2 — grille de prix officielle de la plaquette commerciale // Deux typologies : T2 · 40 m² (4 lots d'angle) et T2 · 48 m² (4 lots) const LOTS = [ // R+1 { id: "A11", floor: 1, type: 1, surface: 40.04, loggia: 9.2, orientation: "Sud-Ouest", position: "Angle SO", price: 170000, loyer: 580, renta: 4.09, status: "available", exposure: "Angle plein soleil couchant", plan: "plan-type-1.png" }, { id: "A12", floor: 1, type: 2, surface: 47.8, loggia: 9.0, orientation: "Sud-Ouest", position: "Milieu O", price: 184000, loyer: 630, renta: 4.11, status: "available", exposure: "Séjour traversant N/S", plan: "plan-type-2.png" }, { id: "A13", floor: 1, type: 2, surface: 47.8, loggia: 9.0, orientation: "Sud-Est", position: "Milieu E", price: 185000, loyer: 630, renta: 4.09, status: "available", exposure: "Lumière du matin", plan: "plan-type-2.png" }, { id: "A14", floor: 1, type: 2, surface: 47.8, loggia: 9.2, orientation: "Sud-Est", position: "Angle SE", price: 190000, loyer: 640, renta: 4.04, status: "available", exposure: "Angle sud-est, le plus lumineux", plan: "plan-type-2.png" }, // R+2 { id: "A21", floor: 2, type: 1, surface: 40.04, loggia: 9.2, orientation: "Sud-Ouest", position: "Angle SO", price: 174000, loyer: 590, renta: 4.07, status: "available", exposure: "Vue dégagée, soleil couchant", plan: "plan-type-1.png" }, { id: "A22", floor: 2, type: 2, surface: 47.8, loggia: 9.0, orientation: "Sud-Ouest", position: "Milieu O", price: 191000, loyer: 645, renta: 4.05, status: "available", exposure: "Séjour traversant N/S", plan: "plan-type-2.png" }, { id: "A23", floor: 2, type: 2, surface: 47.8, loggia: 9.0, orientation: "Sud-Est", position: "Milieu E", price: 192000, loyer: 650, renta: 4.06, status: "available", exposure: "Lumière du matin, vue dégagée", plan: "plan-type-2.png" }, { id: "A24", floor: 2, type: 2, surface: 47.8, loggia: 9.2, orientation: "Sud-Est", position: "Angle SE", price: 200000, loyer: 660, renta: 3.96, status: "available", exposure: "Angle sud-est, vue toits provençaux", plan: "plan-type-2.png" }, ]; // ────────────────────────────────────────────────────────────────────────── // THEME CONTEXT // ────────────────────────────────────────────────────────────────────────── const ThemeCtx = createContext(null); const useTheme = () => useContext(ThemeCtx); // ────────────────────────────────────────────────────────────────────────── // ROOT // ────────────────────────────────────────────────────────────────────────── function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const palette = PALETTES[t.palette] || PALETTES.signature; const [route, setRoute] = useState(() => (window.location.hash.replace("#/", "") || "accueil")); useEffect(() => { const onHash = () => setRoute(window.location.hash.replace("#/", "") || "accueil"); window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); const navigate = (r) => { window.location.hash = "#/" + r; window.scrollTo({ top: 0, behavior: "instant" }); }; const densityPad = { compact: 64, regular: 96, comfy: 128 }[t.density] || 96; // CSS vars const themeVars = { "--bg": palette.bg, "--bg2": palette.bg2, "--surface": palette.surface, "--ink": palette.ink, "--ink2": palette.ink2, "--muted": palette.muted, "--accent": palette.accent, "--accent-dark": palette.accentDark, "--deep": palette.deep, "--line": palette.line, "--font-h": `"${t.headingFont}", "Cormorant Garamond", Georgia, serif`, "--font-b": `"${t.bodyFont}", system-ui, sans-serif`, "--section-py": densityPad + "px", }; return (
{route === "accueil" && } {route === "residence" && } {route === "appartements" && } {route === "orange" && } {route === "investir" && } {route === "contact" && }
); } function routeLabel(r) { return ({ accueil: "Accueil", residence: "La Résidence", appartements: "Appartements", orange: "Orange", investir: "Investir", contact: "Contact", })[r] || "Accueil"; } // expose window.App = App; window.LOTS = LOTS; window.useTheme = useTheme; window.ThemeCtx = ThemeCtx;