- Vendor ArkScope decorative layers (ScrambleTitle / IsometricWave) with provenance notes; decorative-only per AGENTS.md red lines - Migrate theme tokens to Arco, register the Arco theme, and add hook adapter composables (useMessage / useDialog / useNotification) with matching signatures - Sample pages: LoginView and AppSidebar on the new baseline; docs/arco-mapping.md and docs/ui-baseline.md land - agent-bridge: prefer the PM-selected venv from facts.json over legacy in-tree venvs (legacy lacks the mcp extra, so every MCP server showed 0 tools / not connected) - agent-bridge python (vendored, deliberate deviation): MCP discovery import fallback and pyyaml -> hermes_yaml so plugins and MCP work under the PM env; install the mcp extra via `hermes pm install --extra mcp` - Chat-chain fragment: docs/chat-chain-changes/2026-10-17-phase005-arkscope-baseline.md Verified: harness:check, test (2020 passed), test:e2e (30 passed), build all green; manual: plugins 100/0 warnings, MCP 6/6 servers connected with 104 tools.
336 lines
11 KiB
Markdown
336 lines
11 KiB
Markdown
# Phase 005 — ArkScope vendor + 样板页(风格基线)
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 目标 | vendor 2 个 ArkScope 组件;用 LoginView + AppSidebar 定视觉语言基线 |
|
||
| 前置 | Phase 004 通过(项目功能完整) |
|
||
| 产出 | `docs/ui-baseline.md` 定稿;后续批量迁移照它执行 |
|
||
| 参考 | `docs/03-施工蓝图.md` §7 |
|
||
|
||
---
|
||
|
||
## 0. 为什么必须先做样板页
|
||
|
||
naive-ui 渗透面是 **100 个文件 / 105 处**(不只 27 个视图,还含 `components/` `stores/` `composables/`)。
|
||
|
||
先定基线再批量,否则 100 个文件会被改两遍。
|
||
|
||
---
|
||
|
||
## 1. 功能任务 1 — vendor ArkScope
|
||
|
||
### 1.1 上游现状(已核实)
|
||
|
||
`github.com/triplepiers/ArkScope` — "对鹰角 UI 组件的拙劣复现",Vue 3 + Vite,**无 LICENSE**,仓库 322MB。
|
||
|
||
`src/components/` 下的组件绝大多数**强绑定游戏美术素材**(干员立绘、Banner)。`public/assets/` 有 131 个路径全是游戏资源。
|
||
|
||
**只有 2 个组件可脱离素材复用**:
|
||
|
||
| 组件 | 依赖 | 判定 |
|
||
|---|---|---|
|
||
| `ScrambleTitle` | 纯 DOM + CSS,文字解码动画 | ✅ vendor |
|
||
| `IsometricWave` | CSS filter + 位移,类亚克力 hover | ✅ vendor |
|
||
| `Particle2D` / `Particle3D` | 3D 模型 + 遮罩图 | ❌ 太重 |
|
||
| `OperatorCarousel` / `ArknightsMedia` / `GameplayAlbum` / `NoticeCarousel` / `FullScreenNavigator` / `NewsList` / `EndfieldSidebar` / `Endfield/*` | 全部依赖游戏素材,脱离素材无意义 | ❌ 不 vendor |
|
||
|
||
其余组件的价值是**视觉手法**(斜切遮罩、噪点、扫描线、Reveal & Blink),后续页面按需自己实现,不搬代码。
|
||
|
||
### 1.2 做法
|
||
|
||
**不作为 npm 依赖,不 clone 整仓。**
|
||
|
||
1. 定位上游 commit(`main` 分支,记录 `pushed_at`),记下来
|
||
2. 只下载 `ScrambleTitle` 与 `IsometricWave` 两个组件目录
|
||
3. 放到 `packages/client/src/vendor/arkscore/<ComponentName>/`
|
||
4. **剥离**:`useAssetPreloader` / `particle3DModels` / `data/componentRegistry.js` / `router` / `views` / `showcases`(上游 demo 工程的东西)
|
||
5. **不搬**:`src/assets/**`、`public/**`、上游全局 `src/style.css`(只取组件 scoped 样式)
|
||
6. 保留原文件头注释 + 上游 commit hash
|
||
|
||
### 1.3 PROVENANCE.md(**必写**)
|
||
|
||
`packages/client/src/vendor/arkscore/PROVENANCE.md`:
|
||
|
||
```markdown
|
||
# ArkScope vendored components
|
||
|
||
- 上游:https://github.com/triplepiers/ArkScope
|
||
- commit:<hash>
|
||
- 拉取日期:<date>
|
||
- vendor 的组件:ScrambleTitle、IsometricWave
|
||
- 剥离内容:demo 工程(router/views/showcases/componentRegistry)、assets、public
|
||
|
||
## 许可证
|
||
上游仓库无 LICENSE 文件。
|
||
|
||
本 vendor 仅用于个人自用,不分发、不商用。
|
||
若要公开分发,必须先向上游作者取得授权或替换为自研实现。
|
||
|
||
## 未 vendor 的组件
|
||
其余组件强依赖鹰角游戏美术素材,脱离素材无实际价值,故未 vendor。
|
||
本项目仅参考其视觉手法(斜切遮罩、噪点、扫描线等),自行实现。
|
||
```
|
||
|
||
### 1.4 新增机械化测试
|
||
|
||
`tests/client/arkscope-vendor.test.ts`:
|
||
|
||
- 断言 `vendor/arkscore/` 下无 `.png` / `.jpg` / `.webp` / `.mp3` / `.mp4`
|
||
- 断言源码内无 `src/assets` / `public/assets` 引用
|
||
- 断言 `PROVENANCE.md` 存在且含 commit hash
|
||
- 断言组件总数 ≤ 3(防回流)
|
||
|
||
---
|
||
|
||
## 2. 功能任务 2 — 使用边界(硬约束,写进 `AGENTS.md`)
|
||
|
||
| 允许 | 禁止 |
|
||
|---|---|
|
||
| 登录页标题区装饰位面 | 聊天页(消息区 / 输入区 / 侧边栏) |
|
||
| Journey 图谱的背景层 | 任何表单页(Skills / Profiles / Settings / Models) |
|
||
| 首屏 loading / 空状态 | 任何表格页(Usage / Logs / Jobs / Kanban) |
|
||
| | 任何点击交互密集区域 |
|
||
|
||
**判定标准**:装饰位面**不得承载信息、不得承载交互、不得影响可读性**。
|
||
|
||
**`pointer-events: none` 是硬要求**,装饰层绝不能吃掉点击。
|
||
|
||
---
|
||
|
||
## 3. 功能任务 3 — 主题令牌迁移
|
||
|
||
### 3.1 新建 `packages/client/src/styles/arco-theme.ts`
|
||
|
||
替换 `styles/theme.ts`(Naive 的 `GlobalThemeOverrides`):
|
||
|
||
```ts
|
||
export const arcoTheme = {
|
||
// 延续旧版克制灰阶
|
||
colorPrimary: '#2f2f2f',
|
||
colorBgLayout: '#fafafa',
|
||
colorBgContainer: '#ffffff',
|
||
borderRadius: 6,
|
||
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
|
||
fontFamilyMono: '"JetBrains Mono", "Fira Code", monospace',
|
||
}
|
||
```
|
||
|
||
暗色模式走 CSS 变量覆盖,**不用** Arco 的 `dark` theme + overrides 双轨。
|
||
|
||
### 3.2 改 `App.vue`
|
||
|
||
旧版是 `naiveTheme` computed(浅/深两套对象)。改为:
|
||
|
||
```html
|
||
<div class="app-root" :class="{ 'dark': isDark }">
|
||
```
|
||
|
||
暗色由 `body[arco-theme='dark']` 承载(Arco 官方机制),app 只负责切换属性。
|
||
|
||
### 3.3 改 `index.html` 的 FOUC 脚本
|
||
|
||
保留旧版机制(内联脚本读 localStorage 提前定 class),但改为切 `arco-theme` 属性:
|
||
|
||
```html
|
||
<script>
|
||
// 首屏前定主题,避免闪烁
|
||
const t = localStorage.getItem('hermes_style')
|
||
document.documentElement.setAttribute('arco-theme', t === 'dark' ? 'dark' : 'light')
|
||
</script>
|
||
```
|
||
|
||
> localStorage key `hermes_style` **保留**(Phase 002 白名单)。
|
||
|
||
### 3.4 `styles/variables.scss`
|
||
|
||
保留,但把 Naive 相关的 SCSS 变量映射到 Arco CSS 变量名。Phase 007 会重写 `style-system.test.ts`。
|
||
|
||
---
|
||
|
||
## 4. 功能任务 4 — 全局 Provider
|
||
|
||
`main.ts`:
|
||
|
||
```ts
|
||
import ArcoVue from '@arco-design/web-vue'
|
||
import '@arco-design/web-vue/dist/arco.css'
|
||
app.use(ArcoVue)
|
||
```
|
||
|
||
**全量注册,不做按需 tree-shaking** —— 换迁移速度,包体问题后期再优化。
|
||
|
||
---
|
||
|
||
## 5. 功能任务 5 — 三个全局 hook 适配层(**Phase 006/007 强依赖,先写**)
|
||
|
||
Naive 是 hook API,Arco 是命令式。全仓 200+ 处调用,必须先建适配层并**冻结接口**,后续批次只调用适配层。
|
||
|
||
新建 `packages/client/src/composables/`:
|
||
|
||
### 5.1 `useMessage.ts`
|
||
|
||
```ts
|
||
// 模块级单例,main.ts 里 app.use 时把 Message 实例挂上来
|
||
export function useMessage() {
|
||
return {
|
||
success: (c) => Message.success(c),
|
||
error: (c) => Message.error(c),
|
||
warning: (c) => Message.warning(c),
|
||
info: (c) => Message.info(c),
|
||
loading: (c) => Message.loading(c),
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 `useDialog.ts`
|
||
|
||
```ts
|
||
export function useDialog() {
|
||
return { confirm, info, success, error, warning }
|
||
}
|
||
```
|
||
|
||
### 5.3 `useNotification.ts`
|
||
|
||
```ts
|
||
export function useNotification() {
|
||
return { success, error, warning, info }
|
||
}
|
||
```
|
||
|
||
**要求**:这三个文件的对外签名定下后**不再改**。后续所有批次只能调它们。若发现签名不够用,先扩适配层,不要在页面里直接引 Arco 的 `Message`。
|
||
|
||
---
|
||
|
||
## 6. 功能任务 6 — 组件映射表
|
||
|
||
新建 `docs/arco-mapping.md`,把全仓用到的 Naive 组件逐个映射。**先建表再改代码。**
|
||
|
||
已核实的核心映射(完整表在 Phase 006 补全):
|
||
|
||
| Naive | Arco | 备注 |
|
||
|---|---|---|
|
||
| `NConfigProvider` | 直接用 `body[arco-theme]` | 不需要组件 |
|
||
| `NMessageProvider` / `useMessage` | `useMessage()` composable | §5.1 |
|
||
| `NDialogProvider` / `useDialog` | `useDialog()` composable | §5.2 |
|
||
| `NNotificationProvider` / `useNotification` | `useNotification()` composable | §5.3 |
|
||
| `NButton` | `a-button` | prop 名基本一致 |
|
||
| `NInput` | `a-input` / `a-textarea` | `type=textarea` → 独立组件 |
|
||
| `NSelect` | `a-select` | `options` 语义不同,需转换函数 |
|
||
| `NDataTable` | `a-table` | **列定义 API 差异最大** |
|
||
| `NModal` | `a-modal` | `v-model:show` 一致 |
|
||
| `NDrawer` | `a-drawer` | |
|
||
| `NPopover` / `NTooltip` | `a-popover` / `a-tooltip` | trigger 语义有差异 |
|
||
| `NSwitch` | `a-switch` | |
|
||
| `NTag` | `a-tag` | `bordered` 无对应,改 style |
|
||
| `NCard` | `a-card` | |
|
||
| `NProgress` | `a-progress` | |
|
||
| `NEmpty` | `a-empty` | |
|
||
| `NCollapse` | `a-collapse` | |
|
||
| `NTabs` | `a-tabs` | |
|
||
| `NForm` / `NFormItem` | `a-form` / `a-form-item` | **校验规则 API 不同,需适配** |
|
||
| `NGrid` / `NGridItem` | `a-row` / `a-col` | |
|
||
| `NIcon` | `<Icon />` + `@arco-design/web-vue/es/icon` | 需全局注册 |
|
||
| `NLayout` / `NLayoutSider` | `a-layout` / `a-layout-sider` | |
|
||
| `NScrollbar` | `a-scrollbar` | |
|
||
| `NTimeline` | `a-timeline` | |
|
||
| `NUpload` | `a-upload` | |
|
||
| `NTree` | `a-tree` | 结构差异大 |
|
||
|
||
生成实际用到的组件清单:
|
||
|
||
```bash
|
||
grep -rho "from 'naive-ui'" packages/client/src | wc -l # 105 处
|
||
grep -rhoE "N[A-Z][a-zA-Z]+" packages/client/src --include="*.vue" | sort -u
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 功能任务 7 — 样板页 A:LoginView
|
||
|
||
选它的理由:只用到输入框 + 按钮 + 少量文本,是**最小可控面**,且是装饰位面的合法落点。
|
||
|
||
改造点:
|
||
- `NInput` → `a-input`
|
||
- `NButton` → `a-button`
|
||
- 标题区挂 ArkScope `ScrambleTitle`
|
||
- 明暗切换走 §3.2 机制
|
||
- 装饰层 `pointer-events: none`
|
||
- 保留「hermes CLI 缺失引导」的入口(Phase 004 做的 `HermesMissingView`)
|
||
|
||
---
|
||
|
||
## 8. 功能任务 8 — 样板页 B:AppSidebar
|
||
|
||
选它的理由:全站导航唯一入口。Arco 的 `Menu` / `Layout.Sider` 语义在这里定型后,其余 20+ 视图的导航写法全部照抄。
|
||
|
||
改造点:
|
||
- `NLayout` / `NLayoutSider` → `a-layout` / `a-layout-sider`
|
||
- `NMenu` → `a-menu`
|
||
- `NIcon` → Arco Icon
|
||
- `NSelect`(profile 切换)→ `a-select`
|
||
- `NAvatar` → `a-avatar`
|
||
- `NTooltip` → `a-tooltip`
|
||
|
||
**它同时是最难场景**:深层文件 + `v-if="isSuperAdmin"` 条件渲染 + 大量 naive 引用。过了这关,剩下的是体力活。
|
||
|
||
---
|
||
|
||
## 9. 功能任务 9 — 定稿 `docs/ui-baseline.md`
|
||
|
||
本 Phase 的**核心交付物**。必须写清:
|
||
|
||
1. 色板(浅色 / 深色两套,含强调色)
|
||
2. 圆角 / 间距 / 字号阶梯
|
||
3. 字体栈(中英 / 等宽)
|
||
4. 阴影 / 分割线
|
||
5. 组件使用约定(什么时候用 Modal 什么时候用 Drawer、表格空态怎么处理、loading 怎么做)
|
||
6. 装饰位面的边界(复述 §2,落到本文档)
|
||
7. 三条不可破的规则:
|
||
- 不引入第三个 UI 库
|
||
- 消息气泡内部不用 Arco 组件(性能,见 Phase 006)
|
||
- 装饰层一律 `pointer-events: none`
|
||
|
||
---
|
||
|
||
## 10. 验收
|
||
|
||
```bash
|
||
cd /Users/jack/source/MyProject/js/hermes-ui
|
||
|
||
# vendor 边界
|
||
find packages/client/src/vendor/arkscore -type f \
|
||
\( -name "*.png" -o -name "*.jpg" -o -name "*.webp" -o -name "*.mp3" \)
|
||
# 期望:零命中
|
||
|
||
npm run test # 含 arkscope-vendor.test.ts
|
||
npm run build
|
||
```
|
||
|
||
### 手工
|
||
|
||
- [ ] 登录页渲染正常,ArkScope 位面出现且鼠标穿透
|
||
- [ ] 明暗切换无闪烁(刷新页面验证)
|
||
- [ ] 侧边栏菜单全部可点进各视图(视图本身还没迁移,样式不完美是正常的)
|
||
- [ ] `npm run dev` 无 console 报错
|
||
- [ ] `docs/ui-baseline.md` 已写完
|
||
|
||
---
|
||
|
||
## 11. 风险
|
||
|
||
| # | 风险 | 缓解 |
|
||
|---|---|---|
|
||
| P5-1 | ArkScope 上游无 LICENSE | 只 vendor 2 个无素材组件;PROVENANCE.md 标注;仅自用;`arkscope-vendor.test.ts` 卡住素材回流 |
|
||
| P5-2 | 装饰层吃掉点击导致登录按钮点不动 | `pointer-events: none` 写进基线文档 + 手工点一遍 |
|
||
| P5-3 | 暗色切换闪烁 | FOUC 脚本在 `index.html` 内联,必须同步改(§3.3) |
|
||
| P5-4 | composable 适配层签名后续不够用 | §5 要求先定后冻结,不够用先扩适配层 |
|
||
| P5-5 | 样板页看着好,批量时发现约定不够 | §9 的基线文档要覆盖到 Phase 006/007 会遇到的场景 |
|
||
| P5-6 | 忘删 Naive Provider 包裹层 | 改完 grep `NConfigProvider` / `NMessageProvider` 确认归零 |
|
||
|
||
---
|
||
|
||
## 12. 完成标志
|
||
|
||
**风格基线定稿。** 进入 Phase 006(聊天页迁移)。
|