// ─── App principal: theme, navegación, tweaks ──────────────────────────── const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "#00FFB2", "mode": "dark", "intensity": "media" }/*EDITMODE-END*/; // Para light mode usamos versiones más saturadas/oscuras que leen bien sobre blanco const LIGHT_TONE = { '#00FFB2': '#00A574', '#00D4FF': '#0090C2', '#BD55FF': '#8B22D0', '#FFB800': '#B07700', }; function App() { const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS); const [screen, setScreen] = React.useState('detail'); // 'portfolio' | 'detail' const [symbol, setSymbol] = React.useState('NVRA'); const [holdings, setHoldings] = React.useState(window.HOLDINGS); const [watchlist, setWatchlist] = React.useState(window.WATCHLIST); const [query, setQuery] = React.useState(''); const [toast, setToast] = React.useState(null); const [splashOut, setSplashOut] = React.useState(false); // Splash inicial React.useEffect(() => { const t = setTimeout(() => setSplashOut(true), 850); return () => clearTimeout(t); }, []); // Aplicar tema al :root React.useEffect(() => { const root = document.documentElement; const baseHex = tweaks.accent || '#00FFB2'; const c = tweaks.mode === 'dark' ? baseHex : (LIGHT_TONE[baseHex] || baseHex); root.style.setProperty('--accent', c); root.style.setProperty('--accent-glow', hexToRgba(c, tweaks.intensity === 'atrevida' ? 0.55 : tweaks.intensity === 'media' ? 0.38 : 0.18)); root.style.setProperty('--accent-dim', hexToRgba(c, 0.15)); root.style.setProperty('--accent-text', tweaks.mode === 'dark' ? '#07070F' : '#FFFFFF'); root.style.setProperty('--glow-on', tweaks.intensity === 'conservadora' ? '0' : '1'); root.dataset.mode = tweaks.mode; root.dataset.intensity = tweaks.intensity; }, [tweaks]); // Navegación const navigate = (s, sym) => { setScreen(s); if (sym) setSymbol(sym); window.scrollTo({ top: 0, behavior: 'auto' }); }; const openTicker = (sym) => navigate('detail', sym); const toggleWatch = (sym) => { setWatchlist((w) => { if (w.includes(sym)) { flash(`${sym} eliminado del seguimiento`); return w.filter((x) => x !== sym); } flash(`${sym} añadido al seguimiento`); return [sym, ...w]; }); }; const flash = (msg) => { setToast(msg); setTimeout(() => setToast(null), 2200); }; return ( <> {!splashOut && } {screen === 'portfolio' && ( )} {screen === 'detail' && ( navigate('portfolio')} onOpenTicker={openTicker} holdings={holdings} watchlist={watchlist} isWatching={watchlist.includes(symbol)} onToggleWatch={toggleWatch} accent="var(--accent)" intensity={tweaks.intensity}/> )} {toast &&
{toast}
} setTweak('mode', v)}/> setTweak('accent', v)}/> setTweak('intensity', v)}/>
Ir a pantalla
); } // Splash function Splash() { return (
StockPulse
); } // ─── Helpers ────────────────────────────────────────────────────────────── function hexToRgba(hex, alpha) { const h = hex.replace('#', ''); const full = h.length === 3 ? h.replace(/./g, (c) => c + c) : h; const n = parseInt(full, 16); const r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255; return `rgba(${r},${g},${b},${alpha})`; } const root = ReactDOM.createRoot(document.getElementById('root')); root.render();