refactor(desktop/ui): 组件库对齐 shadcn 画廊基调

按已定稿的组件画廊精修 ui/ 基础组件(均走主题令牌,亮/暗自适应):
- Button:主按钮去掉霓虹 shadow-glow(玩具感残留)→ 扁平 + active 微缩;
  次按钮落到 ink-850 表面。
- Input/Textarea/Select:底色对齐表面(ink-900) + 焦点环改 ring-2 ring-brand/25(更柔的聚焦)。
- 新增 Table/Tr/Td:细分隔线 + 弱化表头 + 行 hover,运维/数据场景标准呈现。
- EmptyState/Skeleton/Badge/Tabs/Card 已主题化,沿用。

页面经 ui/ 桶引入,组件升级即全页生效。tsc + 生产构建 + vitest 48 全过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-25 11:23:59 +08:00
parent ca7ce4c26f
commit 94f04bd204
4 changed files with 38 additions and 3 deletions
+2 -2
View File
@@ -9,8 +9,8 @@ const base =
"inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition select-none disabled:cursor-not-allowed disabled:opacity-40 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand/50";
const variants: Record<Variant, string> = {
primary: "bg-brand text-white hover:bg-brand-500 active:bg-brand-600 shadow-glow",
secondary: "border border-line bg-ink-800 text-slate-200 hover:bg-ink-700 hover:border-ink-600",
primary: "bg-brand text-white hover:bg-brand-500 active:scale-[0.98]",
secondary: "border border-line bg-ink-850 text-slate-200 hover:bg-ink-800 hover:border-ink-600",
ghost: "text-slate-400 hover:bg-ink-800 hover:text-slate-200",
danger: "border border-danger/50 text-danger hover:bg-danger/10",
};
+1 -1
View File
@@ -4,7 +4,7 @@ import { cn } from "./cn";
// 注意:基类不含宽度。宽度由调用方决定(Field 内为 flex-col 自动撑满,
// 或显式 w-full / flex-1 / w-16),避免 w-full 与 flex-1/w-16 冲突塌陷。
const fieldBase =
"rounded-md border border-line bg-ink-950 text-sm text-slate-200 placeholder:text-slate-600 transition focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand/40 disabled:opacity-50";
"rounded-md border border-line bg-ink-900 text-sm text-slate-200 placeholder:text-slate-600 transition focus:border-brand focus:outline-none focus:ring-2 focus:ring-brand/25 disabled:opacity-50";
export function Input({ className, ...rest }: InputHTMLAttributes<HTMLInputElement>) {
return <input className={cn(fieldBase, "h-9 px-3", className)} {...rest} />;
@@ -0,0 +1,34 @@
import type { ReactNode } from "react";
import { cn } from "./cn";
// 轻量数据表格:细分隔线、左对齐表头(弱化)、行 hover。运维/数据场景的标准呈现。
// 用法:<Table cols={["任务","状态","耗时"]}><Tr>...<Td>...</Td></Tr></Table>
export function Table({ cols, children, className }: { cols: ReactNode[]; children: ReactNode; className?: string }) {
return (
<table className={cn("w-full border-collapse text-xs", className)}>
<thead>
<tr>
{cols.map((c, i) => (
<th key={i} className="border-b border-line px-2.5 py-2 text-left font-medium text-slate-500">
{c}
</th>
))}
</tr>
</thead>
<tbody>{children}</tbody>
</table>
);
}
export function Tr({ children, onClick, className }: { children: ReactNode; onClick?: () => void; className?: string }) {
return (
<tr onClick={onClick} className={cn("border-b border-line/70 transition hover:bg-ink-800", onClick && "cursor-pointer", className)}>
{children}
</tr>
);
}
export function Td({ children, className }: { children: ReactNode; className?: string }) {
return <td className={cn("px-2.5 py-2 align-middle text-slate-300", className)}>{children}</td>;
}
@@ -4,6 +4,7 @@ export { Button } from "./Button";
export { Input, Textarea, Select, Field } from "./Input";
export { Card, Panel } from "./Card";
export { Badge, Dot } from "./Badge";
export { Table, Tr, Td } from "./Table";
export { Tabs, type TabDef } from "./Tabs";
export { Skeleton, EmptyState } from "./Feedback";
export { Dialog, ConfirmFooter } from "./Dialog";