// Bishop Design — App + router + Tweaks const { useState, useEffect, useMemo } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "#A9853F", "displayFont": "Cormorant Garamond", "heroMode": "dark", "density": "comfortable" }/*EDITMODE-END*/; // Hash router — supports #/, #/projects, #/project/, #/sector/, #/studio, #/awards, #/contact function parseHash() { const h = (location.hash || "#/").replace(/^#/, ""); const parts = h.split("/").filter(Boolean); if (parts.length === 0) return { page: "home" }; if (parts[0] === "projects") return { page: "projects" }; if (parts[0] === "project" && parts[1]) return { page: "case", slug: parts[1] }; if (parts[0] === "sector" && parts[1]) return { page: "sector", slug: parts[1] }; if (parts[0] === "sectors") return { page: "sector", slug: "restaurants" }; if (parts[0] === "studio") return { page: "studio" }; if (parts[0] === "awards") return { page: "awards" }; if (parts[0] === "contact") return { page: "contact" }; return { page: "home" }; } function buildHash(page, params) { if (page === "home") return "#/"; if (page === "projects") return "#/projects"; if (page === "case") return `#/project/${params.slug}`; if (page === "sector") return `#/sector/${params.slug}`; if (page === "studio") return "#/studio"; if (page === "awards") return "#/awards"; if (page === "contact") return "#/contact"; return "#/"; } function App() { const [route, setRoute] = useState(parseHash()); const [locale, setLocale] = useState("en"); const [transientParams, setTransientParams] = useState({}); // e.g. preselected sector for contact form useEffect(() => { const onHash = () => { setRoute(parseHash()); window.scrollTo({ top: 0, behavior: "instant" }); }; window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); // Tweaks state const t = useTweaks(TWEAK_DEFAULTS); const tweaks = t[0]; const setTweak = t[1]; // Apply tweaks to root useEffect(() => { document.documentElement.style.setProperty("--accent", tweaks.accent); document.documentElement.style.setProperty("--brass", tweaks.accent); const map = { "Cormorant Garamond": '"Cormorant Garamond", "Cormorant", Georgia, serif', "Italiana": '"Italiana", "Cormorant Garamond", Georgia, serif', "Playfair Display": '"Playfair Display", "Cormorant Garamond", Georgia, serif', }; document.documentElement.style.setProperty("--display", map[tweaks.displayFont] || map["Cormorant Garamond"]); document.documentElement.style.setProperty("--section-y", tweaks.density === "compact" ? "clamp(64px, 8vw, 110px)" : "clamp(96px, 12vw, 160px)"); }, [tweaks.accent, tweaks.displayFont, tweaks.density]); // Apply locale → direction useEffect(() => { document.body.dir = locale === "ar" ? "rtl" : "ltr"; }, [locale]); function navigate(page, params) { setTransientParams(params || {}); location.hash = buildHash(page, params || {}); setRoute({ page, ...(params || {}) }); window.scrollTo({ top: 0, behavior: "instant" }); } // Dark nav over dark heroes const navMode = useMemo(() => { if (route.page === "home") return "dark"; if (route.page === "case") return "dark"; if (route.page === "sector") return "dark"; return "light"; }, [route.page]); return (