import type { Meta, StoryObj } from '@storybook/react'; import { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartCard, DashboardBarChart, DashboardLineChart, HorizontalBarChart, InteractiveTimeSeriesChart, ComboMetricChart, DonutBreakdownChart, SparklineChart, RadarMetricChart, PieMetricChart, RadialBarMetricChart, GaugeChart, type ChartConfig, type GaugeChartThreshold, } from './chart'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, LineChart, Line } from 'recharts'; import { Card, CardHeader, CardTitle, CardContent } from '../card'; import React from 'react'; import { TrendingUp, TrendingDown, Minus } from 'lucide-react'; const meta: Meta = { title: 'UI/Chart', component: DashboardBarChart, render: args => , parameters: { layout: 'fullscreen', }, decorators: [ Story => (
), ], argTypes: { barSize: { control: 'select', options: ['sm', 'md', 'lg', 'xl'], description: 'Controls only the bar thickness.', }, stacked: { control: 'boolean' }, showGrid: { control: 'boolean' }, showLegend: { control: 'boolean' }, }, }; export default meta; type Story = StoryObj; // ─── Shared data ────────────────────────────────────────────────────────────── const data = [ { month: 'Jan', revenue: 4000, expenses: 2400 }, { month: 'Feb', revenue: 3000, expenses: 1398 }, { month: 'Mar', revenue: 6000, expenses: 3200 }, { month: 'Apr', revenue: 2780, expenses: 3908 }, { month: 'May', revenue: 1890, expenses: 4800 }, { month: 'Jun', revenue: 2390, expenses: 3800 }, ]; const chartConfig: ChartConfig = { revenue: { label: 'Revenue', color: 'var(--chart-1)' }, expenses: { label: 'Expenses', color: 'var(--chart-5)' }, }; const richChartConfig: ChartConfig = { revenue: { label: 'Revenue', color: 'var(--chart-1)' }, pipeline: { label: 'Pipeline', color: 'var(--chart-4)' }, conversion: { label: 'Conversion', color: 'var(--chart-2)' }, churn: { label: 'Churn', color: 'var(--chart-5)' }, }; const richData = [ { date: 'Apr 01', revenue: 4200, pipeline: 2600, conversion: 32, churn: 8 }, { date: 'Apr 08', revenue: 5200, pipeline: 3200, conversion: 38, churn: 7 }, { date: 'Apr 15', revenue: 6100, pipeline: 3900, conversion: 42, churn: 6 }, { date: 'Apr 22', revenue: 5600, pipeline: 4300, conversion: 41, churn: 9 }, { date: 'Apr 29', revenue: 7200, pipeline: 4700, conversion: 48, churn: 5 }, { date: 'May 06', revenue: 7900, pipeline: 5300, conversion: 52, churn: 4 }, { date: 'May 13', revenue: 8400, pipeline: 5800, conversion: 55, churn: 3 }, { date: 'May 20', revenue: 9100, pipeline: 6200, conversion: 58, churn: 4 }, ]; const breakdownConfig: ChartConfig = { enterprise: { label: 'Enterprise', color: 'var(--chart-1)' }, midmarket: { label: 'Mid-market', color: 'var(--chart-4)' }, startup: { label: 'Startup', color: 'var(--chart-2)' }, }; const breakdownData = [ { name: 'enterprise', value: 52 }, { name: 'midmarket', value: 31 }, { name: 'startup', value: 17 }, ]; // ─── Primitive stories ──────────────────────────────────────────────────────── export const BarChartExample: Story = { name: 'Primitive / Bar Chart', render: () => ( Monthly Performance } /> } /> ), }; export const LineChartExample: Story = { name: 'Primitive / Line Chart', render: () => ( Revenue Trends } /> ), }; // ─── Dashboard chart stories ────────────────────────────────────────────────── export const DashboardBarChartExample: Story = { name: 'Bar Chart', args: { data: richData, indexKey: 'date', config: richChartConfig, colors: { revenue: 'var(--chart-1)', pipeline: 'var(--chart-4)', }, barSize: 'lg', series: [ { key: 'revenue', stackId: 'money' }, { key: 'pipeline', stackId: 'money' }, ], stacked: true, }, render: args => ( ), }; export const DashboardLineChartExample: Story = { name: 'Line Chart', render: () => ( ), }; export const HorizontalBarChartExample: Story = { name: 'Horizontal Bar Chart', render: () => ( ), }; export const InteractiveTimeSeriesExample: Story = { name: 'Interactive Time Series', render: () => ( ), }; export const GradientAreaChartExample: Story = { name: 'Gradient Area Chart', render: () => ( ), }; export const ComboMetricChartExample: Story = { name: 'Combo Metric Chart', render: () => ( ), }; export const ComboWithGradientAreaExample: Story = { name: 'Combo Chart with Gradient Area', render: () => ( ), }; export const DonutBreakdownExample: Story = { name: 'Donut Chart', render: () => ( ), }; // ─── Sparkline stories ──────────────────────────────────────────────────────── const sparkData = [ { v: 12 }, { v: 18 }, { v: 14 }, { v: 22 }, { v: 19 }, { v: 28 }, { v: 24 }, { v: 31 }, { v: 27 }, { v: 35 }, ]; const sparkDataDown = [ { v: 35 }, { v: 30 }, { v: 28 }, { v: 22 }, { v: 25 }, { v: 18 }, { v: 20 }, { v: 14 }, { v: 12 }, { v: 8 }, ]; export const SparklineExample: Story = { name: 'Sparkline Chart', render: () => (

Sparklines are minimal inline charts designed for stat cards and table cells.

{/* Stat cards with sparklines */}

Revenue

$35.2K

+12%

Churn

8.4%

-3%

Pipeline

$128K

0%
{/* Sparkline variants */}
Filled (default)
Line only
Step curve
), }; // ─── Dashboard layout story ─────────────────────────────────────────────────── export const DashboardLayoutExample: Story = { name: 'Dashboard Layout', render: () => { const kpiData = [ { label: 'Total Revenue', value: '$128.4K', trend: '+18%', up: true, sparkData: sparkData, color: 'var(--chart-1)', }, { label: 'Active Pipeline', value: '$62.1K', trend: '+9%', up: true, sparkData: sparkData.map(d => ({ v: d.v * 0.7 })), color: 'var(--chart-4)', }, { label: 'Conversion Rate', value: '58%', trend: '+4%', up: true, sparkData: sparkData.map(d => ({ v: d.v * 0.5 })), color: 'var(--chart-2)', }, { label: 'Churn Rate', value: '3.2%', trend: '-1%', up: false, sparkData: sparkDataDown, color: 'var(--chart-5)', }, ]; return (
{/* KPI row */}
{kpiData.map(kpi => (

{kpi.label}

{kpi.value}

{kpi.up ? : } {kpi.trend}
))}
{/* Main charts row */}
{/* Bottom row */}
); }, }; // ─── State stories ──────────────────────────────────────────────────────────── export const EmptyStateExample: Story = { name: 'State / Empty', render: () => ( ), }; export const ConnectionErrorExample: Story = { name: 'State / Connection Error', render: () => ( undefined} /> ), }; export const LoadingStateExample: Story = { name: 'State / Loading', render: () => ( ), }; // ─── Variant stories ────────────────────────────────────────────────────────── export const BarSizeVariantsExample: Story = { name: 'Variants / Bar Sizes', render: () => (
), }; export const CurveTypeVariantsExample: Story = { name: 'Variants / Curve Types', render: () => (
{(['monotone', 'linear', 'step', 'natural', 'basis'] as const).map(curve => ( ))}
), }; export const ColorPaletteExample: Story = { name: 'Variants / Color Palette', render: () => { const paletteConfig: ChartConfig = { chart1: { label: 'chart-1 (indigo)', color: 'var(--chart-1)' }, chart2: { label: 'chart-2 (emerald)', color: 'var(--chart-2)' }, chart3: { label: 'chart-3 (amber)', color: 'var(--chart-3)' }, chart4: { label: 'chart-4 (blue)', color: 'var(--chart-4)' }, chart5: { label: 'chart-5 (red)', color: 'var(--chart-5)' }, chart6: { label: 'chart-6 (purple)', color: 'var(--chart-6)' }, chart7: { label: 'chart-7 (teal)', color: 'var(--chart-7)' }, chart8: { label: 'chart-8 (rose)', color: 'var(--chart-8)' }, }; const paletteData = [ { name: 'A', chart1: 80, chart2: 70, chart3: 60, chart4: 75, chart5: 55, chart6: 65, chart7: 72, chart8: 68, }, ]; return ( ); }, }; // ─── Radar Chart Stories ─────────────────────────────────────────────────────── const radarData = [ { skill: 'Performance', score: 88 }, { skill: 'Reliability', score: 72 }, { skill: 'Security', score: 95 }, { skill: 'Scalability', score: 65 }, { skill: 'Usability', score: 80 }, { skill: 'Maintainability', score: 58 }, ]; const radarMultiData = [ { skill: 'Performance', teamA: 88, teamB: 62 }, { skill: 'Reliability', teamA: 72, teamB: 85 }, { skill: 'Security', teamA: 95, teamB: 70 }, { skill: 'Scalability', teamA: 65, teamB: 90 }, { skill: 'Usability', teamA: 80, teamB: 55 }, { skill: 'Maintainability', teamA: 58, teamB: 78 }, ]; export const RadarChartFilled: Story = { name: 'Radar Chart / Filled', render: () => ( ), }; export const RadarChartOutline: Story = { name: 'Radar Chart / Outline', render: () => ( ), }; export const RadarChartMultiSeries: Story = { name: 'Radar Chart / Multi-Series', render: () => ( ), }; export const RadarChartVariants: Story = { name: 'Radar Chart / All Variants', render: () => (
), }; // ─── Pie Chart Stories ──────────────────────────────────────────────────────── const pieData = [ { category: 'Infrastructure', spend: 42000 }, { category: 'Engineering', spend: 31000 }, { category: 'Marketing', spend: 18500 }, { category: 'Operations', spend: 12000 }, { category: 'Other', spend: 6500 }, ]; export const PieChartSimple: Story = { name: 'Pie Chart / Simple', render: () => ( `$${(v as number).toLocaleString()}`} /> ), }; export const PieChartWithLabels: Story = { name: 'Pie Chart / With Labels', render: () => ( `$${(v as number).toLocaleString()}`} /> ), }; export const PieChartExploded: Story = { name: 'Pie Chart / Exploded Slice', render: () => ( `$${(v as number).toLocaleString()}`} /> ), }; export const PieChartDonutVariant: Story = { name: 'Pie Chart / Donut Variant', render: () => ( `$${(v as number).toLocaleString()}`} /> ), }; export const PieChartVariants: Story = { name: 'Pie Chart / All Variants', render: () => (
), }; // ─── Radial Bar Chart Stories ───────────────────────────────────────────────── const radialData = [ { name: 'Infrastructure', value: 78 }, { name: 'Engineering', value: 62 }, { name: 'Marketing', value: 45 }, { name: 'Operations', value: 91 }, ]; export const RadialBarChartSingle: Story = { name: 'Radial Bar / Single Bar', render: () => ( `${v}%`} /> ), }; export const RadialBarChartMulti: Story = { name: 'Radial Bar / Multi-Bar', render: () => ( `${v}%`} /> ), }; export const RadialBarChartSemiCircle: Story = { name: 'Radial Bar / Semi-Circle', render: () => ( `${v}%`} /> ), }; export const RadialBarChartVariants: Story = { name: 'Radial Bar / All Variants', render: () => (
`${v}%`} /> `${v}%`} /> `${v}%`} />
), }; // ─── Gauge Chart Stories ────────────────────────────────────────────────────── const gaugeThresholds: GaugeChartThreshold[] = [ { value: 33, color: 'var(--chart-5)', label: 'Critical' }, { value: 66, color: 'var(--chart-3)', label: 'Warning' }, { value: 100, color: 'var(--chart-2)', label: 'Healthy' }, ]; export const GaugeChartSimple: Story = { name: 'Gauge Chart / Simple', render: () => (
), }; export const GaugeChartWithThresholds: Story = { name: 'Gauge Chart / With Thresholds', render: () => (
), }; export const GaugeChartNoNeedle: Story = { name: 'Gauge Chart / No Needle', render: () => (
), }; export const GaugeChartVariants: Story = { name: 'Gauge Chart / All Variants', render: () => (
), }; export const GaugeChartDashboard: Story = { name: 'Gauge Chart / Infrastructure Dashboard', render: () => { const metrics = [ { label: 'CPU', value: 34, unit: '%' }, { label: 'Memory', value: 71, unit: '%' }, { label: 'Disk', value: 58, unit: '%' }, { label: 'Network', value: 22, unit: '%' }, ]; return (
{metrics.map(m => (
`${v}${m.unit}`} />
))}
); }, }; // ─── Complete Chart Library Overview ───────────────────────────────────────── export const CompleteLibraryOverview: Story = { name: 'Complete Library / All Chart Types', render: () => (
{/* Bar */} {/* Line */} {/* Donut */} {/* Radar */} {/* Pie */} {/* Radial Bar */} `${v}%`} />
{/* Gauge row */}
{[ { label: 'CPU', value: 34 }, { label: 'Memory', value: 71 }, { label: 'Disk', value: 58 }, ].map(m => (
))}
), };