// Shared utility components used across variations (() => { const { useState, useEffect, useMemo, useRef } = React; // Sparkline / line chart function LineChart({ data, width = 400, height = 120, lines, yPad = 8, showAxis = true, bg = 'transparent', grid = true }) { const all = lines.flatMap(l => data.map(d => d[l.key])); const min = Math.min(...all); const max = Math.max(...all); const range = max - min || 1; const x = i => (i / (data.length - 1)) * (width - 30) + 25; const y = v => height - yPad - ((v - min) / range) * (height - yPad * 2); return ( {grid && [0.25, 0.5, 0.75].map(p => ( ))} {lines.map(line => { const d = data.map((pt, i) => `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(pt[line.key])}`).join(' '); return ( {line.fill && ( )} ); })} ); } // Small blinking dot function BlinkDot({ color = '#22c55e', size = 6 }) { return ( ); } // Progress bar function Bar({ value, max, color = 'currentColor', height = 4, bg = 'currentColor', bgOp = 0.1 }) { const pct = Math.max(0, Math.min(1, value / max)); return (
); } // Number formatting const fmt = { usd: n => (n < 0 ? '-$' : '$') + Math.abs(n).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }), pct: n => (n >= 0 ? '+' : '') + (n * 100).toFixed(2) + '%', pct1: n => (n >= 0 ? '+' : '') + n.toFixed(2) + '%', compact: n => n >= 1000 ? '$' + (n / 1000).toFixed(1) + 'k' : '$' + n.toFixed(0), }; // Hook: ticker (updates "now" every second) function useNow(interval = 1000) { const [t, setT] = useState(new Date('2026-04-22T15:32:00')); useEffect(() => { const id = setInterval(() => setT(prev => new Date(prev.getTime() + 1000)), interval); return () => clearInterval(id); }, [interval]); return t; } const clockStr = d => d.toTimeString().slice(0, 8); const dateStr = d => d.toISOString().slice(0, 10); Object.assign(window, { LineChart, BlinkDot, Bar, fmt, useNow, clockStr, dateStr }); })();