WFDASH-WEBAPP/src/components/charts/sparkline.tsx
SJCoetz bb4233a9f2 feat(dashboard): add multi-theme system and supporting improvements
Add complete multi-theme dashboard system including:
- 8 selectable themes with persistent per-browser preferences
- Theme bootstrap script to prevent FOUC on page load
- 12+ reusable chart components (area, bar, donut, radial gauge, etc)
- Custom checkbox UI component
- New settings page for appearance customization

Other changes:
- Optimize supplier map API payload with getMappableSuppliers helper
- Add aria-label attributes to back buttons on detail pages for better accessibility
- Update next.config.ts to include new local development IP 192.168.1.128
- Update site manifest with all new favicon and PWA assets
- Fix styling and layout spacing in rewrite quote modal
2026-06-26 17:59:40 +02:00

58 lines
1.7 KiB
TypeScript

"use client";
/**
* Sparkline — tiny inline-SVG line chart for KPI cards.
* Includes gradient fill below the line + endpoint dot.
*/
export function Sparkline({
values,
color,
width = 96,
height = 36,
}: {
values: number[];
color: string;
width?: number;
height?: number;
}) {
if (values.length === 0) {
return <div style={{ width, height }} aria-hidden />;
}
const max = Math.max(...values, 1);
const min = Math.min(...values, 0);
const range = max - min || 1;
const step = values.length > 1 ? width / (values.length - 1) : width;
const points = values
.map((v, i) => {
const x = i * step;
const y = height - ((v - min) / range) * height;
return `${x.toFixed(2)},${y.toFixed(2)}`;
})
.join(" ");
const areaPoints = `0,${height} ${points} ${width},${height}`;
const id = `spark-${color.replace("#", "")}-${Math.round(width)}`;
const last = values[values.length - 1];
const lastX = (values.length - 1) * step;
const lastY = height - ((last - min) / range) * height;
return (
<svg width={width} height={height} className="overflow-visible shrink-0">
<defs>
<linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor={color} stopOpacity={0.45} />
<stop offset="100%" stopColor={color} stopOpacity={0} />
</linearGradient>
</defs>
<polygon points={areaPoints} fill={`url(#${id})`} />
<polyline
points={points}
fill="none"
stroke={color}
strokeWidth={2}
strokeLinejoin="round"
strokeLinecap="round"
/>
<circle cx={lastX} cy={lastY} r={3.5} fill={color} />
<circle cx={lastX} cy={lastY} r={6} fill={color} fillOpacity={0.25} />
</svg>
);
}