fix(web): reclaim overlay scrollbar gutter
This commit is contained in:
+2
-2
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-04-composer-tab-gutter-reservation.md
|
||||
2026-08-04-composer-tab-gutter-reservation.md: 3b28c35c1f11676e41cabde76d1b0d16c688f034
|
||||
2026-08-04-composer-tab-gutter-reservation.zh.md: c357dd06c52a834c18d2e8a25246d4ad003db548
|
||||
2026-08-04-composer-tab-gutter-reservation.md: 2c2813371af073eee4bd80ce7813e77af3c0c319
|
||||
2026-08-04-composer-tab-gutter-reservation.zh.md: e450def2482218028875a48fce8842c88b5ba82e
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
Status: implemented
|
||||
|
||||
> Superseded for overlay views by [the seat-width compensation](2026-08-12-composer-overlay-seat-width-compensation.md): the overlay branch no longer reserves a gutter, and the seat compensates for the bar instead. Chat keeps the reservation described here.
|
||||
|
||||
English | [中文](2026-08-04-composer-tab-gutter-reservation.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
Status: implemented
|
||||
|
||||
> 对覆盖视图已被 [座位宽度补偿](2026-08-12-composer-overlay-seat-width-compensation.md) 取代:覆盖分支不再预留滚动条槽,座位改为补偿滚动条宽度。Chat 仍保留本文所述的预留。
|
||||
|
||||
[English](2026-08-04-composer-tab-gutter-reservation.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-composer-overlay-seat-width-compensation.md
|
||||
2026-08-12-composer-overlay-seat-width-compensation.md: 85281ed4301046672ff4c02320b196a397e6d163
|
||||
2026-08-12-composer-overlay-seat-width-compensation.zh.md: 7bcf060e651a828068ef207caaebd01fa2ffd7ae
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Agent Note: The overlay composer seat compensates for the bar instead of reserving a gutter
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-12-composer-overlay-seat-width-compensation.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The [composer-tab gutter reservation](2026-08-04-composer-tab-gutter-reservation.md) made the column's scroller reserve a scrollbar gutter unconditionally, so the composer seat measured the same width in Chat and in a view with a composer overlay. The cost was paid by every overlay view: the view's content column ended 8px short of the column's right edge, because the scroller reserved a gutter for a bar it never draws — the trajectory ledger owns its own scrollers and the outer box never scrolls.
|
||||
|
||||
The trajectory table made that cost visible: its full-width row divider lines stopped 8px short of the pane edge, leaving a strip of whitespace at the right of every line and of the whole content column.
|
||||
|
||||
## Decision
|
||||
|
||||
The reservation now belongs to Chat alone. The overlay branch declares `scrollbar-gutter: auto`, so the view's content spans the full column; the overlay composer seat (absolutely positioned against the padding box) gives back the bar's width with `right: var(--dsh-scrollbar-width)`, so the input card still measures the same width as Chat's seat and does not move between tabs.
|
||||
|
||||
The compensation value is not a literal: ui-theme's scrollbar.css defines `--dsh-scrollbar-width` (8px on the WebKit path) beside the `::-webkit-scrollbar` rule it mirrors, and the seat reads that variable. A change to the sheet's bar width reaches the compensation in the same reviewable diff as the bar itself.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep the unconditional reservation and shrink every overlay view.** The pre-fix behavior. It keeps one declaration for both tabs but taxes every overlay view with an 8px content column, which the trajectory ledger surfaced as visible whitespace. Rejected because the overlay views own their scrolling; they should not pay for Chat's bar.
|
||||
|
||||
**Reserve on the overlay branch too and let the view bleed into the gutter.** More moving parts for the same result: the gutter would still exist on a box that never scrolls, and the view would have to break out of the content box to reclaim its width.
|
||||
|
||||
**Accept the 4px card shift.** Dropping the reservation without compensating the seat would move the input card on every tab switch, which is exactly the symptom the earlier note fixed. Rejected: the card position is a deliberate cross-tab invariant.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Chat keeps its reserved gutter and its stable card position; nothing changes on that tab.
|
||||
- Overlay views (trajectory) span the full column; the trajectory ledger's divider lines reach the pane edge.
|
||||
- The input card still holds one horizontal position across the Chat and Trajectory tabs, now by two mechanisms instead of one: Chat reserves, the overlay seat compensates.
|
||||
- `--dsh-scrollbar-width` becomes a public ui-theme variable read outside ui-theme; the scrollbar-styles spec's indirection checks only scan `--dsh-scrollbar-thumb{,-hover}` rebinds, so the width variable is not covered by the pair gate.
|
||||
|
||||
## Testing
|
||||
|
||||
`apps/web/tests/composer-tab-geometry.e2e.ts` still asserts the card holds its position across tabs and now also asserts the split: Chat's scroller keeps `scrollbar-gutter: stable` and a nonzero band, while the overlay branch resolves `auto` with a zero band. The control cascade changed with the mechanism: it now drops the seat's `right` compensation (instead of dropping a gutter Chat never had on that branch) and measures the same 4px shift, proving the equal rectangles are not a tab switch that never reached layout. The committed golden records both states.
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Agent Note: 覆盖视图的 composer 座位改为补偿滚动条宽度,不再预留滚动条槽
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-12-composer-overlay-seat-width-compensation.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
[composer 标签页滚动条槽预留](2026-08-04-composer-tab-gutter-reservation.md) 让会话列滚动容器无条件预留一条滚动条槽,使 composer 座位在 Chat 与带 composer 覆盖的视图中测得相同宽度。代价由每个覆盖视图承担:视图内容列比列右边缘窄 8px,因为滚动容器为一条它从不绘制的滚动条预留了槽——trajectory 台账由视图内部自己的滚动容器滚动,外层盒子从不滚动。
|
||||
|
||||
trajectory 表格让这个代价显形:整行分隔线在面板右边缘前 8px 处停止,每条线右侧以及整个内容列右侧都留下一条空白带。
|
||||
|
||||
## 决策
|
||||
|
||||
预留现在只属于 Chat。覆盖分支声明 `scrollbar-gutter: auto`,视图内容占满整列;覆盖分支的 composer 座位(相对 padding box 绝对定位)用 `right: var(--dsh-scrollbar-width)` 让出滚动条宽度,使输入卡仍与 Chat 座位测得相同宽度,切换标签页时不移动。
|
||||
|
||||
补偿值不是字面量:ui-theme 的 scrollbar.css 在它镜像的 `::-webkit-scrollbar` 规则旁定义 `--dsh-scrollbar-width`(WebKit 路径 8px),座位读取该变量。样式表滚动条宽度一变,补偿就会与滚动条本身出现在同一次可审阅的 diff 中。
|
||||
|
||||
## 备选方案
|
||||
|
||||
**保留无条件预留,压缩每个覆盖视图。** 修复前行为。两个标签页一条声明,但每个覆盖视图都要付出 8px 内容列,trajectory 台账将其显现为可见空白。已拒绝:覆盖视图自己滚动,不应为 Chat 的滚动条买单。
|
||||
|
||||
**覆盖分支也预留,并让视图渗入滚动条槽。** 同样结果下更多活动部件:从不滚动的盒子上仍存在滚动条槽,视图还得突破内容盒才能取回宽度。
|
||||
|
||||
**接受 4px 卡片位移。** 去掉预留却不补偿座位,会在每次切换标签页时移动输入卡——正是前一份 note 修复的症状。已拒绝:卡片位置是刻意保持的跨标签页不变量。
|
||||
|
||||
## 后果
|
||||
|
||||
- Chat 保留滚动条槽与稳定的卡片位置;该标签页无任何变化。
|
||||
- 覆盖视图(trajectory)占满整列;trajectory 台账的分隔线到达面板右边缘。
|
||||
- 输入卡在 Chat 与 Trajectory 标签页间仍保持同一水平位置,现在由两种机制而非一种达成:Chat 预留,覆盖座位补偿。
|
||||
- `--dsh-scrollbar-width` 成为 ui-theme 对外、且被 ui-theme 之外读取的变量;scrollbar-styles 规格的间接层检查只扫描 `--dsh-scrollbar-thumb{,-hover}` 重绑,宽度变量不受成对门禁覆盖。
|
||||
|
||||
## 测试
|
||||
|
||||
`apps/web/tests/composer-tab-geometry.e2e.ts` 仍断言输入卡在标签页间保持位置,并新增断言拆分:Chat 滚动容器保持 `scrollbar-gutter: stable` 与非零槽宽,覆盖分支解析为 `auto` 且槽宽为零。控制级联随机制改变:现在移除座位的 `right` 补偿(而非移除该分支上 Chat 从未有过的槽),测得同样的 4px 位移,证明相等的矩形并非从未到达布局的标签页切换。提交的 golden 记录两种状态。
|
||||
Reference in New Issue
Block a user