frontend: FE-026 现代桌面风设计基建,系统字体栈+中性灰分层+蓝色主色+圆角阴影动效令牌

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
fenghp
2026-06-11 17:07:56 +08:00
co-authored by Cursor
parent b056f7c1e4
commit 5408f27902
5 changed files with 92 additions and 70 deletions
+74 -53
View File
@@ -1,13 +1,18 @@
@import "tailwindcss"; @import "tailwindcss";
@import "tw-animate-css"; @import "tw-animate-css";
@import "shadcn/tailwind.css"; @import "shadcn/tailwind.css";
@import "@fontsource-variable/roboto-slab";
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
/*
* 现代桌面工具风设计基建(FE-026)
* 基调:中性灰分层底色 + 卡片化 + 克制的蓝色主色,参照 Codex 桌面端 / CC Switch。
* 动效约定:快 150ms / 标准 200ms / 慢 250ms,对应 duration-150 / duration-200 / duration-250。
*/
@theme inline { @theme inline {
--font-heading: var(--font-serif); --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
--font-serif: 'Roboto Slab Variable', serif; --font-heading: var(--font-sans);
--font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
--color-sidebar-ring: var(--sidebar-ring); --color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border); --color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@@ -39,6 +44,7 @@
--color-card: var(--card); --color-card: var(--card);
--color-foreground: var(--foreground); --color-foreground: var(--foreground);
--color-background: var(--background); --color-background: var(--background);
/* 圆角档位:sm 6px / md 8px / lg 10px / xl 14px(--radius = 10px) */
--radius-sm: calc(var(--radius) * 0.6); --radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8); --radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius); --radius-lg: var(--radius);
@@ -46,75 +52,90 @@
--radius-2xl: calc(var(--radius) * 1.8); --radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2); --radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6); --radius-4xl: calc(var(--radius) * 2.6);
/* 阴影分层:卡片极轻 / 浮层轻 / 弹窗明显 */
--shadow-card: 0 1px 2px rgb(0 0 0 / 0.04);
--shadow-overlay: 0 4px 16px rgb(0 0 0 / 0.08), 0 1px 3px rgb(0 0 0 / 0.06);
--shadow-dialog: 0 16px 48px rgb(0 0 0 / 0.16), 0 4px 12px rgb(0 0 0 / 0.08);
/* 缓动曲线:出场用 out-quart,强调动效用 spring 近似 */
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
--ease-spring: cubic-bezier(0.34, 1.3, 0.64, 1);
} }
:root { :root {
--background: oklch(1 0 0); /* 中性灰分层:页面底 0.985 / 卡片 1 / 侧栏 0.967 / 悬停 0.945 */
--foreground: oklch(0.145 0 0); --background: oklch(0.985 0.002 286);
--foreground: oklch(0.21 0.006 286);
--card: oklch(1 0 0); --card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0); --card-foreground: oklch(0.21 0.006 286);
--popover: oklch(1 0 0); --popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0); --popover-foreground: oklch(0.21 0.006 286);
--primary: oklch(0.488 0.243 264.376); /* 克制的蓝色主色:仅用于主按钮、选中态、状态点 */
--primary-foreground: oklch(0.97 0.014 254.604); --primary: oklch(0.546 0.215 262.881);
--secondary: oklch(0.967 0.001 286.375); --primary-foreground: oklch(0.985 0.002 286);
--secondary-foreground: oklch(0.21 0.006 285.885); --secondary: oklch(0.96 0.004 286);
--muted: oklch(0.97 0 0); --secondary-foreground: oklch(0.21 0.006 286);
--muted-foreground: oklch(0.556 0 0); --muted: oklch(0.96 0.004 286);
--accent: oklch(0.488 0.243 264.376); --muted-foreground: oklch(0.552 0.014 285);
--accent-foreground: oklch(0.97 0.014 254.604); /* accent 为中性悬停底色,不再复用主色 */
--accent: oklch(0.945 0.004 286);
--accent-foreground: oklch(0.21 0.006 286);
--destructive: oklch(0.577 0.245 27.325); --destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0); --border: oklch(0.92 0.004 286);
--input: oklch(0.922 0 0); --input: oklch(0.92 0.004 286);
--ring: oklch(0.708 0 0); --ring: oklch(0.623 0.188 259.815);
--chart-1: oklch(0.809 0.105 251.813); --chart-1: oklch(0.809 0.105 251.813);
--chart-2: oklch(0.623 0.214 259.815); --chart-2: oklch(0.623 0.214 259.815);
--chart-3: oklch(0.546 0.245 262.881); --chart-3: oklch(0.546 0.245 262.881);
--chart-4: oklch(0.488 0.243 264.376); --chart-4: oklch(0.488 0.243 264.376);
--chart-5: oklch(0.424 0.199 265.638); --chart-5: oklch(0.424 0.199 265.638);
--radius: 0.875rem; --radius: 0.625rem;
--sidebar: oklch(0.985 0 0); --sidebar: oklch(0.967 0.003 286);
--sidebar-foreground: oklch(0.145 0 0); --sidebar-foreground: oklch(0.21 0.006 286);
--sidebar-primary: oklch(0.546 0.245 262.881); --sidebar-primary: oklch(0.546 0.215 262.881);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604); --sidebar-primary-foreground: oklch(0.985 0.002 286);
--sidebar-accent: oklch(0.97 0 0); --sidebar-accent: oklch(0.92 0.004 286);
--sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-accent-foreground: oklch(0.21 0.006 286);
--sidebar-border: oklch(0.922 0 0); --sidebar-border: oklch(0.91 0.004 286);
--sidebar-ring: oklch(0.708 0 0); --sidebar-ring: oklch(0.623 0.188 259.815);
/* 动效时长:快 / 标准 / 慢 */
--motion-fast: 150ms;
--motion-base: 200ms;
--motion-slow: 250ms;
} }
.dark { .dark {
--background: oklch(0.145 0 0); /* 深灰底而非纯黑:页面 0.185 / 卡片 0.22 / 侧栏 0.165 / 悬停 0.27 */
--foreground: oklch(0.985 0 0); --background: oklch(0.185 0.005 285);
--card: oklch(0.205 0 0); --foreground: oklch(0.96 0.002 286);
--card-foreground: oklch(0.985 0 0); --card: oklch(0.22 0.006 285);
--popover: oklch(0.205 0 0); --card-foreground: oklch(0.96 0.002 286);
--popover-foreground: oklch(0.985 0 0); --popover: oklch(0.22 0.006 285);
--primary: oklch(0.424 0.199 265.638); --popover-foreground: oklch(0.96 0.002 286);
--primary-foreground: oklch(0.97 0.014 254.604); --primary: oklch(0.623 0.188 259.815);
--secondary: oklch(0.274 0.006 286.033); --primary-foreground: oklch(0.985 0.002 286);
--secondary-foreground: oklch(0.985 0 0); --secondary: oklch(0.27 0.006 286);
--muted: oklch(0.269 0 0); --secondary-foreground: oklch(0.96 0.002 286);
--muted-foreground: oklch(0.708 0 0); --muted: oklch(0.26 0.006 286);
--accent: oklch(0.424 0.199 265.638); --muted-foreground: oklch(0.71 0.01 286);
--accent-foreground: oklch(0.97 0.014 254.604); --accent: oklch(0.27 0.006 286);
--accent-foreground: oklch(0.96 0.002 286);
--destructive: oklch(0.704 0.191 22.216); --destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%); --border: oklch(1 0 0 / 8%);
--input: oklch(1 0 0 / 15%); --input: oklch(1 0 0 / 12%);
--ring: oklch(0.556 0 0); --ring: oklch(0.623 0.188 259.815);
--chart-1: oklch(0.809 0.105 251.813); --chart-1: oklch(0.809 0.105 251.813);
--chart-2: oklch(0.623 0.214 259.815); --chart-2: oklch(0.623 0.214 259.815);
--chart-3: oklch(0.546 0.245 262.881); --chart-3: oklch(0.546 0.245 262.881);
--chart-4: oklch(0.488 0.243 264.376); --chart-4: oklch(0.488 0.243 264.376);
--chart-5: oklch(0.424 0.199 265.638); --chart-5: oklch(0.424 0.199 265.638);
--sidebar: oklch(0.205 0 0); --sidebar: oklch(0.165 0.005 285);
--sidebar-foreground: oklch(0.985 0 0); --sidebar-foreground: oklch(0.96 0.002 286);
--sidebar-primary: oklch(0.623 0.214 259.815); --sidebar-primary: oklch(0.623 0.188 259.815);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604); --sidebar-primary-foreground: oklch(0.985 0.002 286);
--sidebar-accent: oklch(0.269 0 0); --sidebar-accent: oklch(0.24 0.006 285);
--sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-accent-foreground: oklch(0.96 0.002 286);
--sidebar-border: oklch(1 0 0 / 10%); --sidebar-border: oklch(1 0 0 / 8%);
--sidebar-ring: oklch(0.556 0 0); --sidebar-ring: oklch(0.623 0.188 259.815);
} }
@layer base { @layer base {
@@ -125,6 +146,6 @@
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
html { html {
@apply font-serif; @apply font-sans;
} }
} }
-1
View File
@@ -12,7 +12,6 @@
"format": "prettier --write \"**/*.{ts,tsx}\"" "format": "prettier --write \"**/*.{ts,tsx}\""
}, },
"dependencies": { "dependencies": {
"@fontsource-variable/roboto-slab": "^5.2.8",
"@react-router/node": "7.13.1", "@react-router/node": "7.13.1",
"@react-router/serve": "7.13.1", "@react-router/serve": "7.13.1",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
-8
View File
@@ -8,9 +8,6 @@ importers:
.: .:
dependencies: dependencies:
'@fontsource-variable/roboto-slab':
specifier: ^5.2.8
version: 5.2.8
'@react-router/node': '@react-router/node':
specifier: 7.13.1 specifier: 7.13.1
version: 7.13.1(react-router@7.13.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) version: 7.13.1(react-router@7.13.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)
@@ -416,9 +413,6 @@ packages:
'@floating-ui/utils@0.2.11': '@floating-ui/utils@0.2.11':
resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
'@fontsource-variable/roboto-slab@5.2.8':
resolution: {integrity: sha512-cdvOSwocP50xS01gXqnGxw7uFcCZQgn1IDlqiAmNuZP4uEVScYAKMDC+aWsbP1grn9QdMJ2frhcuVBNXniBVGA==}
'@hapi/address@5.1.1': '@hapi/address@5.1.1':
resolution: {integrity: sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==} resolution: {integrity: sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@@ -3742,8 +3736,6 @@ snapshots:
'@floating-ui/utils@0.2.11': {} '@floating-ui/utils@0.2.11': {}
'@fontsource-variable/roboto-slab@5.2.8': {}
'@hapi/address@5.1.1': '@hapi/address@5.1.1':
dependencies: dependencies:
'@hapi/hoek': 11.0.7 '@hapi/hoek': 11.0.7
+4 -4
View File
@@ -31,10 +31,10 @@ blocked
| Core | 12 | 12 | 100% | | Core | 12 | 12 | 100% |
| Server API | 10 | 10 | 100% | | Server API | 10 | 10 | 100% |
| CLI | 2 | 2 | 100% | | CLI | 2 | 2 | 100% |
| Frontend | 25 | 34 | 74% | | Frontend | 26 | 34 | 76% |
| Feature E2E | 0 | 5 | 0% | | Feature E2E | 0 | 5 | 0% |
| Release | 0 | 4 | 0% | | Release | 0 | 4 | 0% |
| Overall | 49 | 67 | 73% | | Overall | 50 | 67 | 75% |
## 当前阶段 ## 当前阶段
@@ -46,7 +46,7 @@ UI 风格改版(分支 `feature/ui-modern-restyle`,FE-026 ~ FE-034,需求
## 下一步任务 ## 下一步任务
- [FE-026-建立现代桌面风设计基建.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-026-建立现代桌面风设计基建.md) - [FE-027-Electron无缝窗口与自绘顶栏.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-027-Electron无缝窗口与自绘顶栏.md)
- UI 改版完成后再回到 [FEATURE-001-连接与目录浏览端到端验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/feature/FEATURE-001-连接与目录浏览端到端验收.md)(需要真实 TFS 环境) - UI 改版完成后再回到 [FEATURE-001-连接与目录浏览端到端验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/feature/FEATURE-001-连接与目录浏览端到端验收.md)(需要真实 TFS 环境)
## Core ## Core
@@ -117,7 +117,7 @@ UI 风格改版(分支 `feature/ui-modern-restyle`,FE-026 ~ FE-034,需求
| [FE-023-实现分支.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-023-实现分支.md) | done | P1 | | [FE-023-实现分支.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-023-实现分支.md) | done | P1 |
| [FE-024-实现合并.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-024-实现合并.md) | done | P1 | | [FE-024-实现合并.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-024-实现合并.md) | done | P1 |
| [FE-025-实现访达打开与添加本地文件.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-025-实现访达打开与添加本地文件.md) | done | P0 | | [FE-025-实现访达打开与添加本地文件.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-025-实现访达打开与添加本地文件.md) | done | P0 |
| [FE-026-建立现代桌面风设计基建.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-026-建立现代桌面风设计基建.md) | todo | P0 | | [FE-026-建立现代桌面风设计基建.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-026-建立现代桌面风设计基建.md) | done | P0 |
| [FE-027-Electron无缝窗口与自绘顶栏.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-027-Electron无缝窗口与自绘顶栏.md) | todo | P0 | | [FE-027-Electron无缝窗口与自绘顶栏.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-027-Electron无缝窗口与自绘顶栏.md) | todo | P0 |
| [FE-028-重设计登录页.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-028-重设计登录页.md) | todo | P0 | | [FE-028-重设计登录页.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-028-重设计登录页.md) | todo | P0 |
| [FE-029-工作台外壳与顶栏改版.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-029-工作台外壳与顶栏改版.md) | todo | P0 | | [FE-029-工作台外壳与顶栏改版.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-029-工作台外壳与顶栏改版.md) | todo | P0 |
@@ -2,7 +2,7 @@
## 状态 ## 状态
todo done
## 优先级 ## 优先级
@@ -58,9 +58,19 @@ cd mactfsui && pnpm typecheck && pnpm electron:dev
## 完成记录 ## 完成记录
待完成后填写:
- 实际修改文件: - 实际修改文件:
- `mactfsui/app/app.css`
- `mactfsui/package.json`、`mactfsui/pnpm-lock.yaml`(移除 `@fontsource-variable/roboto-slab`)
- 实际实现内容: - 实际实现内容:
- 全局字体切换为系统无衬线字体栈(`-apple-system / PingFang SC`…),`html` 由 `font-serif` 改为 `font-sans`;新增 `--font-mono` 等宽字体令牌;`--font-heading` 指向 sans(dialog 标题沿用)
- 颜色令牌重定义为中性灰分层:light 页面底 0.985 / 卡片纯白 / 侧栏 0.967 / 悬停 0.945;dark 深灰底 0.185(非纯黑)/ 卡片 0.22 / 侧栏 0.165
- 主色改为克制的蓝色(oklch 0.546 0.215 262.881),`--accent` 与主色解耦、改为中性悬停底色(原先 accent=紫色主色,菜单悬停会大面积铺色)
- 圆角基准 0.875rem → 0.625rem(sm 6 / md 8 / lg 10 / xl 14px)
- 新增阴影分层令牌 `--shadow-card / --shadow-overlay / --shadow-dialog`
- 新增动效令牌:缓动 `--ease-out-quart / --ease-spring`,时长 `--motion-fast/base/slow`(150/200/250ms)
- 测试结果: - 测试结果:
- `pnpm typecheck` 通过
- `pnpm build` 通过(Tailwind CSS 编译无误)
- 未执行 `pnpm electron:dev` 全页面人工走查(属 GUI 交互验证,留待后续任务连带走查),现有类名均基于既有 token 体系,无破坏性重命名
- 遗留问题: - 遗留问题:
- 各组件中残留的散落样式(如紫色 hover 假设)将在 FE-029 ~ FE-032 按面板逐一对齐