import * as React from 'react' import { cn } from '@/lib/utils' export type BarChartVariant = 'DEFAULT' | 'ACTIVE' | 'WARNING' | 'CRITICAL' export interface BarChartEntry { label: string value: number } export interface BarChartProps extends React.HTMLAttributes { data: BarChartEntry[] orientation?: 'horizontal' | 'vertical' variant?: BarChartVariant title?: string showValues?: boolean /** Override the max value for scaling. Defaults to max(data). */ max?: number } const VERTICAL_CHART_HEIGHT = 144 // px — 9rem const BarChart = React.forwardRef( ( { className, data, orientation = 'horizontal', variant = 'ACTIVE', title, showValues = true, max, style, ...props }, ref ) => { const computedMax = max ?? Math.max(...data.map((d) => d.value), 1) const accentColor = variant === 'ACTIVE' ? 'var(--color-green)' : variant === 'WARNING' ? 'var(--color-amber)' : variant === 'CRITICAL' ? 'var(--color-red)' : 'var(--text-secondary)' const accentGlow = variant === 'ACTIVE' ? 'var(--glow-green)' : variant === 'WARNING' ? 'var(--glow-amber)' : variant === 'CRITICAL' ? 'var(--glow-red)' : 'none' return (
{/* Title bar */} {title && (
{title}
)} {orientation === 'horizontal' ? ( /* ── Horizontal bars ── */
{data.map((entry, i) => { const pct = Math.max((entry.value / computedMax) * 100, 0) return (
{/* Label */} {entry.label} {/* Track */}
{/* Value */} {showValues && ( {entry.value} )}
) })}
) : ( /* ── Vertical bars ── */
{/* Bar area */}
{data.map((entry, i) => { const pct = Math.max((entry.value / computedMax) * 100, 0) const barPx = Math.round((pct / 100) * VERTICAL_CHART_HEIGHT) return (
{/* Value above bar */} {showValues && ( {entry.value} )} {/* Bar */}
0 ? barPx : 0, minHeight: entry.value > 0 ? 2 : 0, background: accentColor, boxShadow: accentGlow, opacity: 0.85, flexShrink: 0, transition: 'height 0.4s ease', }} />
) })}
{/* Labels row */}
{data.map((entry, i) => (
{entry.label}
))}
)}
) } ) BarChart.displayName = 'BarChart' export { BarChart }