{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "widget", "title": "Widget", "description": "A widget component for displaying statistics", "files": [ { "path": "registry/cs/ui/widget/widget.tsx", "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport type { CsBtnColor, CsIcon } from \"@/registry/cs/ui/button/button\"\nimport type { CsCardColor } from \"@/registry/cs/ui/card/card\"\n\n/** Widget sizes matching CS design system. */\nconst WIDGET_SIZE_MAP = {\n xs: { gap: \"gap-2\", padding: \"p-2\", icon: \"size-[18px]\", title: \"text-sm\", desc: \"text-xs\" },\n sm: { gap: \"gap-2\", padding: \"p-3\", icon: \"size-[24px]\", title: \"text-sm\", desc: \"text-sm\" },\n md: { gap: \"gap-3\", padding: \"p-4\", icon: \"size-[40px]\", title: \"text-base\", desc: \"text-sm\" },\n md2: { gap: \"gap-4\", padding: \"p-5\", icon: \"size-[48px]\", title: \"text-lg\", desc: \"text-sm\" },\n lg: { gap: \"gap-4\", padding: \"p-6\", icon: \"size-[80px]\", title: \"text-xl font-bold\", desc: \"text-base\" },\n}\n\nconst WIDGET_VARIANT_MAP = {\n default: \"bg-card text-card-foreground border\",\n filled: \"\",\n colorful: \"\",\n white: \"bg-white text-foreground border\",\n}\n\nconst WIDGET_COLOR_BG: Record = {\n primary: \"bg-cs-primary/10\",\n secondary: \"bg-cs-secondary/10\",\n grey: \"bg-cs-grey/10\",\n dark: \"bg-cs-dark/10\",\n red: \"bg-cs-red/10\",\n blue: \"bg-cs-blue/10\",\n green: \"bg-cs-green/10\",\n yellow: \"bg-cs-yellow/10\",\n orange: \"bg-cs-orange/10\",\n white: \"bg-white\",\n light: \"bg-cs-grey-light\",\n}\n\nconst WIDGET_COLOR_FILLED: Record = {\n primary: \"bg-cs-primary text-cs-primary-text\",\n secondary: \"bg-cs-secondary text-cs-secondary-text\",\n grey: \"bg-cs-grey text-cs-grey-text\",\n dark: \"bg-cs-dark text-cs-dark-text\",\n red: \"bg-cs-red text-cs-red-text\",\n blue: \"bg-cs-blue text-cs-blue-text\",\n green: \"bg-cs-green text-cs-green-text\",\n yellow: \"bg-cs-yellow text-cs-yellow-text\",\n orange: \"bg-cs-orange text-cs-orange-text\",\n white: \"bg-white text-foreground\",\n light: \"bg-cs-grey-light text-foreground\",\n}\n\nconst WIDGET_ICON_COLOR: Record = {\n primary: \"text-cs-primary\",\n secondary: \"text-cs-secondary\",\n grey: \"text-cs-grey\",\n dark: \"text-cs-dark\",\n red: \"text-cs-red\",\n blue: \"text-cs-blue\",\n green: \"text-cs-green\",\n yellow: \"text-cs-yellow\",\n orange: \"text-cs-orange\",\n}\n\nexport interface WidgetProps extends Omit, \"color\"> {\n /** Widget icon (component or element). */\n icon: CsIcon\n /** Title text. */\n title?: string\n /** Description or value. If `undefined`, a dash is displayed. */\n description?: string | number\n /** Display number with a sign. */\n withSign?: boolean\n /** Icon alignment. */\n iconAlign?: \"left\" | \"right\"\n /** Widget variant. */\n variant?: \"default\" | \"filled\" | \"colorful\" | \"white\"\n /** Widget size. */\n size?: \"xs\" | \"sm\" | \"md\" | \"md2\" | \"lg\"\n /** Widget color. */\n color?: CsCardColor\n /** Makes the widget clickable. */\n onClick?: React.MouseEventHandler\n}\n\nfunction Widget({\n className,\n icon: Icon,\n title,\n description,\n withSign = false,\n iconAlign = \"left\",\n variant = \"default\",\n size = \"md\",\n color = \"primary\",\n onClick,\n ...props\n}: WidgetProps) {\n const sizeConfig = WIDGET_SIZE_MAP[size]\n\n const iconElement =\n Icon && typeof Icon === \"function\"\n ? React.createElement(Icon as React.FC>, {\n className: cn(sizeConfig.icon, \"shrink-0\"),\n })\n : Icon\n\n const descText =\n description !== undefined\n ? typeof description === \"number\" && withSign && description > 0\n ? `+${description}`\n : String(description)\n : \"—\"\n\n const bgClass =\n variant === \"filled\"\n ? WIDGET_COLOR_FILLED[color]\n : variant === \"colorful\"\n ? WIDGET_COLOR_BG[color]\n : WIDGET_VARIANT_MAP[variant]\n\n return (\n \n {iconElement && (\n \n {iconElement}\n \n )}\n
\n {title && (\n
\n {title}\n
\n )}\n

\n {descText}\n

\n
\n \n )\n}\n\nexport { Widget, WIDGET_SIZE_MAP }\n", "type": "registry:ui" } ], "type": "registry:ui" }