// Facette — App shell // Renders the desktop site + an iPhone-framed mobile mirror const { useState, useEffect } = React; function Site({ page, setPage, branch, setBranch, openBook, openQuiz, openLightbox, isMobile }) { // Page header sticks return (
{page === 'home' && ( )} {page === 'treatments' && ( )} {page === 'memberships' && ( )} {page === 'locations' && ( )}
); } // ────────────────────────────────────────────────────────── // Stage chrome — top bar over both viewports // ────────────────────────────────────────────────────────── function StageChrome({ branch, setBranch, mobileVisible, setMobileVisible, palette, setPalette, openTweaks }) { return (
Facette · Hi-fi prototype
BRANCH
VIEW
); } // ────────────────────────────────────────────────────────── // Mobile shell — wraps the Site in an iPhone frame // ────────────────────────────────────────────────────────── function MobileShell(props) { return (
); } // ────────────────────────────────────────────────────────── // App // ────────────────────────────────────────────────────────── const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": "luminous", "heroLayout": "split", "mobileVisible": true, "showFlyout": true }/*EDITMODE-END*/; function App() { const initialPage = window.__BYTESGLUE_SHOWCASE_ROUTE || 'home'; const [page, setPage] = useState(initialPage); const [branch, setBranch] = useState('jumeirah'); const [bookOpen, setBookOpen] = useState(false); const [bookTreatment, setBookTreatment] = useState(null); const [quizOpen, setQuizOpen] = useState(false); const [lightboxSrc, setLightboxSrc] = useState(null); const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS); const openTweaks = () => { window.postMessage({ type: '__activate_edit_mode' }, '*'); }; // Apply palette to root useEffect(() => { document.documentElement.setAttribute('data-palette', tweaks.palette); }, [tweaks.palette]); // Reset page scroll when changing page (within each scroll container) useEffect(() => { document.querySelectorAll('.stage-desktop, .ios-scroll').forEach((el) => { el.scrollTo({ top: 0, behavior: 'smooth' }); }); }, [page]); // Sticky book CTA visibility tied to desktop scroll const [showSticky, setShowSticky] = useState(false); useEffect(() => { const el = document.querySelector('.stage-desktop'); if (!el) return; const handler = () => setShowSticky(el.scrollTop > 600); el.addEventListener('scroll', handler); return () => el.removeEventListener('scroll', handler); }, []); // Scale-to-fit: stage has a fixed design width; we scale it to viewport. useEffect(() => { const DESIGN_W = tweaks.mobileVisible ? 1680 : 1280; const CHROME_H = 52; const update = () => { const vw = window.innerWidth; const vh = window.innerHeight - CHROME_H; const scale = Math.min(1, vw / DESIGN_W); document.documentElement.style.setProperty('--stage-scale', scale); document.documentElement.style.setProperty('--stage-w', DESIGN_W + 'px'); document.documentElement.style.setProperty('--stage-h', (vh / scale) + 'px'); }; update(); window.addEventListener('resize', update); return () => window.removeEventListener('resize', update); }, [tweaks.mobileVisible]); const openBook = (treatment) => { setBookTreatment(treatment || null); setBookOpen(true); }; const openQuiz = () => setQuizOpen(true); const openLightbox = (src) => setLightboxSrc(src); const siteProps = { page, setPage, branch, setBranch, openBook, openQuiz, openLightbox, }; return ( setTweak('mobileVisible', v)} palette={tweaks.palette} setPalette={(p) => setTweak('palette', p)} openTweaks={openTweaks} />
{tweaks.showFlyout && ( )}
{tweaks.mobileVisible && (
)}
{/* Modals */} {bookOpen && ( setBookOpen(false)} onBranchChange={setBranch} /> )} {quizOpen && ( setQuizOpen(false)} onBook={(treatment) => { setQuizOpen(false); openBook(treatment); }} /> )} {lightboxSrc && ( setLightboxSrc(null)} /> )} {/* Tweaks panel — self-manages open state */} setTweak('palette', v)} options={[ { value: 'luminous', label: 'Luminous' }, { value: 'clinical', label: 'Clinical' }, { value: 'boutique', label: 'Boutique' }, ]} /> setTweak('mobileVisible', v)} /> setTweak('showFlyout', v)} /> openBook()} /> setQuizOpen(true)} />
); } ReactDOM.createRoot(document.getElementById('root')).render();