import * as React from "react"; import { cn } from "@/lib/utils"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; export interface ChartTableView { columns: string[]; rows: Array>; } /** * Card wrapper for a chart: title, description, optional right slot, an "empty" overlay when * there is no data, and a collapsible table twin so every value is reachable without hover. * Server-compatible (no client hooks) so pages can pass client charts as children. */ export function ChartFrame({ title, description, right, empty, emptyMessage = "No data for this period yet.", table, children, className, contentClassName, }: { title: React.ReactNode; description?: React.ReactNode; right?: React.ReactNode; empty?: boolean; emptyMessage?: React.ReactNode; table?: ChartTableView; children: React.ReactNode; className?: string; contentClassName?: string; }) { return (
{title} {description ? {description} : null}
{right ?
{right}
: null}
{children}
{empty ? (

{emptyMessage}

) : null}
{table && !empty && table.rows.length > 0 ? (
View as table Hide table
{table.columns.map((c, i) => ( ))} {table.rows.map((r, i) => ( {r.map((v, j) => ( ))} ))}
0 && "text-right")}> {c}
0 ? "text-right font-mono" : "text-fg-muted")}> {v}
) : null}
); } /** Text legend rendered in HTML (outside the SVG) so it is readable and selectable. */ export function ChartLegend({ items, className }: { items: Array<{ label: string; color: string; value?: React.ReactNode; dashed?: boolean }>; className?: string }) { return ( ); }