zangxx66/dsh-movable-settings--plugins-dsh-movable-settings ↗★ 0

dsh-movable-settings

Make the DSH settings dialog movable, resizable and maximizable, remembering its geometry. 适合需要更灵活调整DSH Web GUI设置弹窗尺寸和位置的用户。

パッケージ
dsh-movable-settings
互換性
未検証
バージョン
1.0.0
最終更新
2026/10/13

インストール

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:zangxx66/dsh-movable-settings#a5d5f74d0c19decbc9a3c91188e1f5c026dbf1ac&path:plugins/dsh-movable-settings

ドキュメント

README 全文を読む ↗

dsh-movable-settings

npm version license

把 DSH Web GUI 内置的「设置」弹窗从固定居中、不可调整,变成可拖动、可八向缩放、可双击最大化,并记住上次位置与尺寸的浮层。

Turn the built-in Settings dialog of the DSH Web GUI into a floating window you can drag, resize in 8 directions and maximize by double-click — with its geometry remembered.

面向 DSH web profile:增强对象是 @deepseek-ai/dsh-client-ui-settings-general 经 createPortal 渲染到 body 的设置 modal。 Targets the DSH web profile: it enhances the settings modal rendered by @deepseek-ai/dsh-client-ui-settings-general.

安装 / Installation

在 DSH 里安装,四种方式任选。Install inside DSH — pick any of the four.

方式一:让会话里的 Agent 装(推荐) — Ask the agent in any DSH session:

帮我安装 dsh-movable-settings 插件

Agent 会替你执行 / the agent runs:

plugin_manager action=install_bundle target=dsh-movable-settings

方式二:dsh 命令行 — With the dsh CLI:

dsh plugin --profile web add dsh-movable-settings

dsh plugin 把剩余参数转发给 profile 目录里的 pnpm,因此它只负责装包,不会把包登记进 profile 的 bundle 层(~/.dsh/profiles/web/package.json 的 dsh.profile.bundles)。装完请在 DSH 的「设置 → 插件」里启用它,或改用方式一 / 方式三由插件管理器一步到位。 dsh plugin merely forwards the arguments to pnpm inside the profile directory — it installs the package but does not register it in dsh.profile.bundles, so enable it under DSH's Settings → Plugins afterwards, or use method 1 / 3 to let the plugin manager do both steps.

方式三:自己调用 plugin_manager 工具(与方式一等价) — Call the tool yourself:

plugin_manager action=install_bundle target=dsh-movable-settings

方式四:本地目录(开发版 / 尚未发布) — From a local checkout (development build):

plugin_manager action=install_bundle target=

安装完成后刷新一次页面:client 半区的新代码只在页面重新加载后生效(除非同时跑着 pnpm run dev:web 的 HMR)。

After installing, refresh the page — the client half only picks up new code on reload (unless the pnpm run dev:web HMR watcher is running).

插件按 profile 安装,装好后该 profile 下的每个会话都会生效。 Plugins are installed per profile, so every session in that profile gets it.

行为 / Behavior

交互 Interaction位置 Where结果 Effect
拖动 Drag面板顶部约 54px 的非交互条带(导航标题区 + 内容列 header 空白处)指针变 move,面板实时跟随;命中按钮 / 输入框 / 链接 / slot 内容时不启动拖动;悬停条带显示原生 title 气泡「拖动移动 · 双击最大化 / 还原」
缩放 Resize四边 + 四角共 8 个手柄(悬停时淡淡显色)最小 480×360,且任意时刻不超出视口可用区
双击 Double-click同拖动条带 Same strip最大化到视口可用区;再次双击还原到最大化前的几何
最大化 / 还原 Maximize / Restore内容列 header 的「最大化」按钮(settings.action 槽位,重置按钮左侧,图标 + 文案随状态切换)与双击完全等价,是最大化能力的可见入口(title / aria-label 点明「也可双击标题栏」)
重置 Reset内容列 header 的「重置位置」按钮清空记忆并回到上游默认的居中布局

按钮顺序 / Button order:最大化(order 19) → 重置位置(order 20) → 上游的 打开配置文件 / Close。

拖动 / 缩放结束的瞬间,只有与抬手点重合(≤4px、120ms 内)的残留 click 会被吞掉;抬手后在新位置的第一次点击一律一次生效 —— 关闭按钮、输入框、下拉都照常触发与聚焦。

title 气泡只挂在两个条带容器上:nav 的第一个子元素(标题容器)与 content 的第一个子元素(54px header)。容器内没有自带 title 的交互后代会被写成 title="" 阻断继承,因此内容列 options 滚动区、nav 列表区与 header 里的上游控件都不会弹出这个提示。

视口可用区 = 视口四边各留 max(24px, --dsh-frame-overlay-top, --dsh-frame-chrome-top),与上游默认面板高度 min(800px, calc(100vh - 2 * max(24px, var(--dsh-frame-overlay-top, 24px)))) 的留白语义一致。窗口 resize 后会重新钳制,标题栏、关闭按钮与缩放手柄始终留在视口内可触达。

设计约束 / Design constraints

  • 纯客户端 DOM 增强 / Pure client-side DOM enhancement:不遮蔽、不重写任何 shipped slot,不接管键盘事件与 useModalLayer 的焦点陷阱;只把面板改成相对 overlay 的绝对定位,并附加一个自管理的交互层。
  • 锚点只用语义属性 / Semantic anchors only:div[data-shortcut-modal="settings"][role="dialog"][aria-modal="true"]。构建期 hash 类名(VOzbGW_*)会随上游构建变化,一律不依赖。
  • 交互层不进 React 树 / Interaction layer stays out of React:8 个手柄与兜底按钮挂在插件自建的 body 子节点(position: fixed)上,绝不 appendChild 进 React 管理的子列表。
  • 静默降级 / Silent degradation:锚点不匹配,或锚点命中但内部缺少 nav / content 两列及其标题 / header 容器时,插件都不改任何原样式、不留多余节点、不抛异常,仅输出一条 console.warn。
  • 主题一致 / Theme-consistent:颜色 / 圆角 / 边框只用 --dsw-alias-*、--dsw-radius-* 主题 token。
  • 提示不误报 / No misleading tooltips:拖动气泡只出现在能力真正生效的条带容器上,并对容器内无自带 title 的交互后代写入 title="" 阻断继承;unbind / dispose 时按原值逐一还原所有被改过的节点(实际改写集合 titleTouched + 原值表 titleBackups),节点中途脱离文档再复用也不会残留 title=""。
  • 完全可回收 / Fully reversible:dispose 时移除注入的 ``、observer、所有监听器、交互层节点与内联覆盖样式。

文件 / Files

package.json          清单(dsh.bundle.patch + dsh.client)
cordis.patch.yml      Loader 补丁,插入 id=movable-settings 的插件行
index.js              Host 半区(空壳:能力全在 Client 半区)
client.js             核心实现(DOM 增强 + settings.action 最大化/重置按钮)
locale/zh.json        插件显示名与描述(中文)
locale/en.json        插件显示名与描述(英文)
icon.svg              插件图标
LICENSE               MIT 许可证
test/dom-stub.mjs     最小 DOM 桩
test/enhancer.test.mjs 行为测试(node:test)

验证 / Verification

npm run check   # node --check index.js client.js
npm test        # 49 项行为与清单断言(node:test)

等价的细项 / equivalent commands:

node --check client.js
node --check index.js
node -e "JSON.parse(require('fs').readFileSync('package.json','utf8'))"
node --test test/enhancer.test.mjs
node --test test/manifest.test.mjs

真机手测 / Manual smoke test

浏览器侧无法自动化的部分,按此逐条走一遍(打开设置:Ctrl/Cmd+Alt+, 或侧栏齿轮):

  1. 拖动:拖动导航标题栏,面板应跟随指针移动,指针为 move,松手后停在新位置。
  2. 缩放:指针移到面板边缘 / 角落,出现细手柄,拖动改宽高;拖到极小不应小于 480×360。
  3. 双击最大化:双击标题栏最大化,再双击还原。悬停标题栏应出现原生气泡「拖动移动 · 双击最大化 / 还原」;悬停设置内容区或 header 里的「打开配置文件」按钮时不应出现该气泡。
  4. 按钮:点内容列 header 的「最大化」按钮,与双击等价;最大化后它应变成「还原」并换图标,点它回到原几何。
  5. 记忆:关闭再打开设置弹窗,以及整页刷新,位置与尺寸应保持。
  6. 钳制:把浏览器窗口缩到很小,面板应被钳制,标题栏 / 关闭按钮 / 手柄都还能点到。
  7. 重置:点「重置位置」回到居中默认布局,且「最大化」按钮同步回到未最大化语义。
  8. 回归:关闭按钮、点击遮罩、Esc 仍能关闭;面板内滚动、Tab 焦点陷阱、设置项切换正常;拖动后不会误触面板内的按钮。
  9. 卸载:在「设置 → 插件」里禁用本插件,弹窗应立刻恢复原始行为,页面无残留样式、手柄与 title。

发布(维护者) / Publishing

npm login      # 首次发布前 / first time only
npm publish    # 包名 dsh-movable-settings 未被占用,清单已移除 private

发布后即可 plugin_manager action=install_bundle target=dsh-movable-settings。

已知边界 / Known limits

  • 上游若连 data-shortcut-modal="settings" 属性一并改名,插件无从识别该弹窗,会完全静默(不改动、不告警);这属于不可探测的结构变更。
  • 缩放手柄覆盖在面板外缘 6px 上,Windows 经典滚动条(约 15px 宽)的最外侧几个像素会被手柄占用,其余滚动条区域仍可点击。
  • 条形气泡的落点靠结构定位(nav / content 的第一个子元素);上游若调整子元素顺序,气泡位置会偏,但拖动 / 缩放 / 最大化能力不受影响。
  • 本仓库的自动化测试跑在最小 DOM 桩上,只覆盖插件自身的逻辑;浏览器渲染与视觉一致性仍需真机核验。

许可证 / License

MIT © 2026 ricardo