/* global React, RDCLogo, CrownMark */ const { useState, useEffect, useRef } = React; // ---------- Navbar ---------- const Navbar = ({ onCTA }) => { const [scrolled, setScrolled] = useState(false); const [open, setOpen] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 40); window.addEventListener("scroll", onScroll, { passive: true }); onScroll(); return () => window.removeEventListener("scroll", onScroll); }, []); const links = [ ["Historia", "#historia"], ["Novedades", "#novedades"], ["Archivo de la Calle", "#equipo"], ["El Regreso", "#impacto"], ["Lo que dice la Cancha", "#prensa"], ["Contacto", "#contacto"]]; return (
Seguir
{/* Mobile drawer */}
{links.map(([l, h]) => setOpen(false)} className="text-white text-lg uppercase tracking-wider font-semibold" style={{ fontFamily: "'Anton', sans-serif" }}> {l} )} setOpen(false)} className="inline-flex items-center justify-center gap-2 text-white font-bold uppercase tracking-widest py-3 rounded-sm transition-transform hover:-translate-y-0.5" style={{ fontFamily: "'Anton', sans-serif", background: "linear-gradient(105deg, #FEDA77 0%, #F58529 22%, #DD2A7B 58%, #8134AF 82%, #515BD4 100%)" }}> Seguir en Instagram
); }; // ---------- Hero ---------- // Pequeño botón que controla el audio del video del hero. Vive sobre el hero, top-right. const HeroSoundToggle = () => { const [muted, setMuted] = useState(true); const [hidden, setHidden] = useState(false); const findVideo = () => document.querySelector('#top video'); const toggle = () => { const v = findVideo(); if (!v) return; if (muted) { v.muted = false; v.volume = 0.85; // Si el video ya terminó, lo reiniciamos para que se escuche if (v.ended) { v.currentTime = 0; v.play().catch(() => {}); } else { v.play().catch(() => {}); } setMuted(false); } else { v.muted = true; setMuted(true); } }; // Cuando el video termina, mostramos un botón de "Repetir" más explícito useEffect(() => { const v = findVideo(); if (!v) return; const onEnd = () => setHidden(false); v.addEventListener("ended", onEnd); return () => v.removeEventListener("ended", onEnd); }, []); return ( ); }; // ---------- Hero ---------- const Hero = ({ onPrimary, onSecondary }) => { return (
{/* Background layers */}
); }; // ---------- Animated counter ---------- const useCounter = (target, suffix = "", duration = 2000) => { const [val, setVal] = useState(0); const ref = useRef(null); const started = useRef(false); useEffect(() => { if (!ref.current) return; const obs = new IntersectionObserver( ([e]) => { if (e.isIntersecting && !started.current) { started.current = true; const start = performance.now(); const tick = (t) => { const p = Math.min(1, (t - start) / duration); const eased = 1 - Math.pow(1 - p, 3); setVal(Math.round(target * eased)); if (p < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); } }, { threshold: 0.4 } ); obs.observe(ref.current); return () => obs.disconnect(); }, [target, duration]); return [ref, val, suffix]; }; const Metric = ({ value, suffix, label, prefix, raw }) => { const [ref, v] = useCounter(value); return (
{prefix && {prefix}} {raw ? v : v.toLocaleString("es-CL")} {suffix && {suffix}}
{label}
); }; const Metrics = () => { return (
{/* Photo backdrop */}
· La calle nos respalda

23 AÑOS
El streetball tiene reyes y creciendo.

En 2002, la marca de ropa deportiva AND1 llegó a Chile. Pero ya desde el 98 se veían acciones basquetboleras en los distintos puntos del país y sobre todo Santiago, gracias a la popularidad de las cintas del Mix Tape And 1 que circulaban mano a mano. Es así como de la mano de la marca y otras empresas organizamos un tour por la Región Metropolitana sumando talentos de los barrios, conformándose el primer equipo oficial de streetbasquet en Sudamérica, llevando el juego y sus valores a cada rincón de la comunidad.
{/* Premium animated collage */}
Archivo Reyes de la Calle — tour AND1, streetball y DJ en la cancha
Archivo · Tour AND1
2002—2003
{/* Metrics */}
{/* Quote band — video background */}
{/* Background video */}
); }; // ---------- Gallery ---------- // Las listas de fotos y videos viven en el store del admin (localStorage). // Merch se mantiene estático mientras la tienda esté en pausa. const galleryMerch = [ { src: "assets/polera-fundadores-v2.png", title: "Polera Fundadores", subtitle: "Oversize" }, { src: "assets/cap-mockup.jpeg", title: "Jockey Desde 2003", subtitle: "Cuero + Algodón", size: "wide" }, { src: "assets/shorts-camo.jpeg", title: "Shorts Camo", subtitle: "Drop 02" }, { src: "assets/zendoh-tee-v2.png", title: "Polera Zendoh", subtitle: "Drop 01" }]; const Gallery = () => { const { useStore, STORE_KEYS, DEFAULT_FOTOS, DEFAULT_VIDEOS } = window; const [galleryFotos] = useStore(STORE_KEYS.fotos, DEFAULT_FOTOS); const [galleryVideos] = useStore(STORE_KEYS.videos, DEFAULT_VIDEOS); const [tab, setTab] = useState("Fotos"); const [lightbox, setLightbox] = useState(null); const tabs = ["Fotos", "Videos", "Merch"]; const tilesFotos = galleryFotos.map((it, i) => ); const tilesVideos = galleryVideos.map((v, i) => ); const tilesMerch = galleryMerch.map((it, i) => ); const currentTiles = tab === "Fotos" ? tilesFotos : tab === "Videos" ? tilesVideos : tilesMerch; const emptyMessage = tab === "Fotos" ? "Aún no hay fotos en la galería. Súmalas desde el panel admin." : tab === "Videos" ? "Aún no hay videos. Súmalos desde el panel admin." : null; return (
· Galería

EL ARCHIVO
DE LA CALLE.

{tabs.map((t) => )}
{currentTiles.length === 0 && emptyMessage ?
{emptyMessage}
:
{currentTiles}
} {tab === "Merch" &&
Pide tu catálogo
}
{/* Lightbox */} {lightbox &&
setLightbox(null)} className="fixed inset-0 z-[100] bg-black/95 backdrop-blur-md flex items-center justify-center p-6 cursor-pointer" style={{ animation: "fadeIn 0.25s ease" }}>
e.stopPropagation()}> {lightbox.isVideo ?