/* Keiko Eyewear — main app: language state, GSAP scrollytelling, lightbox, mount. */
const { Header, Hero, About, Collections, WaGlyph } = window.KeikoSections1;
const { Kids, Gallery, VideoGallery, Retail, Wholesale, Briventi, Contact, Footer } = window.KeikoSections2;
const LINKS = window.KEIKO_LINKS;
const prefersReduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
function FloatingWhatsApp({ label }) {
return (
{ e.currentTarget.style.transform = 'scale(1.08)'; e.currentTarget.style.filter = 'brightness(1.06)'; }}
onMouseLeave={(e) => { e.currentTarget.style.transform = ''; e.currentTarget.style.filter = ''; }}>
);
}
function Lightbox({ src, onClose }) {
React.useEffect(() => {
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [onClose]);
if (!src) return null;
return (
);
}
function App() {
const [lang, setLangState] = React.useState('es');
const [lightbox, setLightbox] = React.useState(null);
const t = window.KEIKO_T[lang];
const rootRef = React.useRef(null);
const setLang = React.useCallback((code) => {
setLangState(code);
}, []);
// sync dir + lang
React.useEffect(() => {
const html = document.documentElement;
html.setAttribute('lang', t.lang);
html.setAttribute('dir', t.dir);
}, [t.lang, t.dir]);
// GSAP scrollytelling — set up once after mount
React.useEffect(() => {
if (prefersReduced || !window.gsap) return;
const gsap = window.gsap;
gsap.registerPlugin(window.ScrollTrigger);
const ctx = gsap.context(() => {
// hero entrance
gsap.from('[data-hero-anim]', {
y: 28, opacity: 0, duration: 0.9, ease: 'power3.out', stagger: 0.12, delay: 0.15,
});
// standard reveals
gsap.utils.toArray('[data-reveal]').forEach((el) => {
gsap.from(el, {
scrollTrigger: { trigger: el, start: 'top 86%' },
y: 36, opacity: 0, duration: 0.85, ease: 'power3.out',
});
});
// playful bounce reveals (Keiko Kids)
gsap.utils.toArray('[data-reveal-bounce]').forEach((el, i) => {
gsap.from(el, {
scrollTrigger: { trigger: el, start: 'top 88%' },
y: 40, opacity: 0, scale: 0.92, duration: 0.7, ease: 'back.out(1.7)', delay: (i % 4) * 0.05,
});
});
gsap.utils.toArray('[data-kids-pop]').forEach((el, i) => {
gsap.from(el, {
scrollTrigger: { trigger: el, start: 'top 95%' },
y: -20, opacity: 0, duration: 0.5, ease: 'back.out(2)', delay: i * 0.06,
});
});
// subtle parallax on hero media
const heroMedia = document.querySelector('[data-hero-media]');
if (heroMedia) {
gsap.to(heroMedia, {
yPercent: 14, ease: 'none',
scrollTrigger: { trigger: '#hero', start: 'top top', end: 'bottom top', scrub: true },
});
}
}, rootRef);
const refresh = () => window.ScrollTrigger && window.ScrollTrigger.refresh();
window.addEventListener('load', refresh);
const tId = setTimeout(refresh, 400);
return () => { ctx.revert(); window.removeEventListener('load', refresh); clearTimeout(tId); };
}, []);
// refresh triggers after a language change (text reflow changes heights)
React.useEffect(() => {
if (window.ScrollTrigger) {
const id = setTimeout(() => window.ScrollTrigger.refresh(), 120);
return () => clearTimeout(id);
}
}, [lang]);
return (
setLightbox(src)} />
setLightbox(null)} />
);
}
ReactDOM.createRoot(document.getElementById('root')).render();