/* global React, Header, Hero, Marquee, Gallery, Collections, Pricing, About, Testimonials, Contact, BookingModal, WhatsAppFloating, Footer, Icon, Grain, useLanguage */ const { useState, useEffect, useRef } = React; function App() { const { isPortuguese } = useLanguage(); const [scrolled, setScrolled] = useState(false); const [bookingOpen, setBookingOpen] = useState(false); const [active, setActive] = useState('top'); const [lightbox, setLightbox] = useState(null); useEffect(() => { let raf = 0; let last = window.scrollY > 80; const update = () => { const next = window.scrollY > 80; if (next !== last) { last = next; setScrolled(next); } raf = 0; }; const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); }; window.addEventListener('scroll', onScroll, { passive: true }); return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); }; }, []); // section spy useEffect(() => { const ids = ['top', 'work', 'about', 'collections', 'testimonials', 'pricing', 'contact']; const obs = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); }); }, { rootMargin: '-40% 0px -50% 0px' }); ids.forEach(id => { const el = document.getElementById(id); if (el) obs.observe(el); }); return () => obs.disconnect(); }, []); // Reveal each major section once as it enters the viewport. useEffect(() => { const sections = Array.from(document.querySelectorAll('#root section')) .filter((section) => section.id !== 'top'); sections.forEach((section) => section.classList.add('tb-scroll-section')); if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { sections.forEach((section) => section.classList.add('tb-scroll-section-visible')); return undefined; } const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (!entry.isIntersecting) return; entry.target.classList.add('tb-scroll-section-visible'); observer.unobserve(entry.target); }); }, { threshold: 0.08, rootMargin: '0px 0px -8% 0px' }); sections.forEach((section) => observer.observe(section)); return () => observer.disconnect(); }, []); const scrollTo = (id) => { const el = document.getElementById(id); if (el) window.scrollTo({ top: id === 'top' ? 0 : el.offsetTop - 60, behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth' }); }; return (
{isPortuguese ? 'cada canto desta cidade guarda uma história. estou aqui para ajudar você a contar a sua.' : 'every corner of this city holds a story. i’m here to help you tell yours.'}
{isPortuguese ? 'grid · sempre presente' : 'grid · always present'}