/* ============================================================ CryptoCalcy homepage — app shell. Assembles nav, hero (ring + center), strips, sections, footer. ============================================================ */ (function () { 'use strict'; var React = window.React, ReactDOM = window.ReactDOM; var h = React.createElement; var DS = window.CryptoCalcyDesignSystem_babfb7; var Button = DS.Button; var CoinRing = window.CoinRing, CoinIcon = window.CoinIcon; var PricesStrip = window.PricesStrip, CalculatorGrid = window.CalculatorGrid; var FearGreed = window.FearGreed, NewsList = window.NewsList, Footer = window.Footer; var CookieBanner = window.CookieBanner, AdSlot = window.AdSlot, SectionHead = window.SectionHead; var fmt = window.CCFmt; var CATS_L = [['Profit tools', 6], ['Converters', 4], ['Staking & DCA', 4]]; var CATS_R = [['Trading calcs', 4], ['Market data', 8], ['Charts', 4]]; // ---------- Theme ---------- function useTheme() { var init = 'dark'; try { init = localStorage.getItem('ccy-theme') || 'dark'; } catch (e) {} var st = React.useState(init), theme = st[0], setTheme = st[1]; React.useEffect(function () { document.documentElement.setAttribute('data-theme', theme); try { localStorage.setItem('ccy-theme', theme); } catch (e) {} }, [theme]); return [theme, function () { setTheme(theme === 'dark' ? 'light' : 'dark'); }]; } // ---------- Nav ---------- function NavBar(props) { return h('header', { className: 'nav' }, h('div', { className: 'nav-inner' }, h('a', { className: 'wordmark', href: '#' }, 'CryptoCalcy'), h('nav', { className: 'nav-links' }, h('a', { href: 'calculators.html' }, 'Calculators'), h('a', { href: 'converters.html' }, 'Converters'), h('a', { href: 'charts.html' }, 'Charts'), h('a', { href: 'data.html' }, 'Data'), h('a', { href: 'tools.html' }, 'Tools'), h('a', { href: 'learn.html' }, 'Learn'), h('a', { href: 'portfolio.html' }, 'Portfolio') ), h('div', { className: 'nav-right' }, h('button', { className: 'theme-btn', onClick: props.onToggleTheme, 'aria-label': 'Toggle color theme' }, props.theme === 'dark' ? h('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.7, strokeLinecap: 'round' }, h('circle', { cx: 12, cy: 12, r: 4 }), h('path', { d: 'M12 2v2M12 20v2M4 12H2M22 12h-2M5 5l1.5 1.5M17.5 17.5L19 19M19 5l-1.5 1.5M6.5 17.5L5 19' })) : h('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' }, h('path', { d: 'M21 12.8A9 9 0 1111.2 3a7 7 0 009.8 9.8z' })) ), h(Button, { variant: 'primary', size: 'md', onClick: function () { location.href = 'calculators.html#profit'; } }, 'Profit calculator') ) ) ); } // ---------- Hero center content ---------- function HeroCenter(props) { var coin = props.coin, locked = props.locked; return h('div', { className: 'hero-center' }, h('div', { className: 'hero-default' + (coin ? ' faded' : '') }, h('span', { className: 'overline hero-eyebrow' }, 'Live market data · No signup'), h('h1', { className: 'hero-title' }, 'Free crypto calculators & live market data.'), h('p', { className: 'hero-sub' }, '16 calculators, live prices and market tools — trusted data, zero signup.'), h('div', { className: 'hero-cta' }, h(Button, { variant: 'primary', size: 'lg', pill: true, onClick: function () { location.href = 'calculators.html#profit'; } }, 'Profit calculator'), h(Button, { variant: 'secondary', size: 'lg', pill: true, onClick: function () { location.hash = '#markets'; } }, 'View markets') ) ), coin ? h('div', { className: 'hero-coin', key: coin.id }, h(CoinIcon, { coin: coin, size: 64 }), h('div', { className: 'hero-coin-name' }, h('span', { className: 'hcn-name' }, coin.name), h('span', { className: 'hcn-sym' }, coin.symbol) ), h('div', { className: 'hero-coin-price' }, fmt.fmtPrice(coin.current_price)), h('div', { className: 'hero-coin-chg ' + ((coin.price_change_percentage_24h || 0) >= 0 ? 'up' : 'down') }, ((coin.price_change_percentage_24h || 0) >= 0 ? '▲ +' : '▼ ') + Math.abs(coin.price_change_percentage_24h || 0).toFixed(2) + '% · 24h'), locked ? h(Button, { variant: 'primary', size: 'md', pill: true, onClick: function () { location.href = 'calculators.html#profit?coin=' + coin.id; } }, 'Calculate profit +') : null ) : null ); } // ---------- Hero ---------- function Hero(props) { var coins = props.coins; var st1 = React.useState(null), hoverCoin = st1[0], setHover = st1[1]; var st2 = React.useState(null), lockCoin = st2[0], setLock = st2[1]; var display = hoverCoin || lockCoin; var locked = !!lockCoin && !hoverCoin; return h('section', { className: 'hero', id: 'top' }, h('div', { className: 'hero-cats hero-cats-l' }, CATS_L.map(function (c, i) { return h('a', { key: i, className: 'cat-label', href: '#calculators' }, c[0], h('sup', {}, c[1])); })), h('div', { className: 'hero-cats hero-cats-r' }, CATS_R.map(function (c, i) { return h('a', { key: i, className: 'cat-label', href: '#markets' }, c[0], h('sup', {}, c[1])); })), h(CoinRing, { coins: coins, onHover: function (c) { setHover(c); }, onLock: function (c) { setLock(c); setHover(null); }, onUnlock: function () { setLock(null); }, onDragStart: function () { setHover(null); } }), h(HeroCenter, { coin: display, locked: locked }), h('div', { className: 'hero-hint' }, 'Move to explore · Click to lock a coin'), h('a', { className: 'hero-a11y', href: '#markets' }, 'Browse all coins →') ); } // ---------- App ---------- function App() { var themeState = useTheme(), theme = themeState[0], toggle = themeState[1]; var st = React.useState(function () { var seed = window.CCData.primeMarkets ? window.CCData.primeMarkets() : window.CCData.mockCoins(); return { coins: seed, live: false, fng: null, news: [], ready: false }; }); var data = st[0], setData = st[1]; React.useEffect(function () { var mounted = true; window.CCData.fetchMarkets().then(function (m) { if (!mounted) return; setData(function (d) { return Object.assign({}, d, { coins: m.coins, live: m.live, ready: true }); }); }); window.CCData.fetchFearGreed().then(function (f) { if (mounted) setData(function (d) { return Object.assign({}, d, { fng: f }); }); }); window.CCData.fetchNews().then(function (n) { if (mounted) setData(function (d) { return Object.assign({}, d, { news: n.items }); }); }); // refresh prices every 60s var iv = setInterval(function () { window.CCData.fetchMarkets().then(function (m) { if (mounted) setData(function (d) { return Object.assign({}, d, { coins: m.coins, live: m.live }); }); }); }, 60000); return function () { mounted = false; clearInterval(iv); }; }, []); var coins = data.coins.length ? data.coins : window.CCData.mockCoins(); return h(React.Fragment, null, h(NavBar, { theme: theme, onToggleTheme: toggle }), h('div', { className: 'ad-wrap' }, h(AdSlot, { variant: 'leaderboard', size: '728 × 90' })), h(Hero, { coins: coins }), h(PricesStrip, { coins: coins }), h('div', { className: 'container' }, !data.live && data.ready ? h('div', { className: 'data-note' }, 'Live data source is busy — showing recent sample values. Prices retry automatically.') : null ), h(CalculatorGrid, null), h('section', { className: 'section', id: 'markets' }, h(SectionHead, { overline: 'Market pulse', title: 'The market, at a glance.', sub: 'Sentiment and the stories moving price — refreshed continuously.' }), h('div', { className: 'pulse-grid' }, h(FearGreed, { data: data.fng }), h(NewsList, { items: data.news }), h(AdSlot, { variant: 'rail', size: '300 × 250' }) ) ), h('section', { className: 'disclaimer-band', id: 'about' }, h('div', { className: 'container disclaimer-inner' }, h('span', { className: 'overline' }, 'Editorial note'), h('p', {}, 'CryptoCalcy provides free tools and market data for informational purposes only. Nothing here is financial, investment or tax advice. Figures are estimates based on live third-party data and may be delayed or incomplete. Always do your own research.'), h('span', { className: 'disc-updated' }, 'Last updated: July 11, 2026 · Data by CoinGecko') ) ), h(Footer, null), h(CookieBanner, null) ); } ReactDOM.createRoot(document.getElementById('root')).render(h(App)); })();