/* FinPulse shared components + formatters. Exports to window. */ // ---- formatters ---- const fmt = { price: (n) => n.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }), pct: (n) => (n > 0 ? '+' : '') + n.toFixed(2) + '%', signed: (n) => (n > 0 ? '+' : '') + n.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }), mcap: (cr) => { if (cr >= 100000) return '₹' + (cr / 100000).toFixed(2) + 'L Cr'; if (cr >= 1000) return '₹' + (cr / 1000).toFixed(1) + 'K Cr'; return '₹' + cr.toFixed(0) + ' Cr'; }, usMcap: (m) => { if (!m || m <= 0) return '—'; if (m >= 1e6) return '$' + (m / 1e6).toFixed(2) + 'T'; if (m >= 1e3) return '$' + (m / 1e3).toFixed(1) + 'B'; return '$' + m.toFixed(0) + 'M'; }, stockMcap: (s) => ((s && s.live && s.cur === 'USD') ? fmt.usMcap(s.mcap) : fmt.mcap(s.mcap)), stockPrice: (s) => { const c = s && s.live ? window.FinnhubMappers.curSym(s.cur) : '$'; return c + fmt.price(s.price); }, vol: (lakh) => lakh.toFixed(1) + 'L', idx: (n) => n.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }), }; // ---- change chip ---- function ChangeChip({ value, sm, showArrow = true }) { const up = value >= 0; return ( {showArrow && {up ? '▲' : '▼'}} {fmt.pct(value)} ); } // ---- stock avatar ---- function StockAvatar({ stock, size = 36 }) { return (
{stock.initials}
); } // ---- index tile ---- function IndexTile({ ix, selected, onClick }) { const up = ix.chg >= 0; const sym = ix.cur === 'INR' ? '₹' : (ix.cur === 'USD' ? '$' : ''); const Tag = onClick ? 'button' : 'div'; return (
{ix.label}
{sym}{fmt.idx(ix.value)} {fmt.pct(ix.chg)}
); } // ---- stock quote card ---- function StockQuoteCard({ stock, onOpen }) { return (
onOpen && onOpen(stock)} style={{ cursor: onOpen ? 'pointer' : 'default' }}>
{stock.name}
{stock.ticker}
{fmt.stockPrice(stock)}
); } // ---- metric card ---- function MetricCard({ label, value, sub, color = 'var(--accent)' }) { return (
{label}
{value}
{sub &&
{sub}
}
); } // ---- category pill ---- function CatPill({ cat, color }) { return {cat}; } // ---- news image: real photo when available, striped placeholder otherwise ---- function NewsImg({ seed, className, h, src }) { const [failed, setFailed] = useState(false); if (src && !failed) { return setFailed(true)} />; } const hue = (seed * 47) % 360; return (
news photo
); } function newsOpenProps(item, onOpen) { if (!onOpen) return {}; return { role: 'button', tabIndex: 0, onClick: () => onOpen(item), onKeyDown: (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onOpen(item); } }, style: { cursor: 'pointer' }, }; } // ---- featured news ---- function NewsFeatured({ item, onOpen }) { return (
{item.source}
{item.headline}
{item.summary &&
{(window.HtmlText ? window.HtmlText.stripHtml(item.summary) : item.summary)}
}
{item.author}·{item.time}·{item.read} read {item.sentiment === 'bull' ? 'Bullish' : 'Bearish'}
); } // ---- standard news card ---- function NewsStandard({ item, onOpen }) { return (
{item.source}
{item.headline}
{item.time}
); } // ---- compact news row ---- function NewsCompact({ items, onOpen }) { return (
{items.map((n) => (
{n.headline} {n.time}
))}
); } // ---- empty state ---- function EmptyState({ icon, title, sub, action }) { return (
{title}
{sub}
{action &&
{action}
}
); } Object.assign(window, { fmt, ChangeChip, StockAvatar, IndexTile, StockQuoteCard, MetricCard, CatPill, NewsImg, NewsFeatured, NewsStandard, NewsCompact, EmptyState });