|
| 1 | +# 熵减 (Entropydecrease) — 共享 UI 原语 |
| 2 | + |
| 3 | +基于 shadcn/radix 封装(cva 变体),前缀类 `rounded-kb-*`、`bg-bg-*`、`text-text-*`、`shadow-kb-*`、`duration-kb-*`、`ease-kb-*`。 |
| 4 | + |
| 5 | +## Button(client/src/components/ui/Button.tsx) |
| 6 | + |
| 7 | +```tsx |
| 8 | +const buttonVariants = cva( |
| 9 | + [ |
| 10 | + 'inline-flex items-center justify-center font-medium', |
| 11 | + 'transition-all duration-kb-fast ease-kb-smooth', |
| 12 | + 'select-none whitespace-nowrap', |
| 13 | + 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', |
| 14 | + 'disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none', |
| 15 | + 'active:scale-[0.97] active:duration-kb-fast', |
| 16 | + ].join(' '), |
| 17 | + { |
| 18 | + variants: { |
| 19 | + variant: { |
| 20 | + primary: ['bg-brand-600 text-white', 'hover:bg-brand-700 hover:shadow-md hover:shadow-brand-600/20', 'active:bg-brand-800', 'shadow-kb-sm'], |
| 21 | + secondary: ['bg-bg-tertiary text-text-primary', 'hover:bg-border hover:shadow-md', 'active:bg-border-strong', 'border border-border/40'], |
| 22 | + ghost: ['bg-transparent text-text-secondary', 'hover:bg-bg-tertiary hover:text-text-primary', 'active:bg-bg-secondary'], |
| 23 | + danger: ['bg-semantic-error text-white', 'hover:bg-semantic-error/90 hover:shadow-md hover:shadow-semantic-error/20', 'active:bg-semantic-error/80', 'shadow-kb-sm'], |
| 24 | + ai: ['bg-gradient-to-r from-accent-500 to-brand-500 text-white', 'hover:from-accent-600 hover:to-brand-600', 'hover:shadow-md hover:shadow-accent-500/20', 'shadow-kb-sm'], |
| 25 | + }, |
| 26 | + size: { sm: 'px-3 py-1.5 text-b3 rounded-kb-sm gap-1.5', md: 'px-4 py-2 text-b2 rounded-kb-md gap-2', lg: 'px-6 py-3 text-b1 rounded-kb-lg gap-2.5' }, |
| 27 | + }, |
| 28 | + defaultVariants: { variant: 'primary', size: 'md' }, |
| 29 | + }, |
| 30 | +); |
| 31 | +// 支持 loading(Loader2 spin)、icon、iconRight、asChild(radix Slot) |
| 32 | +``` |
| 33 | + |
| 34 | +## Card(client/src/components/ui/Card.tsx) |
| 35 | + |
| 36 | +```tsx |
| 37 | +const cardVariants = cva('transition-all duration-300 ease-kb-smooth backdrop-blur-xl overflow-hidden', { |
| 38 | + variants: { |
| 39 | + variant: { |
| 40 | + default: ['bg-bg-secondary/60 rounded-kb-lg shadow-kb-sm kb-squircle', 'border border-border/40', 'hover:shadow-kb-md hover:border-border/60'], |
| 41 | + elevated: ['bg-bg-secondary/60 rounded-kb-lg shadow-kb-md kb-squircle', 'border border-border/20', 'hover:shadow-lg hover:border-border/40'], |
| 42 | + outlined: ['bg-bg-secondary/40 rounded-kb-lg kb-squircle', 'border border-border/50', 'hover:border-border-strong hover:shadow-kb-sm'], |
| 43 | + }, |
| 44 | + padding: { none: '', sm: 'p-kb-sm', md: 'p-kb-md', lg: 'p-kb-lg' }, |
| 45 | + hoverable: { true: 'cursor-pointer hover:-translate-y-0.5 hover:shadow-lg hover:border-border/60', false: '' }, |
| 46 | + }, |
| 47 | + defaultVariants: { variant: 'default', padding: 'md', hoverable: false }, |
| 48 | +}); |
| 49 | +// 子组件:CardHeader(flex flex-col gap-kb-xs pb-kb-md)、CardContent(pb-kb-md last:pb-0)、CardFooter(flex items-center pt-kb-md) |
| 50 | +``` |
| 51 | + |
| 52 | +## Tag(client/src/components/ui/Tag.tsx) |
| 53 | + |
| 54 | +```tsx |
| 55 | +const tagVariants = cva(['inline-flex items-center gap-1', 'px-2.5 py-0.5', 'text-b3 font-medium', 'rounded-kb-full', 'transition-colors duration-kb-fast'], { |
| 56 | + variants: { |
| 57 | + color: { |
| 58 | + brand: 'bg-brand-100/70 text-brand-700', |
| 59 | + pomodoro: 'bg-rose-100/70 text-rose-700', // 注意:硬编码 rose,非令牌 |
| 60 | + note: 'bg-accent-100/70 text-accent-700', |
| 61 | + flashcard: 'bg-cyan-100/70 text-cyan-700', // 注意:硬编码 cyan,非令牌 |
| 62 | + feynman: 'bg-indigo-100/70 text-indigo-700', // 注意:硬编码 indigo,非令牌 |
| 63 | + default: 'bg-bg-tertiary text-text-secondary', |
| 64 | + }, |
| 65 | + }, |
| 66 | + defaultVariants: { color: 'default' }, |
| 67 | +}); |
| 68 | +// 支持 closable(X 关闭按钮) |
| 69 | +``` |
| 70 | + |
| 71 | +## EmptyState(client/src/components/ui/EmptyState.tsx) |
| 72 | + |
| 73 | +```tsx |
| 74 | +<div className="flex flex-col items-center justify-center text-center py-kb-2xl px-kb-lg"> |
| 75 | + <div className="text-text-tertiary/60 mb-kb-md">{icon || <BrandLogo mode="floating" size={64} className="text-brand-500/60" />}</div> |
| 76 | + <h3 className="text-h3 font-medium text-text-secondary">{title}</h3> |
| 77 | + {description && <p className="mt-kb-xs text-b2 text-text-tertiary max-w-xs">{description}</p>} |
| 78 | + {action && <div className="mt-kb-md">{action}</div>} |
| 79 | +</div> |
| 80 | +``` |
| 81 | + |
| 82 | +## 其他共享组件(client/src/components/ui/) |
| 83 | + |
| 84 | +| 组件 | 用途 | |
| 85 | +|------|------| |
| 86 | +| IconButton | 图标按钮(size/tooltip/variant) | |
| 87 | +| Input / AIButton | 输入框 / AI 渐变按钮 | |
| 88 | +| Modal / CloseConfirmDialog / ConsentModal | 模态层(modal-enter 动画) | |
| 89 | +| Toast / AchievementToast | 通知(顶部成就演出) | |
| 90 | +| CommandPalette | 命令面板(⌘K) | |
| 91 | +| ContextMenu / RichTooltip / Tip | 交互辅助 | |
| 92 | +| Skeleton / VirtualList | 加载/虚拟列表 | |
| 93 | +| BrandLogo | SVG 品牌标志(floating/draw 模式) | |
| 94 | +| Avatar | 用户头像 | |
| 95 | +| TypewriterText | 打字机文字 | |
| 96 | +| AIThinkingIndicator | AI 思考指示(三点脉冲) | |
| 97 | +| KnowledgeGalaxy | 知识星系(旋转光点) | |
| 98 | +| AmbientLightPool | 环境光点池 | |
| 99 | +| ModeIndicator / ComingSoonBadge / ComingSoonPlaceholder | 状态标识 | |
| 100 | +| ErrorBoundary / UpdateNotification | 兜底 | |
0 commit comments