- Главная
- Плагины
- Улучшения UI
- dsh-sidebar-panel-visibility
dsh-sidebar-panel-visibility
hzsfn/dsh-sidebar-panel-visibility
Adds a show/hide toggle for each sidebar panel entry to the sidebar More menu, one row per panel with its current state; the choice is stored in localStorage and replayed when the plugin reloads. The Plugins entry stays fixed and cannot be hidden.
Установка
dsh plugin --profile web add github:hzsfn/dsh-sidebar-panel-visibilityREADME
dsh-sidebar-panel-visibility
给 DeepSeek Harness(DSH)Web 端的左侧栏加一个面板入口显隐开关:不想要哪个面板的图标,就在「更多」菜单里把它关掉,状态跨重启保持。
这是 DSH 插件的社区实现。它不改动任何
node_modules里的官方包,全部通过 DSH 的槽位契约完成。
为什么需要它
DSH 的左侧栏面板入口是插件自己注册的,注册了就会一直显示。装了几个带面板的插件之后,左栏会被塞满,而官方没有提供任何关闭入口的界面。
上游代码里其实留了钩子——@deepseek-ai/dsh-client-ui-sidebar 的 SidebarRoot 会把 onPinnedChange(即内部的 setPinned)传给 sidebar.panellist.actions 槽位,但没有任何 UI 消费它;占据该槽位的 dsh-client-ui-entry-customization 里第一行就是 const moreEntries = region === "conversation" ? entries : [];,左栏(region === "sidebar")恒为空数组。
而且那个状态是纯内存的,源码注释原话是 held in memory until plugin reload——插件一重载就复位。
本插件做两件事:
- 往
sidebar.panellist.actions注册一组开关行,把上游留的钩子真正接上; - 把选择存进
localStorage,插件重载后回放一遍。
安装
dsh plugin --profile <你的 profile 名> add dsh-sidebar-panel-visibility
本地开发:
dsh plugin --profile <profile> add link:/绝对路径/dsh-sidebar-panel-visibility
桌面版 DSH 的
desktopprofile 由 Electron 独占管理,dsh plugin会拒绝直接写入。这种情况改profiles/desktop/package.json:把包名加进dependencies(link:或版本号)和dsh.profile.bundles,再在 profile 目录跑pnpm install。
装完重启 DSH。
用法
- 展开左侧栏(窄屏下需要先展开)。
- 点左栏底部的「更多」按钮(图标是方形加号)。
- 菜单最上方是「侧边栏条目」分区,每个面板一行:左边名字,右边「显示中 / 已隐藏」。
- 点一行就切换。隐藏的面板立刻从左栏消失,想找回就再点一次。
「插件」面板由上游 FIXED_PANEL_ID 硬编码保护,藏不掉——这是刻意的,不然插件页没了就没法装插件了。
存储
键名 dsh.sidebar.panelPins.v1,值是被隐藏的面板 id 数组,例如:
["files", "jobs"]
用「隐藏列表」而不是「显示列表」,是因为这样默认值(键不存在)自然等于「全部显示」——最保守的降级方向。任何异常(隐私模式禁用 storage、JSON 坏掉、值被别的脚本写脏)都返回空数组,用户最多是设置丢了,不会丢面板入口。
想彻底复位:浏览器开发者工具里删掉这个键,或执行 localStorage.removeItem("dsh.sidebar.panelPins.v1")。
兼容性
| 项目 | 值 |
|---|---|
| DSH | 0.2.2-rc.1 实测通过 |
| 平台 | Web / 桌面端(Electron)渲染进程 |
| 浏览器 | 任何支持 localStorage 的现代浏览器 |
| 依赖的槽位 | sidebar.panellist.actions(kind: "list") |
| 依赖的服务 | slots、locale |
槽位是 list 类型,所以本插件和内置的 entry-customization 是并列渲染关系,不抢占、不遮蔽。本插件注册时 order: -10,排在「浏览更多插件 / 创建你的插件」之前。
已知限制
- 只在左栏生效。会话头部和右侧栏的「更多」菜单不显示这组开关——那里的条目语义不同,混在一起容易误操作。
- 面板被卸载时残留 id。插件卸了但
localStorage里还留着它的 id,不影响使用(那个面板本来就不存在了),下次装回来会重新生效。目前不做过期清理。 localStorage是按浏览器隔离的。换个浏览器、清了站点数据,设置就没了。这符合「界面偏好」的定位,没往 profile 配置文件里写。- 不提供排序。上游
setPinned只有开关语义,排序需要另一套契约,不在本插件范围。
开发
node --check lib/index.js
node --check lib/client.js
npm test
两个测试都不碰浏览器:
test/storage.test.mjs— 用最小window桩把lib/client.js的 factory 跑起来,测纯函数(切换语义、六种异常降级、空列表删键、往返一致性)。测的是真正上线的那份代码,不是复制品。test/smoke.test.mjs— 用假react/ 假 jsx runtime / 假 ctx 把apply()真跑一遍,验证模块形状(id、name、inject、apply)、槽位注册参数(id、order、locale)、八种语言词条齐全,以及组件在给定 props 下能渲染、点击会以正确参数调用onPinnedChange、缺 props 时不炸。
代码结构
lib/index.js 主机半身:空壳,只为让 cordis loader 能加载插件行
lib/client.js 浏览器半身:显隐开关组件 + localStorage 读写 + 8 种语言词条
cordis.patch.yml bundle 补丁:把插件行插进 profile
test/ 纯函数单测 + 冒烟测试
菜单行用的是 primitives 的 MenuItemButton(和内置「更多」菜单项同一个组件),所以悬停、焦点环、键盘导航都是宿主原生的,不用自己仿一套。
为什么不改 node_modules
@deepseek-ai/dsh-client-ui-* 这些包在 profile 的 node_modules 里没有实体目录,由客户端模块加载器 window.__ModuleLoader__ 在浏览器侧解析。就算改已发布的 lib/client.js,那些文件通常是 pnpm store 的硬链(nlink=2),直接写会污染全局 store,必须先 unlink 再写。每次 DSH 升级还会被刷掉。
走槽位契约没有这些问题:插件是独立包,升级不受影响,卸载干净。
License
MIT
Похожие плагины
dsh-web (dsh-task-board)
zhu1090093659/dsh-web
dsh-web (dsh-web-all)
zhu1090093659/dsh-web
dsh-TUI
ccch1mneyyy/dsh-tui
dsh-web-ui (dsh-task-board)
zhu1090093659/dsh-web-ui