SPB Git forge

spb/market-atlas

Public
12commits 1branches 0releases
1.1 MBsize
maindefault branch
10 days agolast push
TypeScript 96.7% SQL 1.6% CSS 0.8% JavaScript 0.5%
1.3 KB · 22 lines tsx
Raw Blame History
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