dsh-mobile-adapt
Verified@clxzl/dsh-mobile-adapt · v1.1.0 · MIT · Web UI
Phone and tablet adaptation layer for the DeepSeek Harness (DSH) web GUI: single-column layout with a drawer sidebar, readable type, 40px touch targets, safe-area and soft-keyboard handling.
Install
dsh plugin add @clxzl/dsh-mobile-adapt Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-mobile-adapt
DSH Web GUI 的手机端适配层 —— 让 DeepSeek Harness 在手机上真正能用。
English · 中文
它解决什么
DSH 的 Web GUI 是一套纯桌面布局:样式表里只有 prefers-reduced-motion 一种媒体查询,
没有任何宽度断点;布局宽度由 AppFrame 的 JS 求解器直接内联写在元素上。
所以窄屏下它只是把侧边栏"折叠"成 56px 的图标 rail,那 56px 依然占着横向空间。
390px 视口下的实测对比:
| 原生 | 装上本插件 | |
|---|---|---|
| 内容区宽度 | 334px(被 56px rail 吃掉) | 390px 满宽 |
| 侧边栏 | 只剩图标 rail,会话列表看不到 | 86vw 抽屉 + 遮罩,按钮或边缘右滑打开 |
| 设置页内容区 | 154px,标签逐字换行 | 390px 正常单栏 |
| 折叠摘要行 | 单行 nowrap,实测宽 1128~3949px,被裁到只剩前 1/3 |
允许换行,内容完整 |
| 代码块字号 | 11px | 13px |
| 会话行高 | 32px | 40px |
| 视口高度 | height:100%,底部被浏览器工具栏盖住 |
100dvh,并随软键盘收缩 |
| 正文字号 | 14px | 15px(输入区 16px,顺带避免 iOS 聚焦缩放) |
桌面宽度下完全不激活:所有规则都挂在 html[data-dsh-mobile] 之下,
并且不会留下任何属性残留。
安装
dsh plugin --profile web add @clxzl/dsh-mobile-adapt
然后重启 dsh:
systemctl restart deepseek-harness # 服务名按你的实际部署调整
包内声明了 dsh.bundle.patch,所以 dsh plugin add 会自动把它挂进 profile 的
bundle 栈,不需要手工改 cordis.patch.yml。
手动安装(不经过 npm)
cd <DSH_HOME>/profiles/web/node_modules
git clone https://github.com/YOUR_GITHUB_USERNAME/dsh-mobile-adapt.git
然后在 profiles/web/cordis.patch.yml 末尾追加:
- insert:
- id: mobile-adapt
name: 'dsh-mobile-adapt'
重启 dsh。
适配内容
- 布局:三列压成单列,内容占满视口
- 侧边栏:
position: fixed覆盖式抽屉(86vw,上限 340px),带遮罩; 点左上角按钮或从屏幕左缘右滑打开,点遮罩或左滑关闭 - 视口:改用
100dvh,并监听visualViewport把软键盘高度让给应用框架 - 输入:输入区字号 16px(避免 iOS 聚焦时缩放整页)
- 可读性:正文 15px;代码块内部横向滚动、宽表格内部滚动、长链接换行
- 触控:会话头部 / 输入区 / 侧边栏按钮 ≥40px,列表行 40px,
touch-action: manipulation去掉 300ms 点击延迟 - 安全区:补上
viewport-fit=cover,抽屉、输入区、会话头部让出safe-area-inset-* - 设置页:桌面两栏对话框折叠成单栏,导航栏变顶部横向滚动条
为什么不能只写几个 media query
踩过才知道的三个结构性原因:
- 布局宽度不是 CSS 写的。AppFrame 用 JS 求解列宽,直接内联成
style="grid-template-columns: ..."。要覆盖它,只能用!important。 - 类名是 CSS-module 哈希(形如
pI_x6G_frame、wSkVaW_header),跨版本就变。 本插件因此只依赖公开的data-slot锚点和data-composer-*/data-conversation-*这类稳定属性,一个哈希类名都没有用。 - slot host 是
display: contents。真正的网格列是它向上第一个display !== contents的祖先。而且在contents元素上写overflow/max-width是完全无效的——这点很容易误判为"改了没生效"。
另外两个具体的坑写在 CHANGELOG 里:
抽屉脱离 grid 流后自动放置会错位(要显式钉住 grid-column),
以及折叠摘要行是 inline 元素、max-width 对它无效。
它不接管 DSH 的状态
抽屉的开关状态不自己维护:读 AppFrame 的 data-sidebar-collapsed 属性判断,
切换时调 ctx.layout.toggleSidebar(),让 DSH 自己改状态。所以不会出现
"插件的状态和壳的状态不一致"。
开发
npm run build # src/ → lib/
src/mobile.css—— 全部样式src/client.js—— 浏览器端逻辑(构建时把 CSS 注入到__MOBILE_CSS__占位符)lib/client.js—— 构建产物,DSH 直接加载的就是它(已提交,装包即用)
对 DSH 客户端插件的格式说明:产物必须是 lazy-CJS 形式
(window.__ModuleLoader__.load({ id, factory }),在 exports 上挂 apply / inject),
宿主只负责把它作为 bundle 提供给浏览器。
已知限制
- 第三方插件自己的按钮不放大。例如 dsh-better-sidebar 的 28px 图标按钮不在 适配范围内——强行放大会破坏它自己的工具栏布局。
- 手机首次加载仍然慢。首屏要下载数 MB 的插件 bundle,这不归本插件管。
- 手机上的右侧栏没有专门适配。DSH 的列求解器在窄屏本就不给它轨道, 走的是 occupant 自己的全屏呈现。
- PWA / 添加到主屏需要服务端配合(manifest 与 iOS 的
apple-touch-icon必须在 静态 HTML 里,客户端注入不可靠),不属于本插件的能力范围。