huhaa-myskills 0.2.13 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -375
- package/bin/huhaa-myskills.mjs +194 -12
- package/{scripts → build}/verify.mjs +3 -1
- package/docs/Frontend-Spec.md +1149 -0
- package/docs/assets/layout-wireframe.png +0 -0
- package/docs/assets/theme-reference.png +0 -0
- package/docs/scan_rules.md +172 -0
- package/package.json +33 -9
- package/packages/scanner/src/adapters/directory-skill.mjs +239 -0
- package/packages/scanner/src/adapters/skill-adapter.mjs +345 -0
- package/packages/scanner/src/icon/brand-map.mjs +84 -0
- package/packages/scanner/src/icon/icon-extractor.mjs +246 -0
- package/packages/scanner/src/index.mjs +107 -82
- package/packages/scanner/src/types.d.ts +18 -0
- package/packages/scanner/test/icon.test.mjs +61 -0
- package/packages/scanner/test/scanner.test.mjs +37 -41
- package/packages/scanner/test/skill-adapter.test.mjs +70 -0
- package/packages/scanner/tests/directory-skill.test.mjs +93 -0
- package/packages/scanner/tests/scanner-integration.test.mjs +139 -0
- package/packages/server/src/index.mjs +164 -12
- package/packages/server/src/labels.mjs +62 -0
- package/packages/server/test/server.test.mjs +1 -1
- package/packages/web/README.md +33 -2
- package/packages/web/dist/assets/index-BCY2cRaO.js +175 -0
- package/packages/web/dist/assets/index-DALKjJPi.css +1 -0
- package/packages/web/dist/favicon-16x16.png +0 -0
- package/packages/web/dist/favicon-192x192.png +0 -0
- package/packages/web/dist/favicon-32x32.png +0 -0
- package/packages/web/dist/favicon-512x512.png +0 -0
- package/packages/web/dist/favicon-source.svg +5 -0
- package/packages/web/dist/index.html +23 -9
- package/packages/web/index.html +22 -8
- package/packages/web/package-lock.json +2989 -0
- package/packages/web/package.json +21 -8
- package/packages/web/postcss.config.js +6 -0
- package/packages/web/public/favicon-16x16.png +0 -0
- package/packages/web/public/favicon-192x192.png +0 -0
- package/packages/web/public/favicon-32x32.png +0 -0
- package/packages/web/public/favicon-512x512.png +0 -0
- package/packages/web/public/favicon-source.svg +5 -0
- package/packages/web/src/App.test.ts +40 -0
- package/packages/web/src/App.tsx +177 -0
- package/packages/web/src/components/ComingSoon.tsx +14 -0
- package/packages/web/src/components/layout/Sidebar.test.tsx +74 -0
- package/packages/web/src/components/layout/Sidebar.tsx +114 -0
- package/packages/web/src/components/layout/Topbar.tsx +74 -0
- package/packages/web/src/components/ui/ActionButton.tsx +48 -0
- package/packages/web/src/components/ui/button.tsx +48 -0
- package/packages/web/src/components/ui/card.tsx +45 -0
- package/packages/web/src/components/views/DashboardView.tsx +122 -0
- package/packages/web/src/components/views/OtherSkillsView.test.tsx +126 -0
- package/packages/web/src/components/views/OtherSkillsView.tsx +306 -0
- package/packages/web/src/components/views/SettingsView.tsx +95 -0
- package/packages/web/src/components/views/SkillDetail.test.tsx +57 -0
- package/packages/web/src/components/views/SkillDetail.tsx +81 -0
- package/packages/web/src/components/views/SkillsView.test.ts +28 -0
- package/packages/web/src/components/views/SkillsView.tsx +226 -0
- package/packages/web/src/hooks/QUICK_REFERENCE.md +165 -0
- package/packages/web/src/hooks/README.md +378 -0
- package/packages/web/src/hooks/__tests__/useOtherSkills.test.ts +422 -0
- package/packages/web/src/hooks/__tests__/useSkillIcons.test.ts +272 -0
- package/packages/web/src/hooks/useLiveReload.ts +20 -0
- package/packages/web/src/hooks/useOtherSkills.ts +387 -0
- package/packages/web/src/hooks/useSkillIcons.ts +248 -0
- package/packages/web/src/hooks/useTheme.ts +36 -0
- package/packages/web/src/index.css +161 -0
- package/packages/web/src/lib/api.test.ts +47 -0
- package/packages/web/src/lib/api.ts +77 -0
- package/packages/web/src/lib/cn.ts +7 -0
- package/packages/web/src/lib/editors.test.ts +30 -0
- package/packages/web/src/lib/editors.ts +70 -0
- package/packages/web/src/lib/markdown.test.ts +27 -0
- package/packages/web/src/lib/markdown.ts +14 -0
- package/packages/web/src/main.tsx +13 -0
- package/packages/web/src/types/index.ts +62 -0
- package/packages/web/src/types/other-skill.ts +88 -0
- package/packages/web/src/types/skill.ts +136 -0
- package/packages/web/src/types.ts +47 -0
- package/packages/web/src/vite-env.d.ts +1 -0
- package/packages/web/tailwind.config.ts +66 -0
- package/packages/web/tsconfig.json +28 -0
- package/packages/web/vite.config.ts +36 -0
- package/packages/web/vitest.config.ts +21 -0
- package/packages/web/vitest.setup.ts +1 -0
- package/scripts/activate-data-sources.sh +223 -0
- package/scripts/brand-completion.py +586 -0
- package/scripts/init-nextjs-project.sh +421 -0
- package/scripts/install-and-sync.sh +209 -0
- package/scripts/start-dev.sh +72 -0
- package/docs/GUIDE.md +0 -190
- package/docs/PLAN.md +0 -359
- package/docs/RULES.md +0 -329
- package/docs/RUNBOOK-myskills.md +0 -258
- package/docs/SYNC-SKILLS.md +0 -259
- package/docs/releases/README.md +0 -47
- package/docs/releases/v0.1.0.md +0 -256
- package/docs/releases/v0.1.1.md +0 -297
- package/docs/releases/v0.1.2.md +0 -207
- package/docs/releases/v0.1.3.md +0 -269
- package/docs/todo/v0.1.2.md +0 -98
- package/docs/todo/v0.1.3.md +0 -40
- package/docs/todo/v0.1.4.md +0 -36
- package/docs/todo/v0.1.5.md +0 -41
- package/docs/todo/v0.1.6.md +0 -43
- package/docs/todo/v0.1.7.md +0 -38
- package/docs/todo/v0.1.8.md +0 -36
- package/docs/todo/v0.1.9.md +0 -54
- package/packages/web/dist/assets/index-BPepSb3q.js +0 -36
- package/packages/web/dist/assets/index-CIGkgT5w.css +0 -1
- package/packages/web/src/App.vue +0 -483
- package/packages/web/src/components/AppTree.vue +0 -230
- package/packages/web/src/components/DirectoryTree.vue +0 -263
- package/packages/web/src/components/SkillTree.vue +0 -208
- package/packages/web/src/lib/api.js +0 -43
- package/packages/web/src/main.js +0 -6
- package/packages/web/src/stores/i18n.js +0 -161
- package/packages/web/src/stores/skills.js +0 -287
- package/packages/web/src/styles.css +0 -365
- package/packages/web/vite.config.js +0 -17
- /package/{scripts → build}/build-web.mjs +0 -0
- /package/{scripts → build}/prepare-publish.mjs +0 -0
|
@@ -0,0 +1,1149 @@
|
|
|
1
|
+
# 🎨 HuHaa-MySkills 前端工程完整规范 v2.0
|
|
2
|
+
|
|
3
|
+
> **一站式前端文档** — 工程规范、设计系统、框架说明、重构计划、实现指南
|
|
4
|
+
>
|
|
5
|
+
> 本文整合了所有前端规范、约束、设计、主题和实现细节。
|
|
6
|
+
>
|
|
7
|
+
> **最后更新** — 2026-07-01
|
|
8
|
+
> **版本** — v2.0(Vite + React + Tailwind 重构)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 📋 快速导航
|
|
13
|
+
|
|
14
|
+
- **§I** — 工程规范(技术栈、版本、目录、代码质量)
|
|
15
|
+
- **§II** — 设计系统(色彩、排版、间距、组件、响应式)
|
|
16
|
+
- **§III** — 框架说明(Vite、React、配置、构建模型)
|
|
17
|
+
- **§IV** — 重构计划(路线决策、分阶段路线、执行清单)
|
|
18
|
+
- **§V** — 实现指南(Sidebar、状态管理、API 集成)
|
|
19
|
+
- **§VI** — 快速启动(环境、命令、验证)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# 一、工程规范
|
|
24
|
+
|
|
25
|
+
## I.1 核心原则
|
|
26
|
+
|
|
27
|
+
1. **一致性优先** — 全项目统一技术栈、风格、规范
|
|
28
|
+
2. **可维护性优先** — 代码结构清晰,易于扩展和迭代
|
|
29
|
+
3. **质量优先** — 类型安全、测试覆盖、性能达标
|
|
30
|
+
4. **自动化优先** — CI/CD、代码审查、构建验证自动化
|
|
31
|
+
5. **文档优先** — 规范文档是代码基础,所有决策可追溯
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## I.2 技术栈选型标准
|
|
36
|
+
|
|
37
|
+
### 必选
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Language: TypeScript (strict 模式)
|
|
41
|
+
Runtime: Node.js >= 20.0.0
|
|
42
|
+
Format: ESLint + Prettier
|
|
43
|
+
VCS: Git + GitHub
|
|
44
|
+
CI/CD: GitHub Actions
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 前端框架(已定型)
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
选型: Vite + React 18
|
|
51
|
+
理由: 快速开发体验、轻量级 SPA、直接落地设计系统
|
|
52
|
+
输出: 纯静态 SPA (packages/web/dist)
|
|
53
|
+
部署: Fastify 后端托管 (localhost:11520)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### UI 库标准
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
基础组件: shadcn/ui 风格(cva + cn 手写,不跑官方 CLI)
|
|
60
|
+
CSS 方案: Tailwind CSS 3.4 + CSS 变量驱动主题
|
|
61
|
+
图标库: lucide-react
|
|
62
|
+
表单验证: React Hook Form + Zod
|
|
63
|
+
搜索: Fuse.js(客户端模糊搜索)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 禁止项
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
❌ CSS Module / Styled Components(与 Tailwind 重复)
|
|
70
|
+
❌ 商业 UI 库硬依赖(Ant Design Pro、Material UI)
|
|
71
|
+
❌ jQuery / 大型 jQuery 插件
|
|
72
|
+
❌ 未经 Review 的重型依赖
|
|
73
|
+
❌ 自建重复轮子(按钮、输入框等)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## I.3 版本管理规范
|
|
79
|
+
|
|
80
|
+
### 语义化版本
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
MAJOR.MINOR.PATCH-pre+build
|
|
84
|
+
|
|
85
|
+
MAJOR:破坏性改动(API 变更、升级迁移)
|
|
86
|
+
MINOR:新功能(向后兼容)
|
|
87
|
+
PATCH:修复(Bug 修复、性能优化)
|
|
88
|
+
pre:预发版(alpha/beta/rc)
|
|
89
|
+
build:构建元数据
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### package.json 版本策略
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"version": "1.0.0",
|
|
97
|
+
"engines": {
|
|
98
|
+
"node": ">=20.0.0",
|
|
99
|
+
"npm": ">=10.0.0"
|
|
100
|
+
},
|
|
101
|
+
"dependencies": {
|
|
102
|
+
"react": "^18.2.0"
|
|
103
|
+
},
|
|
104
|
+
"devDependencies": {}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**版本锁定规则**:
|
|
109
|
+
- 生产依赖:使用 `^` 范围(允许小版本更新)
|
|
110
|
+
- 开发依赖:使用 `^` 或 `~`
|
|
111
|
+
- `package-lock.json` 必须提交
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## I.4 目录结构
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
HuHaa-MySkills/
|
|
119
|
+
├── packages/web/ # Vite + React 前端 SPA
|
|
120
|
+
│ ├── index.html # 入口 (<div id="app"> + 防暗色闪烁脚本)
|
|
121
|
+
│ ├── vite.config.ts # React 插件 / @ 别名 / dev 代理 /api→11520
|
|
122
|
+
│ ├── tsconfig.json # strict 模式
|
|
123
|
+
│ ├── tailwind.config.ts # 主题 token
|
|
124
|
+
│ ├── postcss.config.js
|
|
125
|
+
│ ├── vitest.config.ts # 单测配置(P1 接入)
|
|
126
|
+
│ ├── public/ # favicon / manifest
|
|
127
|
+
│ └── src/
|
|
128
|
+
│ ├── main.tsx # 入口,挂载到 #app
|
|
129
|
+
│ ├── index.css # 主题 CSS 变量 + 三栏布局类
|
|
130
|
+
│ ├── types.ts # SkillItem / Stats(镜像后端 IR)
|
|
131
|
+
│ ├── lib/
|
|
132
|
+
│ │ ├── cn.ts # clsx + tailwind-merge
|
|
133
|
+
│ │ ├── api.ts # 类型化 API 客户端
|
|
134
|
+
│ │ └── editors.ts # editor → {label, color, icon}(P3)
|
|
135
|
+
│ ├── hooks/
|
|
136
|
+
│ │ └── useTheme.ts # 亮/暗主题切换 + 持久化
|
|
137
|
+
│ ├── components/
|
|
138
|
+
│ │ ├── ui/ # button / card / select(shadcn 风格)
|
|
139
|
+
│ │ ├── layout/ # Sidebar / Topbar / DashboardView
|
|
140
|
+
│ │ └── views/ # SkillsView / SettingsView
|
|
141
|
+
│ └── App.tsx # 状态机 + 三区外壳
|
|
142
|
+
│
|
|
143
|
+
├── docs/
|
|
144
|
+
│ ├── Frontend-Spec.md # 本文件(完整规范)
|
|
145
|
+
│ └── hermes_docs_project_plan.md # 项目需求
|
|
146
|
+
│
|
|
147
|
+
└── ...
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## I.5 代码质量标准
|
|
153
|
+
|
|
154
|
+
### TypeScript Strict
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// tsconfig.json
|
|
158
|
+
{
|
|
159
|
+
"compilerOptions": {
|
|
160
|
+
"strict": true,
|
|
161
|
+
"noUnusedLocals": true,
|
|
162
|
+
"noUnusedParameters": true,
|
|
163
|
+
"noImplicitReturns": true,
|
|
164
|
+
"noFallthroughCasesInSwitch": true
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**规则**:
|
|
170
|
+
- ✅ 所有变量、函数参数都有完整类型
|
|
171
|
+
- ✅ 禁止 `any`、`@ts-ignore`
|
|
172
|
+
- ✅ 返回值必须标注
|
|
173
|
+
- ✅ 对象字面量属性必须有类型
|
|
174
|
+
|
|
175
|
+
### 代码风格
|
|
176
|
+
|
|
177
|
+
**ESLint + Prettier**:
|
|
178
|
+
```bash
|
|
179
|
+
npm run lint # 检查
|
|
180
|
+
npm run lint:fix # 自动修复
|
|
181
|
+
npm run format # 格式化
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**命名约定**:
|
|
185
|
+
```typescript
|
|
186
|
+
// 组件:PascalCase
|
|
187
|
+
export function SkillListItem() {}
|
|
188
|
+
|
|
189
|
+
// 函数/变量:camelCase
|
|
190
|
+
const fetchSkills = () => {}
|
|
191
|
+
let selectedId = ''
|
|
192
|
+
|
|
193
|
+
// 常量:UPPER_SNAKE_CASE
|
|
194
|
+
const MAX_ITEMS = 100
|
|
195
|
+
const DEFAULT_THEME = 'light'
|
|
196
|
+
|
|
197
|
+
// 私有/内部:_前缀
|
|
198
|
+
const _internal = () => {}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 单测覆盖
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
npm test # 运行 scanner + server 单测
|
|
205
|
+
cd packages/web && npm test # 前端单测(P1 接入 vitest)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**目标**:
|
|
209
|
+
- 关键路径 ≥ 80% 覆盖
|
|
210
|
+
- 组件单测 + 集成测试
|
|
211
|
+
- API 单测(mocked 请求)
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## I.6 Git 工作流
|
|
216
|
+
|
|
217
|
+
### 分支命名
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
feature/xxx # 新功能
|
|
221
|
+
fix/xxx # bug 修复
|
|
222
|
+
refactor/xxx # 重构
|
|
223
|
+
docs/xxx # 文档
|
|
224
|
+
chore/xxx # 配置/依赖
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Conventional Commits
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
feat(web): 添加技能详情 markdown 渲染
|
|
231
|
+
fix(theme): 修复暗色模式对比度
|
|
232
|
+
refactor(web): 抽取列表卡片组件
|
|
233
|
+
docs(spec): 补充设计系统文档
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 代码审查
|
|
237
|
+
|
|
238
|
+
**PR 前检查**:
|
|
239
|
+
```bash
|
|
240
|
+
npm run lint:fix && npm run build && npm run test
|
|
241
|
+
cd packages/web && ../../node_modules/.bin/tsc --noEmit
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**审查清单**:
|
|
245
|
+
- ✅ 功能正确性 — 逻辑无误、满足需求
|
|
246
|
+
- ✅ 代码质量 — 易读、无冗余、遵循规范
|
|
247
|
+
- ✅ 类型安全 — 无 any、类型完整
|
|
248
|
+
- ✅ 性能 — 无明显瓶颈、无不必要重渲染
|
|
249
|
+
- ✅ 测试覆盖 — 关键路径有测试
|
|
250
|
+
- ✅ 文档 — 复杂逻辑有注释
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
# 二、设计系统 v2.0
|
|
255
|
+
|
|
256
|
+
## II.1 设计来源与参考
|
|
257
|
+
|
|
258
|
+
### 核心参考
|
|
259
|
+
|
|
260
|
+
本设计系统基于两份参考图(见 `docs/assets/`):
|
|
261
|
+
1. **布局蓝图** — 信息架构(顶部模块栏 + 左侧图标导航 + 三态内容区)
|
|
262
|
+
2. **视觉参考** — 配色风格(干净浅色、柔和投影、品牌色图标)
|
|
263
|
+
|
|
264
|
+
### 设计理念
|
|
265
|
+
|
|
266
|
+
- **干净留白** — 大量留白、柔和投影、克制描边,信息密度适中
|
|
267
|
+
- **柔和现代** — 浅色基底 + 柔和蓝点缀,避免高饱和大色块
|
|
268
|
+
- **品牌可辨** — 平台/来源以品牌色图标标识,一眼可辨
|
|
269
|
+
- **一致性** — 统一的圆角、间距、卡片语言与状态色
|
|
270
|
+
- **可扩展** — CSS 变量主题系统,亮/暗双主题,易于定制
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## II.2 配色系统
|
|
275
|
+
|
|
276
|
+
> 颜色以 **HSL 通道值** 存储于 CSS 变量,配合 `tailwind.config.ts` 的 `hsl(var(--x) / <alpha-value>)` 使用。
|
|
277
|
+
|
|
278
|
+
### 亮色模式(Light — 默认)
|
|
279
|
+
|
|
280
|
+
| 颜色类型 | 16进制 | HSL 通道 | CSS 变量 | 用途 |
|
|
281
|
+
|---------|--------|---------|---------|------|
|
|
282
|
+
| **Background** | `#F7F8FA` | `220 20% 98%` | `--color-background` | 页面画布(点阵纹理底) |
|
|
283
|
+
| **Foreground** | `#1F2937` | `220 9% 12%` | `--color-foreground` | 正文 / 大号数字 |
|
|
284
|
+
| **Card** | `#FFFFFF` | `0 0% 100%` | `--color-card` | 卡片 / 面板底 |
|
|
285
|
+
| **Card-FG** | `#1F2937` | `220 9% 12%` | `--color-card-foreground` | 卡片内文本 |
|
|
286
|
+
| **Sidebar** | `#FBFCFD` | `210 20% 99%` | `--color-sidebar` | 左侧图标导航底 |
|
|
287
|
+
| **Border** | `#EDF0F3` | `220 16% 94%` | `--color-border` | 极淡描边 / 分隔线 |
|
|
288
|
+
| **Input** | `#F3F4F6` | `220 13% 96%` | `--color-input` | 搜索框 / 输入底 |
|
|
289
|
+
| **Ring** | `#3B82F6` | `215 100% 46%` | `--color-ring` | Focus 环 |
|
|
290
|
+
| **Primary** | `#3B82F6` | `215 100% 46%` | `--color-primary` | 主操作 / 选中文字 |
|
|
291
|
+
| **Primary-FG** | `#FFFFFF` | `0 0% 100%` | `--color-primary-foreground` | 主按钮文字 |
|
|
292
|
+
| **Primary-Soft** | `#EAF2FE` | `215 100% 96%` | `--color-primary-soft` | 选中态胶囊柔和底 |
|
|
293
|
+
| **Muted** | `#F1F3F5` | `220 13% 95%` | `--color-muted` | 二级面 / 悬停底 |
|
|
294
|
+
| **Muted-FG** | `#6B7280` | `217 11% 45%` | `--color-muted-foreground` | 副标题 / 说明文字 |
|
|
295
|
+
| **Accent** | `#F59E0B` | `38 92% 50%` | `--color-accent` | 高亮 / 提示(如 `+1` 角标) |
|
|
296
|
+
| **Destructive** | `#EF4444` | `0 84% 60%` | `--color-destructive` | 删除 / 危险操作 |
|
|
297
|
+
|
|
298
|
+
### 暗色模式(Dark)
|
|
299
|
+
|
|
300
|
+
| 颜色类型 | 16进制 | HSL 通道 | CSS 变量 | 用途 |
|
|
301
|
+
|---------|--------|---------|---------|------|
|
|
302
|
+
| **Background** | `#0F172A` | `222 47% 11%` | `--color-background` | 页面画布 |
|
|
303
|
+
| **Foreground** | `#F8FAFC` | `210 40% 96%` | `--color-foreground` | 正文 |
|
|
304
|
+
| **Card** | `#1A2336` | `217 33% 14%` | `--color-card` | 卡片 / 面板 |
|
|
305
|
+
| **Sidebar** | `#151D2E` | `222 33% 13%` | `--color-sidebar` | 左侧导航底 |
|
|
306
|
+
| **Border** | `#26324A` | `217 33% 20%` | `--color-border` | 描边 / 分隔 |
|
|
307
|
+
| **Primary** | `#3B82F6` | `215 100% 46%` | `--color-primary` | 主操作 |
|
|
308
|
+
| **Primary-Soft** | `#1E2A45` | `217 40% 20%` | `--color-primary-soft` | 选中态底 |
|
|
309
|
+
| **Muted-FG** | `#94A3B8` | `215 14% 65%` | `--color-muted-foreground` | 副标题 |
|
|
310
|
+
| **Accent** | `#F59E0B` | `38 92% 50%` | `--color-accent` | 高亮 |
|
|
311
|
+
|
|
312
|
+
### Editor 色图标(数据驱动)
|
|
313
|
+
|
|
314
|
+
| 平台 | 主色(参考) | 平台 | 主色(参考) |
|
|
315
|
+
|------|------------|------|--------------|
|
|
316
|
+
| Claude / Anthropic | 珊瑚橙 `#D97757` | Codex / OpenAI | 墨黑 `#10A37F` |
|
|
317
|
+
| 中转站 (AK) | 橙 `#F97316` | Antigravity | 黑 `#111827` |
|
|
318
|
+
| Windsurf | 青 `#10B6C4` | Kiro | 紫 `#8B5CF6` |
|
|
319
|
+
| Cursor | 深灰 `#1F2937` | Gemini Cli | 蓝紫 `#4285F4` |
|
|
320
|
+
| CodeBuddy | 蓝 `#2563EB` | Qoder | 绿 `#22C55E` |
|
|
321
|
+
| GitHub Copilot | 灰黑 `#24292F` | Zed / Trae | 黑 `#0B0B0B` |
|
|
322
|
+
|
|
323
|
+
**实现**:维护 `src/lib/editors.ts` 映射表(`editor → { label, color, icon }`),含 unknown/缺失兜底。
|
|
324
|
+
|
|
325
|
+
### CSS 变量实现
|
|
326
|
+
|
|
327
|
+
```css
|
|
328
|
+
:root {
|
|
329
|
+
--color-background: 220 20% 98%;
|
|
330
|
+
--color-foreground: 220 9% 12%;
|
|
331
|
+
--color-card: 0 0% 100%;
|
|
332
|
+
--color-sidebar: 210 20% 99%;
|
|
333
|
+
--color-border: 220 16% 94%;
|
|
334
|
+
--color-primary: 215 100% 46%;
|
|
335
|
+
--color-primary-soft: 215 100% 96%;
|
|
336
|
+
--color-muted-foreground: 217 11% 45%;
|
|
337
|
+
--color-accent: 38 92% 50%;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.dark {
|
|
341
|
+
--color-background: 222 47% 11%;
|
|
342
|
+
--color-sidebar: 222 33% 13%;
|
|
343
|
+
--color-primary-soft: 217 40% 20%;
|
|
344
|
+
/* … 其余见 packages/web/src/index.css */
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 画布点阵纹理
|
|
349
|
+
|
|
350
|
+
参考图画布带细点阵。用 `radial-gradient` 实现,仅作用于主内容画布:
|
|
351
|
+
|
|
352
|
+
```css
|
|
353
|
+
.canvas-dotted {
|
|
354
|
+
background-color: hsl(var(--color-background));
|
|
355
|
+
background-image: radial-gradient(hsl(var(--color-border)) 1px, transparent 1px);
|
|
356
|
+
background-size: 20px 20px;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## II.3 字体系统
|
|
363
|
+
|
|
364
|
+
```css
|
|
365
|
+
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
366
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
367
|
+
--font-mono: 'SF Mono', 'JetBrains Mono', 'Fira Code', Menlo, Consolas, monospace;
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
| 级别 | 字号 | 行高 | 字重 | 用途 |
|
|
371
|
+
|------|------|------|------|------|
|
|
372
|
+
| **H1** | 32px | 40px | 700 | 页面标题 |
|
|
373
|
+
| **H2** | 28px | 36px | 700 | 板块标题 |
|
|
374
|
+
| **H3** | 24px | 32px | 600 | 小节标题 / 详情标题 |
|
|
375
|
+
| **H4** | 20px | 28px | 600 | 卡片标题 |
|
|
376
|
+
| **Stat** | 28–32px | — | 700 | 统计卡大号数字 |
|
|
377
|
+
| **Body** | 16px | 24px | 400 | 正文 |
|
|
378
|
+
| **Body-sm** | 14px | 20px | 400 | 列表项 / 设置项标题 |
|
|
379
|
+
| **Caption** | 12px | 18px | 400 | 副标题 / 角标 / 路径 |
|
|
380
|
+
| **Code** | 14px | 20px | 500 (mono) | 路径 / 代码 |
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## II.4 间距系统(4px 网格)
|
|
385
|
+
|
|
386
|
+
| 值 | 用途 |
|
|
387
|
+
|-----|------|
|
|
388
|
+
| **px-3 py-2** | 导航项 / 列表项内间距 |
|
|
389
|
+
| **gap-4** | 卡片网格间距 |
|
|
390
|
+
| **p-5 / p-6** | 卡片 / 面板内容区 |
|
|
391
|
+
| **px-6** | 顶栏 / 内容区水平内边距 |
|
|
392
|
+
| **gap-2** | 图标与文字间距 |
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## II.5 圆角系统
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
borderRadius: { lg: '12px', md: '8px', sm: '4px' }
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
| 半径 | 用途 |
|
|
403
|
+
|------|------|
|
|
404
|
+
| **rounded-lg (12px)** | 卡片、详情面板、统计卡、品牌图标 |
|
|
405
|
+
| **rounded-md (8px)** | 按钮、输入框、导航胶囊 |
|
|
406
|
+
| **rounded-sm (4px)** | 标签、徽章、角标 |
|
|
407
|
+
| **rounded-full** | 分段标签页选中胶囊 / 头像 |
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## II.6 阴影系统
|
|
412
|
+
|
|
413
|
+
参考图整体投影**很轻**,以「浮起感」为度,避免重阴影。
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
shadow-sm // 卡片默认(柔和浮起)
|
|
417
|
+
shadow // 悬停 / 选中卡片
|
|
418
|
+
shadow-md // 下拉菜单 / 弹层
|
|
419
|
+
shadow-lg // 模态框
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
层级:`0 扁平` → `sm 卡片` → `md 浮层` → `lg 顶层`。
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## II.7 布局规范(核心)
|
|
427
|
+
|
|
428
|
+
整体为「**顶部模块标签栏 + 左侧图标导航栏 + 内容区**」三区结构。
|
|
429
|
+
|
|
430
|
+
```
|
|
431
|
+
┌──────────────────────────────────────────────────────────┐
|
|
432
|
+
│ [Logo] 技能(Skills) 命令(待开发) 编辑器(待开发) │ ← 顶部模块标签栏 (topbar)
|
|
433
|
+
├──────────┬───────────────────────────────────────────────┤
|
|
434
|
+
│ ◎ 仪表盘 │ │
|
|
435
|
+
│ ◍ Claude │ 内容区 (main) │
|
|
436
|
+
│ ◍ Hermes │ · 仪表盘 → 卡片网格 │
|
|
437
|
+
│ ◍ Codex │ · 技能 → 搜索栏 + 列表 + 详情面板 │ ← 左侧栏 (sidebar)
|
|
438
|
+
│ │ · 设置 → 分页设置 │
|
|
439
|
+
│ ⚙ 设置 │ │ ← 设置固定底部
|
|
440
|
+
└──────────┴───────────────────────────────────────────────┘
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### 7.1 顶部模块标签栏(topbar)
|
|
444
|
+
|
|
445
|
+
- 左:品牌 logo + 名称
|
|
446
|
+
- 中/左:模块标签 `技能(Skills)` / `命令(待开发)` / `编辑器(待开发)`
|
|
447
|
+
- 选中态:高亮底(参考蓝图配色),未开发模块带「待开发」灰字 + 禁用样式
|
|
448
|
+
- 高度 56px
|
|
449
|
+
|
|
450
|
+
### 7.2 左侧图标导航栏(sidebar)
|
|
451
|
+
|
|
452
|
+
- 图标 + 文字的纵向导航项:`仪表盘`、按 `editor` 数据驱动(`Claude Code`/`Hermes Agent`/`Cursor`/`Codex`…,**过滤 `(none)`**)
|
|
453
|
+
- 选中态:`bg-primary-soft` + `text-primary` 圆角胶囊
|
|
454
|
+
- 悬停态:`hover:bg-muted`
|
|
455
|
+
- **底部固定**:`设置` 项(`mt-auto` 推到底部)
|
|
456
|
+
- 宽度 280px,底为 `--color-sidebar`
|
|
457
|
+
|
|
458
|
+
### 7.3 内容区(main)三态
|
|
459
|
+
|
|
460
|
+
| 模块/选择 | 形态 | 说明 |
|
|
461
|
+
|-----------|------|------|
|
|
462
|
+
| **仪表盘** | 卡片网格 | 响应式 grid(`grid-cols-1 md:grid-cols-2 lg:grid-cols-4`),每卡 = editor 图标 + 标签 + 技能聚合数字 |
|
|
463
|
+
| **技能** | 三段主从 | 搜索栏 + kind chip 次筛选 + 列表(项=名称+描述+来源标签) + 右侧详情面板 |
|
|
464
|
+
| **设置** | 分页设置 | 右上分段标签页(通用/网络服务/数据管理/关于)+ 设置项行 |
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## II.8 组件设计规范
|
|
469
|
+
|
|
470
|
+
### 统计卡(StatCard,仪表盘)
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
<Card className="flex items-center gap-3 p-5 rounded-lg shadow-sm">
|
|
474
|
+
<span className="grid h-10 w-10 place-items-center rounded-lg" style={{ background: editor.color + '1A', color: editor.color }}>
|
|
475
|
+
<BrandIcon size={20} />
|
|
476
|
+
</span>
|
|
477
|
+
<div>
|
|
478
|
+
<p className="text-body-sm text-muted-foreground">{label}</p>
|
|
479
|
+
<p className="text-h3 font-bold tabular-nums">{count}</p>
|
|
480
|
+
</div>
|
|
481
|
+
{delta && <span className="ml-auto rounded-sm bg-accent/15 px-1.5 text-caption text-accent">+{delta}</span>}
|
|
482
|
+
</Card>
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### 搜索栏(技能模块顶部)
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
<input
|
|
489
|
+
type="search"
|
|
490
|
+
placeholder="搜索账号 / 技能…"
|
|
491
|
+
className="h-10 w-full rounded-md border border-border bg-input px-3 text-body-sm
|
|
492
|
+
placeholder:text-muted-foreground
|
|
493
|
+
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
494
|
+
/>
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### 列表项(SkillListItem)
|
|
498
|
+
|
|
499
|
+
```tsx
|
|
500
|
+
<button className={cn(
|
|
501
|
+
'flex w-full flex-col gap-1 rounded-md border border-border bg-card p-3 text-left transition-colors',
|
|
502
|
+
selected ? 'border-primary bg-primary-soft' : 'hover:bg-muted'
|
|
503
|
+
)}>
|
|
504
|
+
<span className="text-body-sm font-medium text-foreground">{name}</span>
|
|
505
|
+
<span className="line-clamp-2 text-caption text-muted-foreground">{description}</span>
|
|
506
|
+
<span className="mt-1 w-fit rounded-sm bg-muted px-1.5 py-0.5 text-caption text-muted-foreground">{source}</span>
|
|
507
|
+
</button>
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### 详情面板(detail)
|
|
511
|
+
|
|
512
|
+
```tsx
|
|
513
|
+
<section className="detail">
|
|
514
|
+
<h2 className="text-h3 text-foreground">{title}</h2>
|
|
515
|
+
<p className="mt-2 text-body-sm text-muted-foreground">{description}</p>
|
|
516
|
+
<dl className="mt-4 grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-body-sm">
|
|
517
|
+
<dt className="text-muted-foreground">类型</dt><dd>{kind}</dd>
|
|
518
|
+
<dt className="text-muted-foreground">来源</dt><dd>{source}</dd>
|
|
519
|
+
<dt className="text-muted-foreground">路径</dt>
|
|
520
|
+
<dd className="break-all font-mono text-caption">{path}</dd>
|
|
521
|
+
</dl>
|
|
522
|
+
</section>
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### 设置项行(SettingRow)+ 分段标签页
|
|
526
|
+
|
|
527
|
+
```tsx
|
|
528
|
+
{/* 分段标签页 */}
|
|
529
|
+
<div className="inline-flex rounded-md bg-muted p-1 text-body-sm">
|
|
530
|
+
{tabs.map(t => (
|
|
531
|
+
<button className={cn('rounded-sm px-3 py-1', active === t && 'bg-card text-primary shadow-sm')}>{t}</button>
|
|
532
|
+
))}
|
|
533
|
+
</div>
|
|
534
|
+
|
|
535
|
+
{/* 设置项行 */}
|
|
536
|
+
<div className="flex items-center justify-between border-b border-border py-4">
|
|
537
|
+
<div>
|
|
538
|
+
<p className="text-body-sm text-foreground">{title}</p>
|
|
539
|
+
<p className="text-caption text-muted-foreground">{subtitle}</p>
|
|
540
|
+
</div>
|
|
541
|
+
<Select value={value} options={options} />
|
|
542
|
+
</div>
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## II.9 响应式设计
|
|
548
|
+
|
|
549
|
+
| 前缀 | 宽度 | 行为 |
|
|
550
|
+
|------|------|------|
|
|
551
|
+
| **sm** | 640px | 卡片网格 1 列 |
|
|
552
|
+
| **md** | 768px | 卡片网格 2 列;技能三段可折叠详情为抽屉 |
|
|
553
|
+
| **lg** | 1024px | 卡片网格 4 列;技能列表+详情并列 |
|
|
554
|
+
| **xl** | 1280px | 内容区最大化 |
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## II.10 动画系统
|
|
559
|
+
|
|
560
|
+
```ts
|
|
561
|
+
animation: {
|
|
562
|
+
'fade-in': 'fadeIn 200ms ease-in',
|
|
563
|
+
'slide-up': 'slideUp 300ms ease-out',
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
| 类型 | 时长 |
|
|
568
|
+
|------|------|
|
|
569
|
+
| 微交互(hover/选中) | 150–200ms |
|
|
570
|
+
| 模块/页面切换 | 300ms |
|
|
571
|
+
| Toast / 弹层 | 300ms |
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## II.11 深浅主题切换
|
|
576
|
+
|
|
577
|
+
```ts
|
|
578
|
+
// src/hooks/useTheme.ts(已实现)
|
|
579
|
+
document.documentElement.classList.toggle('dark', next === 'dark')
|
|
580
|
+
localStorage.setItem('theme', next)
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
`index.html` 内联防闪烁脚本在首屏前读取 `localStorage.theme` 应用 `.dark`。
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## II.12 无障碍性(A11y · WCAG AA)
|
|
588
|
+
|
|
589
|
+
- 色彩对比度 ≥ 4.5:1(正文)、≥ 3:1(大文本与图标)
|
|
590
|
+
- 所有导航/标签/设置项为可聚焦交互元素,`:focus-visible` 可见环(`--color-ring`)
|
|
591
|
+
- 键盘可达:模块标签、侧栏、列表、设置下拉
|
|
592
|
+
- 语义化:`<nav>` / `<aside>` / `<button>` / `<dl>`,图标按钮带 `aria-label`
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## II.13 设计与代码的映射
|
|
597
|
+
|
|
598
|
+
| 设计项 | 落地位置 |
|
|
599
|
+
|--------|---------|
|
|
600
|
+
| 颜色 token(CSS 变量) | `packages/web/src/index.css` |
|
|
601
|
+
| Tailwind 颜色/字号/圆角 | `packages/web/tailwind.config.ts` |
|
|
602
|
+
| 三区布局类(sidebar/topbar/detail/main-pane) | `packages/web/src/index.css`(`@layer components`) |
|
|
603
|
+
| 主题切换 | `packages/web/src/hooks/useTheme.ts` |
|
|
604
|
+
| editor 色映射 | `packages/web/src/lib/editors.ts` |
|
|
605
|
+
| verify 断言约束 | `build/verify.mjs`(`#app`;CSS 子串 OR 含 `topbar`/`sidebar`/`detail` 任一) |
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
# 三、框架说明
|
|
610
|
+
|
|
611
|
+
## III.1 技术栈定型
|
|
612
|
+
|
|
613
|
+
| 维度 | 选型 | 说明 |
|
|
614
|
+
|------|------|------|
|
|
615
|
+
| 构建工具 | **Vite 6** | 输出纯静态 SPA,由后端 Fastify 托管 |
|
|
616
|
+
| 运行时 | **React 18.3** | 函数组件 + Hooks |
|
|
617
|
+
| 语言 | **TypeScript 5.x (strict)** | 禁 `any` / `@ts-ignore` |
|
|
618
|
+
| 样式 | **Tailwind CSS 3.4** | CSS 变量驱动主题 |
|
|
619
|
+
| 组件 | **shadcn 风格**(`cva + cn` 手写) | 不跑官方 CLI,按需手写 |
|
|
620
|
+
| 图标 | **lucide-react** | — |
|
|
621
|
+
| 搜索 | **Fuse.js** | 客户端模糊搜索 |
|
|
622
|
+
| 取数 | **fetch** → Fastify `/api/*` | 同源,dev 由 vite 代理 |
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## III.2 服务与构建模型
|
|
627
|
+
|
|
628
|
+
```
|
|
629
|
+
huhaa-myskills start
|
|
630
|
+
└─ Fastify(packages/server) :11520
|
|
631
|
+
├─ /api/* # skills/stats/events/copy/open/translate/reload
|
|
632
|
+
├─ / → packages/web/dist/index.html
|
|
633
|
+
└─ /assets/* → packages/web/dist/assets/*
|
|
634
|
+
|
|
635
|
+
npm run build:web → build/build-web.mjs → (packages/web) vite build → dist/
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
- 前端 `base='/'`、`assetsDir='assets'`,与服务器静态路由约定一致。
|
|
639
|
+
- 服务器侧(`packages/server/src/index.mjs`)无需为前端改动。
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## III.3 核心配置
|
|
644
|
+
|
|
645
|
+
### TypeScript Strict
|
|
646
|
+
|
|
647
|
+
`tsconfig.json` 开启 `strict`、`noUnusedLocals`、`noUnusedParameters`;路径别名 `@/* → src/*`。
|
|
648
|
+
|
|
649
|
+
### Tailwind 主题 token
|
|
650
|
+
|
|
651
|
+
颜色全部走 CSS 变量;`darkMode: 'class'`;扩展了 `fontSize`(h1~caption)、`borderRadius`、`fontFamily`。
|
|
652
|
+
|
|
653
|
+
### 三栏布局类(重要约束)
|
|
654
|
+
|
|
655
|
+
`src/index.css` 的 `.sidebar` / `.topbar` / `.detail` 同时被 `build/verify.mjs` 的 CSS 冒烟断言引用,**重命名需同步改 verify**。
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## III.4 快速启动
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
# 本机 NODE_ENV=production,需显式带 dev 依赖安装构建工具链
|
|
663
|
+
NODE_ENV=development npm install --include=dev
|
|
664
|
+
|
|
665
|
+
# 生产方式:构建 + 启动后端托管
|
|
666
|
+
npm run build:web
|
|
667
|
+
npm start # → http://localhost:11520
|
|
668
|
+
|
|
669
|
+
# 开发方式:前后端分离
|
|
670
|
+
npm start # 终端 A:后端 API(11520)
|
|
671
|
+
cd packages/web && npm run dev # 终端 B:前端 dev(11521),/api 代理到 11520
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### 质量检查
|
|
675
|
+
|
|
676
|
+
```bash
|
|
677
|
+
npm run verify # 构建 + 单测 + HTTP/API/静态冒烟
|
|
678
|
+
cd packages/web && ../../node_modules/.bin/tsc --noEmit # TS strict 类型检查
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
# 四、重构计划 v2.0
|
|
684
|
+
|
|
685
|
+
## IV.1 背景与现状
|
|
686
|
+
|
|
687
|
+
仓库已从「两套并存空壳前端」收敛为单一 **Vite + React + Tailwind + shadcn 风格** 前端(P0 已完成)。
|
|
688
|
+
|
|
689
|
+
### 与新蓝图的差距
|
|
690
|
+
|
|
691
|
+
| 维度 | 现状(P0) | 新蓝图目标 |
|
|
692
|
+
|------|-----------|-----------|
|
|
693
|
+
| **顶部** | Topbar 只放搜索 + 主题/刷新按钮 | **模块标签栏**:Logo + 技能 / 命令(待开发) / 编辑器(待开发) |
|
|
694
|
+
| **左侧栏** | 按 `kind`(skill/plugin/mcp/instruction)过滤的按钮 | **图标导航**:仪表盘 + 按 **`editor`**(Claude Code/Hermes Agent/Cursor/Codex…) + 底部固定「设置」 |
|
|
695
|
+
| **内容区** | 固定为「列表 + 详情」两栏 | **三态**:仪表盘卡片网格 / 技能三段主从(搜索+列表+详情) / 设置分页 |
|
|
696
|
+
| **新页面** | 无 | **仪表盘**(技能聚合统计卡网格)、**设置**(分段标签页 + 设置项) |
|
|
697
|
+
| **视觉** | 蓝/琥珀、白底 | 柔和浅色、点阵画布、品牌色图标、`primary-soft` 选中胶囊 |
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
701
|
+
## IV.2 架构约束(务必遵守)
|
|
702
|
+
|
|
703
|
+
1. **挂载节点 id 必须为 `app`** — `verify.mjs:91` 断言 `index.html` 含 `<div id="app"></div>`。
|
|
704
|
+
2. **保留 `topbar`/`sidebar`/`detail` 三个类名中至少其一** — `verify.mjs:103` 仅做子串冒烟(OR)。本计划保留全部三者。
|
|
705
|
+
3. **资源走 `/assets/*`,`base='/'`** — 与服务器 `/assets/*` 路由(`index.mjs:293`)一致。
|
|
706
|
+
4. **TypeScript strict、禁 `any`/`@ts-ignore`** — P1 起 `tsc --noEmit` 进 `verify` 门禁。
|
|
707
|
+
5. **前端 `types.ts` 与 `packages/scanner/src/types.d.ts` 同步** — 现有漂移(缺 `mcp-tool`)P1 一并修。
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
## IV.3 评审锁定决策(2026-06-30)
|
|
712
|
+
|
|
713
|
+
| # | 决策 | 结论 |
|
|
714
|
+
|---|------|------|
|
|
715
|
+
| **D2** | 侧栏/筛选的规范轴 | **用 `editor`**(`Stats.byEditor` 已预算),`kind` 降为列表内 chip 次筛选 |
|
|
716
|
+
| **D3** | 仪表盘语义 | **技能聚合指标**(`total / byKind / byEditor / bySource / byCategory / parseError`),复用卡片视觉、**不照搬账号管理器** |
|
|
717
|
+
| **D4** | 阶段顺序 + 测试 | **P2 与 P4 合并**(换外壳同时重建技能三段,零回退窗口);**P1 接入 vitest + 把 `tsc --noEmit` 纳入 `verify`/CI** |
|
|
718
|
+
| **D5** | dist 发布 | **P0 阻塞项**:`prepare`/`prepublishOnly` 构建钩子,保证 npm 用户装后即见新 UI |
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
## IV.4 分阶段路线
|
|
723
|
+
|
|
724
|
+
| 阶段 | 内容 | 关键产出 | 状态 |
|
|
725
|
+
|------|------|---------|------|
|
|
726
|
+
| **P0** | 清理旧栈 + Vite/React + 主题 token + 两栏外壳 + 列表/详情 + 搜索 | — | ✅ 已完成 |
|
|
727
|
+
| **P1** | v2.0 token + 接入 vitest + `tsc --noEmit` 纳入 `verify` + 修 types 漂移 | `index.css`/`tailwind.config.ts`/`vitest.config.ts`/`verify.mjs` | ⏳ 待办 |
|
|
728
|
+
| **P2+P4** | topbar→模块标签栏;sidebar→`editor` 图标导航;App 状态机;**同步重建** SkillsView | 新 Topbar/Sidebar/App/SkillsView + 单测 | ⏳ 待办 |
|
|
729
|
+
| **P3** | `DashboardView` + `StatCard` + `lib/editors.ts` | 统计卡网格 + 单测 | ⏳ 待办 |
|
|
730
|
+
| **P5** | `SettingsView`:分段标签页 + `SettingRow` | 设置分页 + 单测 | ⏳ 待办 |
|
|
731
|
+
| **P6** | 命令 / 编辑器模块占位 + 禁用态 | `ComingSoon` 组件 | ⏳ 待办 |
|
|
732
|
+
| **P7** | 消费 `/api/skills/:id` raw,markdown-it 渲染 + 代码高亮 | 富文本详情 | ⏳ 待办 |
|
|
733
|
+
| **P8** | 接 `/api/copy`、`/api/open`、`/api/events`(SSE);修契约 | 实时刷新 + 复制/打开 | ⏳ 待办 |
|
|
734
|
+
| **P9** | 覆盖率补齐 + A11y + 响应式 + 分包 | 测试 + 优化 | ⏳ 待办 |
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
## IV.5 P1 执行清单(视觉系统 + 测试门禁)
|
|
739
|
+
|
|
740
|
+
- [ ] `index.css`:新增 `--color-sidebar`、`--color-primary-soft`(亮/暗),背景 `220 20% 98%`,border `220 16% 94%`
|
|
741
|
+
- [ ] `tailwind.config.ts`:补 `sidebar` / `primary-soft` 颜色映射
|
|
742
|
+
- [ ] 新增 `.canvas-dotted` 点阵纹理类(仅 main 画布);卡片阴影 `shadow-sm`
|
|
743
|
+
- [ ] **安装并配置 vitest + @testing-library/react**;`package.json` `test` 脚本纳入前端
|
|
744
|
+
- [ ] **`verify.mjs` 增加 `tsc --noEmit`**(前端 strict 类型门禁)
|
|
745
|
+
- [ ] **修 `types.ts`**:`SkillKind` 补 `mcp-tool`,与 `scanner/types.d.ts` 对齐
|
|
746
|
+
|
|
747
|
+
---
|
|
748
|
+
|
|
749
|
+
# 五、实现指南
|
|
750
|
+
|
|
751
|
+
## V.1 Sidebar 架构升级
|
|
752
|
+
|
|
753
|
+
### 问题背景
|
|
754
|
+
|
|
755
|
+
Phase 2 实现时,Tier 过滤逻辑设计为:
|
|
756
|
+
1. Backend: 返回 tier/brand/dirName 字段 ✅
|
|
757
|
+
2. Frontend Hook: useSkillIcons 映射 icon ✅
|
|
758
|
+
3. SkillsView 内部: Tier filter chips 和过滤 ✅
|
|
759
|
+
4. **Sidebar 菜单**: 未实现 ← **遗漏**
|
|
760
|
+
|
|
761
|
+
导致用户体验割裂:Sidebar 只能通过"技能来源"(Editor) 过滤,页面内有 Tier 过滤 chips,但无法通过 Sidebar 一级菜单访问。
|
|
762
|
+
|
|
763
|
+
### 修复方案
|
|
764
|
+
|
|
765
|
+
#### 5.1.1 Sidebar 组件升级
|
|
766
|
+
|
|
767
|
+
```typescript
|
|
768
|
+
// 前: 仅支持 editor 过滤
|
|
769
|
+
interface SidebarProps {
|
|
770
|
+
view: 'dashboard' | 'skills' | 'settings'
|
|
771
|
+
editorFilter: string | null
|
|
772
|
+
stats: Stats | null
|
|
773
|
+
onDashboard: () => void
|
|
774
|
+
onSettings: () => void
|
|
775
|
+
onEditor: (key: string | null) => void
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// 后: 新增 tier 过滤支持
|
|
779
|
+
interface SidebarProps {
|
|
780
|
+
view: 'dashboard' | 'skills' | 'settings'
|
|
781
|
+
editorFilter: string | null
|
|
782
|
+
tierFilter: 'tool' | 'directory' | 'other' | null // NEW
|
|
783
|
+
stats: Stats | null
|
|
784
|
+
onDashboard: () => void
|
|
785
|
+
onSettings: () => void
|
|
786
|
+
onEditor: (key: string | null) => void
|
|
787
|
+
onTier: (tier: 'tool' | 'directory' | 'other' | null) => void // NEW
|
|
788
|
+
}
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
**菜单结构变更**:
|
|
792
|
+
|
|
793
|
+
```
|
|
794
|
+
前:
|
|
795
|
+
├─ 仪表盘
|
|
796
|
+
├─ 技能来源 ← 仅此分类
|
|
797
|
+
│ ├─ 全部技能
|
|
798
|
+
│ ├─ Claude Code
|
|
799
|
+
│ ├─ Hermes
|
|
800
|
+
│ └─ Cursor
|
|
801
|
+
└─ 设置
|
|
802
|
+
|
|
803
|
+
后:
|
|
804
|
+
├─ 仪表盘
|
|
805
|
+
├─ 技能分类 ← NEW: 一级分类
|
|
806
|
+
│ ├─ 全部分类
|
|
807
|
+
│ ├─ 🔧 Official Tools
|
|
808
|
+
│ ├─ 📁 Custom Skills
|
|
809
|
+
│ └─ ⚙️ Other Sources
|
|
810
|
+
├─ 技能来源 ← 二级分类(保留)
|
|
811
|
+
│ ├─ 全部来源
|
|
812
|
+
│ ├─ Claude Code
|
|
813
|
+
│ ├─ Hermes
|
|
814
|
+
│ └─ Cursor
|
|
815
|
+
└─ 设置
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
**关键代码片段**:
|
|
819
|
+
|
|
820
|
+
```typescript
|
|
821
|
+
const tierIcons = [
|
|
822
|
+
{ tier: 'tool' as const, icon: '🔧', label: 'Official Tools' },
|
|
823
|
+
{ tier: 'directory' as const, icon: '📁', label: 'Custom Skills' },
|
|
824
|
+
{ tier: 'other' as const, icon: '⚙️', label: 'Other Sources' },
|
|
825
|
+
]
|
|
826
|
+
|
|
827
|
+
{tierIcons.map(({ tier, icon, label }) => {
|
|
828
|
+
const count = byTier[tier] ?? 0
|
|
829
|
+
const active = view === 'skills' && tierFilter === tier
|
|
830
|
+
return (
|
|
831
|
+
<button key={tier} onClick={() => onTier(tier)} className={rowCls(active)}>
|
|
832
|
+
<span className="flex items-center gap-2">
|
|
833
|
+
<span className="text-base">{icon}</span>
|
|
834
|
+
<span>{label}</span>
|
|
835
|
+
</span>
|
|
836
|
+
<span className="text-caption opacity-80">{count}</span>
|
|
837
|
+
</button>
|
|
838
|
+
)
|
|
839
|
+
})}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
#### 5.1.2 App.tsx 状态管理升级
|
|
843
|
+
|
|
844
|
+
```typescript
|
|
845
|
+
// UIState 接口
|
|
846
|
+
export interface UIState {
|
|
847
|
+
module: ModuleKey
|
|
848
|
+
view: View
|
|
849
|
+
editorFilter: string | null
|
|
850
|
+
tierFilter: 'tool' | 'directory' | 'other' | null // NEW
|
|
851
|
+
kindFilter: string | null
|
|
852
|
+
query: string
|
|
853
|
+
selectedId: string | null
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// Action 类型新增
|
|
857
|
+
export type Action =
|
|
858
|
+
| { type: 'module'; module: ModuleKey }
|
|
859
|
+
| { type: 'dashboard' }
|
|
860
|
+
| { type: 'settings' }
|
|
861
|
+
| { type: 'editor'; key: string | null }
|
|
862
|
+
| { type: 'tier'; tier: 'tool' | 'directory' | 'other' | null } // NEW
|
|
863
|
+
| { type: 'query'; query: string }
|
|
864
|
+
| { type: 'kind'; kind: string | null }
|
|
865
|
+
| { type: 'select'; id: string }
|
|
866
|
+
|
|
867
|
+
// Reducer 处理新增
|
|
868
|
+
case 'tier':
|
|
869
|
+
return { ...state, view: 'skills', tierFilter: action.tier, kindFilter: null, selectedId: null }
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
#### 5.1.3 SkillsView 调整
|
|
873
|
+
|
|
874
|
+
```typescript
|
|
875
|
+
// Props 接口更新
|
|
876
|
+
interface SkillsViewProps {
|
|
877
|
+
items: SkillItem[]
|
|
878
|
+
editorFilter: string | null
|
|
879
|
+
tierFilter: 'tool' | 'directory' | 'other' | null // NEW: 从外部传入
|
|
880
|
+
query: string
|
|
881
|
+
onQuery: (q: string) => void
|
|
882
|
+
kindFilter: string | null
|
|
883
|
+
onKind: (k: string | null) => void
|
|
884
|
+
selectedId: string | null
|
|
885
|
+
onSelect: (id: string) => void
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Tier 过滤逻辑(从 Sidebar 通过 props 传入)
|
|
889
|
+
const byTier = useMemo(() => {
|
|
890
|
+
if (tierFilter === null) return byEditor
|
|
891
|
+
return byEditor.filter((it) => (it.tier || 'other') === tierFilter)
|
|
892
|
+
}, [byEditor, tierFilter])
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
|
|
897
|
+
## V.2 API 集成
|
|
898
|
+
|
|
899
|
+
### 类型化 API 客户端(`src/lib/api.ts`)
|
|
900
|
+
|
|
901
|
+
```typescript
|
|
902
|
+
export const api = {
|
|
903
|
+
async getSkills(): Promise<SkillItem[]> {
|
|
904
|
+
const res = await fetch('/api/skills')
|
|
905
|
+
if (!res.ok) throw new Error(`GET /api/skills: ${res.status}`)
|
|
906
|
+
return res.json()
|
|
907
|
+
},
|
|
908
|
+
|
|
909
|
+
async getStats(): Promise<Stats> {
|
|
910
|
+
const res = await fetch('/api/stats')
|
|
911
|
+
if (!res.ok) throw new Error(`GET /api/stats: ${res.status}`)
|
|
912
|
+
return res.json()
|
|
913
|
+
},
|
|
914
|
+
|
|
915
|
+
async getSkillDetail(id: string): Promise<SkillItem> {
|
|
916
|
+
const res = await fetch(`/api/skills/${id}`)
|
|
917
|
+
if (!res.ok) throw new Error(`GET /api/skills/${id}: ${res.status}`)
|
|
918
|
+
return res.json()
|
|
919
|
+
},
|
|
920
|
+
|
|
921
|
+
async copy(skillId: string, type: 'path' | 'dir' | 'rel' | 'name' | 'raw' | 'prompt'): Promise<void> {
|
|
922
|
+
const res = await fetch('/api/copy', {
|
|
923
|
+
method: 'POST',
|
|
924
|
+
headers: { 'Content-Type': 'application/json' },
|
|
925
|
+
body: JSON.stringify({ skillId, type }),
|
|
926
|
+
})
|
|
927
|
+
if (!res.ok) throw new Error(`POST /api/copy: ${res.status}`)
|
|
928
|
+
},
|
|
929
|
+
|
|
930
|
+
async open(skillId: string): Promise<void> {
|
|
931
|
+
const res = await fetch('/api/open', {
|
|
932
|
+
method: 'POST',
|
|
933
|
+
headers: { 'Content-Type': 'application/json' },
|
|
934
|
+
body: JSON.stringify({ skillId }),
|
|
935
|
+
})
|
|
936
|
+
if (!res.ok) throw new Error(`POST /api/open: ${res.status}`)
|
|
937
|
+
},
|
|
938
|
+
|
|
939
|
+
// SSE: 监听实时 skill reload 事件
|
|
940
|
+
events(): EventSource {
|
|
941
|
+
return new EventSource('/api/events')
|
|
942
|
+
},
|
|
943
|
+
|
|
944
|
+
async translate(skillId: string, targetLang: string): Promise<SkillItem> {
|
|
945
|
+
const res = await fetch('/api/translate', {
|
|
946
|
+
method: 'POST',
|
|
947
|
+
headers: { 'Content-Type': 'application/json' },
|
|
948
|
+
body: JSON.stringify({ skillId, targetLang }),
|
|
949
|
+
})
|
|
950
|
+
if (!res.ok) throw new Error(`POST /api/translate: ${res.status}`)
|
|
951
|
+
return res.json()
|
|
952
|
+
},
|
|
953
|
+
}
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
---
|
|
957
|
+
|
|
958
|
+
## V.3 数据流与状态管理
|
|
959
|
+
|
|
960
|
+
```
|
|
961
|
+
Fastify /api/{skills,stats}
|
|
962
|
+
↓
|
|
963
|
+
App useReducer state
|
|
964
|
+
│ module × view × {tierFilter, editorFilter, kindFilter, query, selectedId}
|
|
965
|
+
│
|
|
966
|
+
├─ DashboardView (Stats 聚合)
|
|
967
|
+
├─ SkillsView (Fuse 搜索 + tier/editor filter + kind chip + 列表 + 详情)
|
|
968
|
+
└─ SettingsView (本地配置)
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
### 事件流示例
|
|
972
|
+
|
|
973
|
+
```
|
|
974
|
+
1. 用户点击 Sidebar "Official Tools" Tier
|
|
975
|
+
↓
|
|
976
|
+
2. dispatch({ type: 'tier', tier: 'tool' })
|
|
977
|
+
↓
|
|
978
|
+
3. reducer 更新: UIState.tierFilter = 'tool', view = 'skills'
|
|
979
|
+
↓
|
|
980
|
+
4. Sidebar 高亮 "Official Tools" 按钮
|
|
981
|
+
↓
|
|
982
|
+
5. SkillsView 接收 tierFilter prop
|
|
983
|
+
↓
|
|
984
|
+
6. 列表按 tier 重新过滤并重渲染
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
---
|
|
988
|
+
|
|
989
|
+
# 六、快速启动指南
|
|
990
|
+
|
|
991
|
+
## VI.1 环境设置
|
|
992
|
+
|
|
993
|
+
```bash
|
|
994
|
+
# 第一次克隆后,本机 NODE_ENV=production,需显式带 dev 依赖
|
|
995
|
+
NODE_ENV=development npm install --include=dev
|
|
996
|
+
|
|
997
|
+
# 验证环境
|
|
998
|
+
node --version # >= 20.0.0
|
|
999
|
+
npm --version # >= 10.0.0
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
## VI.2 构建与运行
|
|
1003
|
+
|
|
1004
|
+
### 生产模式(完整构建 + 后端托管)
|
|
1005
|
+
|
|
1006
|
+
```bash
|
|
1007
|
+
# 构建前端 → packages/web/dist
|
|
1008
|
+
npm run build:web
|
|
1009
|
+
|
|
1010
|
+
# 启动后端服务(:11520)
|
|
1011
|
+
npm start
|
|
1012
|
+
|
|
1013
|
+
# 浏览器访问
|
|
1014
|
+
# → http://localhost:11520
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
### 开发模式(前后端分离)
|
|
1018
|
+
|
|
1019
|
+
```bash
|
|
1020
|
+
# 终端 A:启动后端 API(:11520)
|
|
1021
|
+
npm start
|
|
1022
|
+
|
|
1023
|
+
# 终端 B:启动前端 dev 服务(:11521)
|
|
1024
|
+
cd packages/web
|
|
1025
|
+
npm run dev
|
|
1026
|
+
|
|
1027
|
+
# 浏览器访问
|
|
1028
|
+
# → http://localhost:11521
|
|
1029
|
+
# (/api/* 自动代理到 http://localhost:11520)
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
## VI.3 代码检查
|
|
1033
|
+
|
|
1034
|
+
```bash
|
|
1035
|
+
# 构建 + 单测 + HTTP/API/静态冒烟
|
|
1036
|
+
npm run verify
|
|
1037
|
+
|
|
1038
|
+
# 前端 TypeScript strict 检查
|
|
1039
|
+
cd packages/web && ../../node_modules/.bin/tsc --noEmit
|
|
1040
|
+
|
|
1041
|
+
# 前端代码风格检查与修复
|
|
1042
|
+
cd packages/web && npm run lint
|
|
1043
|
+
cd packages/web && npm run lint:fix
|
|
1044
|
+
|
|
1045
|
+
# 前端单测(P1 接入 vitest)
|
|
1046
|
+
cd packages/web && npm test
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
## VI.4 常见命令速查
|
|
1050
|
+
|
|
1051
|
+
```bash
|
|
1052
|
+
# 安装
|
|
1053
|
+
NODE_ENV=development npm install --include=dev
|
|
1054
|
+
|
|
1055
|
+
# 构建与运行
|
|
1056
|
+
npm run build:web # 构建前端 → packages/web/dist
|
|
1057
|
+
npm start # 启动后端托管 → http://localhost:11520
|
|
1058
|
+
npm stop # 停止服务
|
|
1059
|
+
|
|
1060
|
+
# 前端开发(前后端分离)
|
|
1061
|
+
cd packages/web && npm run dev # 前端 dev(11521),/api 代理到 11520
|
|
1062
|
+
|
|
1063
|
+
# 检查
|
|
1064
|
+
npm run verify # 构建 + 单测 + HTTP/API/静态冒烟
|
|
1065
|
+
npm test # scanner + server 单测
|
|
1066
|
+
cd packages/web && ../../node_modules/.bin/tsc --noEmit # 前端 TS strict 检查
|
|
1067
|
+
|
|
1068
|
+
# 提交
|
|
1069
|
+
git commit -m "feat(web): 添加仪表盘"
|
|
1070
|
+
git commit -m "fix(theme): 修复暗色对比度"
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
---
|
|
1074
|
+
|
|
1075
|
+
## VI.5 验证清单
|
|
1076
|
+
|
|
1077
|
+
启动后,按以下步骤验证系统正常运行:
|
|
1078
|
+
|
|
1079
|
+
```bash
|
|
1080
|
+
# 1. 后端启动检查
|
|
1081
|
+
curl -s http://localhost:11520/api/stats | jq .
|
|
1082
|
+
|
|
1083
|
+
# 2. 技能列表加载
|
|
1084
|
+
curl -s http://localhost:11520/api/skills | jq 'length'
|
|
1085
|
+
|
|
1086
|
+
# 3. 前端页面加载(访问浏览器)
|
|
1087
|
+
# http://localhost:11520
|
|
1088
|
+
# → 应显示仪表盘 / 技能列表(Phase 3+ 后完全UI)
|
|
1089
|
+
|
|
1090
|
+
# 4. 构建验证
|
|
1091
|
+
npm run verify
|
|
1092
|
+
# → ✅ 1669 modules 构建通过
|
|
1093
|
+
# → ✅ 单测全绿
|
|
1094
|
+
# → ✅ 冒烟断言通过
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
---
|
|
1098
|
+
|
|
1099
|
+
## VI.6 项目结构一览
|
|
1100
|
+
|
|
1101
|
+
```
|
|
1102
|
+
HuHaa-MySkills/
|
|
1103
|
+
├── packages/
|
|
1104
|
+
│ ├── web/ # 前端 Vite + React SPA
|
|
1105
|
+
│ │ ├── index.html # 入口
|
|
1106
|
+
│ │ ├── vite.config.ts
|
|
1107
|
+
│ │ ├── tailwind.config.ts
|
|
1108
|
+
│ │ ├── vitest.config.ts
|
|
1109
|
+
│ │ └── src/
|
|
1110
|
+
│ │ ├── App.tsx # 状态机 + 三区外壳
|
|
1111
|
+
│ │ ├── index.css # 主题 token + 布局类
|
|
1112
|
+
│ │ ├── types.ts # SkillItem / Stats
|
|
1113
|
+
│ │ ├── lib/
|
|
1114
|
+
│ │ │ ├── cn.ts
|
|
1115
|
+
│ │ │ ├── api.ts # API 客户端
|
|
1116
|
+
│ │ │ └── editors.ts # editor 色映射
|
|
1117
|
+
│ │ ├── hooks/useTheme.ts
|
|
1118
|
+
│ │ └── components/
|
|
1119
|
+
│ │ ├── ui/ # button / card / select
|
|
1120
|
+
│ │ └── layout/ # Sidebar / Topbar
|
|
1121
|
+
│ ├── server/ # Fastify 后端(:11520)
|
|
1122
|
+
│ ├── scanner/ # 技能扫描
|
|
1123
|
+
│ └── ...
|
|
1124
|
+
│
|
|
1125
|
+
├── docs/
|
|
1126
|
+
│ ├── Frontend-Spec.md # 本文件
|
|
1127
|
+
│ └── hermes_docs_project_plan.md
|
|
1128
|
+
│
|
|
1129
|
+
├── build/verify.mjs # 冒烟断言
|
|
1130
|
+
├── README.md
|
|
1131
|
+
├── CLAUDE.md
|
|
1132
|
+
└── package.json
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
---
|
|
1136
|
+
|
|
1137
|
+
# 七、相关资源
|
|
1138
|
+
|
|
1139
|
+
- **[Vite 官方文档](https://vite.dev)**
|
|
1140
|
+
- **[React 官方文档](https://react.dev)**
|
|
1141
|
+
- **[Tailwind CSS 文档](https://tailwindcss.com/docs)**
|
|
1142
|
+
- **[TypeScript Handbook](https://www.typescriptlang.org/docs)**
|
|
1143
|
+
- **[shadcn/ui 组件库](https://ui.shadcn.com)**
|
|
1144
|
+
|
|
1145
|
+
---
|
|
1146
|
+
|
|
1147
|
+
**最后更新** — 2026-07-01
|
|
1148
|
+
**版本** — v2.0 (完整规范整合)
|
|
1149
|
+
**状态** — ✅ 规范锁定,P0 已落地,可迭代业务功能
|