* feat(editor): 编辑器实施 M0-M1 - 剪辑入口占位与插件 SDK v2 垂直切片 - detail.tsx 新增剪辑成片视图(editor tab,常驻),概览页插入剪辑步骤卡 - plugin-types.ts 新增 v2 类型(EditorSlotKind/EditorPluginPermission/PluginManifestV2),修复权限数组交叉归约 bug - editor-slot-registry.ts 插槽注册表(优先级排序、幂等注册、订阅机制) - plugin-registry.ts 注册器 v1/v2 分支校验,v1 路径零改动 - editor-shell.tsx 垂直切片插件:timeline-panel 插槽真实渲染,验证插件链路全通 - 测试:插槽注册表 5 用例 + 命令测试骨架,v1 插件回归 21 例零回归 * feat(editor): 命令协议黄金文件 - editor-commands 纯函数 reducer + 8 个黄金 op * feat(editor): 快照撤销历史 - editor-history 有界 200 层 undo/redo * feat(editor): 命令状态机 store - dispatch/手势预览/1.5s 防抖保存/串行保存链 * fix(editor): createEditorStore 返回 zustand hook 类型修复 typecheck * feat(editor): 手势 echo 最小件 - 时间线面板拖拽移动/裁剪 + store 接线与本地持久化 * docs(editor): M2 完成状态记录 * feat(editor): M3.1 时间线面板选中联动 - store 选中状态 + 片段高亮/点击取消 * feat(editor): M3.2 预览监视器 - preview-renderer 插槽 + 真实媒体帧/播放头/时间码 * feat(editor): M3.3 片段检查器 - inspector 插槽 + 属性编辑入队可撤销 * feat(editor): M3.4 asset-ingest 素材库插件(addClip 命令入轨) * feat(editor): M3.4 补充 - host 上下文(项目信息+资产)、editor.tsx 接线、asset-ingest 纯函数、死代码清理 * feat(editor): M3.5 subtitle-tools - SRT import/export + rebuild from node snapshot * feat(editor): M3.6 transcription - deterministic mock ASR to subtitle track * feat(editor): M3.7 export - render plan + ffmpeg.wasm fallback export * feat(editor): M3.8 - render all 8 editor slots in three-pane layout + ai-assistant placeholder * docs(editor): M3 完成状态 - 8 插件 + 全插槽接线,冒烟待确认 * feat(editor): 编辑器媒体与时间线打磨 - 资产来源分组筛选、时间线全宽布局、拖拽末片段修复、OSS 降级本地存储、Concat 风格控制条与检查器 * fix(plugins): 合并上游后修复插件分类筛选对 v2 清单的类型兼容 * feat(editor): 时间线工具态与轨道操作打磨 - 工具按钮选中仅图标变色、监视器 Concat 式控制条、removeTrack 黄金命令与轨道行头移除按钮、maskClosable 迁移 * fix(api): 资源上传超 MaxBytesReader 上限时报中文大小限制而非英文裸 400 * fix(editor): 监视器控制条 - 修复播放按钮 JSX 模板闭合花括号缺失导致的编译错误 * feat(api): 本地媒体导入分片化对齐 Concat - >50MB 视频不再失败 - 分片会话三接口(POST开始/PUT单片/complete合并)、前端超50MB自动切8MB分片并失败整传重试、默认配额放宽(日200MB→2GB、总2GB→20GB)、UploadResourceFile 豁免单文件限 * feat(editor): 轨道行头新增可见性/静音开关按钮 - 复用现有图标资源,按轨道类型显隐;命令层新增 setTrackFlag 黄金命令(flag 白名单 fail-closed)并补单测 * docs(progress): 记录轨道可见/静音开关改动与复测项 * docs(editor): M4 转写与渲染任务设计 - 复用 Task 表与状态机、独立创建 API、worker 领取类型过滤、whisper HTTP provider(OpenAI 兼容 /v1/audio) * fix(api): OSS 上传失败自动降级本地存储时 body 已被 Transport 关闭 - newOSSRequest 用 NopCloser 包装请求体,服务端提前返回(签名 403)时不再关闭调用方持有的文件,降级分支 Seek 重读生效;补回归测试 * docs(progress): 记录媒体导入根治(分片+OSS 降级修复)复测项 * feat(api): 视频播放副本转码 H.265→H.264 + variant=playback 服务与启动回填 - 上传视频后异步探测 codec,H.265/AV1 走 moov 快速探测并转码 H.264 播放副本;GET /api/user-data/...?variant=playback 就绪时服务副本(独立 ETag :pb),未就绪回退原件并撤销后缀防 304 黑屏;storeResource 触发、启动幂等回填存量;前端播放失败自动轮询副本就绪后刷新 * fix(editor): 轨道至少保留一条 - 不可移除轨道点击 X 时居中浮现原因提示(2.2s 自动消失, aria-live);修正可见性 toggle 传参 (visible===false 语义) ;轨道行内移除按钮改为常驻(不可移除时点击给提示) * feat(timeline): M4.1 字幕转写后台任务 - whisper.cpp 本地执行 - 新增 timeline_transcription 任务类型,worker 按类型分叉独立执行器(不走计费与模型渠道);输入 resourceId+language,读取用户资源后 ffmpeg 预处理 16k 单声道 wav,POST 本地 whisper.cpp /inference,结果写回 segments+srt+language;未配置 CANVAS_WHISPER_BASE_URL 等失败均落明确终态;feature 门控;进度分阶段;含解析/SRT/快速失败单元测试 * feat(media): 素材卡片时长与媒体面板打磨 - 导入媒体解析时长(前端 media-metadata + 后端 project_asset durationMs 透出)随卡片展示;媒体面板/监视器/时间线相关样式细节收尾 * docs(progress): 阶段 C 监视器播放复检清单 - H.265 播放副本/真实播放驱动/时长链路待浏览器确认 * feat(timeline): M4.1 转写任务创建 API - POST /api/timeline/transcriptions - service CreateTimelineTranscriptionTask:IsDraining 守护 + feature 门控 + 资源归属与可转写类型校验 + 排队计 active 限额(含任务级/项目级存储估算);local/whisper.cpp 标记,任务不经过模型路由与计费;createTaskWithinStorageQuota 复用与 ErrActiveTaskLimit 用户可读映射;测试覆盖排队成功(owner/type/provider 断言)、跨用户资源拒绝、非音视频拒绝 * feat(timeline): M4.3 字幕转写前端接线 - 真实任务替换 mock - 新增 services/api/timeline-tasks.ts(POST /timeline/transcriptions,复用 apiClient+request);EditorTranscription 改为 创建任务→waitForGenerationTask 轮询(25min)→结果 segments 映射 SrtEntry[]→rebuildSubtitleClips 写入字幕轨道;实时展示 stage/progress,失败/空识别/无字幕轨道分别提示;素材选择支持音频与视频(取 storageKey 中的 resource id 提交) * fix(media): 播放副本状态收敛与轮询终态 - 无ffmpeg/远端存储/编码不可处理落 none 避免重复探测;前端 none 停轮询回原生播放并加 processing 上限 * feat(timeline): M4.2 时间线渲染任务 - POST /api/timeline/renders 创建(buildRenderPlan 校验含可渲染媒体、配额入队、local/ffmpeg、60min 超时);worker 顶部按类型分叉 processTimelineRender;ffmpeg 合成产物写资源存储并经 ResultJSON 记 resourceId;render 计划/结果测试 PASS * fix(resource): 转码原子抢占与 OSS 请求体加固 - ClaimPlaybackTranscode 空/none→processing 单实例抢占避免重复转码,runPlaybackTranscode defer recover 落 failed;If-Range 与带 :pb 后缀的 serveETag 比较;无请求体的 OSS 请求不再包 NopCloser(nil)(防 Go 1.26 body 探测 nil 解引用) * style(editor): 修正字幕回写面板缩进 * docs(timeline): M4 设计文档按实现回写 - 单一 worker 池 + processClaimedTask 顶部按类型分叉(决策 3/4),端点统一为复数 /api/timeline/transcriptions 与 /api/timeline/renders(注册于 RegisterTaskRoutes),ResultJSON/feature gate/ffmpeg env 同步;Runbook M4 表格与状态行更新;auth.go API 前缀白名单补 timeline * fix(service): 修复上游 v1.2.5 公告配图删除保护自锁与测试夹具缺口 上游 #385 资源引用走查器对公告配图/草稿做了硬性引用检查,导致三个问题: - UpdateAnnouncement 在更新公告前对旧配图走查,必然命中当前公告自身引用而自锁, 公告替换配图功能实际不可用;DiscardAnnouncementImage 同理被草稿自身引用阻塞。 修复:ensureResourceHasNoBusinessReferences 支持忽略指定引用(当前公告/当前草稿), 其余引用仍按原语义拦截。 - admin DeleteAdminResources 将公告草稿引用视为阻塞,但删除事务会级联清理草稿与 资源绑定,service 层永不进入事务,回滚审计注入测试无法到达预期路径。修复:service 预检时过滤公告草稿引用,与 repository 级联语义对齐。 - project_settings_test.go 夹具未建 ResourceReferenceSnapshot 走查的 Task/Session/ Message/TaskLog/Result/Announcement/AnnouncementImageDraft 表,报 no such table。 修复:夹具 AutoMigrate 补齐。 后端全量 go test ./... 通过。 * feat(editor): 成片导出接入后端渲染任务(M4.2 前端接线)- timeline-tasks 增 createTimelineRenderTask;editor-export 主路径改 POST /timeline/renders 轮询取 resourceId 内嵌预览/下载,ffmpeg.wasm 降级保留 * feat(editor): M5 插件权限执行(fail-closed)- plugin-permission-check 新建(8 插槽最小权限表/判定/断言);SlotStack 渲染前过滤缺权限插槽改诊断条;editor-shell manifest 补 timeline.command/export.run;测试 10 用例含 editor-shell 真实回归 * feat(editor): M6.1 AI 命令 schema + M6.2 时间线摘要 - ai-command-schema(parse/dry-run 校验/12-op 提示词契约/版本化+golden);timeline-summary(确定性中文摘要/折叠上限);各 20/10 用例全绿 * docs(progress): M6 质检清单 - M6.1 schema/M6.2 摘要标记完成(含测试计数),M6.3 待模型源确认;清理 M5.1 重复条目 * feat(editor): AI 命令 schema 支持只读问答 - commands 空数组合法化(无法执行/纯提问时 reasoning 直接作答),新增 AI_EDITING_MAX_COMMANDS=8 上限防失控编辑,提示词同步 * feat(editor): AI 助手重构为右上悬浮对话面板(M6.3)+ 素材入库原子化收尾 - editor-ai-assistant.tsx: 占位面板替换为 OpenAI Canvas 风格右上悬浮对话面板; 面板内文本模型选择器(effective.textModels,选择即持久化并覆写请求模型), 消息流 user/assistant/error/preview 四类气泡 + 思考中占位,空态引导示例 chips 一键发送,底部输入条;顶部工具栏常驻 Sparkles 入口(aria-pressed 切换)。 修复上一版重复/截断函数声明(appendToEntry 双定义、settleAnswer 三声明等)。 宿主链路:buildAiEditingSystemPrompt(summarizeTimeline(project)) 喂上下文 → parseAiCommandPlan → validateAiCommandBatch dry-run(任一非法整批拒绝)→ ≤3 条 dispatch 直执行 / >3 条预览确认卡片;宿主拒绝时 failTurn 回填 FAILED_MARK 可重试。 - editor-asset-ingest/editor-preview-monitor/detail/editor.tsx: 配套接线与打磨 (编辑器顶栏 AI 入口、素材导入面板、预览监视、项目页顶栏整理)。 - backend: LinkProjectAsset 事务内原子创建资产 + 项目链接(OnConflict 幂等), 资产首次入库不再预落库,失败整体回滚,消除"有资产无链接"孤儿记录。 - docs: pending-test.mdx / runbook M6.3 状态更新(tsc + 测试 + 构建通过, 浏览器冒烟待真实文本渠道)。
180 lines
14 KiB
Plaintext
180 lines
14 KiB
Plaintext
# 工作区外壳设计沉淀:侧栏 + 主区 + 顶部栏
|
||
|
||
> 范围:用户工作台外壳(`UserLayout` → `AppWorkspaceShell`)的侧栏、主区卡片与主区顶部栏的设计决策与实现约束。
|
||
> 参考:shadcn 风格工作台(侧栏导航 + 主内容区 + 顶栏图标按钮组),`SelectItem` 式紧凑交互(hover 浅背景反馈 + Chevron 指示)。
|
||
> 硬约束:不改变任何既有功能入口;明暗主题由三层 token 驱动;不引入装饰性线条(竖杠 / hairline / 默认边框)。
|
||
> 状态:`bunx tsc --noEmit` 通过;未运行构建与浏览器实测(真机回归项见文末)。
|
||
|
||
## 1. 布局架构
|
||
|
||
工作台外壳为「**侧栏卡片 + 主区卡片**」双卡片布局,顶部栏**位于主区卡片内部顶部**(不再占全宽,视觉上位于侧栏右侧):
|
||
|
||
```text
|
||
┌────────────────────────────────────────────────────────┐
|
||
│ .app-workspace-shell padding: var(--workspace-shell-gutter) │
|
||
│ ┌──────────────┐ ┌───────────────────────────────────┐│
|
||
│ │ 侧栏卡片 │ │ 主区卡片 .app-workspace-stage ││
|
||
│ │ 260px 可折叠 │ │ ┌───────────────────────────────┐ ││
|
||
│ │ │ │ │ 顶部栏(面包屑…账户) │ ││
|
||
│ │ 切换器/搜索 │ │ ├───────────────────────────────┤ ││
|
||
│ │ 分组导航 │ │ │ 页面内容 │ ││
|
||
│ │ footer │ │ │ │ ││
|
||
│ └──────────────┘ │ └───────────────────────────────┘ ││
|
||
│ └───────────────────────────────────┘│
|
||
└────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- 两张卡片共享同一外观规则(**单一来源**):1px 边框 + `--r-xl` 圆角 + 阴影栈,见 §5.1。
|
||
- 例外(连体契约):画布编辑器 `/canvas/:id` 与运营后台 `/admin`(`:not(.is-spatial)`)取消外壳留白与卡片圆角,保持全屏连体。
|
||
- 侧栏折叠为 0 宽时(`:has(.is-collapsed)`)外壳留白/行间距/主区圆角同步归零,四周贴齐视口。
|
||
|
||
## 2. 侧栏设计(`.app-workspace-sidebar`)
|
||
|
||
### 2.1 尺寸与卡片
|
||
|
||
| 项 | 值 | 说明 |
|
||
| --- | --- | --- |
|
||
| 展开宽度 | `--workspace-sidebar-width: 260px` | 组件 token;含 1px 卡片边框 |
|
||
| 折叠态 | `width: 0 !important`,边框/阴影同步收起 | 内存态,不持久化(沿用 admin-shell 先例) |
|
||
| 圆角 | `--r-xl`(14px) | 卡片合同 |
|
||
| 背景 | `--workspace-sidebar`(= `--workspace-navigation`) | 与主区 `--workspace-content` 区分 |
|
||
|
||
### 2.2 纵向结构(自上而下)
|
||
|
||
1. **工作区切换器** `WorkspaceSwitcher`:品牌 mark(`size-8`、`--r-sm` 圆角、`InfinityIcon`)+「影策」wordmark + 副标题「创作工作台」(`--fs-label`、42% 灰)→ 点击展开切换浮层 `.app-workspace-nav-popover`(无阴影,1px 边框 + 实底背景)。
|
||
2. **快速搜索**:`h-9`、`--r-lg` 圆角、`bg-foreground/5` 浅底;占位文字与 `Search` 图标均为 `text-muted-foreground`(语义占位色);hover 加深至 `bg-foreground/[.07]` + 70%;右侧常驻 `⌘K` kbd 提示(复用导航项 kbd 合同);点击打开命令面板。
|
||
3. **分组导航区** `.app-workspace-sidebar-scroll-area`(`flex-1` 滚动,滚动条隐藏):
|
||
- 无标题分组(首页 / 短剧创作 / 画布 / 任务中心 / 资产…核心入口)**常驻展示,不折叠**;「短剧创作」入口(`/projects`)**常驻**(不随 `shortDramaEnabled` 隐藏,该开关仅作部署级兜底:关闭时由 `RequireFeature` 提示「暂未开放」而非隐藏入口);「任务中心」等按功能开关条件渲染(`workspace-sidebar-nav.tsx` `buildNav`)。
|
||
- 有标题分组渲染为 `NavGroup`(见 §2.3)。
|
||
4. **Footer**(设置分区 + 退出登录):无分隔线(见 §2.5)。
|
||
|
||
### 2.3 分组折叠 `NavGroup`
|
||
|
||
- 触发:有标题的分组(如「工作台管理」)标题变为**按钮**(`.app-workspace-nav-group-toggle`),点击折叠/展开组内导航项。
|
||
- 视觉:`min-height: 28px` 紧凑按钮,`--r-sm` 圆角;右侧 `ChevronRight` 指示——展开 `rotate-90`(向下)、折叠水平(向右),200ms 旋转过渡。
|
||
- 交互:hover/focus-visible 浅背景 `--surface-hover`;标签文字 36% → 55%、图标 35% → 70%(成对递进,深浅主题一致)。
|
||
- 动画:`grid-template-rows: 1fr ↔ 0fr` + opacity,300ms `ease-in-out`(与 NavItem 子项折叠同款,交互一致)。
|
||
- 可用性:**激活项所在分组自动展开**(`useEffect` 监听 `hasActive`),保证当前位置可见。
|
||
|
||
### 2.4 导航项 `NavItem` 状态设计
|
||
|
||
| 状态 | 表现 |
|
||
| --- | --- |
|
||
| 默认 | 文字/图标 62% 中性灰(`text-foreground/62`),图标 60% |
|
||
| hover | `--surface-hover` 浅底 + 文字 100%、图标 80% |
|
||
| 激活 | `is-active` + `font-medium`,文字 100% |
|
||
| 子项展开 | `ChevronRight` 旋转 + `grid-rows` 动画 + **引导线**(`(level+1)*12+12.5px`,居中于子项圆点) |
|
||
|
||
- 行容器:`min-h-9`、`--r-sm` 圆角、`px-2.5`、图标 16px/1.6 描边。
|
||
- 子项缩进:`padding-left: ${level * 12 + 10}px`;子项无图标时显示 `size-1.5` 圆点(`opacity-40`)。
|
||
- 徽章(钱包余额):`bg-primary/10` + `text-primary` 圆角胶囊,`tabular-nums`。
|
||
- 快捷键:`kbd`(`h-5`、描边 `--workspace-border`、浅底、mono、55% 灰),hover 才显示。
|
||
- 激活分支自动展开(设置分区子项同款逻辑)。
|
||
- 点击既有 `to` 又有子项时:**同时折叠切换 + 导航**(接受的既定交互)。
|
||
|
||
### 2.5 Footer:无分隔线
|
||
|
||
- **禁止 `border-t` 分隔线**——层级改用淡背景表达:`bg-foreground/[.04]` + 自身 `rounded-b-[var(--r-xl)]`(侧栏根无 `overflow-hidden`,需自身圆角防背景溢出卡片底角)。
|
||
- 内容:设置(6 个 `/settings?section=` 子项,自定义渠道按功能开关过滤)+ 退出登录(`LogOut`,走 `useWorkspaceLogout`)。
|
||
|
||
## 3. 主区设计(`.app-workspace-stage`)
|
||
|
||
- 卡片合同与侧栏**共享单一规则**(§5.1);背景 `--workspace-content`。
|
||
- 顶部栏在卡片内顶部全宽(见 §4);页面内容容器(`.app-user-content` / `WorkspacePage` / `.app-workspace-grid`)继承卡片背景。
|
||
- 空间工作台(`is-spatial`):侧栏与主区**连体**——主区 `border: 0; border-radius: 0; box-shadow: none`,侧栏仅保留 `border-right`(7% 分隔线),无卡片间隙(`gap/padding` 归零)。
|
||
- 侧栏折叠后:`:has(.is-collapsed)` → shell `padding: 0`、主区圆角归零、四周贴齐。
|
||
|
||
## 4. 主区顶部栏设计(`.app-workspace-topbar`)
|
||
|
||
### 4.1 位置与内容
|
||
|
||
- 位于主区卡片内部顶部(侧栏右侧),`flex` 两端布局:
|
||
- 左:折叠按钮(`PanelLeftClose/Open`)+ 面包屑「影策 / 页面标题」(`--fs-caption`、50% 灰、当前页 100%)。
|
||
- 右:公告中心(登录用户)→ 主题切换(`AnimatedThemeToggler`)→ 账户菜单(`WorkspaceAccountMenu`)。
|
||
|
||
### 4.2 图标按钮合同(`.app-workspace-topbar-icon-button`)
|
||
|
||
顶栏所有图标按钮(折叠/公告/主题/账户)复用同一合同,保证视觉一致:
|
||
|
||
| 项 | 值 |
|
||
| --- | --- |
|
||
| 容器 | 36px(`size-9`)、`--r-md` 圆角 |
|
||
| 图标 | 18px、`stroke-width: 1.8`(`> span > svg` 规则匹配占位图标) |
|
||
| 默认色 | `color-mix` 58% |
|
||
| hover | `--surface-hover` 底 + 100% 前景 |
|
||
|
||
账户按钮:真实头像 24px(`size-6`);未登录/占位 `CircleUserRound` 撑满(`size-full` → 18px);**无背景容器**(默认态纯图标,反馈由按钮 hover 提供);触发按钮不含徽章(完整徽章在菜单头部)。
|
||
|
||
### 4.3 展开浮层(账户菜单 / 公告中心)
|
||
|
||
- **不透明**:AntD 主题 `colorBgElevated` 统一 `alpha 1`(浅色 `#fff` / 深色 `#1f1f20`),杜绝透出下层内容(曾因 0.96 透明度 + AntD 6 类名变更失效而暴露,见 §7 经验)。
|
||
- **无阴影**:`.app-spatial-overlays` 下菜单类浮层(`.ant-dropdown-menu`、`.ant-select-dropdown`、`.ant-popover-container`、cascader、mentions)`box-shadow: none`——层级由 **1px 边框 + 背景对比**表达;Modal/Drawer 不受影响。
|
||
- 背景/边框/圆角收敛到 `--workspace-overlay-bg-strong` / `--workspace-overlay-border` 等唯一源 token。
|
||
|
||
## 5. 共享规则与 token
|
||
|
||
### 5.1 卡片合同(单一来源)
|
||
|
||
```css
|
||
/* globals.css:.app-workspace-sidebar, .app-workspace-stage 共享 */
|
||
border: 1px solid color-mix(in srgb, var(--foreground) 7%, transparent); /* 减线:9% → 7% */
|
||
border-radius: var(--r-xl);
|
||
box-shadow: 0 14px 44px color-mix(in srgb, var(--foreground) 12%, transparent),
|
||
inset 0 1px 0 color-mix(in srgb, white 6%, transparent);
|
||
/* .dark 覆盖:0 14px 44px rgba(0, 0, 0, 0.45) + inset 白 6%(阴影永远取真黑,禁止用 foreground 推导) */
|
||
```
|
||
|
||
深色阴影必须为 `rgba(0, 0, 0, 0.45)` 级真黑(`var(--foreground)` 在深色下是白 → 发光)。`.dark` 覆盖**必须放在折叠规则之前**(两者 specificity 相同 (0,2,0),源顺序决定胜负)。
|
||
|
||
### 5.2 关键 token 映射
|
||
|
||
| Token | 值 | 用途 |
|
||
| --- | --- | --- |
|
||
| `--workspace-sidebar-width` | 260px | 侧栏展开宽度 |
|
||
| `--workspace-shell-gutter` | 6px | 外壳留白与卡片间隙 |
|
||
| `--workspace-sidebar` / `--workspace-content` | navigation / page | 侧栏 / 主区背景 |
|
||
| `--surface-hover` | 5% / 7% (dark) | 行 hover 反馈 |
|
||
| `--r-sm / --r-lg / --r-xl` | — / — / 14px | 行 / 搜索 / 卡片圆角 |
|
||
| `--fs-label / --fs-caption / --fs-body` | 11 / 12 / 14px | 标签 / 说明 / 正文 |
|
||
| `--motion-state` / `--ease-aceternity` | 180ms / ease-out | 状态过渡 |
|
||
| `--workspace-overlay-*` | strong / border 等 | 浮层背景、边框、分隔 |
|
||
|
||
## 6. 视觉与交互规范(沉淀约束)
|
||
|
||
- **禁止装饰性线条**:卡片无左侧竖杠、无默认 border/hairline;层级用**明度、间距、淡背景**表达(footer 分隔即用 `bg-foreground/[.04]`)。导航引导线、markdown 引用线属于内容层级,不在此列。
|
||
- **不重复声明**:相似组件样式合并共享选择器(侧栏/主区卡片已合并);新增覆盖前先搜索同名规则,回到唯一源修改。
|
||
- **色彩角色成对**:主操作 / 普通选中 / 勾选 / 开关各为其政;hover 递进必须成对定义(文字 62→100 与图标 60→80 同步)。
|
||
- **状态一致**:持久切换用 `aria-pressed`;`type="primary"` 仅用于当前主命令。
|
||
- **可访问性**:键盘导航保留 `:focus-visible`(点击态用 `:focus:not(:focus-visible)` 消除);折叠/展开控件使用 `aria-expanded`。
|
||
- **AntD 6 浮层类名**:Popover 背景容器为 `.ant-popover-container`(不再是 v5 的 `.ant-popover-inner`),覆盖选择器必须按实际 DOM 类名书写。
|
||
|
||
## 7. 关键经验(踩坑记录)
|
||
|
||
1. **AntD 6 类名迁移**:`.ant-popover-inner` → `.ant-popover-container`,旧选择器静默失配(无报错),导致背景/边框规则全部失效——覆盖第三方组件前必须核对 `node_modules` 内实际类名。
|
||
2. **半透明浮层**:`colorBgElevated: 0.96` 在内容滚动时会透出下层 → 浮层一律实底。
|
||
3. **深色阴影**:用 `color-mix` 从 `--foreground` 推导阴影在深色主题下变成白色光晕 → 显式 `rgba(0,0,0,.45)`。
|
||
4. **specificity 平手靠顺序**:`.dark .x` (0,2,0) 与 `.shell .x.is-collapsed` (0,2,0) 相同时,源顺序决定——覆盖块必须置于折叠规则之前。
|
||
5. **编辑防重复**:多 anchor 编辑后行号漂移导致重复内容(搜索占位文本曾出现两份),改后必须复查目标行区域。
|
||
|
||
## 8. 实现文件清单
|
||
|
||
| 文件 | 职责 |
|
||
| --- | --- |
|
||
| `web/src/components/layout/app-top-nav.tsx` | `AppWorkspaceShell` 外壳、侧栏/主区行布局、折叠态类 |
|
||
| `web/src/components/layout/workspace-sidebar-nav.tsx` | 切换器、搜索、`NavGroup` 分组折叠、`NavItem`、footer |
|
||
| `web/src/components/layout/workspace-top-bar.tsx` | 主区顶部栏:折叠按钮、面包屑、公告、主题、账户 |
|
||
| `web/src/components/layout/workspace-account-menu.tsx` | 账户菜单与 `UserAvatar`(按钮图标合同) |
|
||
| `web/src/components/layout/workspace-command-palette.tsx` | ⌘K 命令面板(feature-gated) |
|
||
| `web/src/hooks/use-workspace-logout.ts` | 登出 hook |
|
||
| `web/src/lib/app-theme.ts` | AntD 主题:`colorBgElevated` 不透明、控件色 |
|
||
| `web/src/styles/globals.css` | 卡片合同、`NavGroup`/`NavItem` 状态、浮层唯一源规则 |
|
||
| 已删除 `workspace-sidebar-footer.tsx` | 无引用,逻辑并入 nav footer |
|
||
|
||
## 9. 真机回归清单(未运行,待确认后补测)
|
||
|
||
- [ ] 明暗主题下侧栏/主区卡片边框、阴影、分组折叠展开动画
|
||
- [ ] 侧栏折叠(0 宽贴齐)与移动端抽屉
|
||
- [ ] 账户菜单、公告中心浮层:不透明、无阴影、边框层级
|
||
- [ ] ⌘K 命令面板打开/过滤/快捷键提示
|
||
- [ ] 设置分区子项展开 + 引导线对齐 + 激活自动展开
|