/* ============================================================ Homepage sections — composed from the CryptoCalcy design system. Exposes components on window. ============================================================ */ (function () { 'use strict'; var React = window.React; var DS = window.CryptoCalcyDesignSystem_babfb7; var Button = DS.Button, Card = DS.Card, PriceChange = DS.PriceChange, Badge = DS.Badge, Tag = DS.Tag, Stat = DS.Stat; // ---------- helpers ---------- function fmtPrice(n) { if (n == null || isNaN(n)) return '—'; if (n >= 1000) return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 2, minimumFractionDigits: 2 }); if (n >= 1) return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 2, minimumFractionDigits: 2 }); if (n >= 0.01) return '$' + n.toFixed(4); return '$' + n.toFixed(8).replace(/0+$/, ''); } function fmtCompact(n) { if (n == null) return '—'; if (n >= 1e12) return '$' + (n / 1e12).toFixed(2) + 'T'; if (n >= 1e9) return '$' + (n / 1e9).toFixed(2) + 'B'; if (n >= 1e6) return '$' + (n / 1e6).toFixed(2) + 'M'; return '$' + n.toLocaleString('en-US'); } function timeAgo(ts) { var s = Math.floor((Date.now() - ts) / 1000); if (s < 60) return s + 's ago'; if (s < 3600) return Math.floor(s / 60) + 'm ago'; if (s < 86400) return Math.floor(s / 3600) + 'h ago'; return Math.floor(s / 86400) + 'd ago'; } window.CCFmt = { fmtPrice: fmtPrice, fmtCompact: fmtCompact, timeAgo: timeAgo }; var h = React.createElement; // ---------- Coin token (logo with fallback) ---------- function CoinIcon(props) { var c = props.coin, size = props.size || 24; var ref = React.useRef(null); return h('span', { className: 'coin-token', style: { width: size, height: size } }, h('span', { ref: ref, className: 'coin-token-fb show', style: { background: c.color || '#6D5EF6', width: size, height: size, fontSize: size * 0.42 } }, c.symbol.slice(0, 1)), h('img', { src: c.image, alt: '', width: size, height: size, loading: 'lazy', decoding: 'async', onLoad: function (e) { e.target.style.opacity = '1'; if (ref.current) ref.current.style.display = 'none'; }, onError: function (e) { e.target.style.display = 'none'; if (ref.current) ref.current.style.display = 'flex'; } }) ); } window.CoinIcon = CoinIcon; // ---------- Prices strip (auto-scroll marquee) ---------- function PricesStrip(props) { var coins = (props.coins || []).slice(0, 12); if (!coins.length) return null; var row = coins.concat(coins); // duplicate for seamless loop return h('div', { className: 'prices-strip', 'aria-label': 'Live top coin prices' }, h('div', { className: 'prices-track' }, row.map(function (c, i) { return h('a', { key: i, className: 'price-chip', href: '#markets' }, h(CoinIcon, { coin: c, size: 22 }), h('span', { className: 'pc-sym' }, c.symbol), h('span', { className: 'pc-price' }, fmtPrice(c.current_price)), h(PriceChange, { value: c.price_change_percentage_24h || 0, size: 'sm' }) ); }) ) ); } window.PricesStrip = PricesStrip; // ---------- Calculator grid ---------- var CALCS = [ ['Profit calculator', 'Buy, sell, fees → exact P/L, ROI and returned value.', 'M3 17l5-5 4 4 8-9', 'calculators.html#profit', true], ['Converter', 'Coin ⇄ USD, EUR, GBP, INR and coin ⇄ coin at live rates.', 'M7 8h11l-3-3M17 16H6l3 3', 'calculators.html#converter', false], ['Staking calculator', 'APY, duration and compounding → rewards and final value.', 'M12 3v18M5 8l7-5 7 5', 'calculators.html#staking', false], ['DCA calculator', 'Recurring buys over time vs current value, plotted.', 'M4 19V5M4 19h16M8 15l3-4 3 2 4-6', 'calculators.html#dca', false], ['Liquidation price', 'Isolated-margin liquidation for any leverage.', 'M12 2v6M4.9 7l4.2 2.4M19.1 7l-4.2 2.4M2 15h20', 'calculators.html#liquidation', true], ['Position size', 'Risk a fixed % of your account per trade.', 'M4 12h16M12 4v16', 'calculators.html#position-size', false], ['Compound interest', 'Any frequency → growth table and chart.', 'M4 19V5M4 19h16M7 15l4-5 3 3 5-7', 'calculators.html#compound', false], ['US tax estimator', 'Estimate federal tax by holding period.', 'M9 7h6M9 11h6M9 15h4M6 3h12v18H6z', 'calculators.html#us-tax', false] ]; function CalculatorGrid() { return h('section', { className: 'section', id: 'calculators' }, h(SectionHead, { overline: 'Calculators', title: 'Twenty-plus tools. Zero signup.', sub: 'Every calculator runs instantly in your browser on live market data.' }), h('div', { className: 'calc-grid' }, CALCS.map(function (c, i) { return h(Card, { key: i, interactive: true, padding: 'lg', radius: 'lg', style: { display: 'flex', flexDirection: 'column', gap: '14px', minHeight: 168 }, onClick: function () { location.href = c[3]; } }, h('div', { className: 'calc-ico' }, h('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' }, h('path', { d: c[2] })) ), h('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } }, h('span', { className: 'calc-name' }, c[0]), c[4] ? h(Badge, { tone: 'brand' }, 'Popular') : null ), h('p', { className: 'calc-desc' }, c[1]), h('span', { className: 'calc-link' }, 'Open tool →') ); }) ), h('div', { style: { display: 'flex', justifyContent: 'center', marginTop: 28 } }, h(DS.Button, { variant: 'secondary', size: 'lg', pill: true, onClick: function () { location.href = 'calculators.html'; } }, 'View all 16 calculators →') ) ); } window.CalculatorGrid = CalculatorGrid; // ---------- Section head ---------- function SectionHead(props) { return h('div', { className: 'section-head' }, h('span', { className: 'overline' }, props.overline), h('h2', { className: 'section-title' }, props.title), props.sub ? h('p', { className: 'section-sub' }, props.sub) : null ); } window.SectionHead = SectionHead; // ---------- Fear & Greed gauge ---------- function FearGreed(props) { var d = props.data || { value: 64, label: 'Greed', live: false }; var v = Math.max(0, Math.min(100, d.value)); var CX = 110, CY = 118, R = 84, NEEDLE = 66; // value 0..100 -> angle 180deg (left) .. 0deg (right) across the TOP function P(val, r) { var th = (180 - val * 1.8) * Math.PI / 180; return [CX + r * Math.cos(th), CY - r * Math.sin(th)]; } function col(x) { if (x < 25) return 'var(--color-down)'; if (x < 45) return 'var(--amber-500)'; if (x < 55) return 'var(--amber-400)'; if (x < 75) return 'var(--green-400)'; return 'var(--color-up)'; } // arc band between two values, drawn over the top (sweep clockwise) function band(v0, v1) { var p0 = P(v0, R), p1 = P(v1, R); return 'M' + p0[0].toFixed(1) + ' ' + p0[1].toFixed(1) + ' A' + R + ' ' + R + ' 0 0 1 ' + p1[0].toFixed(1) + ' ' + p1[1].toFixed(1); } var segs = [[0, 20, 'var(--color-down)'], [20, 40, 'var(--amber-500)'], [40, 60, 'var(--amber-400)'], [60, 80, 'var(--green-400)'], [80, 100, 'var(--color-up)']]; var tip = P(v, NEEDLE); return h(Card, { padding: 'lg', radius: 'lg', style: { display: 'flex', flexDirection: 'column' } }, h('div', { className: 'fg-head' }, h('span', { className: 'overline' }, 'Fear & Greed index'), h(Badge, { tone: d.live ? 'success' : 'neutral' }, d.live ? 'LIVE' : 'SAMPLE') ), h('div', { className: 'fg-gauge' }, h('svg', { viewBox: '0 0 220 150', width: '100%' }, segs.map(function (s, i) { return h('path', { key: i, d: band(s[0], s[1]), stroke: s[2], strokeWidth: 15, fill: 'none', strokeLinecap: 'round', opacity: 0.9 }); }), h('line', { x1: CX, y1: CY, x2: tip[0].toFixed(1), y2: tip[1].toFixed(1), stroke: 'var(--text-strong)', strokeWidth: 3, strokeLinecap: 'round', style: { transition: 'all 900ms cubic-bezier(0.2,0,0,1)' } }), h('circle', { cx: CX, cy: CY, r: 6, fill: 'var(--text-strong)' }) ), h('div', { className: 'fg-readout' }, h('span', { className: 'fg-val', style: { color: col(v) } }, v), h('span', { className: 'fg-label' }, d.label) ) ), h('p', { className: 'fg-note' }, 'Aggregated market sentiment, 0 = extreme fear, 100 = extreme greed.') ); } window.FearGreed = FearGreed; // ---------- News list ---------- function NewsList(props) { var items = props.items || []; return h(Card, { padding: 'lg', radius: 'lg', style: { display: 'flex', flexDirection: 'column' } }, h('div', { className: 'fg-head', style: { marginBottom: 4 } }, h('span', { className: 'overline' }, 'Latest headlines'), h('a', { className: 'calc-link', href: '#news' }, 'All news →') ), h('ul', { className: 'news-list' }, items.map(function (n, i) { return h('li', { key: i }, h('a', { href: n.url, target: '_blank', rel: 'noopener noreferrer', className: 'news-item' }, h('span', { className: 'news-title' }, n.title), h('span', { className: 'news-meta' }, n.source + ' · ' + timeAgo(n.ts)) ) ); }) ) ); } window.NewsList = NewsList; // ---------- Ad slot (ad-ready, no visible placeholder) ---------- function AdSlot(props) { return h('div', { className: 'ad-slot ad-ready ' + (props.variant || ''), 'data-ad-slot': props.variant || 'inline', 'aria-hidden': 'true' }); } window.AdSlot = AdSlot; // ---------- Footer ---------- function Footer() { var cols = [ ['Tools', [['Profit calculator', 'calculators.html#profit'], ['Converter', 'converters.html'], ['Staking', 'calculators.html#staking'], ['DCA', 'calculators.html#dca'], ['Satoshi converter', 'converters.html']]], ['Data', [['Markets', 'watchlist.html'], ['Charts', 'charts.html'], ['Fear & Greed', 'charts.html#altseason'], ['Halving', 'charts.html#halving']]], ['Learn', [['Guides', 'learn.html'], ['Glossary', 'glossary.html'], ['FAQ', 'faq.html']]], ['Company', [['About', 'pages.html#about'], ['Contact', 'pages.html#contact'], ['Editorial policy', 'pages.html#editorial']]], ['Legal', [['Privacy policy', 'pages.html#privacy'], ['Terms', 'pages.html#terms'], ['Disclaimer', 'pages.html#disclaimer']]] ]; return h('footer', { className: 'site-footer' }, h('div', { className: 'footer-inner' }, h('div', { className: 'footer-brand' }, h('a', { className: 'wordmark', href: 'CryptoCalcy Homepage.html' }, 'CryptoCalcy'), h('p', { className: 'footer-tag' }, 'Free crypto calculators and live market data. You own it — we just do the math.'), h('p', { className: 'footer-attrib' }, 'Market data by CoinGecko · Sentiment by alternative.me') ), h('div', { className: 'footer-cols' }, cols.map(function (c, i) { return h('div', { key: i, className: 'footer-col' }, h('span', { className: 'footer-col-title' }, c[0]), c[1].map(function (l, j) { return h('a', { key: j, href: l[1] }, l[0]); }) ); }) ) ), h('div', { className: 'footer-bottom' }, h('span', {}, '© 2026 CryptoCalcy. All rights reserved.'), h('span', { className: 'footer-disc' }, 'Estimates for informational purposes only — not financial, investment or tax advice.') ) ); } window.Footer = Footer; // ---------- Cookie consent ---------- function CookieBanner() { var seen = false; try { seen = localStorage.getItem('ccy-consent'); } catch (e) {} var st = React.useState(!seen), show = st[0], setShow = st[1]; function set(v) { try { localStorage.setItem('ccy-consent', v); } catch (e) {} setShow(false); } if (!show) return null; return h('div', { className: 'cookie-banner', role: 'dialog', 'aria-label': 'Cookie consent' }, h('p', {}, 'We use cookies for analytics and to serve ads. See our ', h('a', { href: 'pages.html#privacy' }, 'Privacy Policy'), '. You can reject non-essential cookies.'), h('div', { className: 'cookie-actions' }, h(Button, { variant: 'ghost', size: 'sm', onClick: function () { set('reject'); } }, 'Reject'), h(Button, { variant: 'primary', size: 'sm', onClick: function () { set('accept'); } }, 'Accept all') ) ); } window.CookieBanner = CookieBanner; })();