// Shared UI: Nav, Footer, Reveal, helpers const { useState, useEffect, useRef, useContext, createContext } = React; // Router context const RouterContext = createContext({ route: { name: 'home' }, navigate: () => {} }); const useRouter = () => useContext(RouterContext); // Format AED function aed(n) { return 'AED ' + n.toLocaleString('en-US'); } // Reveal-on-scroll function Reveal({ children, delay = 0, as: As = 'div', className = '', ...rest }) { const ref = useRef(null); const [seen, setSeen] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } }); }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' } ); io.observe(el); return () => io.disconnect(); }, []); return ( {children} ); } // Link that uses router navigate function NavLink({ to, params, children, className = '', onClick }) { const { navigate } = useRouter(); return ( { e.preventDefault(); if (onClick) onClick(e); navigate(to, params); }} > {children} ); } // Top bar function TopNav({ arabicAccent }) { const { route, navigate } = useRouter(); const [scrolled, setScrolled] = useState(false); const [mobileOpen, setMobileOpen] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 12); window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); return () => window.removeEventListener('scroll', onScroll); }, []); const links = [ { to: 'collections', label: 'Collections' }, { to: 'bespoke', label: 'Bespoke' }, { to: 'concierge', label: 'Concierge' }, { to: 'story', label: 'Our Story' }, { to: 'boutiques', label: 'Boutiques' }, { to: 'contact', label: 'Contact' }, ]; return ( <>
{links.slice(0, 3).map((l) => ( { e.preventDefault(); navigate(l.to); }}>{l.label} ))}
{ e.preventDefault(); navigate('home'); }}> GAFLA قافِلة
{links.slice(3).map((l) => ( { e.preventDefault(); navigate(l.to); }}>{l.label} ))} { e.preventDefault(); navigate('contact', { tab: 'majlis' }); }}> Book a Viewing
{ e.preventDefault(); navigate('contact', { tab: 'majlis' }); }}> Book
{links.map((l) => ( { e.preventDefault(); navigate(l.to); setMobileOpen(false); }}> {l.label} ))}
); } // Footer function Footer() { const { navigate } = useRouter(); return ( <> ); } // Generic split layout — image + text function Split({ image, alt, kicker, title, body, cta, reverse, tall }) { return ( <>
{alt}
{kicker}

{body}

{cta && (
{cta}
)}

); } // Caravan divider — animated dotted line referencing the caravan name + 4-bead pattern from Sak function CaravanDivider({ label }) { return ( <>
{label &&
{label}
}
); } // Product card function ProductCard({ product, onClick }) { return ( <>
{product.type}
{product.name}
{product.name}
{COLLECTIONS.find(c => c.id === product.collection)?.name} {aed(product.price)}
); } // Quiet "scroll" indicator function ScrollHint({ label = 'Scroll' }) { return ( <>
{label}
); } Object.assign(window, { useRouter, RouterContext, aed, Reveal, NavLink, TopNav, Footer, Split, CaravanDivider, ProductCard, ScrollHint, });