{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "metric-card", "title": "Metric Card", "description": "The dashboard tile: category mark, action, label and number. Stack, ledger and billboard layouts across glass, solid and ink materials.", "dependencies": [ "class-variance-authority", "lucide-react" ], "registryDependencies": [ "http://localhost:5173/r/liquid-theme.json", "http://localhost:5173/r/glass-surface.json", "http://localhost:5173/r/action-orb.json", "http://localhost:5173/r/icon-ring.json", "http://localhost:5173/r/stat-value.json" ], "files": [ { "path": "src/components/ui/metric-card.tsx", "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ActionOrb } from \"@/components/ui/action-orb\"\nimport { GlassSurface, type Corner } from \"@/components/ui/glass-surface\"\nimport { IconRing } from \"@/components/ui/icon-ring\"\nimport { StatValue } from \"@/components/ui/stat-value\"\n\n/**\n * Every tile in the reference dashboard is the same four parts in a different\n * arrangement: a category mark, an action, a label, and a number. The layout\n * variant chooses the arrangement; it does not change what a tile *is*.\n */\nconst card = cva(\"flex flex-col\", {\n variants: {\n layout: {\n /** Icon row, label, then the number with its glyph beside it. */\n stack: \"gap-0\",\n /** Icon row, then a single baseline: label left, number right. */\n ledger: \"gap-0\",\n /** Label at the top, number at the bottom-left, aux at bottom-right. */\n billboard: \"gap-0\",\n },\n density: {\n compact: \"p-4 gap-3\",\n normal: \"p-5 gap-5\",\n roomy: \"p-6 gap-7\",\n },\n },\n defaultVariants: { layout: \"stack\", density: \"normal\" },\n})\n\nexport interface MetricCardProps\n extends Omit, \"prefix\">,\n VariantProps {\n material?: \"glass\" | \"solid\" | \"ink\"\n corner?: Corner | (string & {})\n tint?: string\n interactive?: boolean\n\n /** Category mark, wrapped in an IconRing unless `iconRing` is false. */\n icon?: React.ReactNode\n iconRing?: boolean\n iconVariant?: React.ComponentProps[\"variant\"]\n badge?: React.ComponentProps[\"badge\"]\n\n /** Top-right action. Pass `false` for tiles that are not links. */\n action?: React.ReactNode | false\n actionVariant?: React.ComponentProps[\"variant\"]\n actionLabel?: string\n\n /** Small caps line above the label — `GLUCOSE · Active`. */\n eyebrow?: React.ReactNode\n label?: React.ReactNode\n\n value?: number | string\n unit?: React.ReactNode\n prefix?: React.ReactNode\n emphasis?: React.ComponentProps[\"emphasis\"]\n unitAlign?: React.ComponentProps[\"unitAlign\"]\n valueSize?: React.ComponentProps[\"size\"]\n\n /** A micro-chart set beside the number. */\n chart?: React.ReactNode\n /** A richer companion — a ring, a dial — in place of `chart`. */\n aux?: React.ReactNode\n /** Full-width block below everything: a trend line, a legend, a note. */\n footer?: React.ReactNode\n}\n\nexport function MetricCard({\n layout = \"stack\",\n density,\n material = \"solid\",\n corner = \"lg\",\n tint,\n interactive,\n icon,\n iconRing = true,\n iconVariant,\n badge,\n action,\n actionVariant,\n actionLabel,\n eyebrow,\n label,\n value,\n unit,\n prefix,\n emphasis,\n unitAlign,\n valueSize = \"lg\",\n chart,\n aux,\n footer,\n className,\n children,\n ...props\n}: MetricCardProps) {\n const defaultActionVariant =\n actionVariant ?? (material === \"solid\" ? \"ink\" : \"chalk\")\n const defaultIconVariant =\n iconVariant ?? (material === \"ink\" ? \"muted\" : \"hairline\")\n\n const head =\n icon || action !== false ? (\n
\n {icon ? (\n iconRing ? (\n \n {icon}\n \n ) : (\n {icon}\n )\n ) : (\n \n )}\n {action === false ? null : action !== undefined ? (\n action\n ) : (\n \n )}\n
\n ) : null\n\n const heading =\n eyebrow || label ? (\n
\n {eyebrow ? (\n \n {eyebrow}\n \n ) : null}\n {label ? (\n \n {label}\n \n ) : null}\n
\n ) : null\n\n const stat =\n value !== undefined ? (\n \n ) : null\n\n const glyph = aux ?? chart\n\n return (\n \n {head}\n\n {layout === \"ledger\" ? (\n <>\n {heading ?
{heading}
: null}\n
\n {heading ? null : }\n {stat}\n {glyph ?
{glyph}
: null}\n
\n \n ) : layout === \"billboard\" ? (\n <>\n
\n {heading}\n {glyph ?
{glyph}
: null}\n
\n {stat ?
{stat}
: null}\n \n ) : (\n <>\n {heading}\n
\n {stat}\n {glyph ?
{glyph}
: null}\n
\n \n )}\n\n {children}\n {footer ?
{footer}
: null}\n \n )\n}\n\n/**\n * The ledger pair from the reference — Net Worth beside Total Dept. Exposed\n * because two ledger tiles share a baseline, and getting that alignment right\n * is the whole reason the layout exists.\n */\nexport function MetricPair({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n \n )\n}\n", "type": "registry:ui" } ], "type": "registry:ui" }