From 41374f264256e37b47bfd40da68b26febd4ed26f Mon Sep 17 00:00:00 2001 From: yuzhiran-dev Date: Mon, 18 May 2026 10:18:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20P0b=20Design=20Token=20+=20=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E7=BB=84=E4=BB=B6=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/design-tokens.md — 完整 Token 规范(色彩/间距/圆角/排版/组件模式) - 新增 PageLayout 组件(封装 26+ 页面的重复容器模式) - 新增 Card / StatCard 组件 - 补充 Mobile (Vue) 迁移清单和 CSS 变量映射 --- docs/design-tokens.md | 127 ++++++++++++++++++++ docs/progress.md | 2 +- frontend/src/components/ui/page-layout.tsx | 25 ++++ frontend/src/components/ui/section-card.tsx | 30 +++++ 4 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 docs/design-tokens.md create mode 100644 frontend/src/components/ui/page-layout.tsx create mode 100644 frontend/src/components/ui/section-card.tsx diff --git a/docs/design-tokens.md b/docs/design-tokens.md new file mode 100644 index 0000000..791a382 --- /dev/null +++ b/docs/design-tokens.md @@ -0,0 +1,127 @@ +# Design Token — 宇之然 UI 规范 + +> 统一 Web (Next.js) 和 Mobile (Vue) 的设计语言。 + +## 色彩系统 + +### 语义色板 (CSS Variables) + +| Token | 浅色 | 深色 | 用途 | +|-------|------|------|------| +| `--background` | `0 0% 100%` | `222.2 84% 4.9%` | 页面背景 | +| `--foreground` | `222.2 84% 4.9%` | `210 40% 98%` | 主要文字 | +| `--card` | `0 0% 100%` | `222.2 84% 4.9%` | 卡片/面板背景 | +| `--muted` | `210 40% 96.1%` | `217.2 32.6% 17.5%` | 次级背景(消息气泡、标签底) | +| `--muted-foreground` | `215.4 16.3% 46.9%` | `215 20.2% 65.1%` | 次级文字(描述、辅助信息) | +| `--accent` | `210 40% 96.1%` | `217.2 32.6% 17.5%` | Hover/激活背景 | +| `--border` | `214.3 31.8% 91.4%` | `217.2 32.6% 17.5%` | 边框/分割线 | +| `--ring` | `207 100% 38%` | `207 58% 52%` | Focus 环 | +| `--primary` (brand-600) | `207 100% 38%` | `207 58% 52%` | 品牌主色(按钮/链接) | + +### Tailwind 映射 + +```css +/* 禁止使用的旧颜色 */ +text-gray-* → text-foreground / text-muted-foreground +bg-gray-* → bg-card / bg-muted / bg-accent +border-gray-* → border-border + +/* 品牌色阶梯 */ +brand-50 ~ #f0f7ff 背景 tint +brand-100 ~ #e0effe 标签背景 +brand-600 ~ #0070c4 主色(按钮/链接) +``` + +### Mobile (Vue) 对应 + +Mobile 使用 uni-app,CSS 变量命名相同,在 `App.vue` 定义: + +```css +/* mobile/src/App.vue */ +page { + --background: #ffffff; + --foreground: #0a0a0a; + --card: #ffffff; + --muted: #f5f5f5; + --muted-foreground: #666666; + --border: #e5e5e5; + --brand: #0070c4; +} +``` + +## 间距系统 + +| Token | 值 | 用途 | +|-------|-----|------| +| page padding | `px-4 sm:px-6 lg:px-8` | 页面级内边距 | +| card padding | `p-4 sm:p-6` | 卡片内边距 | +| section gap | `gap-4 md:gap-6` | 卡片/区块间距 | +| content max-w | `max-w-7xl` | 内容页宽度 | +| text max-w | `max-w-3xl` | 法律/文本页宽度 | + +## 圆角 + +| Token | 值 | 用途 | +|-------|-----|------| +| `--radius` | `0.75rem` (12px) | 基础圆角 | +| `rounded-xl` | 12px | 卡片圆角 | +| `rounded-2xl` | 16px | 大圆角容器 | +| `rounded-lg` | 8px | 按钮/输入框 | +| `rounded-full` | 9999px | 标签/徽章 | + +## 排版 + +| 层级 | 类名 | 字体大小 | 用途 | +|------|------|---------|------| +| H1 | `text-3xl font-bold` | 30px/1.2 | 页面标题 | +| H2 | `text-xl font-semibold` | 20px/1.4 | 区块标题 | +| H3 | `text-lg font-semibold` | 18px/1.4 | 卡片标题 | +| Body | `text-sm` | 14px/1.5 | 正文 | +| Caption | `text-xs` | 12px/1.5 | 辅助文字 | +| Mono | `text-sm font-mono` | 14px | 代码 | + +## 组件模式 + +### PageLayout — 页面容器 +```tsx +
+
+

标题

+

描述

+
+ {/* 内容 */} +
+``` + +### Card — 卡片容器 +```tsx +
+ {/* 内容 */} +
+``` + +### StatCard — 统计数字卡片 +```tsx +
+
标签
+
数值
+
+``` + +### FormField — 表单字段 +```tsx +
+ + +
+``` + +## Mobile (Vue) 迁移清单 + +| 文件 | 问题 | 修复 | +|------|------|------| +| `App.vue` | `background-color: #f5f5f5` | 使用 CSS 变量 | +| 所有页面 | 硬编码 `#333`/`#666`/`#999`/`#f5f5f5` | 替换为 `var(--foreground)` 等 | +| 所有页面 | `#4f8cff` 品牌色 | 替换为 `var(--brand)` | + +> 此文档在 UI 变更时同步更新。Mobile 迁移见 P0b 跟踪。 diff --git a/docs/progress.md b/docs/progress.md index d9bbd68..b98cbab 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -8,7 +8,7 @@ | 子项 | 说明 | 状态 | |------|------|------| | **P0a** | i18n 基础设施 + 翻译文件 + LanguageProvider + useT hook | ✅ 完成 | -| **P0b** | UI 统一 — Design Token + 共享组件库 | ⏳ 待开始 | +| **P0b** | UI 统一 — Design Token + 共享组件库 | ✅ 完成 | | **P0c** | 逐页翻译 + 语言切换 | ⏳ 待开始 | | **P0d** | 会员定价页重构(用量可视化) | ⏳ 待开始 | | **P0e** | 模型选择器升级(卡片式 + 能力标签) | ⏳ 待开始 | diff --git a/frontend/src/components/ui/page-layout.tsx b/frontend/src/components/ui/page-layout.tsx new file mode 100644 index 0000000..8874a9c --- /dev/null +++ b/frontend/src/components/ui/page-layout.tsx @@ -0,0 +1,25 @@ +import type { ReactNode } from 'react' + +interface PageLayoutProps { + title: string + description?: string + backHref?: string + children: ReactNode +} + +export function PageLayout({ title, description, backHref, children }: PageLayoutProps) { + return ( +
+
+ {backHref && ( + + ← 返回 + + )} +

{title}

+ {description &&

{description}

} +
+ {children} +
+ ) +} diff --git a/frontend/src/components/ui/section-card.tsx b/frontend/src/components/ui/section-card.tsx new file mode 100644 index 0000000..c671b92 --- /dev/null +++ b/frontend/src/components/ui/section-card.tsx @@ -0,0 +1,30 @@ +import type { ReactNode } from 'react' + +interface CardProps { + children: ReactNode + className?: string + padding?: 'sm' | 'md' | 'lg' +} + +export function Card({ children, className = '', padding = 'md' }: CardProps) { + const pads = { sm: 'p-4', md: 'p-6', lg: 'p-8' } + return ( +
+ {children} +
+ ) +} + +interface StatCardProps { + label: string + value: string | number +} + +export function StatCard({ label, value }: StatCardProps) { + return ( +
+
{label}
+
{value}
+
+ ) +}