"use client"; import * as React from "react"; import { cn } from "./lib/utils"; export interface AreaChartDataItem { id: string; label: string; color?: string; data: number[]; } export interface AreaChartProps extends React.HTMLAttributes { series: AreaChartDataItem[]; labels?: string[]; height?: number; } const SERIES_TONES = ["text-accent", "text-foreground", "text-muted-foreground"]; const TOKEN_TONES: Record = { accent: "text-accent", foreground: "text-foreground", muted: "text-muted-foreground", destructive: "text-destructive", primary: "text-primary", }; export function AreaChart({ series, labels, height = 300, className, ...props }: AreaChartProps) { const [hoveredIndex, setHoveredIndex] = React.useState(null); const max = Math.max(...series.flatMap((s) => s.data), 1); const y = (val: number) => 90 - (val / max) * 70; if (series.length === 0) { return
; } return (
{/* Background grid lines (dashed) */} {Array.from({ length: 5 }, (_, i) => ( ))} {/* X axis labels */} {labels?.map((label, i) => { const n = Math.max(labels.length - 1, 1); return ( {label} ); })} {/* Area paths */} {series.map((s, si) => { const n = Math.max(s.data.length - 1, 1); const points = s.data.map((val, i) => `${5 + (i / n) * 90},${y(val)}`); const closedPath = [`M5,90`, ...points, `L95,90 Z`]; const toneClass = s.color ? (TOKEN_TONES[s.color] ?? undefined) : SERIES_TONES[si % SERIES_TONES.length]; return ( setHoveredIndex(si)} onMouseLeave={() => setHoveredIndex(null)} className={cn(toneClass)} style={s.color && !toneClass ? { color: s.color } : undefined} > {s.data.map((val, i) => ( {`${s.label}: ${val}`} ))} ); })}
); }