spb/market-atlas
Public
TypeScript 96.7%
SQL 1.6%
CSS 0.8%
JavaScript 0.5%
1import { cx } from "@/lib/format";23/** Inline SVG sparkline (no library). Colour follows the sign of the series unless `stroke` is given. */4export function Sparkline({ values, width = 96, height = 28, className, stroke, fill = true }: { values: number[]; width?: number; height?: number; className?: string; stroke?: string; fill?: boolean }) {5 const pts = values.filter((v) => Number.isFinite(v));6 if (pts.length < 2) return <svg width={width} height={height} className={className} aria-hidden="true" />;7 const min = Math.min(...pts);8 const max = Math.max(...pts);9 const span = max - min || 1;10 const step = width / (pts.length - 1);11 const coords = pts.map((v, i) => [i * step, height - 2 - ((v - min) / span) * (height - 4)] as const);12 const d = coords.map(([x, y], i) => `${i ? "L" : "M"}${x.toFixed(1)},${y.toFixed(1)}`).join(" ");13 const up = pts[pts.length - 1]! >= pts[0]!;14 const color = stroke ?? (up ? "var(--positive)" : "var(--negative)");15 return (16 <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} className={cx("overflow-visible", className)} aria-hidden="true">17 {fill && <path d={`${d} L${width},${height} L0,${height} Z`} fill={color} opacity="0.12" />}18 <path d={d} fill="none" stroke={color} strokeWidth="1.4" strokeLinejoin="round" strokeLinecap="round" />19 </svg>20 );21}22