# dsh-sidebar-rail · 产品需求说明(PRD) > 本文件与项目内其他文档均保存在 `dsh-sidebar-rail/` 目录下,不在上层目录散落。 > 范围已按「增量插件」重构修订:只补 macOS Desktop 折叠态,展开态与 Web 完全交给宿主。 ## 1. 背景 - **macOS Desktop**:侧栏折叠时 `AppFrame` 把左侧列折到 0 宽(`collapsedWidth = darwin ? 0 : 56`)并 `overflow: hidden`,宿主注释写明「The darwin closed sidebar has no rail」——折叠后左侧是一块空地,没有任何入口。 - **Web**:宿主 `ui-sidebar` 自带 56px 折叠轨(面板图标 + 折叠切换),Web 用户不缺轨道。 - **展开态**:宿主原生侧栏功能完整(搜索、视图选项、添加工作区、拖拽排序、行内菜单、设置座位、账号菜单)。 因此需要一个**增量**能力:只在 macOS Desktop 折叠态出现一条 Codex 风格图标轨,悬停展开列表;其他状态不要动宿主的任何东西。 ## 2. 目标与非目标 ### 目标 1. macOS Desktop 折叠态提供默认隐藏的 56px 图标轨,靠近左缘或聚焦时唤出:工作区、定时任务、插件、更多;底部为账号入口。 2. 悬停图标 → 展开对应浮层(工作区列表 / 定时任务列表 / 我的插件 / 更多面板 / 账号与余额)。 3. 工作区支持**浮层内置顶**,并按 `置顶项目 / 项目 / 最近会话` 分组显示。 4. 不替换宿主侧栏:展开态与 Web 下不渲染图标轨,宿主能力原样保留;插件详情页设置块独立提供。 5. 最近会话条数默认 5、可调 1–20,在工作区浮层与插件详情页提供设置,保存为本地偏好。 ### 非目标 - 不替换宿主 `sidebar` 槽,不接管展开态(替换会让宿主 `SettingsRoot` 不再挂载、设置整体不可达)。 - 不改宿主栅格列宽,不用 `!important` 覆盖宿主样式。 - 不做 native 模式(原 `docs/native-mode.md` 已随重构删除)。 - 不持久化折叠状态(折叠状态归宿主)。 - 不写宿主存储、不改宿主数据模型(不改 `packages/*`,不新增 RPC)。 - 不实现 Codex 的活动视图、自定义分区、永久删除。 - 不动右侧栏(right sidebar)。 - 不承诺 Windows / Linux 支持(未验证)。 ## 3. 支持范围 | 环境 / 状态 | 行为 | | --- | --- | | macOS Desktop,侧栏折叠且视口宽度 ≥ 768px | 图标轨默认隐藏,唤出后可打开浮层 | | macOS Desktop,视口宽度 < 768px | 不渲染图标轨,展开侧栏使用宿主控件 | | macOS Desktop,侧栏展开 | 插件不渲染;宿主原生侧栏行为 | | Web(折叠 / 展开) | 插件不渲染;宿主自带 56px 折叠轨与原生侧栏 | | Windows / Linux | 未验证,不渲染,不宣称支持 | ## 4. 用户故事 | 编号 | 角色 | 故事 | 验收标准 | | --- | --- | --- | --- | | US-1 | 日常使用者(macOS Desktop) | 我把侧栏收起后,仍能按需唤出工作区/任务/插件入口 | 折叠态靠近左缘唤出轨,含 4 个功能图标 + 1 个账号入口;均有可访问名称 | | US-2 | 日常使用者 | 我悬浮「工作区」图标,直接看到我的项目列表并切换 | 浮层出现,分「置顶项目 / 项目」两段(行内只显示工作区名称,无路径);底部附最近会话;点击项目即打开该工作区 | | US-3 | 日常使用者 | 我悬浮「定时任务」看已创建任务 | 浮层列出任务标题与下次运行时间;点击打开任务面板,底部可「打开面板」 | | US-4 | 日常使用者 | 我悬浮「插件」看自己启用的插件 | 浮层列出用户安装并启用的组合包,过滤宿主内置包;点击打开插件管理面板,底部可「打开面板」 | | US-5 | 日常使用者 | 我悬浮头像查看余额并找回完整设置 | 浮层只读展示可用的余额、赠金及用量/充值链接,未登录或不可用时显示提示;「展开侧栏」回到宿主完整入口 | | US-6 | 重度使用者 | 我在浮层里把常用项目置顶 | 置顶项目出现在「置顶项目」段最前;刷新后仍在 | | US-9 | 重度使用者 | 我调整最近会话条数并查看状态 | 默认 5,两个入口可调 1–20;列表独立滚动,并展示宿主提供的会话状态标识 | | US-8 | 老用户 | 我展开侧栏,界面还是熟悉的 DSH 样子 | **由宿主原生侧栏保证,插件不介入**:搜索、视图选项、添加工作区、设置座位、账号菜单都保持宿主行为,插件不渲染任何节点 | > 原 US-7(插件持久化折叠状态)随重构移除:折叠状态由宿主持有并随宿主持久化,插件只读 `data-sidebar-collapsed`。 ## 5. 交互规格 ### 5.1 折叠态(rail,仅 macOS Desktop) ``` ┌──────┐ │ 🗂 │ 工作区 │ ⏱ │ 定时任务 │ 🧩 │ 插件 │ ⋯ │ 更多 │ │ │ 👤 │ 账号座位(底部固定) └──────┘ ``` - 浮轨 `position: fixed`,`left: 0; top: var(--dsh-frame-top-clearance, 48px); bottom: 0; width: 56px`。 - 图标 20px、按钮 36×36、垂直间距 4px、左右居中;浮轨右边框 `.5px`。 - 悬浮 120ms 后展开浮层;移出图标与浮层共同区域 200ms 后收起(防抖,避免鼠标穿越间隙时闪断);`Escape` 关闭浮层。 - 浮层锚定在浮轨右侧,宽度 288px,按实际锚点与视口剩余空间计算最大高度;账号浮层底对齐,工作区列表与最近会话分别滚动。 - 点击语义: - 工作区 / 更多 → 展开宿主侧栏(`layout.toggleSidebar()`),后续操作由宿主原生侧栏承接; - 定时任务 → 选中 `schedules` 面板;插件 → 选中 `plugins` 面板; - 账号座位 → 展开宿主侧栏(设置入口由宿主提供)。 - 顶部 48px 不渲染图标:避开 macOS 红绿灯与宿主挂在 `shell.leading` 的重开 / 新会话控件。 - 浮轨只在「视口足够宽」时渲染:判定为纯函数 `shouldRenderRail(platform, collapsed, innerWidth)`,阈值 **768px** = 680(宿主正文最小宽)+ 56(轨宽)+ 32(两侧安全)。低于阈值整条浮轨不渲染,避免浮轨压住正文;宿主在 `shell.leading` 自带重开入口,不损失回头路。 - **默认隐藏,指针靠近左缘才滑出**。宿主折叠时主区占满窗口,标签行没有左侧避让(`ConversationRoot.module.css` 的 `.tabs` 无 `--dsh-frame-leading-clearance`),常驻轨会挡住首个「对话」标签。左缘 12px 热区负责唤出;键盘聚焦轨内控件同样唤出,顶部功能图标支持 `↓` / `→` 进入浮层,浮层内 Escape 关闭并返回触发图标。在图标间移动不应触发轨反复显隐。 ### 5.2 展开态 **由宿主原生侧栏负责,插件不渲染图标轨。** 本插件不绘制原生侧栏的品牌行、新会话、面板行或分组列表,也不修改宿主列宽与样式;自己的条数设置位于插件详情页。 ### 5.3 分组规则(浮层内) | 段 | 规则 | 排序 | | --- | --- | --- | | 置顶项目 | `pinnedWorkspaceIds` 命中的工作区 | 置顶顺序(最近置顶在前) | | 项目 | 其余工作区 | 宿主返回顺序 | | 最近会话 | 全部工作区中未归档、非空白、非子代理的会话 | `updatedAt` 倒序,默认 5 条,可调 1–20 条,独立滚动 | - 没有置顶项目时不显示置顶段;没有工作区时显示空态;没有最近会话时保留最近会话标题与条数设置。 - 定时任务只列未结束 / 未暂停的任务;插件只列用户安装并启用的组合包。 ### 5.4 状态归属 - **置顶**:插件本地状态,`localStorage['dsh.sidebar-rail.v1'] = { pinnedWorkspaceIds: string[] }`,写入用合并语义。 - **最近会话条数**:同一存储键的 `recentCount`,默认 5,范围 1–20;工作区浮层底部与插件详情页共享该偏好。 - **账号**:通过宿主服务读取,不把头像、余额或账号凭据写入插件偏好;登录、退出及付款由宿主或目标网页负责。 - **折叠状态**:归宿主。插件只读 frame 上的 `data-sidebar-collapsed`,不写入、不校正、不持久化。 ## 6. 约束 - 纯 Client 插件:不新增宿主路由、不写宿主存储、不注册服务。 - 图标轨只通过 `shell.overlay`(`kind: 'list'`)增量注册,条目 `id: 'dsh-sidebar-rail.rail'`、`order: 10`;不注册 `sidebar` 单槽、不声明 `children`;自己的偏好设置块注册到 `plugins.bundle.config`。 - 不得替换 `sidebar` 槽(会让宿主 `SettingsRoot` 不再挂载,设置整体不可达)。 - 不得用 `!important` 覆盖宿主栅格轨或宿主样式;不改宿主列宽。 - 主题:文字 `--dsw-alias-label-*`、悬停 `--dsw-alias-interactive-bg-*`、浮层底 `--dsw-alias-bg-overlay`、边框 `--dsw-alias-border-l1/l3`、当前态 `--dsw-specific-sidebar-nav-item-active`、浮轨底色 `--dsw-specific-sidebar-fill`;圆角与阴影使用宿主 token,缺失时使用 fallback。 - 不使用 `@deepseek-ai/dsh-client-ui-primitives` 等宿主包模块;自绘控件并复刻宿主可访问性属性。 - 组件崩溃不得影响宿主:错误边界兜底,overlay 条目降级为空渲染。 ## 7. 验收清单(macOS Desktop 折叠态) | # | 用例 | 预期 | | --- | --- | --- | | A1 | 收起侧栏后靠近左缘;再完成导航或移开指针 | 默认不遮挡「对话」标签;热区唤出 56px 浮轨,含 5 个有可访问名称的图标;结束后可收起,图标间移动不反复振荡 | | A2 | 悬浮工作区图标并调整最近条数 | 浮层分「置顶项目 / 项目」两段(行内只有名称);最近会话默认 5,可调 1–20 并独立滚动;点击**跳到已有会话** | | A3 | 悬浮延时 | 快速划过图标不弹浮层;停留 120ms 才弹;移出 200ms 后关闭;跨间隙不闪断 | | A4 | 点击置顶按钮 | 项目移入「置顶项目」段;刷新后仍在 | | A5 | 点击工作区 / 更多图标 | 展开宿主原生侧栏;点击定时任务 / 插件图标选中对应面板 | | A6 | 展开侧栏 | 图标轨不渲染;宿主搜索、视图选项、添加工作区、设置座位、账号菜单全部可用 | | A7 | Web 端 | 不出现第二条轨;宿主 56px 折叠轨与原生侧栏原样 | | A8 | 键盘 | Tab 聚焦图标唤出轨;顶部功能图标用 `↓` / `→` 进入浮层,Tab 遍历内容,浮层内 Escape 返回触发图标 | | A9 | 主题切换 | 亮 / 暗色下浮层与图标颜色正确(走宿主 token) | | A10 | 无数据 / remote 服务缺失、失败、超时 / 请求期间切换入口 | 成功空列表与失败文案明确区分;失败时有「打开面板」;关闭重开或切回后能重新请求 | | A11 | 窄窗口(< 768px) | `shouldRenderRail` 返回 false,浮轨不渲染,正文不被压住 | | A12 | 卸载插件 | 无残留样式与 portal 节点;宿主侧栏与正文保持原状 | | A13 | 头像、余额与账号链接 | 按登录态及宿主返回数据显示头像、主余额和赠金,缺失时提示;仅使用宿主提供的 http(s) 用量与充值链接 | | A14 | 插件详情页与浮层分别调整最近条数 | 两处使用同一偏好;验证即时同步、重新挂载及刷新后保存结果 | ## 8. 验收环境与未验证项 - 验收环境:macOS Desktop(真实窗口),需要能观察悬浮、点击、展开 / 折叠与卸载恢复。 - 各项的已执行结果与未验证范围以 [verify.md](verify.md) 为准;上述清单描述验收预期,不代表全部通过。 - 仅 `npm test` 通过不构成验收:单测只覆盖纯逻辑(分组 / 置顶 / 归一 / 时间文案),不覆盖渲染、槽注册与视觉。