Skip to content

fix(composer): fade the transcript instead of painting an opaque dock band - #1015

Merged
vastsa merged 3 commits into
mainfrom
fix/composer-dock-themeable-occlusion
Sep 24, 2026
Merged

vastsa merged 3 commits into
mainfrom
fix/composer-dock-themeable-occlusion

Conversation

@Tioit-Wang

Copy link
Copy Markdown
Collaborator

问题

.composer-dock-docked 横跨整幅宽度绘制不透明的 --ds-bg-primary,用来遮住滚到悬浮胶囊下方 / 圆角外侧的转写稿行(#728 / D603)。它确实解决了「漏字」,但代价是:

  • 这条带子是固定内置色,任何主题区域都够不到。主题填充 .main-pane(region main)或 .thread-scroll(region thread)时,聊天底部会出现一块硬边矩形;
  • 唯一的杠杆是 --ds-bg-primary 本身,而所有其它主表面都跟着它走,改它等于全应用一起动。

改动

文件 改动
apps/desktop/src/styles/composer.css .composer-dock-docked 的 background 由 var(--ds-bg-primary) 改为 transparent
apps/desktop/src/styles/chat-shell.css .thread-scroll 增加自渐隐遮罩,两个色标锚在 --composer-dock-height
scripts/e2e/theme-surfaces.js、scripts/e2e-theme-surfaces.mjs 旧断言硬编码「遮挡带必须等于 --ds-bg-primary 且不透明」,改为「停靠区必须全透明」+「遮罩随 --composer-dock-height 变化」;夹具补一个 .thread-scroll
docs/spec/04-ux/08-component-spec.md、docs/spec/06-delivery/04-e2e-test-plan.md、docs/spec/08-meta/decisions-log.md(+ docs/zh-CN 镜像) 同步描述与 D624 决策记录

为什么遮罩挂在 .thread-scroll 而不是 .thread-wrap:.thread-wrap 的直接子节点不止滚动容器(ChatTranscript.tsx:224-359),还有 .minimap-rail(bottom: dock+16px)、.jump-latest-btn(dock+12px)、.transcript-settle-veil(inset: 0)和 .transcript-navigation-loading。挂在外层会把缩略导航和「跳到最新」按钮一起渐隐。

为什么色标对齐 dock + 16px:.thread-content 的底部预留正是 padding-bottom: calc(dock-height + 16px)(chat-shell.css:258),所以滚到底时最后一行完全在渐隐带之上 —— 静止态零代价,只有滚动途中的行会淡出。

输入框上方渲染面的核对结论

ask 工具卡片、Plan/Goal 审批条、排队提示、增强失败提示、输入胶囊都在 .composer-stack 里,是 .thread-wrap 的兄弟节点,遮罩碰不到;而且它们本来就自带 composer 底板与投影 —— composer.css:52-62 与 563-566 的注释明确写着「the dock itself is transparent, so this plate uses the composer elevated fill and shadow」。本 PR 等于把这些面板原本的设计前提恢复回来。自动补全面板、权限菜单、模型菜单 portal 到 document.body,错误通知挂 .chat-surface,均不受影响。

验证

检查 结果
pnpm build:js 通过(229s,产出 apps/desktop/out/renderer)
pnpm test:e2e:composer-occlusion 通过 ok:true,6/6 pass(light/dark × default/custom)
pnpm test:e2e:theme-surfaces 通过 ok:true,6/6 pass
pnpm --filter @pi-desktop/desktop typecheck 通过
14 个引用主题/样式表面的测试文件(transcript-style、theme-surface-tokens、home-empty-layout、macos-sidebar-vibrancy 等) 115/115 通过
pnpm lint:biome 通过(86 files)
pnpm check:pr-base 通过(origin/main 21dcd3ddbb61 是 HEAD 的祖先)

E2E 实测输出:dock 计算背景 rgba(0, 0, 0, 0)、box-shadow: none;--composer-dock-height 取 120px/200px 时遮罩色标偏移为 [136, 118] / [216, 198],即 h+16 与 h-2。

反向验证:把旧实现(不透明带 + 无遮罩)塞回去再跑同一探针,断言立刻失败并报出 dock paints a backing band again、transcript mask is not a two-stop fade at 120px/200px: none —— 新断言确实能在旧代码上失败。

未通过的检查(均与本 PR 无关,相关文件与 origin/main 逐字节一致)

  • pnpm lint:apps/desktop/src/styles/ui-kit.css:349 使用字面量 border-radius: 4px,被 check-style-tokens.mjs 判违规。
  • pnpm docs:check:check:locales 报 04-ux/07-ui-design-system.md 的中文镜像来源声明无效。
  • apps/desktop 全量 node --test:2781 项中 82 项失败,集中在 macOS 签名 / 公证 / DMG staple、logger、npm 工具链等区域(Windows 上必然失败)。所有能观察到本改动的测试文件已单独跑过,115/115 通过。

环境说明

宿主检出缺少 packages/voice-runtime 等新包的 node_modules,且两侧都没有 Electron 二进制:为在 worktree 内跑 E2E,我执行了一次 pnpm install --offline --frozen-lockfile 并补装 Electron 二进制(先安全移除了临时 junction)。主检出的 node_modules 未被改动(已验证 root / apps/desktop / docs 三处目标仍存在),且提交只包含上述 10 个文件。

已知取舍

  • 遮罩作用于整棵子树,滚动条末端 18px 会淡出。现状是不透明带把它「硬盖」住,改成渐隐只是把「盖住」换成「淡出」,观感相近。
  • mask-image 叠在 will-change: scroll-position 的滚动容器上,滚动性能建议在真机再确认一次。若掉帧,退路是把滚动区收在胶囊之上(纯布局方案),本 PR 未包含。
  • 停靠区自身不再有不透明底衬,堆叠面板之间 8px 的缝隙会露出主题背景(默认主题下与 .main-pane 同色,观感不变)。

备注

调研过程中发现的 packages/i18n pt-BR 缺键问题,已由同时段合入的 #1011(fix(i18n): add missing pt-BR table action strings)修复。decisions-log.md 里 D603 被两处占用(Windows portable ZIP 与本文所述的 dock 遮挡),本 PR 的新决策取 D624,未改动既有条目。

refs #728

@vastsa

vastsa commented Sep 24, 2026

Copy link
Copy Markdown
Owner

Conflict resolution and validation update:

  • Merged the latest origin/main (35d6903) into the task branch without force-pushing contributor history. The D624 collision was resolved by retaining the Windows stdio decision as D624 and renumbering the themeable composer dock decision to D625, with references updated.
  • Added supplemental commit 86b2b343f to tokenize the existing composer model-menu metrics/shadow so the current pnpm lint gate passes without changing the visual shadow values.
  • Local pnpm build:js, pnpm lint, Desktop typecheck, docs/policy checks, PR-base check, diff check, and the composer-occlusion/theme-surface E2E probes all pass.
  • Remote Docs, Rust, PR-base, build, typecheck, lint, and architecture checks pass.

The remote JS Unit tests check is still red in apps/desktop/test/composer-model-thinking-menu.test.mjs: it expects a 300px menu and 22px nested-row padding, while the current origin/main source is 280px and 8px. This PR does not modify that test or those layout rules; only the existing tokenization changes in composer-menus.css are present. I am leaving the PR open and not bypassing the required test gate.

v_wyxgwang and others added 3 commits September 25, 2026 01:42
… band

`.composer-dock-docked` painted `--ds-bg-primary` across its full width to
hide transcript rows that had scrolled below the floating shell (issue #728,
D603). That band is a fixed built-in colour no theme region can reach: a
theme that fills `.main-pane` or `.thread-scroll` got a hard-edged rectangle
of the workspace colour across the bottom of the chat, and the only lever was
`--ds-bg-primary` itself, which every other primary surface follows.

The dock now paints nothing and `.thread-scroll` masks its own content out
across the composer reserve, so a themed conversation surface stays visible
behind the shell. The mask sits on the scroller rather than on `.thread-wrap`
because the minimap rail, the jump-to-latest button, the settle veil and the
navigation status are `.thread-wrap` children that must stay fully painted.
Its stops are anchored to the same `dock-height + 16px` trailing reserve
`.thread-content` already holds, so a transcript pinned to its end keeps its
last row fully opaque and only rows crossing the boundary fade. The dock's
own plates (ask-tool card, plan approval bar, queued prompts, shell) are
opaque siblings of `.thread-wrap`, so they are unaffected.

The theme surface regression now pins the dock to fully transparent and
asserts the mask tracks `--composer-dock-height`; both assertions fail against
the previous implementation. Renderer CSS, the regression probe and the
matching spec/decisions entries only: no scroll state, protocol, persistence,
theme schema, or permission change.

refs #728
Keep the model picker light-mode shadow unchanged while routing it through the design-token guard, and express its unit line height with the existing leading scale so the current main lint gate passes.
…-transcript-jump

The traffic-light-reserve test asserts that work-panel.css must not
restate the traffic-light footprint literal. Use a calc expression
based on --st-composer-dock-height instead.
@vastsa
vastsa force-pushed the fix/composer-dock-themeable-occlusion branch from fb0a857 to 4840b72 Compare September 24, 2026 17:42
@vastsa
vastsa merged commit 100d4d9 into main Sep 24, 2026
3 of 4 checks passed
@vastsa
vastsa deleted the fix/composer-dock-themeable-occlusion branch September 27, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants