"use client"; import { type MouseEvent, useId, useState } from "react"; import { cn } from "@/lib/utils"; // A tiny dependency-free trend chart: a line with a soft shaded fill beneath it. // Stretches to its container width; colored via `currentColor` (default text-primary). // Moving the cursor over it reveals the value at the nearest reading. export function Sparkline({ points, unit, className, }: { points: number[]; unit?: string; className?: string; }) { const gradientId = useId(); const [active, setActive] = useState(null); if (points.length === 0) { return null; } const width = 100; const top = 3; const bottom = 29; const viewHeight = 32; const min = Math.min(...points); const max = Math.max(...points); const range = max - min; const coords = points.map((value, index) => { const x = points.length === 1 ? width / 2 : (index / (points.length - 1)) * width; const y = range === 0 ? (top + bottom) / 2 : bottom - ((value - min) / range) * (bottom - top); return { value, x, y, xPct: x, yPct: (y / viewHeight) * 100 }; }); const line = coords .map((c, i) => `${i === 0 ? "M" : "L"}${c.x.toFixed(2)},${c.y.toFixed(2)}`) .join(" "); const area = `${line} L${width},${viewHeight} L0,${viewHeight} Z`; const handleMove = (event: MouseEvent) => { const rect = event.currentTarget.getBoundingClientRect(); const ratio = (event.clientX - rect.left) / rect.width; const index = Math.round(ratio * (points.length - 1)); setActive(Math.max(0, Math.min(points.length - 1, index))); }; const point = active === null ? null : coords[active]; return (
setActive(null)} onMouseMove={handleMove} > {point && ( <> {point.value} {unit ? ( {unit} ) : null} )}
); }