From d451415edcc07090e3822642f8d0fa7085469486 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Mon, 5 Oct 2026 15:59:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=20PR=20#607=20=E5=A4=8D=E6=A0=B8?= =?UTF-8?q?=E6=84=8F=E8=A7=81=E4=BF=AE=E6=8E=89=209=20=E9=A1=B9=EF=BC=88D1?= =?UTF-8?q?/D2/D3/D4/D5/D6/D7/D8/D9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - D1 档位点被轨道压住且与圆钮错位:容器改 `display: flex; justify-content: space-between; padding: 0 6.5px`(= 圆钮半径 10 − 半点宽 3.5),首末点中心因此落在圆钮两端极限位置;`z-index: 2` 抬到 range 之上;当前档位那一点 `opacity: 0`(圆钮已压在那儿);点改深暖底 `--platform-text-strong` + `--platform-input-highlight` 描边。无头 Chromium 实测(222px 轨道):5 个点中心与圆钮算式偏移全部 0.00px(旧实现 +12.19/+6.09/−0.02/−6.11/−12.20)、点与相邻轨道对比度 10.51~10.59:1(旧 1.21~1.23:1)、当前档位点被圆钮覆盖(中心差 ≤0.5px) - D2 状态文案(`role="status"`)也会把那排控件顶成两行高:`ConversationModelSelect` 的 notice 与失败分开两条浮层通道(`onNotice` / `onUnavailable`,各自去重),`ComposerReasoningEffortSelect` 加 `noticePresentation: 'inline' | 'toast'` + `onNotice`;`toast` 形态下两种常驻行都不渲染,状态浮层用 `tone="neutral"`、失败仍 `tone="error"`。Direct 用 `toast`,首页/策划/画布默认 `inline` 行为不变 - D4 `forced-colors` 下焦点完全不可见(thumb 的 box-shadow 会被系统丢弃):加 `@media (forced-colors: active)` 回退 `outline: 2px solid Highlight; outline-offset: 2px`(系统色,亮色观感不变) - D5 键盘长按每个事件都落盘:`selectEffort` 比对「最近一次落盘成功的档位」(`persistedEffortRef`,挂载回读时种上),相同不写。真实按键序列实测:单击 1 次;长按 1.5s(34 个重复事件)4 次(每个新档位一次);已在最高档继续长按 1.2s(28 个事件)0 次(旧行为 ~30 次/秒) - D6 拖动中途卸载会丢档位:卸载 cleanup 里 flush 一次预览值(读 ref,不碰已卸载组件的 state)。实测:拖到「中」未松手落盘 0 次,`unmount()` 后恰好 1 次;单次拖动(按下 + 6 步横移 + 松手)全程 1 次且终值 = 松手位置 - D7 文档与实现对齐:pitfalls 里 `--strength-progress` → `--strength-ratio`、圆钮改实心 `--platform-panel-fill` + `--platform-subpanel-border` 1px 描边、输入盒最高高度 254 → 256(工具栏行高由 30px 模型钮决定)、「提示改成控件排内独占一行」按现行浮层口径改写 - D8 去掉 10 处新硬编码色值 `rgb(112 57 30 / x%)`:卡片投影改用既有 token `--platform-desktop-hover-shadow`,圆钮/焦点影由 `color-mix(in srgb, var(--platform-accent) …)` 派生,不新增 token - D9 注释与实现不一致:`.resource-reference-input` 的 `min-height: 0 / padding: 0` 写回前面那条六类规则(不再依赖源码顺序),末尾那条只留网格与行距,注释同步改成「不依赖源码先后」 - D3 深色主题焦点环间隙不可靠:只在 pitfalls 记录(深色 `--platform-input-fill` 仅 5% 不透明;工作台根节点固定 `platform-theme--light`,暂不可达) - 测试:`chat-composer.suite.ts` 新增「notice 走浮层且输入区无 `[role=status]`/`[role=alert]`」「键盘长按同一档位只写一次、换档仍写」「拖动中途卸载恰好提交一次」;`chatDialogFrameLayout.test.ts` 新增档位点对齐/层级/激活点隐藏的声明级断言 - 校验:相关 vitest(chat-composer / chatDialogFrameLayout / design-agent / project-development)、typecheck、eslint、prettier、encoding、spacetime-schema、diff-check Refs #600, PR #607 --- .../ConversationModelSelect.tsx | 38 ++++- apps/ai-game-creator-shell/src/styles.css | 72 ++++++---- .../ComposerControls.tsx | 87 ++++++++++- .../DirectProjectComposer.tsx | 26 +++- .../tests/appSurface/chat-composer.suite.ts | 136 +++++++++++++++++- .../tests/chatDialogFrameLayout.test.ts | 43 ++++++ docs/project-memory/shared-memory/pitfalls.md | 16 ++- 7 files changed, 377 insertions(+), 41 deletions(-) diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx index 266eef271..fb6e11cbd 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx @@ -67,6 +67,7 @@ export function ConversationModelSelect({ ref, errorPresentation = 'inline', onUnavailable, + onNotice, strengthSection, }: { className?: string; @@ -85,6 +86,13 @@ export function ConversationModelSelect({ errorPresentation?: 'inline' | 'toast'; /** `errorPresentation: 'toast'` 时,对**新出现**的失败消息回调一次(同一条不重复)。 */ onUnavailable?: (message: string) => void; + /** + * 状态文案(「模型列表已刷新」「正在刷新模型列表」「默认模型已停用」等)的浮层通道。 + * + * 只在 `errorPresentation: 'toast'` 时回调,且与失败**分开**:语气不同(状态不是失败)、 + * 去重名额也各算各的。`toast` 模式下没有常驻 `role="status"`,输入区不再被一行状态文字顶高。 + */ + onNotice?: (message: string) => void; /** * 菜单顶部的附加区(Direct 输入盒用来放「思维强度」滑块)。 * @@ -146,6 +154,31 @@ export function ConversationModelSelect({ onUnavailableRef.current?.(error); }, [error, errorPresentation]); + /** + * 状态文案(「模型列表已刷新」「默认模型已停用」等)在 toast 形态下走**另一条**通道: + * 它和失败的语气不同(失败是 error,状态是 neutral),报告也不该占用失败的"同一条只报一次" + * 名额。输入区子树因此不再有常驻 `role="status"`。 + */ + const onNoticeRef = useRef(onNotice); + useEffect(() => { + onNoticeRef.current = onNotice; + }, [onNotice]); + const reportedNoticeRef = useRef(''); + useEffect(() => { + if (errorPresentation !== 'toast') { + return; + } + if (notice === '') { + reportedNoticeRef.current = ''; + return; + } + if (reportedNoticeRef.current === notice) { + return; + } + reportedNoticeRef.current = notice; + onNoticeRef.current?.(notice); + }, [errorPresentation, notice]); + useEffect(() => { mountedRef.current = true; return () => { @@ -493,7 +526,10 @@ export function ConversationModelSelect({ {error && errorPresentation === 'inline' ? ( {error} ) : null} - {notice ? {notice} : null} + {/* 状态文案同理:Direct 输入区不留常驻 `role="status"`,一并交给浮层通道。 */} + {notice && errorPresentation === 'inline' ? ( + {notice} + ) : null}