43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
"use client";
|
|
|
|
import { ResponsiveContainer, AreaChart, Area } from "recharts";
|
|
|
|
type Props = {
|
|
data: (number | null)[];
|
|
color: string;
|
|
height?: number;
|
|
};
|
|
|
|
export function Sparkline({ data, color, height = 36 }: Props) {
|
|
const points = data.map((v, i) => ({ i, v: v ?? 0 }));
|
|
const max = Math.max(0.001, ...data.filter((v): v is number => v != null));
|
|
// Pad values: if all 0, draw a flat line at 0 for visual presence
|
|
const flat = data.every((v) => !v);
|
|
const displayData = flat ? points.map((p) => ({ ...p, v: 1 })) : points;
|
|
const displayMax = flat ? 1 : max;
|
|
|
|
return (
|
|
<div style={{ width: 120, height }} className="shrink-0">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<AreaChart data={displayData} margin={{ top: 2, right: 2, left: 2, bottom: 2 }}>
|
|
<defs>
|
|
<linearGradient id={`spark-${color.replace("#", "")}`} x1="0" y1="0" x2="0" y2="1">
|
|
<stop offset="0%" stopColor={color} stopOpacity={0.4} />
|
|
<stop offset="100%" stopColor={color} stopOpacity={0.02} />
|
|
</linearGradient>
|
|
</defs>
|
|
<Area
|
|
type="monotone"
|
|
dataKey="v"
|
|
stroke={color}
|
|
strokeWidth={1.5}
|
|
fill={`url(#spark-${color.replace("#", "")})`}
|
|
isAnimationActive={false}
|
|
baseValue={0}
|
|
/>
|
|
</AreaChart>
|
|
</ResponsiveContainer>
|
|
<div className="hidden">{displayMax}</div>
|
|
</div>
|
|
);
|
|
}
|