// app.jsx — Main shell: Navbar + routing + Footer function Navbar({ page, go, scrolled }) { const [menuOpen, setMenuOpen] = React.useState(false); // Lock body scroll when menu is open React.useEffect(() => { if (menuOpen) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } return () => { document.body.style.overflow = ''; }; }, [menuOpen]); // Close menu on page change React.useEffect(() => { setMenuOpen(false); }, [page]); const links = [ { id: 'home', label: 'Inicio' }, { id: 'copytrading', label: 'CopyTrading' }, { id: 'signals', label: 'Premium' }, { id: 'tradingview', label: 'Análisis' }, { id: 'fondeadas', label: 'Cuentas de Fondeo' }, { id: 'academia', label: 'Academia' }, ]; const handleClick = (id) => { setMenuOpen(false); go(id); }; return ( <>
{/* Logo */} {/* Desktop nav */} {/* CTA */}
{/* Mobile */}
{/* Mobile menu overlay — OUTSIDE header for proper fixed positioning */} {menuOpen && (
{links.map(l => { const active = page === l.id; return ( ); })}
)} ); } function Footer({ go }) { return ( ); } // ============================================================ // LANDING (composed) // ============================================================ function Landing({ go }) { return ( <> ); } // ============================================================ // APP // ============================================================ // Mapa de rutas URL ↔ pageId const ROUTES = { '/': 'home', '/copytrading': 'copytrading', '/premium': 'signals', '/analisis': 'tradingview', '/fondeadas': 'fondeadas', '/academia': 'academia', '/empezar': 'empezar', }; // Inverso: pageId → path const PAGE_TO_PATH = Object.fromEntries(Object.entries(ROUTES).map(([k, v]) => [v, k])); function pathToPage(pathname) { // Normalizar: quitar trailing slash excepto en "/" const clean = pathname.replace(/\/$/, '') || '/'; return ROUTES[clean] || 'home'; } function App() { const [page, setPage] = React.useState(() => pathToPage(window.location.pathname)); const [scrolled, setScrolled] = React.useState(false); // Scroll listener para el navbar React.useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 40); onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); return () => window.removeEventListener('scroll', onScroll); }, []); // Escuchar botón "atrás / adelante" del navegador React.useEffect(() => { const onPop = () => { const p = pathToPage(window.location.pathname); setPage(p); window.scrollTo({ top: 0, behavior: 'instant' }); }; window.addEventListener('popstate', onPop); return () => window.removeEventListener('popstate', onPop); }, []); const go = React.useCallback((p) => { const path = PAGE_TO_PATH[p] || '/'; // Solo hacer pushState si la ruta cambia if (window.location.pathname !== path) { window.history.pushState({ page: p }, '', path); } setPage(p); window.scrollTo({ top: 0, behavior: 'instant' }); }, []); useReveal(); React.useEffect(() => { // re-trigger reveal on page change const t = setTimeout(() => { document.querySelectorAll('.reveal').forEach(el => { const r = el.getBoundingClientRect(); if (r.top < window.innerHeight - 40) el.classList.add('in'); }); }, 50); return () => clearTimeout(t); }, [page]); let content; if (page === 'home') content = ; else if (page === 'copytrading') content = ; else if (page === 'signals') content = ; else if (page === 'tradingview') content = ; else if (page === 'fondeadas') content = ; else if (page === 'academia') content = ; else if (page === 'empezar') content = ; else content = ; return (
{content}
); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render();