Files
deepseek-harness/.agents/notes/implemented/feature/2026-08-04-web-composer-shared-width-axis.zh.md
T
Yif 92dd231ce4 polish(web): 打磨 Web 会话界面的布局、自适应与组件一致性
1. 统一会话列宽度轴:新增 --dsh-chat-content-width(748px),输入框、todo、goal、queue、approval、plan review、ask question 等容器的宽度与边距全部由该变量推导,消除各面板之间的像素漂移,窄视口下的边缘留白也保持一致。
2. 输入框自适应与细节:控制行改为容器查询(460px 阈值以下权限选择器只显示图标+下拉,隐藏文字);卡片圆角 20→22、行内边距调整并整体下移 2px(发送按钮除外);permission/model 触发器统一 24px 圆角;Plan 与 Read Only 间距 +8。
3. 修复浮层菜单溢出:slash 菜单与命令弹层钳制到输入卡片宽度,超长行以省略号截断;Tooltip 增加 12px 视口边缘安全距离。
4. 增加与替换图标:Add provider 改用输入框同款加号图标(IconPlusOutline16),统一图标尺寸与字号。
5. 统一 Settings → Models 组件:补齐按钮 hover 态、select 下拉箭头不再贴边、标题区与 provider 卡片间距 +12。
6. 侧边栏交互:add workspace / group by / create session / 收起侧边栏四个图标按钮增加 500ms 延迟 tooltip(前两个向下弹出);展开态的 New Session 不再重复显示 tooltip;侧边栏窄屏自适应收起逻辑微调。
7. 其他:hero 区 workspace 徽章右移对齐;附带 Agent Note(中英双语)记录共享宽度轴与容器查询的设计取舍。
2026-08-04 14:14:12 +08:00

3.8 KiB
Raw Blame History

Agent Note: Web 输入区共享宽度轴与控制行打磨

Status: implemented

English | 中文

Problem

Web 会话列的各个界面各自独立设定尺寸:转录列、输入卡片、todo/goal/queue 停靠卡片、ask-question/approval/plan-review 接管卡片各自硬编码 max-width(736/752/776/800px 等变体)与各自的侧边内边距。这些界面在全宽下彼此漂移几个像素,在窄视口下偏差更大——有的面板保留了到屏幕边缘的间隙,有的却贴边。另外,输入卡片的控制行没有自适应行为——窄卡片下权限触发器的文字标签会挤压整行;锚定在卡片上的浮层菜单也可能渲染得比卡片更宽,越过其右边缘。

Decision

一个内容宽度变量拥有整列。--dsh-chat-content-width(748px)声明在 ConversationRoot 的 .root 上——转录与 composer 座位是兄弟子树,声明必须放在共同祖先上,CSS 自定义属性才能通过继承同时到达两者。其他几何全部由它推导:输入卡片上限为 content + 32px(--dsh-composer-card-max-width),停靠卡片从卡片宽度中减去四个停靠 inset(4 × 8px)正好回到内容宽度,接管卡片直接使用内容宽度。窄视口不变式以结构而非数值表达:内容宽度的界面每侧 pad calc(var(--dsh-composer-side-clearance) + 16px),而输入卡片只留裸 clearance(16px),因此"输入卡片 = 内容 + 32px"在任意视口宽度下都成立,而不只是在上限处。

卡片内的控制行是一个 container-type: inline-size 容器,权限触发器在 460px 容器查询下收起文字标签(保留图标 + 下拉箭头)。查询刻意匿名:CSS modules 按模块哈希 container-name,InputBar 样式表里声明的名字永远无法匹配 PermissionSelect 样式表里写的查询——两个哈希后的名字悄然不同,查询永不触发。只有带模式图标的触发器才收起(:has(.triggerIcon));没有图标的宿主自定义模式保留文字作为其唯一标识。

锚定在卡片上的浮层菜单(slash 菜单、command popupSelect)钳制到锚点宽度(max-width: min(<设计上限>, 100%)),过长的行以省略号截断而不是溢出卡片。Tooltip 气泡在钳制中保留 12px 的视口边缘安全距离(ui-primitives Tooltip)。

Alternatives considered

保留各界面独立宽度,手工对齐数值。 否决:本次改动消除的漂移正是手工对齐常量的残留;未来任何宽度调整都需要五处协同编辑,且没有任何机制强制这组关系。

把变量声明在 .composerStack 上。 尝试后否决:接管面板在 composer 座位中是 stack 的兄弟节点,转录更是完全不同的子树,变量根本到不了它们;共同祖先(.root)是唯一正确的家。

用命名容器查询实现标签收起。 经实测否决:CSS modules 按模块作用域化 container-name,跨模块名字永不匹配,查询是死的。匿名查询解析到最近的祖先容器,在这里没有歧义(该行是唯一的容器)。

用 JS ResizeObserver 实现标签收起。 否决:容器查询是声明式的,无需监听器生命周期,而 460px 阈值无论哪种方案都是设计选择。

Consequences

修改列宽现在是一行编辑,比例关系由构造保证——评审期间 736 → 748 的重调已经验证了这一点。代价是间接性:五个界面的宽度不再能从各自的样式表直接读出,需要沿变量链追到 ConversationRoot。容器查询收起增加了一个约束:InputBar 的行必须保持为尺寸容器;删掉那条声明会静默禁用权限触发器的自适应行为。匿名查询也意味着未来若在行与触发器之间出现第二个容器,它会截获该查询——届时查询必须迁移,或避免中间容器。