← 返回列表
未验证
把侧边栏改为覆盖抽屉,设置面板变全屏单列
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/6 · 已提供中文文档
DeepSeek Harness (dsh) Web GUI 的手机外壳——侧边栏变为覆盖式抽屉,设置变为全屏单列。零硬编码宿主类哈希。
综合分
29.7
GitHub 分
29.7
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add AliceLJY/dsh-thumb该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-thumb
一个用于 DeepSeek Harness (dsh) Web GUI 的手机外壳。侧边栏不再挤压聊天区域,而是变成覆盖式抽屉;点击会话即可关闭它;设置面板变为全屏单列布局;对话记录也针对手机阅读距离重新调整。桌面端不受影响。
中文说明
个人工具,按原样发布。 为一个人的手机和一个 dsh 版本(0.1.0-rc.6)而写。不承诺维护,也不承诺回应 issue。如果 dsh 升级导致它失效,src/client.js 顶部 LOCATORS 中的四个条目就是排查入口——那只是几分钟的修改。
为什么
在手机上,dsh 的首屏没问题——侧边栏会自动折叠成 56px 的图标栏,输入框也放得下。一切问题都只在侧边栏展开后才出现,而这偏偏是你切换会话时必经的唯一路径。
在 iPhone 14 Pro 视口(393×660)、dsh 0.1.0-rc.6、安装本插件之前测得:
| 情况 | 之前 | 之后 |
|---|---|---|
| 折叠图标栏 | 正常 | 不受影响 |
| 侧边栏展开 | 占据屏幕 71%,把聊天区域挤压到 113px | 覆盖显示;聊天区域保持完整的 393px |
| 点击会话后 | 保持展开,于是你在 113px 的窄条里阅读 | 自动关闭 |
| 关闭侧边栏 | 只能通过折叠按钮 | 点击遮罩任意位置 |
| 设置面板 | 800px 双列布局硬塞进 393px;每个英文单词都换行;数值选择器掉出屏幕 | 全屏单列,文本正常换行,选择器在屏幕内 |
| 设置中被裁切的元素 | 7 | 1 |
| 对话记录高度(3 轮会话) | 610px——按桌面阅读距离设定 | 490px,短了五分之一 |
这不是上游的 bug——而是一项明确的约定。来自 @deepseek-ai/dsh-client-ui-layout 中的列宽求解器:
侧边栏从不退让:其渲染宽度始终是拖拽偏好值(或折叠图标栏),而中间列作为最后手段吸收所有剩余的宽度缺口。
在 SIDEBAR_DEFAULT = 280 的情况下,393px 的视口恰好得到 393 − 280 = 113。退让链会先缩小详情面板,然后关闭它,接着中间列吃掉剩下的一切。在还有几百像素余量的窄桌面窗口里这很合理;在手机上则不然。
安装 / 移除 / 关闭
安装
dsh plugin --profile web add github:AliceLJY/dsh-thumb
确认 ~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 中有 "dsh-thumb",然后重启服务
移除
dsh plugin --profile web remove dsh-thumb
再次确认它已从 bundles 数组中消失,然后重启
没有 npm 包:dsh plugin add 会把参数交给 pnpm,因此
github: 说明符会直接安装该仓库。冷存储下实测耗时 8.9 秒,dsh 会自行将其追加到 dsh.profile.bundles。
想在本地开发它?把同一条命令指向一个路径即可:
dsh plugin --profile web add link:/absolute/path/to/dsh-thumb
⚠️ 回滚意味着要撤销两件事:package.json 以及 node_modules 中的链接。只恢复前者,下一次 pnpm add 会看到链接仍然存在,判定“已是最新”,然后什么都不写入却报告成功——看起来已安装,实际并没有。
要在不重启任何东西的情况下关闭:
- 在 URL 后追加 ?thumb=0,或者
- 在控制台运行 localStorage.setItem('dsh-thumb','0') 并重新加载
这与 GitHub 上类似插件的区别
大约同一时间出现了十几个 dsh 移动端项目,做这件事的常见方式是在 CSS 中硬编码 dsh 的类名(pI_x6G_sidebarCol、Md3f7G_scroll 等等)。这些类名由 CSS Modules 在构建时生成,所以每次 dsh 重新构建它们都会变化,插件就会悄无声息地失效——样式不再生效,页面照常渲染,日志里什么都没有。只是某一天感觉变差了。
CSS 中任何地方都没有出现宿主类名(有几处注释提到一个类名,作为不要硬编码的反面例子)。取而代之的是,三列在运行时通过它们的语义后缀(sidebarCol——这一半来自上游源码变量,能经受哈希处理)定位一次,并打上我们自己的 data-thumb 属性;每条规则都基于这些属性。如果上游重命名了某个东西,一个定位器会在一处失效,而你能在那里找到它,而不是样式在所有地方悄悄失效。
行为也通过官方接口实现:关闭抽屉调用 ctx.layout.toggleSidebar()——ui-sidebar 自身使用的公共 ILayout 方法——而不是在某个按钮上合成点击。
适用范围
布局规则仅在两个条件同时成立时适用:视口 ≤1023px(与上游的 SIDEBAR_AUTO_COLLAPSE = 1024 一致,因此只有一个断点起作用)并且侧边栏已被手动展开。56px 的窄栏完全不受影响——它本来就能正常工作。
在平板上抽屉还值得吗?
本文件的早期版本猜测,它在平板宽度附近的某个地方就不再值得了,并建议把断点降到 767px。实测下来,这个猜测是错的。
重要的是你点击某个会话之后所处的状态,因为那是你切换会话必须走的路径。原版会让侧边栏保持打开,所以对话区停留在 width − 280。本外壳会关闭它,留下 56px 的窄栏和 width − 56:
| 视口 | 原版 | 使用本外壳 | 增益 |
|---:|---:|---:|---:|
| 393px | 113px | 337px | +198% |
| 480px | 200px | 424px | +112% |
| 604px | 324px | 548px | +69% |
| 768px | 488px | 712px | +46% |
| 900px | 620px | 844px | +36% |
| 1023px | 743px | 967px | +30% |
用 node test/measure-widths.mjs 重新生成该表格;该文件还解释了为什么它测量的是你最终剩下的宽度,而不是抽屉覆盖的宽度——这正是第一次尝试搞错的地方。
增益随宽度缩小,符合预期——但在支持范围内它从未在任何地方反转。降低断点会在它本应帮助的尺寸下关掉仍然值得 30–46% 的东西。1023px 断点保持不变。
密度规则是唯一刻意的例外:它们在 ≤1023px 且抽屉关闭时生效,因为那正是你阅读对话记录时的状态。在实测会话中,那是从 610px 的列宽降到 490px——其中 60px 仅来自轮次之间的间隙(16px → 10px),而这不会带来任何交互成本。正文从 16px/28px → 14px/21px,操作按钮从 28px → 24px;这些按钮本来就已经低于 44px 的 iOS 触摸目标,所以最后这一项是一种取舍,而样式表顶部的 --thumb-hit 把它补了回来。
桌面端已验证未变:侧边栏 280px,中心 1160px,position: static,无遮罩,设置仍是 800px 的双栏面板。
已知限制
- 悬停提示仍可能从右边缘溢出(悬停工作区行时的深色卡片)。刻意不修复:它的类名(_card / _copyable)过于通用,无法安全地定位,而正确地修复意味着每帧扫描每一个 position: fixed 图层并把它们夹回视口——对于一个不阻塞任何东西的外观问题来说,影响范围不明确。正确的修复属于上游,在提示自身的触摸处理中。
- 在 393、480、560、604、640、700、768、900 和 1023px 下测量,外加桌面端 1440×900——见 Scope 下的表格。手机尺寸是日常使用的尺寸;其余尺寸只测量过一次,并未长期使用。
- 设置导航仍然垂直堆叠,而不是水平滚动。flex-direction: row 规则落在一个包装器上,而实际布局这些项目的并不是它,所以它在面板顶部占用了一些垂直空间。保持原样:面板从不可用变为可用,而追查确切的导航容器是打磨,不是修复。
- 助手回复下方的操作行保持 28px,而用户消息下方的操作行缩小到 24px。它们位于第二个 flex 包装器中,对 height、align-self 或 min-height 都没有反应,而且没有任何命名这些类的规则设置高度——所以无论是什么决定了它们的尺寸,都需要比类名扫描更广泛的探查。刻意保持原样:在一个三轮会话中是 12px,约占列宽的 2%。
- 上游对其列布局方式的更改意味着需要更新此处。 定位器是 src/client.js 顶部 LOCATORS 中的四个条目——一次几分钟的编辑。
验证
node test/smoke.mjs # 针对运行中的 dsh 的 21 条断言
该测试套件在手机视口下驱动一个真实的 dsh 实例,然后在 1440×900 下再次运行:定位器被标记,聊天在抽屉后方保持全宽,四个密度数值,包含性,平板宽度,关闭开关,以及一次桌面回归测试,断言正文文本在那里仍然是 16px。有一个断言是端到端的,而非属性检查——它加载同一份记录两次,一次带 ?thumb=0,并要求 shell 的版本至少短 15%。
到目前为止,它已经捕获了两个真实的回归,两者都值得了解。
关闭开关,在测试套件首次运行时。?thumb=0 一直只禁用 React 组件,而在密度规则落地之前这就足够了——每条规则都以只有活动组件才会设置的抽屉属性为门槛。密度规则在抽屉关闭时也会生效,因此样式表变得自身具有承载作用,而开关不再能触及它。ensureStyle 和 stampFrame 现在会直接检查它。
包含性,这是测试套件没有捕获的——它来自一部手机。中央窗格除了挂载记录之外还挂载了 trace 视图,而 trace 工具栏由文本按钮组成。[class*="_actions"] > button 将其中每一个都设为 24px 见方,把 Duration / Turns / Calls 压缩成无法阅读的重叠。现在每条密度规则都经过 FLOW,这是一个作用域,它通过所持有的消息项而非类名来标识记录列。教训不在于选择器;而在于一个只打开一个标签页的测试套件会在相邻视图损坏时继续通过。因此有了包含性断言——并且它通过重新引入该 bug 并观察其失败得到了验证,它确实失败了,并指出了那三个按钮。
关于复现那一个的说明:trace 标签页在手机宽度下不接受 Playwright 点击。在桌面尺寸下打开它,然后缩小视口——同一个已挂载视图,窄布局,中间没有导航。
运行时的截图未发布——它们显示了真实的工作区和会话标题。
在复现它之前,有三个值得了解的陷阱:
1. ESM 忽略 NODE_PATH——全局安装的 playwright 需要绝对说明符,而且它是 CommonJS,因此导入默认值。
2. Chrome 会拾取系统代理,并且 ts.net 地址会超时——使用 http://127.0.0.1:3080 并加上 --no-proxy-server。
3. waitUntil: 'networkidle' 永远不会触发——dsh 保持一个活动连接打开,因此使用 domcontentloaded 加上固定等待。
开发说明
两个陷阱,都属于“看起来像是别处的问题,实际上是你自己造成的”那种:
插件从不激活,整个页面空白。 package.json 中的 dsh.client.inject 与 client.js 导出的 inject 看起来一模一样,含义却截然不同:前者列出的是包名(模块加载顺序),后者列出的是 cordis 服务名(['slots', 'layout'])。后者写错,插件就会一直处于 pending 状态,shell 会报告 web boot: 1 entry did not activate,并且什么都渲染不出来。照抄 @deepseek-ai/dsh-client-ui-sidebar 注入的内容即可。
一个永远关不掉的抽屉。 展开状态的判断最初读取的是侧边栏的渲染宽度(大于 56px 即视为展开)——而抽屉的 CSS 正是把该侧边栏固定到 320px 的元凶。这个条件被它自身的副作用污染了,于是它永远为真:折叠按钮、遮罩和自动关闭全都像是坏了,而且看起来像是 ctx.layout.toggleSidebar() 在窄视口下毫无作用(其实它一直没问题)。现在它改为读取 AppFrame 写在 frame 上的内联 grid-template-columns——这才是上游的本意,而本插件从不触碰它。规则:永远不要从你自己会覆写的量中推导条件。
许可证
MIT扫码进群