dsh-web-mobile

38Star9Fork0Issue0Watching

把 DSH Web 在手机浏览器上变成接近 App 的体验:侧栏改抽屉、文件预览改为底部弹层、设置弹窗近全宽,并在桌面端完全无感。

语言
JavaScript
License
MIT
分支
main
deepseek-harnessdshdsh-pluginmobilemobile-uipluginresponsiveweb-ui

安装

$ dsh plugin --profile web add github:mexiaosqwq/dsh-web-mobile

在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程

一句话定位

把 DSH Web 在 ≤1023px 的视口上重排为接近原生 App 的体验:侧栏变成可滑出的抽屉、文件树与预览变成底部弹层、设置弹窗近全宽并把工具栏并入分类栏;在 ≥1024px 时完全无操作。

核心能力

  • 侧栏改抽屉:会话头部新增「打开目录」图标按钮,点按抽出/收起抽屉;首页/空白页等没有会话头的阶段,由左上角浮动按钮接管开关
  • 文件浏览一键直达:会话头部新增「文件浏览」图标按钮,直接把 dsh-web-ui 的 aionui 资源管理器展开成底部弹层,无需先开抽屉
  • 抽屉底部双胶囊:抽屉打开时底部多出「文件浏览」「导出会话日志」两个胶囊按钮;会话日志按钮在没有当前会话时自动禁用
  • 状态栏与安全区适配:写入 viewport-fit=cover + theme-color,按 env(safe-area-inset-top) 把所有可见面顶到刘海之下;安卓系统状态栏颜色随明暗主题切换
  • 预览浮层全屏:dsh-web-ui 预览浮层标题栏右侧新增一个全屏切换按钮,按下后浮层填满视口(含安全区),再次按下恢复
  • 关闭交互全套:抽屉打开时点击遮罩关闭、按 Esc 关闭(弹窗打开时让位)、点击抽屉里的会话行/任务板/搜索结果收起抽屉;会话行的三点按钮被显式排除,点它打开的菜单不会被收起
  • 媒体查询限宽:768–1023px(折叠屏、平板竖屏)下,弹窗与浮层改为居中并限宽至 min(100vw-32px, 720px),避免内容挤在屏幕一角
  • 诊断浮条:URL 加 ?mobile-nav-debug=1 后,右上角出现实时显示视口、断点匹配、帧标记、浮层可见性、最近 5 条 JS 错误的悬浮面板

技术实现

  • 语言: TypeScript(React 18 + DSH client SDK);客户端编译为 CommonJS 并由 scripts/build-client.mjs 自定义打包器内联成 lib/client.js
  • 关键依赖: @deepseek-ai/cordis(宿主容器)、@deepseek-ai/dsh-client-runtime(cordis fiber + ClientContext)、@deepseek-ai/dsh-client-ui-slots(slot 注册)、react ^18.2.0(头部 / 抽屉底部 React 组件)
  • 架构模式: 双面插件。Host 端 src/index.ts:7 暴露一个空 apply(),仅用于在宿主 Loader 里登记 dsh-mobile-nav 行;真正的工作全部在 Browser 端 src/client/index.tsx:27-97:注入一张移动端 <style data-plugin>、注册三个 slot(conversation.session.header.actionssidebar.footer.action,以及 README 与 AGENTS.md 提到的 settings.general.item,但 src/client/index.tsx:66-97 仅注册前两个)、挂一组生命周期受管的 DOM effect
  • 入口文件: 客户端 src/client/index.tsx:27apply(ctx);cordis patch 在 cordis.patch.yml:4-5 写入一行 insert: { id: dsh-mobile-nav, name: '@dsh-external/dsh-mobile-nav' }
  • 核心机制: src/client/effects/reconciler-core.ts 维护零导入的脏键注册表,按动画帧合并 MutationObserver 突发,src/client/effects/phone-chrome.ts:124-165 把这层 DOM-free 引擎接到单一全树观察者上;任务声明自己的脏键(如 data-aionui-preview-open)后,只有真正变化的属性才会唤醒相关任务

适用场景

在手机浏览器(包括安卓 Chrome / iOS Safari)上使用 DSH Web、嫌默认三栏布局在窄屏下挤不下的用户;或需要在桌面窗口临时拉窄时仍然可用、又不想失去桌面版体验的开发者。安装一次即可同时改善首页、会话进行中、设置、文件树、预览五个场景。

前置依赖与兼容性

依赖最低版本说明
DSH 客户端 SDK@deepseek-ai/dsh-client-runtime ^0.1.0-rc.6 等系列(同版本号)package.json:48-57 声明 peerDependencies,涵盖 locale / runtime / ui-primitives / ui-slots / ui-conversation / ui-layout / ui-settings / ui-sidebar / session-log-export
Cordis@deepseek-ai/cordis ^4.0.1package.json:47 声明,由宿主提供
React^18.2.0package.json:52 声明,仅 peer
Node.js未声明package.json 未设置 engines;运行 pnpm verifypnpm build 的最低 Node 由 @types/react 与 TS 6.x 间接决定
平台浏览器package.json:39-44 声明 dsh.client.platform: "web",无 host 端代码,无原生模块依赖
宿主注入项slots / layout / locale / sessionLogDownloadsrc/client/index.tsx:19inject = [...] 列表,缺失任意一个 cordis fiber 会拒绝加载
第三方兼容插件dsh-web-ui-all 0.1.14、dshmarket 1.2.2、dsh-usage-stats 0.1.2、dsh-genui 0.8.3README.md:50-55 明示;UI 兼容补丁写在 src/client/styles/compat.css.ts

安装方式

dsh plugin --profile web add github:mexiaosqwq/dsh-web-mobile

配置项

配置类型说明默认值
?mobile-nav-debug=1URL 查询参数在右上角显示诊断浮条(视口、断点、帧标记、预览/资源管理器列可见性、预览/资源管理器是否打开、当前 phase、最近 5 条 JS 错误)。仅用于手机端排查,不影响功能不传 = 不显示

本插件没有 Schema / 配置文件 / 环境变量形式的配置项(src/ 内未读取 process.envSchema 字段或 localStorage 键,仅调试面板会读取 URL 查询参数)。

常见问题

Q: 安装后需要重启 DSH 吗?

A: 需要。README.md:63 明确写出「装完重启 dsh web」。插件在 host 启动时通过 cordis.patch.yml 注入 dsh-mobile-nav 行,运行中的 dsh web 进程不会动态加载。

Q: 桌面端会被这个插件影响吗?

A: 不会。源码里 src/client/styles/misc.css.ts:140-150(min-width: 1024px) 媒体查询里把所有 [data-mobile-nav=...] 控件设为 display:none !important;同时 src/client/effects/phone-chrome.ts:23-42installMobileEffect 只在 matchMedia('(max-width: 1023px)') 命中时安装副作用。>=1024px 时不创建 MutationObserver、不写 DOM、不注册事件。

Q: 预览浮层全屏按钮在哪儿?怎么用?

A: 仅在 dsh-web-ui 的预览浮层打开时出现在标题栏右侧(约 right: 36px; top: 8px)。点一下预览浮层铺满整个视口(含状态栏安全区),再点一下恢复到底部弹层尺寸。aria-label 会随状态在「全屏预览」/「退出全屏」之间切换。

Q: 点「文件浏览」按钮没反应怎么办?

A: 这通常不是按钮坏了,而是当前已经打开了预览浮层(compat.css.ts:104-115 让预览盖住资源管理器)。先在预览浮层标题栏点收起按钮(chevron),再点「文件浏览」。AGENTS.md:117 明确把这点列入「Pitfalls」。

Q: 升级后界面回到桌面版布局了怎么办?

A: 拉宽窗口或用桌面浏览器(≥1024px)就会回到桌面版;如果在手机视口下仍然是桌面版布局,先确认 dsh web 进程确实重启了,再加 ?mobile-nav-debug=1 看顶部 W 视口宽度与 mq≤1023 是否为 true。

Q: 怎么卸载?

A: dsh plugin --profile web remove dsh-web-mobile,然后重启 dsh web。本插件无 host 端进程、无持久化文件、无外部网络请求,卸载即清空。

上手难度

入门 — 不需要任何代码改动,安装重启即可生效;唯一的开关是排查用的 ?mobile-nav-debug=1 URL 参数,普通用户可以完全忽略。

已知问题与限制

  • CSS 依赖 :has() 选择器,要求 Chromium 105+;老旧 WebView 上的 :has() 规则会被静默丢弃,可能出现抽屉/弹层异常。源码在 src/client/styles/layout.css.ts:1-3compat.css.ts 大量使用 :has()
  • 当用户系统设置启用了「减少动态效果」,@media (prefers-reduced-motion: reduce) 会让浮层的滑入动画与变换过渡关闭(compat.css.ts:210-216
  • 预览浮层与资源管理器存在互斥关系:同时只能开一个;预览打开时点「文件浏览」按钮看似失效是预期行为。AGENTS.md:117 把这点列为排查「按钮看似失效」的优先级检查项
  • 抽屉内点击关闭逻辑使用 capture 阶段事件,并显式排除会话行的三点菜单按钮(phone-chrome.ts:415);如果将来第三方插件的会话行按钮选择器形态变化,需要同步更新这里的选择器,否则会误收起抽屉
  • 全树 reconciler 的任务在 src/client/effects/phone-chrome.ts:48-88 用模块级 installed 标志防重复挂载;同一宿主环境下热重载插件会先卸载再重建,期间会有极短的闪烁