/* PhotoCarousel — auto-rotating carousel com loading progressivo. ────────────────────────────────────────────────────────────────────── PERFORMANCE - Primeira imagem do carrossel: carrega imediatamente (eager, alta prioridade) - Outras imagens: carregam de forma preguiçosa (lazy), em paralelo - Cada imagem tem largura/altura declaradas → zero CLS (layout shift) - Shimmer dourado enquanto a imagem carrega → o usuário vê a interface pronta antes mesmo das fotos baixarem. COMO TROCAR FOTOS 1) Salve em `assets/fotos/cidades/` ou `assets/fotos/condominio/` 2) Mantenha o mesmo nome listado em PHOTOS abaixo OU edite o campo `src` da linha correspondente. Veja `assets/fotos/README.md` para o passo a passo. ────────────────────────────────────────────────────────────────────── */ function PhotoCarousel({ photos, interval = 5000, compact = false, labelOverride, width, height }) { const [i, setI] = React.useState(0); const [paused, setPaused] = React.useState(false); const [loaded, setLoaded] = React.useState(() => new Set()); React.useEffect(() => { if (photos.length <= 1 || paused) return; const t = setInterval(() => setI(p => (p + 1) % photos.length), interval); return () => clearInterval(t); }, [photos.length, interval, paused]); const go = (delta) => setI(p => (p + delta + photos.length) % photos.length); const markLoaded = (idx) => setLoaded(prev => { if (prev.has(idx)) return prev; const next = new Set(prev); next.add(idx); return next; }); return (
setPaused(true)} onMouseLeave={() => setPaused(false)}> {photos.map((p, idx) => (
{p.label} markLoaded(idx)} onError={() => markLoaded(idx)} />
))}
{photos.length > 1 && (
)}
{labelOverride || photos[i]?.label}
{photos.length > 1 && (
{photos.map((_, idx) => (
)}
); } /* ────────────────────────────────────────────────────────────────────── PHOTOS — bancos de fotos do site. Os caminhos `src` apontam direto para os arquivos otimizados que ficam em `assets/fotos/`. Os campos `fallback` (Picsum) só são usados como rede de segurança caso o arquivo local não exista. ────────────────────────────────────────────────────────────────────── */ const PHOTOS = { /* HERO — 8 cidades atendidas (vertical 900×1200, ~150-250 KB cada) */ beaches: [ { src: "assets/fotos/cidades/saquarema.jpg", label: "Saquarema" }, { src: "assets/fotos/cidades/marica.jpg", label: "Maricá" }, { src: "assets/fotos/cidades/cabo-frio.jpg", label: "Cabo Frio" }, { src: "assets/fotos/cidades/buzios.jpg", label: "Búzios" }, { src: "assets/fotos/cidades/arraial-do-cabo.jpg", label: "Arraial do Cabo" }, { src: "assets/fotos/cidades/araruama.jpg", label: "Araruama" }, { src: "assets/fotos/cidades/sao-pedro-da-aldeia.jpg", label: "São Pedro da Aldeia" }, { src: "assets/fotos/cidades/iguaba-grande.jpg", label: "Iguaba Grande" } ], /* PORTARIA — 3 fotos rotativas (horizontais, 800×600 recomendado) */ portaria: [ { src: "https://picsum.photos/seed/portaria-cond-1/800/600", localPath: "assets/fotos/condominio/portaria-1.jpg", label: "Portaria · entrada principal" }, { src: "https://picsum.photos/seed/portaria-cond-2/800/600", localPath: "assets/fotos/condominio/portaria-2.jpg", label: "Portaria · recepção" }, { src: "https://picsum.photos/seed/portaria-cond-3/800/600", localPath: "assets/fotos/condominio/portaria-3.jpg", label: "Portaria · acesso noturno" } ], /* FACHADA — 3 fotos rotativas */ fachada: [ { src: "https://picsum.photos/seed/fachada-cond-1/800/600", localPath: "assets/fotos/condominio/fachada-1.jpg", label: "Fachada · vista frontal" }, { src: "https://picsum.photos/seed/fachada-cond-2/800/600", localPath: "assets/fotos/condominio/fachada-2.jpg", label: "Fachada · jardim" }, { src: "https://picsum.photos/seed/fachada-cond-3/800/600", localPath: "assets/fotos/condominio/fachada-3.jpg", label: "Fachada · alto-padrão" } ], /* ÁREA COMUM — 3 fotos rotativas */ comum: [ { src: "https://picsum.photos/seed/area-comum-1/800/600", localPath: "assets/fotos/condominio/comum-1.jpg", label: "Salão de festas" }, { src: "https://picsum.photos/seed/area-comum-2/800/600", localPath: "assets/fotos/condominio/comum-2.jpg", label: "Piscina e deck" }, { src: "https://picsum.photos/seed/area-comum-3/800/600", localPath: "assets/fotos/condominio/comum-3.jpg", label: "Espaço gourmet" } ], /* ASSEMBLEIA — 3 fotos rotativas */ assembleia: [ { src: "https://picsum.photos/seed/assembleia-1/800/600", localPath: "assets/fotos/condominio/assembleia-1.jpg", label: "Assembleia · condução" }, { src: "https://picsum.photos/seed/assembleia-2/800/600", localPath: "assets/fotos/condominio/assembleia-2.jpg", label: "Assembleia · registro" }, { src: "https://picsum.photos/seed/assembleia-3/800/600", localPath: "assets/fotos/condominio/assembleia-3.jpg", label: "Reunião do conselho" } ] }; Object.assign(window, { PhotoCarousel, PHOTOS });