import type { ReactNode } from "react"; import type { LucideIcon } from "lucide-react"; import { Card } from "@/components/ui/Card"; import { Eyebrow } from "@/components/ui/Eyebrow"; import { cn } from "@/lib/ui/variants"; // 空态外框形态: // - "inline"(默认):虚线中性框,用于列表/面板内联占位(向后兼容旧默认外观)。 // - "card":包裹在 Card(tone=soft) 内,用于独立区块的引导卡片。 // - "bare":无外框,仅内容,交由调用方自行放置(如已在卡片里)。 type EmptyStateVariant = "inline" | "card" | "bare"; type EmptyStateSize = "sm" | "md"; interface EmptyStateProps { icon: LucideIcon; title: string; description: string; action?: ReactNode; /** 可选眉题,置于标题上方,用于分类/上下文提示。 */ eyebrow?: string; /** 外框形态,默认 "inline"。 */ variant?: EmptyStateVariant; /** 留白密度,默认 "md"。 */ size?: EmptyStateSize; className?: string; } const SIZE_PAD: Record = { sm: "px-5 py-8", md: "px-6 py-10", }; const SIZE_CHIP: Record = { sm: "h-10 w-10", md: "h-11 w-11", }; // 内容主体:图标片 + 眉题 + 标题 + 描述 + 动作。中性、编辑部化,留白克制。 function EmptyStateBody({ icon: Icon, title, description, action, eyebrow, size, }: Pick< EmptyStateProps, "icon" | "title" | "description" | "action" | "eyebrow" > & { size: EmptyStateSize; }) { return (
{eyebrow ? {eyebrow} : null}

{title}

{description}

{action ?
{action}
: null}
); } export function EmptyState({ icon, title, description, action, eyebrow, variant = "inline", size = "md", className, }: EmptyStateProps) { const body = ( ); if (variant === "bare") { return
{body}
; } if (variant === "card") { return ( {body} ); } return (
{body}
); }