OpenProgram · Web UI · implementation design

Settings 可折叠导航列

问题:主侧栏、设置分类栏、Provider 列表栏同时展开时占用 864px 左右,Provider 详情在窄窗口中被压缩并出现横向溢出。

Audience
Web / Desktop UI 实现
Scope
Settings 三层左侧导航
Expanded
每列约 288px
Collapsed
每列 49px

当前状态与目标状态

当前:三列固定展开

Provider 详情只能使用剩余宽度。

Programs
LLM Providers
General
OpenAI Codex
DeepSeek
Provider detail

目标:三个导航列独立收起

窄轨保留展开按钮和可识别图标。

列级契约

展开态收起态持久化必须保留
应用主侧栏--sidebar-width49pxsidebarOpen(现有)展开按钮、导航图标
Settings 分类栏--sidebar-width - 1px49pxsettingsNavOpen展开按钮、分类图标、当前页状态
Provider 列表栏--sidebar-width - 1px49pxproviderListOpen展开按钮、Provider 图标、当前 Provider 状态

交互与状态边界

独立控制收起任意一列不修改另外两列的状态。 选择不展开在窄轨点击分类或 Provider,只切换内容,不强制展开导航列。 完整键盘入口折叠按钮使用原生 buttonaria-expanded、明确的中英文名称。 宽度过渡只过渡 grid column width;不改变详情表单数据、Provider 选择或滚动根。 持久化刷新和重新进入 Settings 后恢复用户最后一次选择。 窄窗固定轨主侧栏进入 fixed 模式后,Settings 保留 49px 左侧空间,窄轨不覆盖页面标题或设置内容。

方案比较

方案结论原因
React 本地 disclosure 状态 + CSS Grid 列宽采用沿用主侧栏模式,不增加 store 或依赖;每列状态边界明确。
只在固定 breakpoint 自动隐藏不采用窗口和字体缩放组合不同,固定阈值会替用户改变布局且无法手动恢复。
Provider 详情整体横向滚动不采用不释放导航占用,表单操作仍需横向滚动。
拖拽调整三列宽度不采用本次只解决显示/隐藏;增加三个 resize handle 会扩大状态和指针交互范围。

规范基础:CSS Grid 列宽负责布局;原生 disclosure 语义由 buttonaria-expanded 表达;不引入新组件库。

验收与排除项

验收

  • 两处新增折叠按钮均可用鼠标和键盘触发。
  • 三列收起后各为 49px,详情区得到释放的全部宽度。
  • 收起态没有标签、搜索框和分组标题溢出。
  • 分类与 Provider 仍可通过图标选择。
  • 默认安装版在窄窗口中验证。

排除

  • 不改 Provider 账号行的字段和动作。
  • 不新增可拖拽列宽。
  • 不改变主侧栏已有持久化语义。
  • 不把导航改成弹窗或 overlay。

实现证据

状态:已实现并安装到默认 App。

  • settings-tabs-layout.tsx:Settings 分类图标窄轨、独立按钮与 settingsNavOpen
  • providers/index.tsx:Provider 图标窄轨、独立按钮与 providerListOpen
  • check:settings-columns、TypeScript、生产构建、文档链接和补丁格式检查通过。
  • 默认安装版 800px 视口实测:三列均为 49px;Provider 详情 clientWidth = scrollWidth = 652px;Settings 标题起点 x=73px,没有被 fixed 主侧栏覆盖。