优化 AGC 工作台顶栏布局:一行到底、版本入口钉右分级、播放并入运行页签(Issue #613) #615

Merged
suzmii merged 6 commits from fix/agc-toolbar-layout into master 2026-10-04 20:04:31 +08:00
Member

Closes #613

落地做法

1. 顶栏一行到底,空间不足按三档降级(不再换行)

  • styles.css:工具条 flex-wrap: nowrap + overflow: hidden;两处 ≤1000px / ≤760px 把工具条改成 flex-direction: column 的媒体查询删除(那是「第二行」的另一个来源),≤1000px 里给动作区的 justify-content: flex-end 一并删除(溢出会甩到左边,scrollWidth 看不见)。
  • 新增纯判据 view/project-development/workbenchToolbarModel.ts:档位顺序 full → compact-version → collapsed-actions,每档 1px 判定余量。
  • 新增 view/project-development/useWorkbenchToolbarLayout.ts:ResizeObserver(可用宽度)× MutationObserver(切运行页、出现「恢复草稿」这类不改宽度的内容变化),每次把候选档位写到 DOM 再读 scrollWidth,结果写在工具条 data-layout 上。档位不参与 React 状态(React 不声明该属性,不会被覆盖)。
  • 两个实测踩出来的坑:overflow: hidden 的 flex 子项能用省略号 / 缩到 0 吸收溢出,档位判定就量不到真实溢出——版本入口默认 min-width: max-content(只在最后一档放开为 0),「依赖 / 类型」分段补 flex: 0 0 auto(此前窄宽度下被压成 0 宽)。最后一档确实放不下时改右对齐:宁可裁左边,也不把钉右的版本入口裁没。
档位 藏什么 实测触发(视口)
full 全内联 + 版本 N(原因 · 时间) 1412
compact-version 括号那一层 1240 / 1100 / 760
collapsed-actions 三枚动作 → 「更多」下拉 1024 / 960 / 860 / 800 / 700 / 640 / 560 / 480

2. 版本入口钉最右 + 分级显示

  • .game-run-version-picker { margin-left: auto } → 始终贴动作区右缘(实测 toolbar.right - 12 - chip.right === 0)。
  • 标识改 版本 N(原因 · 时间):版本 N 复用资源画布版本卡编号口径(manifest.versions 落盘顺序 +1);括号那截独立成 .game-run-version-trigger-detail,窄档位只 display: none 这一层——可访问名、菜单项、排障文案一律保留完整标识。

3. 「更多」下拉(WorkbenchMoreActionsMenu.tsx)

「打开项目目录 / 资源面板 / 整理画布」在行内与菜单里是同一批动作(同一个 onSelect、同一份禁用判据);菜单 portal 到 body,复用既有浮层「点外部关闭」hook。

4. 「播放」并入「运行」页签

删掉独立播放按钮,页签前加 ▶ 图标;点页签=showRunView() + onPlay?.()(与旧播放按钮逐字等价,含「再点一次=重跑」)。不可运行时页签不置灰:点了既不切视图也不发播放请求,只出既有提示(showRunView 的门槛与自动切运行的两条路径不变,不会多发播放请求)。

5. 运行画面「刷新运行画面」

浮在画面右下角、全屏那一枚左侧:点击=onPlay?.()(命中活体预览只切视图、不重启服务)+ reloadNonce + 1;LocalGamePreviewFrame 用 key={reloadNonce} 换 iframe 元素身份重新载入页面(跨域 iframe 不能 location.reload())。

前后对照

改动前(用户现场):顶栏换行成两行;版本入口悬在中间;「播放」「运行」并列;运行画面无刷新入口。
改动后(真实 Chromium 实测截图,见 docs/technical/assets/agc-toolbar-layout-after-20261004/):

图 内容
01-toolbar-resources-full-1412.jpg 一行到底,版本入口贴右并显示完整 版本 1(智能体修订 · 2026/10/3 14:21:05)
02-toolbar-resources-compact-1240.jpg 第一档:只留 版本 1,动作一枚不动
03-toolbar-more-menu-800.jpg 第二档:三枚动作收进「更多」下拉
04-toolbar-run-tab-and-preview-refresh-1412.jpg 「运行 ▶」页签 + 运行画面右下角「刷新运行画面」/「全屏预览」

验证

  • npx vitest run apps/ai-game-creator-shell/tests → 199 passed / 1 skipped 文件,1925 passed / 17 skipped 用例(末次全量,含新增 workbenchToolbarLayout、runPreviewRefresh)。
  • 改写既有用例:appSurface/project-development.suite.ts(播放按钮 → 运行页签的播放语义、CSS 声明断言改为档位/钉右)、gameRunToolbarActionsStyle.test.ts、resourceCanvasVersionBindingModel.test.ts(标识加序号)。
  • tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit、eslint --max-warnings 0、prettier --check、npm run check:encoding、npm run check:doc-index、git diff --check 全绿。
  • 真机几何:一次性 Vite 夹具(.codex/skills/agc-workbench-browser-smoke)在真实 Chromium 里逐档量了 13 个视口宽度,确认「始终单行、版本入口贴右、档位按预期切换、『更多』里三条动作可点、点『刷新』iframe 换新节点而 src 不变」。
  • 文档同步:PRD 顶栏条款、验收用例 S17/S17a、decision-log.md、docs/README.md 索引、改动后对照图 README。

未做 / 边界

  • 不改后端、OpenAPI 契约、SpacetimeDB。
  • 窄于 1280×720 合同宽度的视口只保证不崩(最后一档右对齐 + 裁切),不做移动端布局。
  • 「刷新运行画面」只重载页面,不重跑构建(重跑构建仍是顶栏「运行」页签的语义)。
Closes #613 ## 落地做法 ### 1. 顶栏一行到底,空间不足按三档降级(不再换行) - `styles.css`:工具条 `flex-wrap: nowrap` + `overflow: hidden`;两处 `≤1000px` / `≤760px` 把工具条改成 `flex-direction: column` 的媒体查询删除(那是「第二行」的另一个来源),`≤1000px` 里给动作区的 `justify-content: flex-end` 一并删除(溢出会甩到左边,`scrollWidth` 看不见)。 - 新增纯判据 `view/project-development/workbenchToolbarModel.ts`:档位顺序 `full → compact-version → collapsed-actions`,每档 1px 判定余量。 - 新增 `view/project-development/useWorkbenchToolbarLayout.ts`:`ResizeObserver`(可用宽度)× `MutationObserver`(切运行页、出现「恢复草稿」这类**不改宽度**的内容变化),每次把候选档位写到 DOM 再读 `scrollWidth`,结果写在工具条 `data-layout` 上。档位不参与 React 状态(React 不声明该属性,不会被覆盖)。 - 两个实测踩出来的坑:`overflow: hidden` 的 flex 子项能用省略号 / 缩到 0 吸收溢出,档位判定就量不到真实溢出——版本入口默认 `min-width: max-content`(只在最后一档放开为 `0`),「依赖 / 类型」分段补 `flex: 0 0 auto`(此前窄宽度下被压成 0 宽)。最后一档确实放不下时改右对齐:宁可裁左边,也不把钉右的版本入口裁没。 | 档位 | 藏什么 | 实测触发(视口) | |---|---|---| | `full` | 全内联 + `版本 N(原因 · 时间)` | 1412 | | `compact-version` | 括号那一层 | 1240 / 1100 / 760 | | `collapsed-actions` | 三枚动作 → 「更多」下拉 | 1024 / 960 / 860 / 800 / 700 / 640 / 560 / 480 | ### 2. 版本入口钉最右 + 分级显示 - `.game-run-version-picker { margin-left: auto }` → 始终贴动作区右缘(实测 `toolbar.right - 12 - chip.right === 0`)。 - 标识改 `版本 N(原因 · 时间)`:`版本 N` 复用资源画布版本卡编号口径(`manifest.versions` 落盘顺序 +1);括号那截独立成 `.game-run-version-trigger-detail`,窄档位只 `display: none` 这一层——可访问名、菜单项、排障文案一律保留完整标识。 ### 3. 「更多」下拉(`WorkbenchMoreActionsMenu.tsx`) 「打开项目目录 / 资源面板 / 整理画布」在行内与菜单里是**同一批动作**(同一个 `onSelect`、同一份禁用判据);菜单 portal 到 `body`,复用既有浮层「点外部关闭」hook。 ### 4. 「播放」并入「运行」页签 删掉独立播放按钮,页签前加 ▶ 图标;点页签=`showRunView() + onPlay?.()`(与旧播放按钮逐字等价,含「再点一次=重跑」)。不可运行时页签不置灰:点了既不切视图也不发播放请求,只出既有提示(`showRunView` 的门槛与自动切运行的两条路径不变,不会多发播放请求)。 ### 5. 运行画面「刷新运行画面」 浮在画面右下角、全屏那一枚左侧:点击=`onPlay?.()`(命中活体预览只切视图、不重启服务)+ `reloadNonce + 1`;`LocalGamePreviewFrame` 用 `key={reloadNonce}` 换 iframe 元素身份重新载入页面(跨域 iframe 不能 `location.reload()`)。 ## 前后对照 改动前(用户现场):顶栏换行成两行;版本入口悬在中间;「播放」「运行」并列;运行画面无刷新入口。 改动后(真实 Chromium 实测截图,见 `docs/technical/assets/agc-toolbar-layout-after-20261004/`): | 图 | 内容 | |---|---| | `01-toolbar-resources-full-1412.jpg` | 一行到底,版本入口贴右并显示完整 `版本 1(智能体修订 · 2026/10/3 14:21:05)` | | `02-toolbar-resources-compact-1240.jpg` | 第一档:只留 `版本 1`,动作一枚不动 | | `03-toolbar-more-menu-800.jpg` | 第二档:三枚动作收进「更多」下拉 | | `04-toolbar-run-tab-and-preview-refresh-1412.jpg` | 「运行 ▶」页签 + 运行画面右下角「刷新运行画面」/「全屏预览」 | ## 验证 - `npx vitest run apps/ai-game-creator-shell/tests` → **199 passed / 1 skipped 文件,1925 passed / 17 skipped 用例**(末次全量,含新增 `workbenchToolbarLayout`、`runPreviewRefresh`)。 - 改写既有用例:`appSurface/project-development.suite.ts`(播放按钮 → 运行页签的播放语义、CSS 声明断言改为档位/钉右)、`gameRunToolbarActionsStyle.test.ts`、`resourceCanvasVersionBindingModel.test.ts`(标识加序号)。 - `tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、eslint `--max-warnings 0`、`prettier --check`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 全绿。 - 真机几何:一次性 Vite 夹具(`.codex/skills/agc-workbench-browser-smoke`)在真实 Chromium 里逐档量了 13 个视口宽度,确认「始终单行、版本入口贴右、档位按预期切换、『更多』里三条动作可点、点『刷新』iframe 换新节点而 src 不变」。 - 文档同步:PRD 顶栏条款、验收用例 S17/S17a、`decision-log.md`、`docs/README.md` 索引、改动后对照图 README。 ## 未做 / 边界 - 不改后端、OpenAPI 契约、SpacetimeDB。 - 窄于 1280×720 合同宽度的视口只保证不崩(最后一档右对齐 + 裁切),不做移动端布局。 - 「刷新运行画面」只重载页面,不重跑构建(重跑构建仍是顶栏「运行」页签的语义)。
suzmii added the Kind/Enhancement label 2026-10-04 14:23:13 +08:00
suzmii added 2 commits 2026-10-04 14:23:13 +08:00
- 顶栏去掉两侧 flex-wrap、工具条改 overflow: hidden,空间不足按 data-layout 三档降级而不是换行
- 新增 workbenchToolbarModel(档位顺序与 1px 判据)与 useWorkbenchToolbarLayout(ResizeObserver 管宽度、MutationObserver 管内容,实测内容宽度写档位)
- 版本入口 margin-left: auto 钉在动作区最右,标识改「版本 N(原因 · 时间)」,窄档只留「版本 N」(序号复用资源画布版本卡编号口径)
- 新增 WorkbenchMoreActionsMenu:「打开项目目录 / 资源面板 / 整理画布」在 collapsed-actions 档收进「更多」下拉
- 删除独立「播放」按钮,运行页签前加 ▶ 图标,点页签即切视图并载入游戏资源
- 运行画面右下角新增「刷新运行画面」,LocalGamePreviewFrame 新增 reloadNonce 换 iframe 元素身份重新载入页面
- 用例:新增 workbenchToolbarLayout / runPreviewRefresh;改写 appSurface 顶栏与播放/刷新断言、版本标识断言与顶栏样式断言
文档:同步 AGC 顶栏布局口径与改动后对照图
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m37s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m12s
Project CI / Native shell tests (pull_request) Failing after 1m47s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m28s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m2s
Project CI / Frontend tests (pull_request) Successful in 2m34s
Project CI / Backend tests (pull_request) Successful in 6m8s
Project CI / Repository checks (pull_request) Successful in 4m20s
2bfc62f695
- PRD 顶栏条款改为一行到底 + 三档降级 + 运行页签即播放入口 + 运行画面刷新入口
- 验收用例 S17 改为「运行」页签入口语义,新增 S17a 刷新运行画面(含排障索引与验收记录表)
- decision-log 新增 2026-10-04 顶栏布局决策(档位判据、两处「吞掉溢出」的坑、验证范围)
- docs/README.md 索引新增改动后对照图;新增 docs/technical/assets/agc-toolbar-layout-after-20261004/(4 张真实 Chromium 实测截图)
suzmii added 1 commit 2026-10-04 14:52:34 +08:00
修正运行页刷新用例的 preview 类型:改用 GameCreationAppPreviewState
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m59s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m13s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m20s
Project CI / Backend tests (pull_request) Successful in 6m36s
Project CI / Frontend tests (pull_request) Successful in 3m15s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m16s
Project CI / Native shell tests (pull_request) Successful in 7m14s
Project CI / Repository checks (pull_request) Successful in 6m4s
0e75d132a7
- runPreviewRefresh 的 preview 形参从自造字面量类型改为契约类型,避免 status 被放宽成 string 与 view 的 props 冲突(tsconfig.tests.json 才会覆盖 tests/ 目录,此前只跑 tsc -p tsconfig.json 漏检)
- 已跑 npm run ai-game-creator-shell:typecheck(含 check:tests:types)与定向用例确认通过
suzmii added 2 commits 2026-10-04 17:17:14 +08:00
- index.tsx:新增 autoRunPreviewProjectRef 记账,站在运行视图却没有可嵌入预览且可运行时自动补发一次 onPlay,同一个项目只补一次
- index.tsx:showRunView 先记账再发播放,避免点页签时被自动补发重复触发一次
- 用例:新增 runAutoLoadOnEnter(切项目自动补发一次、同项目不重复、点页签只发一次、有活体预览时不补发)
- 文档:PRD 顶栏条款、验收用例 S17 判据、decision-log 同步自动载入口径
顶栏两端留给两枚大分组:排序分段收行尾,版本入口移到它左边
Project CI / Backend tests (pull_request) Failing after 18s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m14s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m11s
Project CI / Repository checks (pull_request) Failing after 25s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m4s
Project CI / Frontend tests (pull_request) Successful in 2m37s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m9s
Project CI / Native shell tests (pull_request) Successful in 5m32s
206c625a58
- index.tsx:把「依赖 / 类型」分段从动作区中部挪到动作行最后一个子元素,版本入口紧邻其左(版本不再是最右那一枚)
- styles.css:排序分段左边距的注释改成与左邻无关(现在左邻是版本入口)
- 用例:资源版本切换新增顶栏顺序断言(版本入口在排序分段之前、排序分段是动作行行尾);生成任务侧栏用例改判排序分段为动作行最后一个子元素
- 文档:PRD 两端分组条款、验收用例 S16 入口位置、决策记录、改动后对照图与 README 重拍
Author
Member

迭代记录(按现场反馈补的两笔,已推到本 PR)

1. 9eb537c6f 运行视图没有画面时自动补一次载入

  • 现场:「进入项目时如果在运行页是空态、不会自动加载」。原因是工作台不重挂时 mode 会跟着走(从别的项目切过来,运行视图原样留下),而画面已经没了,只剩一句「点击顶部「运行」页签」。
  • 改动:站在运行视图、没有可嵌入预览且可运行时自动补发一次 onPlay;showRunView 先记账再发播放,所以点页签不会被重复触发;同一个项目只补一次,失败不打转,手动重跑仍走页签或画面上的刷新按钮。
  • 用例:新增 tests/runAutoLoadOnEnter.test.tsx(切项目自动补发一次 / 同项目不重复 / 点页签只发一次 / 已有画面时不补发)。

2. 206c625a5 顶栏两端留给两枚大分组

  • 现场:「最大的这两个放两边」「版本应该在依赖/类型左边」。
  • 改动:依赖 / 类型 分段从动作区中部挪到动作行最后一个子元素(右端),版本入口紧邻它左侧(不再是最右那一枚);左端仍是「资源管理 / 运行」。降级顺序不变,行尾始终由「依赖 / 类型」收住。
  • 用例:tests/resourceVersionSwitch.test.tsx 新增顶栏顺序断言(版本入口在排序分段之前、排序分段是动作行行尾),tests/resourceCanvasGenerationTasksSidebarDismiss.test.tsx 改判排序分段为行列尾。
  • 真机复测(真实 Chromium,13 个视口宽度):工具栏右缘 - padding - 排序分段右缘 = 0、版本入口始终在排序分段左侧、1240 / 1100 走 compact-version、≤1024 走 collapsed-actions;对照图与 docs/technical/assets/agc-toolbar-layout-after-20261004/README.md 已重拍。

验证(末次全量)

npx vitest run apps/ai-game-creator-shell/tests → 200 passed / 1 skipped 文件,1929 passed / 17 skipped 用例;npm run typecheck(含 check:tests:types)、eslint --max-warnings 0、prettier --check、check:encoding、check:doc-index、git diff --check 全绿。

## 迭代记录(按现场反馈补的两笔,已推到本 PR) ### 1. `9eb537c6f` 运行视图没有画面时自动补一次载入 - 现场:「进入项目时如果在运行页是空态、不会自动加载」。原因是工作台不重挂时 `mode` 会跟着走(从别的项目切过来,运行视图原样留下),而画面已经没了,只剩一句「点击顶部「运行」页签」。 - 改动:站在运行视图、没有可嵌入预览且可运行时自动补发一次 `onPlay`;`showRunView` 先记账再发播放,所以点页签不会被重复触发;同一个项目只补一次,失败不打转,手动重跑仍走页签或画面上的刷新按钮。 - 用例:新增 `tests/runAutoLoadOnEnter.test.tsx`(切项目自动补发一次 / 同项目不重复 / 点页签只发一次 / 已有画面时不补发)。 ### 2. `206c625a5` 顶栏两端留给两枚大分组 - 现场:「最大的这两个放两边」「版本应该在依赖/类型左边」。 - 改动:`依赖 / 类型` 分段从动作区中部挪到动作行**最后一个子元素**(右端),版本入口紧邻它左侧(不再是最右那一枚);左端仍是「资源管理 / 运行」。降级顺序不变,行尾始终由「依赖 / 类型」收住。 - 用例:`tests/resourceVersionSwitch.test.tsx` 新增顶栏顺序断言(版本入口在排序分段之前、排序分段是动作行行尾),`tests/resourceCanvasGenerationTasksSidebarDismiss.test.tsx` 改判排序分段为行列尾。 - 真机复测(真实 Chromium,13 个视口宽度):`工具栏右缘 - padding - 排序分段右缘 = 0`、版本入口始终在排序分段左侧、1240 / 1100 走 `compact-version`、≤1024 走 `collapsed-actions`;对照图与 `docs/technical/assets/agc-toolbar-layout-after-20261004/README.md` 已重拍。 ### 验证(末次全量) `npx vitest run apps/ai-game-creator-shell/tests` → **200 passed / 1 skipped 文件,1929 passed / 17 skipped 用例**;`npm run typecheck`(含 `check:tests:types`)、eslint `--max-warnings 0`、`prettier --check`、`check:encoding`、`check:doc-index`、`git diff --check` 全绿。
suzmii added 1 commit 2026-10-04 18:37:59 +08:00
Merge branch 'master' into fix/agc-toolbar-layout
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m48s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m30s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m12s
Project CI / Frontend tests (pull_request) Successful in 3m20s
Project CI / Backend tests (pull_request) Successful in 7m47s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m42s
Project CI / Repository checks (pull_request) Successful in 7m5s
Project CI / Native shell tests (pull_request) Successful in 9m43s
f418ecfee9
suzmii merged commit 6c95660588 into master 2026-10-04 20:04:31 +08:00
suzmii deleted branch fix/agc-toolbar-layout 2026-10-04 20:04:32 +08:00
Sign in to join this conversation.