Repository navigation
fix(desktop): square icon-only controls, one chrome-control seat, one traffic-light reserve, one preview drag owner - #455
Merged
Conversation
The windowed space the renderer left clear for the macOS traffic lights was a hand-copied 76px in five declarations, each with its own fullscreen sibling, tied to nothing: the main process places the buttons with its own `trafficLightPosition` literal. Either side could move alone. The reserve also ended exactly on the cluster's right edge, so the first shell control sat flush against the green light. Native geometry now has one home in `@pi-desktop/shared`: `MAC_TRAFFIC_LIGHT_POSITION` (what the main process applies) and `MAC_TRAFFIC_LIGHT_CLUSTER_WIDTH_DIP`, with `MAC_TRAFFIC_LIGHT_EDGE_DIP` as their sum. The renderer injects that edge into `--ds-traffic-light-edge` before first paint, and `chrome.css` composes `--ds-window-lead-inset` once as the edge plus the new `--ds-traffic-light-gap` (12px), so windowed macOS reserves 88px. Fullscreen (buttons hidden) falls back to the 8px gutter through the same token, which removes the five per-selector overrides; Windows/Linux keep 0. `.main-titlebar-left` now derives its 64px as `max(0px, inset - 12px)`, so the title keeps starting at the reserve without a negative padding where the reserve is 0. The intended behavior change: the cluster's right edge is unchanged and the first shell control gains 12px of clearance.
Updates every place that stated the macOS windowed traffic-light reserve as 76px to the new derivation: the shared geometry constant's cluster edge plus the 12px gap, i.e. 88px (8px in fullscreen, 0 on Windows/Linux). Adds D433 in both decisions logs, amends D408 and ADR 0238 in place, and rewrites the E2E-LAYOUT-three-column-width-priority expectation to the resolved-padding check the suite now runs.
`.icon-btn` is shared with label-driven pills, so it takes its width from its content: glyph plus 8px of side padding. Every icon-only use of it was therefore taller than it was wide — 31x28 for the sidebar collapse control and the composer's add button, 35x28 for the composer's enhance and undo controls inside `.composer-right`, and 30x28 in the settings provider actions — while the same function in the conversation topbar was already a 28x28 square. Icon-only uses now state `.icon-btn-square`, which pins both axes to the new `--ds-control-size` token (28px), keeps `flex: 0 0` so a crowded toolbar row cannot shrink the control back out of square, and drops the side padding that under the global `border-box` would leave a 12px content box for a 15px glyph. `.composer-right .icon-btn` no longer sets inline padding: the label-driven model/thinking chip sets its own padding with `!important`, so that declaration only ever widened the icon-only controls beside it. The maximize enhance control keeps its label geometry while it is loading. Renderer only: no protocol, storage, host, permission, or migration change.
The layout suite already drives the sidebar toggle and the work-panel geometry over CDP, so it is where the rendered control size can be checked: every visible `.icon-btn` without a label must be a 28px square. A stylesheet contract alone cannot catch a control that a flex row or the cascade resized.
07 §11.1 gains the icon-only row and the rule behind it, 08 §3.7 says which controls state it, and the decisions log carries the entry. Both locales are updated so the pair check stays green.
The preview- and route-band lane actions rendered as 22px tiles with `--radius-2xs` and a `--ds-tile` seat, beside 28px siblings: the same dock toggle in the conversation topbar, the viewport-fixed work-panel toggle, and the work-panel's own actions. One control, two sizes and two shapes, in the same 46px band. They now take the shared chrome-control geometry: a 28px square from `--ds-work-panel-toggle-size`, `flex: 0 0` so a crowded band cannot squeeze them out of square, `--radius-md`, a transparent seat with the semantic hover wash, and the 15px glyph every other chrome control uses. `.title-nav-btn` keeps only its press feedback and active tone. The preview action lane is derived from the control it reserves room for (`calc(2 * var(--ds-work-panel-toggle-size) + 4px + 8px)` = 68px), so the panel header's reserve and the buttons cannot drift apart. Renderer only: no protocol, storage, host, permission, or migration change.
08 §2 states the shared 28px square for every chrome icon control and the derived lane reserve; the decisions log carries the entry. Both locales are updated so the pair check stays green.
The panel header's `+`, maximize, and the viewport-fixed collapse toggle read as two clusters: four declarations on `.work-panel-actions` (an 8px margin, an 8px padding inset, a 1px `--ds-border-subtle` divider) plus the separate `--ds-work-panel-toggle-gap: 20px` lane token put 37px and a hairline rule between the maximize control and the toggle. One token now spaces the whole row. `--ds-work-panel-control-gap` replaces the lane token and is the header's flex gap (tab strip to action group), the `.work-panel-actions` gap (`+` to maximize), and — spent by the header's right padding as `calc(toggle-size + toggle-inset + control-gap)`, 44px — the gap from the action group to the fixed collapse toggle. The action group states spacing only, so the same three 28px squares read as one group. The fixed toggle keeps its ownership, 12px viewport inset, and platform control reservation; only the header's right padding changes, so the native drag rectangle and the action group's own geometry are untouched. The lane still reserves the whole toggle and the `+` trigger still clears it by 36px, keeping the 24px hit-region contract. The stylesheet contract test now asserts the shared token in both places and the absent separator, and the layout suite measures the resolved gap in the live chrome.
Both locales state the panel header's 44px safe lane (28px control + 12px viewport inset + the shared 4px control gap) instead of the retired 60px lane plus a separated action rail, so `+`, maximize, and the viewport-fixed collapse toggle are documented as one button group. The decisions log carries the entry and E2E-152 and E2E-LAYOUT-three-column-width-priority now state the same contract.
`+` and maximize carried a `--ds-tile` seat of their own, and the viewport-fixed collapse toggle added `--ds-tile-deep` plus `--ds-raised-shadow` while `aria-pressed="true"`. In the light theme that turned the panel header's three 28px controls into filled squares, with the toggle reading as a raised circular pill floating over the header — nothing like the top-left sidebar toggle and new-task controls beside them. Both controls now join the shared chrome-control group in `chrome.css`, which already seats the topbar's dock toggle, the viewport-fixed panel toggle, and the preview/route-band lane actions: one geometry (28px square, `--radius-md`, `flex: 0 0`), one transparent seat, the semantic `--ds-bg-hover` wash on pointer, and the `opacity: 0.4` disabled state. The duplicated rules in `work-panel.css` are gone so the geometry is stated once; the partial keeps only the action group's spacing. The toggle's pressed state drops the fill and the raised shadow and keeps the engaged ink, so the open state is the glyph swap plus `--ds-text-primary`. `aria-pressed` still carries the state to assistive technology, keyboard focus keeps the global `:focus-visible` outline, and the toggle's viewport-fixed ownership and `no-drag` carve-out are unchanged. The 4px control gap, 12px viewport inset, and lane reserve are untouched. `chrome-control-geometry.test.mjs` pins the panel controls' membership in the shared group and its rest/hover/disabled states, and `work-panel.test.mjs` asserts the transparent seat instead of the retired `--ds-tile` one.
07 §4.3 and 08 §2.3/§5.2 now state the shared transparent seat and the glyph-and-ink open state, the decisions log carries the entry, and E2E-LAYOUT-three-column-width-priority gains the appearance expectation plus an honest status note: the seat is pinned by source contracts while the rendered surface needs the eyes-on pass. Both locales are updated so the pair check stays green.
Contributor
Author
Owner
|
非常感谢您的 pr |
Contributor
Author
|
Added follow-up fix b96a8ab to this PR. The shared chrome-control rules previously covered preview Regression coverage:
Validation:
This update does not merge the PR. Validation above applies to the stated commit, not to an untested merge with newer upstream main. |
Resolve decisions-log conflicts by keeping both ADR 0268 (already on main) and the window-chrome geometry entries from PR vastsa#455, including D433.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

摘要 / Summary
本次 PR 修复 5 处窗口 chrome 问题。共同线索是同一个控件被反复重新描述:它的尺寸是偶然决定的,它的座(seat)随所在界面不同,一处留白被手工复制,一条带上有两个原生拖拽区域而实际只需要一个。本修订确定的几何量是 28 / 4 / 12 / 88 / 44 / 68。
This PR fixes five window-chrome issues. The through-line is one control that kept being described more than once: its size was decided by accident, its seat varied by which surface it sat on, a reserve was hand-copied, and a band had two native drag regions where it needed one. The geometry this revision settles is 28 / 4 / 12 / 88 / 44 / 68.
1. 仅图标控件此前并非正方形 / Icon-only controls were never square
.icon-btn与带文字的 pill 共用,因此宽度由内容决定——字形加左右各 8px 内边距——而高度是固定的。于是每个「仅图标」用法都宽大于高:侧边栏折叠控件与 Composer 的添加按钮渲染为 31×28(宽 31、高 28),Composer 的润色与撤销控件在.composer-right内为 35×28,设置页的 provider 操作按钮为 30×28。同一个控件在会话顶栏中已是 28×28 正方形,即一个功能有两种尺寸。现在仅图标用法显式声明.icon-btn-square,把两个轴都钉到新 token--ds-control-size(28px),保留flex: 0 0以免拥挤的工具行把控件压出正方形,并去掉左右内边距——在全局border-box下,它此前把 15px 字形挤进 12px 内容盒。.icon-btnis shared with label-driven pills, so it took its width from its content — glyph plus 8px of side padding — while its height was fixed. Every icon-only use was therefore wider than tall: the sidebar collapse control and the composer's add button rendered 31×28 (31 wide, 28 tall), the composer's enhance and undo controls 35×28 inside.composer-right, and the settings provider actions 30×28. The same control in the conversation topbar was already a 28×28 square, so one function had two sizes. Icon-only uses now state.icon-btn-square, which pins both axes to a new--ds-control-sizetoken (28px), keepsflex: 0 0so a crowded toolbar row cannot shrink the control back out of square, and drops the side padding that under the globalborder-boxleft a 12px content box for a 15px glyph.2. 同一控件曾有两套几何 / The same control had two geometries
预览带与路由带的行内操作渲染为 22px 方块,使用
--radius-2xs和--ds-tile座,与同一 46px 带内的 28px 同类控件并列——会话顶栏的同一个 dock 切换、视口固定的工作面板切换、以及工作面板自身的头部操作。它们现在采用共享的 chrome-control 几何:来自--ds-work-panel-toggle-size的 28px 正方形,flex: 0 0以免拥挤的带把控件压出正方形,--radius-md,透明座加语义 hover 底色,以及与其他 chrome 控件一致的 15px 字形。.title-nav-btn只保留按压反馈与激活色调。预览操作通道由它为其预留空间的控件推导(calc(2 * var(--ds-work-panel-toggle-size) + 4px + 8px)= 68px),因此通道与按钮不会漂移。The preview- and route-band lane actions rendered as 22px tiles with
--radius-2xsand a--ds-tileseat, beside 28px siblings — the same dock toggle in the conversation topbar, the viewport-fixed work-panel toggle, and the work-panel's own header actions — in the same 46px band. They now take the shared chrome-control geometry: a 28px square from--ds-work-panel-toggle-size,flex: 0 0so a crowded band cannot squeeze them out of square,--radius-md, a transparent seat with the semantic hover wash, and the 15px glyph every other chrome control uses..title-nav-btnkeeps only its press feedback and active tone. The preview action lane is derived from the control it reserves room for (calc(2 * var(--ds-work-panel-toggle-size) + 4px + 8px)= 68px), so the lane and the buttons cannot drift apart.3. macOS 红绿灯留白原先没有单一来源 / The macOS traffic-light reserve had no single source
窗口化时为原生红绿灯留出的空间此前是手工复制的
76px,出现在五处声明中(.main-titlebar-left作为其派生值64px、.conversation-topbar.ct-collapsed、.sidebar-header、.window-chrome-row:not(.sidebar-expanded)、预览的.work-panel-header),每处各配一个[data-fullscreen="true"]兄弟选择器。它们都不与主进程交给 Electron 的trafficLightPosition关联,任一侧单独变动都会造成漂移。该留白也正好停在集群右边缘,这正是第一个 shell 控件紧贴绿灯的原因。原生几何现在在@pi-desktop/shared中只有一个归属:MAC_TRAFFIC_LIGHT_POSITION(主进程实际应用的值)、MAC_TRAFFIC_LIGHT_CLUSTER_WIDTH_DIP,以及二者之和MAC_TRAFFIC_LIGHT_EDGE_DIP;渲染进程在首帧之前把该边缘注入--ds-traffic-light-edge。chrome.css一次性组合出--ds-window-lead-inset= 边缘 + 新 token--ds-traffic-light-gap(12px),因此窗口化 macOS 预留 88px,第一个 shell 控件获得 12px 净空。全屏(按钮隐藏)通过同一 token 回退到 8px gutter,由此删除了五个逐选择器覆盖。.main-titlebar-left现在以max(0px, calc(var(--ds-window-lead-inset) - 12px))推导偏移,使标题在留白处开始,同时避免在留白为 0 时出现负 padding。The windowed space the renderer left clear for the native traffic lights was a hand-copied
76pxin five declarations (.main-titlebar-leftas its derived64px,.conversation-topbar.ct-collapsed,.sidebar-header,.window-chrome-row:not(.sidebar-expanded), and the preview.work-panel-header), each with its own[data-fullscreen="true"]sibling. None of them was tied to thetrafficLightPositionthe main process hands Electron, so either side changing alone would have drifted. The reserve also ended exactly on the cluster's right edge, which is why the first shell control sat flush against the green light. Native geometry now has one home in@pi-desktop/shared—MAC_TRAFFIC_LIGHT_POSITION(what the main process applies),MAC_TRAFFIC_LIGHT_CLUSTER_WIDTH_DIP, and their sum asMAC_TRAFFIC_LIGHT_EDGE_DIP— and the renderer injects that edge into--ds-traffic-light-edgebefore first paint.chrome.csscomposes--ds-window-lead-insetonce as the edge plus the new--ds-traffic-light-gap(12px), so windowed macOS reserves 88px and the first shell control gains 12px of clearance. Fullscreen (buttons hidden) falls back to the 8px gutter through the same token, which removes the five per-selector overrides..main-titlebar-leftnow derives its offset asmax(0px, calc(var(--ds-window-lead-inset) - 12px)), so the title keeps starting at the reserve without a negative padding where the reserve is 0.4. 预览模式曾有两个重叠的原生拖拽区域 / Preview mode had two overlapping native drag regions
侧边栏收起且工作面板最大化时,shell 会挂载一条承载侧边栏与新任务控件的 overlay 行,其下方的面板头部同样横跨窗口。两者都声明了整带拖拽区域,因此该行的控件落进了头部矩形之内。在 Electron 中拖拽区域不是命中测试:Blink 收集有序矩形列表,由包含该点的最后一个矩形决定,所以该行自己的
no-drag控件无法把这条带切回来,控件失去指针输入而变成窗口拖拽。项目此前已为其他带修过两次同类故障,这也是chrome.css中「视觉内边距不排除拖拽矩形」规则的由来。现在 overlay 行及其 spacer 既不声明 drag 也不声明 no-drag——完全不贡献矩形——面板头部成为这条带唯一的拖拽归属,其边框盒在 shell 操作通道之前结束(用margin-left,而不是padding-left),使排除是几何的而非视觉的。通道保留自己的头部高度背景,带在视觉上仍然连续。留白现在在所有平台上以同一方式推导:macOS 使用共享 lead inset,Windows 与 Linux 得到相同的通道预留但没有红绿灯留白,展开侧边栏的情况也预留新任务控件。此前通道预留只存在于 macOS,因此在 Windows 与 Linux 上第一个面板标签曾压在那些控件之下。With the sidebar collapsed and the work panel maximized, the shell mounts an overlay row carrying the sidebar and new-task controls, and the panel header beneath it also spans the window. Both declared a full-band drag region, so the row's controls fell inside the header's rectangle. In Electron a draggable region is not a hit test: Blink collects an ordered rect list and the last rect containing the point decides, so the row's own
no-dragcontrols could not carve the band back out, and the controls lost their pointer input to window dragging. This is the same failure the project already fixed twice for other bands, which is whychrome.csscarries the rule that visual padding does not exclude a drag rectangle. The overlay row and its spacer now declare neither drag nor no-drag — they contribute no rectangle at all — and the panel header is the band's single drag owner, with its border box ending before the shell-action lane (margin-left, notpadding-left) so the exclusion is geometric rather than visual. The lane keeps its own header-height background so the band reads continuous. The reserve is now derived the same way on every platform: macOS uses the shared lead inset, Windows and Linux get the same lane reserve with no traffic-light reserve, and the expanded-sidebar case reserves the new-task control too. Previously the lane reserve existed only on macOS, so on Windows and Linux the first panel tab sat underneath those controls.5. 工作面板头部的三个按钮曾是两个簇、两个座 / The work-panel header's three buttons were two clusters with two seats
头部内的操作组(
+与最大化,间距 4px)与它之外、视口固定的折叠切换,被.work-panel-actions上四层叠加声明分隔——margin-right: 8px、padding-right: 8px、1px 的--ds-border-subtle分隔线,以及一条独立的--ds-work-panel-toggle-gap: 20px通道 token——实际形成 37px 间距再加一条发丝线。此外+与最大化各自带--ds-tile座,而切换按钮在其上又叠加--ds-tile-deep与aria-pressed="true"下的--ds-raised-shadow,因此在浅色主题下这一行读起来是三个实心方块,切换按钮像一个悬浮的凸起药丸,与旁边的左上角侧边栏、新任务控件完全不像。现在由一个 token 决定整行间距:
--ds-work-panel-control-gap: 4px取代--ds-work-panel-toggle-gap,同时作为头部的 flex gap(标签条到操作组)、.work-panel-actions的 gap(+到最大化),以及由头部右内边距以calc(size + inset + control-gap)支出的 44px——即操作组到固定折叠切换的间距。.work-panel-actions只声明间距;分隔线、inset 与 margin 均已移除。+与最大化随后加入chrome.css中的共享 chrome-control 组,因此三个按钮共用一套几何、一个透明座、指针悬停时的语义--ds-bg-hover底色,以及opacity: 0.4的禁用态;work-panel.css中重复的规则被删除,几何只声明一次。切换按钮的按下态去掉填充与浮起阴影,只保留激活墨色,因此打开态 = 字形切换 +--ds-text-primary。aria-pressed仍把状态传达给辅助技术,键盘焦点保留全局:focus-visible轮廓,切换按钮的视口固定归属与no-drag豁免不变。4px 控件间距的取值、12px 视口 inset、通道预留,以及所有命中区域契约均未改动。The action group inside the header (
+and maximize, 4px apart) and the viewport-fixed collapse toggle outside it were separated by four compounding declarations on.work-panel-actions—margin-right: 8px,padding-right: 8px, a 1px--ds-border-subtledivider, and a separate--ds-work-panel-toggle-gap: 20pxlane token — for a real 37px gap plus a hairline rule. On top of that,+and maximize carried a--ds-tileseat of their own while the toggle added--ds-tile-deepplus--ds-raised-shadowunderaria-pressed="true", so in the light theme the row read as three filled squares with the toggle floating as a raised circular pill — nothing like the top-left sidebar and new-task controls beside them.One token now spaces the whole row:
--ds-work-panel-control-gap: 4pxreplaces--ds-work-panel-toggle-gapand is the header's flex gap (tab strip to action group), the.work-panel-actionsgap (+to maximize), and — spent by the header's right padding ascalc(size + inset + control-gap), 44px — the gap from the action group to the fixed collapse toggle..work-panel-actionsstates spacing only; the divider, inset, and margin are gone.+and maximize then join the shared chrome-control group inchrome.css, so all three buttons take one geometry, one transparent seat, the semantic--ds-bg-hoverwash on pointer, and theopacity: 0.4disabled state; their duplicated rules inwork-panel.cssare deleted, leaving the geometry stated once. The toggle's pressed state drops the fill and the raised shadow and keeps the engaged ink, so the open state is the glyph swap plus--ds-text-primary.aria-pressedstill carries the state to assistive technology, keyboard focus keeps the global:focus-visibleoutline, and the toggle's viewport-fixed ownership andno-dragcarve-out are unchanged. The 4px control-gap value, the 12px viewport inset, the lane reserve, and every hit-region contract are untouched.受影响的规范、ADR 与 E2E 场景 / Affected specs, ADRs and E2E scenarios
04-ux/07-ui-design-system.md(§2 工具栏行、§4.3 工作面板头部行与座、§10 预览模式、§11.1 图标控件)、04-ux/08-component-spec.md(§2.3 Topbar chrome 图标控件、§3.7 控件、§5.2 WorkPanel 头部)、04-ux/01-ui-ia.md、04-ux/09-interaction-patterns.md—— 英文原文与zh-CN镜像同步。04-ux/07-ui-design-system.md(§2 toolbar row, §4.3 work-panel header row and seat, §10 preview mode, §11.1 icon controls),04-ux/08-component-spec.md(§2.3 Topbar chrome icon control, §3.7 controls, §5.2 WorkPanel header),04-ux/01-ui-ia.md,04-ux/09-interaction-patterns.md— EN andzh-CNmirrors.08-meta/decisions-log.md:新增条目 D433("macOS 红绿灯留白只有一个来源")、两条图标控件条目、共享的工作面板控件间距、安静的图标座;D408 就地修订。ADR 0238 §6 记录 88px 留白与单一预览拖拽归属。08-meta/decisions-log.md: new entry D433 ("The macOS traffic-light reserve has one source"), the two icon-control entries, the shared work-panel control gap, and the quiet icon seat; D408 amended in place. ADR 0238 §6 records the 88px reserve and the single preview drag owner.06-delivery/04-e2e-test-plan.md:顶栏场景与E2E-LAYOUT-three-column-width-priority描述渲染留白检查、单一拖拽归属路径、面板操作组的共享控件间距,以及透明座(并明确标注:座由源码契约钉住,渲染出的表面仍需人眼确认)。06-delivery/04-e2e-test-plan.md: the topbar scenario andE2E-LAYOUT-three-column-width-prioritydescribe the rendered-reserve check, the single-drag-owner path, the panel action group's shared control gap, and the transparent seat (with an explicit status note that the seat is source-contract-pinned while the rendered surface needs the eyes-on pass).不需要新的 E2E 场景:
E2E-LAYOUT-three-column-width-priority获得了正方形控件断言,改为读取解析后的左内边距而不是复述留白数值,断言 overlay 行不贡献拖拽区域且头部盒子在操作通道之前结束,并新增对面板控件共享控件间距的断言。No new E2E scenario was needed:
E2E-LAYOUT-three-column-width-prioritygained the square-control assertion, reads the resolved left padding instead of restating the reserve number, asserts the overlay row contributes no drag region and the header's box stops before the action lane, and now asserts the panel controls' shared control gap.不需要 ADR:没有架构边界、公共契约、安全边界或已冻结决策的变化。
No ADR is needed: no architectural boundary, public contract, security boundary, or frozen decision changes.
验证 — 集成的本地
main@4e9bb650/ Validation — integrated localmain@4e9bb650分支头
fix/window-chrome-geometry=4e9bb650;以下结果均来自该集成的本地main提交。Branch head
fix/window-chrome-geometry=4e9bb650; every result below comes from that integrated localmaincommit.pnpm build:jspnpm --filter @pi-desktop/desktop typecheckpnpm lintcheck-style-tokens.mjs)node scripts/check-architecture.mjspnpm -r --if-present testcargo fmt --all -- --checkcargo test -p host-core --lockedpnpm test:e2ePI_DESKTOP_TEST_API_KEY未设置 / unset)pnpm test:e2e:bootpnpm test:e2e:layoutpnpm test:e2e:theme-surfacesok,failures: []pnpm docs:checkpnpm docs:buildE2E 套件依据
06-delivery/04-e2e-test-plan.md的集成表选择:默认的跨系统 smoke、Electron boot/preload 探针、三栏布局套件(本次改动自身的回归面),以及针对浅色/深色 chrome 座的主题表面探针。E2E suites were selected from the integration table in
06-delivery/04-e2e-test-plan.md: the default cross-system smoke, the Electron boot/preload probe, the three-column layout suite (the change's own regression surface), and the theme-surface probe for the light/dark chrome seats.布局套件中的三条断言(在运行中的应用里测得)/ Three assertions from the layout suite, as measured in the running app:
留白断言也检查过「有牙齿」:把
window.ts还原为字面量{x:16,y:16}会立即让traffic-light-reserve.test.mjs失败。座的变化由两侧的源码契约覆盖——面板控件必须是共享 chrome-control 组的成员且静止态为透明座,git grep级别的检查确认它们不再出现在任何自有规则中。The reserve assertions were also checked for teeth: reverting
window.tsto the literal{x:16,y:16}failstraffic-light-reserve.test.mjsimmediately. The seat change is covered by source contracts on both sides — the panel controls must be members of the shared chrome-control group with a transparent rest seat, andgit grep-level checks confirm they appear in no rule of their own.兼容性、迁移与安全 / Compatibility, migration, security
Windows/Linux:这两个平台保留渲染进程绘制的控件与右侧 120px 带,
--ds-window-lead-inset保持默认0px。契约测试会遍历每条data-platform="win32"/"linux"规则,若其中一条设置了该留白即失败。预览通道预留不再是 macOS 专属,从而消除了这些平台在预览模式下第一个标签的重叠。Windows/Linux: they keep the renderer-drawn controls in the 120px right-side band, and
--ds-window-lead-insetkeeps its0pxdefault. A contract test walks everydata-platform="win32"/"linux"rule and fails if one sets the reserve. The preview lane reserve is no longer macOS-only, which removes the first-tab overlap those platforms had in preview mode.全屏不变:8px,现在经由同一 token。
Fullscreen unchanged: 8px, now via the same token.
插件面板窗口创建的是无原生红绿灯的朴素无边框
BrowserWindow,因此不受影响。Plugin panel windows create a plain frameless
BrowserWindowwith no native traffic lights, so they are unaffected.外观变化,行为不变(作用域限定):工作面板的
+、最大化与折叠控件失去填充/浮起的座,+控件失去聚焦时的背景底色;指针悬停使用与其他 chrome 图标控件相同的--ds-bg-hovertoken,键盘焦点保留全局:focus-visible轮廓。这一「不变」只针对座与视觉表现:按钮尺寸、标签、tooltip、aria-pressed、12px 视口 inset、通道预留与命中区域都未改变。但这不等于整行布局完全没动:第 5 项中操作组与固定折叠切换之间由叠加声明形成的 37px 实际间距加 1px 分隔线,已被共享的 4px 控件间距取代(由头部 44px 右内边距calc(size + inset + control-gap)支出),这一累积间距的变化是有意的。Visual change, no behavior change (scoped): the work-panel
+, maximize, and collapse controls lose their filled/raised seats and the+control's focus-time background wash. Pointer hover uses the same--ds-bg-hovertoken as every other chrome icon control, and keyboard focus keeps the global:focus-visibleoutline. That "unchanged" claim is scoped to the seat and the visual treatment: button sizes, labels, tooltips,aria-pressed, the 12px viewport inset, the lane reserve, and hit regions are unchanged. It is not a claim that the row's layout is untouched: in item 5, the effective 37px gap plus 1px divider between the action group and the fixed collapse toggle is replaced by the shared 4px control gap (spent as the header's 44px right padding,calc(size + inset + control-gap)); that cumulative-spacing change is intentional.无协议、IPC、存储、schema 或迁移变化;无新默认值;无新依赖。
No protocol, IPC, storage, schema, or migration change; no new default; no new dependency.
遗留风险 / Remaining risk
1. 60 DIP 常量与 88px 留白 / The 60 DIP constant and the 88px reserve. 88px 留白依赖
MAC_TRAFFIC_LIGHT_CLUSTER_WIDTH_DIP(60 DIP),该值来自 macOS 26、2x 显示器上的一次测量。Electron 不在运行时暴露原生按钮的 frame,因此该常量由单元测试与注释钉住,而非从系统读取,也不随显示器缩放或缩放比例做补偿。若未来的 macOS 改变红绿灯几何,需要重新测量(按钮位置会自动跟随MAC_TRAFFIC_LIGHT_POSITION)。The 88px reserve depends on
MAC_TRAFFIC_LIGHT_CLUSTER_WIDTH_DIP(60 DIP), measured on macOS 26 at a 2x display. Electron does not expose the native buttons' frames at runtime, so the constant is pinned by a unit test and a comment rather than read from the OS, and it carries no compensation for display zoom or scale changes; a future macOS that changes the traffic-light metrics would need this re-measured (the button position followsMAC_TRAFFIC_LIGHT_POSITIONautomatically).2. 原生拖拽区域只能靠人工确认 / Native drag regions are backed only by a manual check. 原生拖拽区域行为属于窗口服务器范畴,没有任何已提交的测试能触达:DOM
click()、CDPInput.dispatchMouseEvent与elementFromPoint都绕过它。因此评审依据是一次手工、尚未自动化的检查,且它是在本分支较早的一个修订版本上完成的,不是对当前 head4e9bb650的验证:在该分支构建上(侧边栏收起、面板最大化),一次坐标驱动的按压把受信任的pointerdown/click投递给侧边栏切换与新任务控件,二者都改变了预期的 shell 状态——即本 PR 所修的症状。当前修订没有再做手工 UI 检查。用带的空白区域拖动窗口,以及 Windows/Linux 上的预览交互,均未验证。建议这两个平台的评审者确认带仍能拖动、其控件仍有响应。Native drag-region behaviour is a window-server concern that no committed test can reach: DOM
click(), CDPInput.dispatchMouseEvent, andelementFromPointall bypass it. Review is therefore backed by a manual, not-yet-automated check that was performed on an earlier revision of this branch, not on the current head4e9bb650: a coordinate-driven press on that branch build (sidebar collapsed, panel maximized) delivered trustedpointerdown/clickto both the sidebar toggle and the new-task control, and each changed the expected shell state — the symptom this PR fixes. That evidence belongs to the earlier revision; no manual UI check was repeated for the current revision. Dragging the window by the empty part of the band, and preview interaction on Windows/Linux, were not exercised. Reviewers on those platforms should confirm the band still drags and its controls still respond.3. 渲染出的座未被观察 / The rendered seat was not observed. chrome 控件的新座在样式表层被断言(属于共享组、静止态透明座、任何状态规则中都没有 tile 或浮起座),并在构建后的 CSS bundle 中确认,但渲染出的外观未被观察:布局套件测量矩形与计算几何,而不是绘制出的座,且本次修订没有做截图或人眼检查。评审者应以目视确认工作面板的
+、最大化与折叠控件静止时是安静的透明图标、悬停时为灰色 wash,以及折叠切换的打开态表现为字形切换加更亮的墨色。把scripts/e2e-three-column-layout.mjs扩展为测量这三个控件的计算background-color/box-shadow可以补上这个缺口;它不属于本次修订。The chrome-controls' new seat is asserted at the stylesheet level (membership in the shared group, transparent rest seat, no tile or raised seat in any state rule) and verified in the built CSS bundle, but the rendered appearance was not observed: the layout suite measures rectangles and computed geometry, not the painted seat, and no screenshot/eyes-on pass was run for this revision. A reviewer should confirm by eye that the work-panel
+, maximize, and collapse controls are quiet transparent icons at rest, grey-wash on hover, and that the collapse toggle's open state reads as the glyph swap plus brighter ink. Extendingscripts/e2e-three-column-layout.mjsto measure the computedbackground-color/box-shadowof the three controls would close this gap; it is not part of this revision.4. 远程检查(先前检查时的状态,不是当前断言)/ Remote checks (status at the prior check, not current assertions). 本 PR 上当时只有一个
Verceldeployment 检查,它对该 fork PR 报告Authorization required to deploy——缺少组织授权时它无法通过,也不说明代码情况;当时也没有本 PR 的 GitHub Actions 运行记录。本次正文更新未重新运行 CI。At the prior check, the only remote check on this PR was a
Verceldeployment check reportingAuthorization required to deployfor this fork PR — it cannot pass without org authorization and says nothing about the code — and no GitHub Actions run was reported for this PR at that time. These are statuses observed then, not claims about the current state; CI was not re-run for this body update.