/* ═══════════════════════════════════════════════════════════════════ logos.jsx — real coin logos with graceful letter-glyph fallback Load AFTER the page's CoinGlyph is defined: this wraps it. Coins the icon CDN doesn't know simply keep their colored letter glyph. ═══════════════════════════════════════════════════════════════════ */ /* ── Accent theme (set on the Settings page) — applied on EVERY page since they all load this file. Overrides the --amber CSS vars site-wide. ── */ (function () { window.ST_ACCENTS = { amber: { c: '#F7A600', dim: 'rgba(247,166,0,0.10)', line: 'rgba(247,166,0,0.22)' }, teal: { c: '#2BD4C0', dim: 'rgba(43,212,192,0.10)', line: 'rgba(43,212,192,0.24)' }, violet: { c: '#B68CFF', dim: 'rgba(182,140,255,0.10)',line: 'rgba(182,140,255,0.24)' }, blue: { c: '#6EA8FF', dim: 'rgba(110,168,255,0.10)',line: 'rgba(110,168,255,0.24)' }, green: { c: '#2EE49B', dim: 'rgba(46,228,155,0.10)', line: 'rgba(46,228,155,0.24)' }, }; /* paint the CSS vars only — no persistence (used by the server-fallback path) */ const _paintAccent = (name) => { const a = window.ST_ACCENTS[name] || window.ST_ACCENTS.amber; const r = document.documentElement.style; r.setProperty('--amber', a.c); r.setProperty('--amber-dim', a.dim); r.setProperty('--amber-line', a.line); }; /* the picker: paint AND remember this device's choice (instant, no flash) */ window.ST_applyAccent = (name) => { _paintAccent(name); try { localStorage.setItem('st_accent', name); } catch (e) {} }; /* Accent resolution on load: 1. this device's saved choice wins (instant, survives offline) 2. otherwise fall back to the account-level choice on the server, so the accent follows Nizam onto a fresh browser / another device. We DON'T persist the server value — localStorage stays empty so the server remains the source of truth until a deliberate pick on this device. */ try { const saved = localStorage.getItem('st_accent'); if (saved) { if (saved !== 'amber') _paintAccent(saved); } else { const api = window.ST_API || ((location.hostname === 'localhost' || location.hostname === '127.0.0.1') ? 'http://127.0.0.1:8000/api' : location.origin + '/api'); fetch(api + '/settings') .then(r => (r.ok ? r.json() : null)) .then(s => { const a = s && s.theme_accent; if (a && a !== 'amber' && window.ST_ACCENTS[a]) _paintAccent(a); }) .catch(() => {}); } } catch (e) {} })(); (function () { /* coincap uses lowercase symbols; a few of ours need mapping; null = no icon exists upstream (fallback renders) */ const OVERRIDES = { POL: 'matic', POPCAT: null, HYPE: null, SPX: null }; window.ST_LOGO_URL = (sym) => { if (!sym) return null; const key = (sym in OVERRIDES) ? OVERRIDES[sym] : sym.toLowerCase(); return key ? `https://assets.coincap.io/assets/icons/${key}@2x.png` : null; }; const LetterGlyph = window.CoinGlyph || null; function CoinLogo({ sym, size = 32 }) { const [err, setErr] = React.useState(false); const url = window.ST_LOGO_URL(sym); if (err || !url) { return LetterGlyph ? : {(sym || '?')[0]}; } return ( {sym} setErr(true)} style={{ borderRadius: '50%', display: 'block', flexShrink: 0, background: 'rgba(255,255,255,0.04)' }} /> ); } window.CoinLogo = CoinLogo; if (LetterGlyph) window.CoinGlyph = CoinLogo; /* drop-in upgrade site-wide */ })();