dsh-remote-mobile 1.4.2 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +61 -16
- package/README_EN.md +61 -16
- package/lib/bridge/compat.d.ts +2 -2
- package/lib/bridge/compat.js +11 -12
- package/lib/client.js +2 -2
- package/lib/styles/style-snippets.js +36 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.3] - 2026-09-03
|
|
9
|
+
|
|
10
|
+
### Fixed (缺陷修复)
|
|
11
|
+
- **修复:样式覆写启用后提问弹窗被全屏黑纱遮罩盖住且宽度被强制撑满**。`preset-sidebar` 的 `[class*="_frame"]` 选择器用后缀匹配,同时命中三栏布局帧(`pI_x6G_frame`)与提问卡片(`Mbwy4a_frame`,其 class 名同样含 `_frame`)。提问卡片没有 `data-sidebar-collapsed` 属性,被 `:not(...)::after` 规则叠加了 `position:fixed; inset:0; z-index:899; background:rgb(0 0 0/24%)` 的全屏黑纱(表现为弹窗上面多了一层遮罩),同时被 `width:100vw !important` 强制撑满、覆盖了自身 `max-width:var(--dsh-chat-content-width)` 导致不自适应宽度。现用 `:has([class*="_sidebarCol"])` 把 `_frame` 相关规则精确锁定到三栏布局帧,提问卡片不再被误伤。
|
|
12
|
+
- **修复:提问弹窗左右边距过宽、选项字号偏大**。`preset-main` 新增提问卡片适配(以官方稳定属性 `data-question-key` 为锚点):左右内边距收窄到 `8px`(官方为 `calc(composer-side-clearance + 16px)`),选项标题字号 14px→13px、说明 14px→12.5px,行高同步收敛,标题微调 16px→15px,与对话正文紧凑排版保持一致。
|
|
13
|
+
- **修复:移动端侧边栏点击项目名称后抽屉被自动收起**。生态插件「点条目自动收回抽屉」增强会把条目内所有点击一律视为选中、下一帧程序化收起抽屉,导致选中高亮刚浮现,展开/收起箭头与新增/更多操作图标来不及操作抽屉就被关掉。现把防误收起守卫的记录范围从「条目内次级控件(按钮/箭头)」扩展到「条目任意部位(含项目名称主体)」,900ms 窗口内的程序化收起调用被吞掉,抽屉保持展开;真实点击收起按钮与点抽屉外暗处收起的官方行为不受影响。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
8
17
|
## [1.4.2] - 2026-08-26
|
|
9
18
|
|
|
10
19
|
### Features (新功能)
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<a href="#config">必备配置</a> •
|
|
23
23
|
<a href="#preview">界面预览</a> •
|
|
24
24
|
<a href="#features">功能特性</a> •
|
|
25
|
-
<a href="#install"
|
|
25
|
+
<a href="#install">安装与更新</a> •
|
|
26
26
|
<a href="#faq">常见问题</a>
|
|
27
27
|
</p>
|
|
28
28
|
|
|
@@ -69,7 +69,7 @@ dsh plugin --profile web add dsh-remote-mobile
|
|
|
69
69
|
<span id="config"></span>
|
|
70
70
|
### 2. 前置配置(开放外部监听)
|
|
71
71
|
|
|
72
|
-
由于 DSH 默认仅监听 `127.0.0.1`,为了使 Tailscale 私网或局域网设备能够正常连通,请确保在 `~/.dsh/profiles/web/cordis.patch.yml`
|
|
72
|
+
由于 DSH 默认仅监听 `127.0.0.1`,为了使 Tailscale 私网或局域网设备能够正常连通,请确保在 `~/.dsh/profiles/web/cordis.patch.yml`(Windows 对应 `C:\Users\<用户名>\.dsh\profiles\web\cordis.patch.yml` 或在资源管理器直接输入 `%USERPROFILE%\.dsh`)中包含以下配置:
|
|
73
73
|
|
|
74
74
|
```yaml
|
|
75
75
|
# 1. 允许 webserver 监听外部网络连接(必选)
|
|
@@ -88,7 +88,7 @@ dsh plugin --profile web add dsh-remote-mobile
|
|
|
88
88
|
disabled: true
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
> **💡 说明**:插件自身注册已由 DSH Bundle 体系全自动处理,**无需**在 `cordis.patch.yml` 中额外添加 `id: remote-mobile`。
|
|
91
|
+
> **💡 说明**:插件自身注册已由 DSH Bundle 体系全自动处理,**无需**在 `cordis.patch.yml` 中额外添加 `id: remote-mobile`。Windows 用户可按 `Win + R` 键输入 `%USERPROFILE%\.dsh\profiles\web` 快速直达配置目录。
|
|
92
92
|
|
|
93
93
|
---
|
|
94
94
|
|
|
@@ -176,7 +176,7 @@ DSH Web 界面在手机上仍有不少沿袭桌面端的样式问题,插件内
|
|
|
176
176
|
---
|
|
177
177
|
|
|
178
178
|
<span id="install"></span>
|
|
179
|
-
## 📦
|
|
179
|
+
## 📦 安装与更新
|
|
180
180
|
|
|
181
181
|
<details>
|
|
182
182
|
<summary><b>展开查看全部 4 种安装方式</b></summary>
|
|
@@ -203,6 +203,7 @@ pnpm add dsh-remote-mobile
|
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
### 方式 4:本地源码开发与调试(软链接即时生效)
|
|
206
|
+
|
|
206
207
|
```bash
|
|
207
208
|
# 1. 克隆代码至本地
|
|
208
209
|
git clone https://github.com/IceApriler/dsh-remote-mobile.git
|
|
@@ -211,15 +212,45 @@ cd dsh-remote-mobile
|
|
|
211
212
|
# 2. 安装依赖并编译打包
|
|
212
213
|
npm install
|
|
213
214
|
npm run build
|
|
214
|
-
|
|
215
|
-
# 3. 建立软链接到 DSH 运行环境(开发修改后 npm run build 即时生效)
|
|
216
|
-
rm -rf ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
217
|
-
ln -s $(pwd) ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
218
215
|
```
|
|
219
216
|
|
|
217
|
+
**建立软链接到 DSH 运行环境(开发修改后 `npm run build` 即时生效):**
|
|
218
|
+
|
|
219
|
+
* **macOS / Linux**:
|
|
220
|
+
```bash
|
|
221
|
+
rm -rf ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
222
|
+
ln -s $(pwd) ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
* **Windows (PowerShell)**:
|
|
226
|
+
```powershell
|
|
227
|
+
Remove-Item -Recurse -Force "$HOME\.dsh\profiles\web\node_modules\dsh-remote-mobile"
|
|
228
|
+
New-Item -ItemType Junction -Path "$HOME\.dsh\profiles\web\node_modules\dsh-remote-mobile" -Target (Get-Location)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
* **Windows (CMD)**:
|
|
232
|
+
```cmd
|
|
233
|
+
rmdir /s /q %USERPROFILE%\.dsh\profiles\web\node_modules\dsh-remote-mobile
|
|
234
|
+
mklink /J %USERPROFILE%\.dsh\profiles\web\node_modules\dsh-remote-mobile %CD%
|
|
235
|
+
```
|
|
236
|
+
|
|
220
237
|
</details>
|
|
221
238
|
|
|
222
|
-
###
|
|
239
|
+
### 🔄 更新插件
|
|
240
|
+
|
|
241
|
+
在终端执行更新指令,更新后重启 DSH 即可生效:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# 方式 1:通过 DSH 命令行一键更新(推荐)
|
|
245
|
+
dsh plugin --profile web update dsh-remote-mobile
|
|
246
|
+
|
|
247
|
+
# 方式 2:通过 Profile 目录包管理器更新
|
|
248
|
+
cd ~/.dsh/profiles/web && pnpm update dsh-remote-mobile
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
> **💡 提示**:也可以在 Web 控制台 **设置 ⚙️ -> 插件 -> 插件管理** 中点击对应插件的更新按钮,或重新执行 `dsh plugin --profile web add dsh-remote-mobile@latest`。
|
|
252
|
+
|
|
253
|
+
### 🗑️ 卸载插件
|
|
223
254
|
|
|
224
255
|
```bash
|
|
225
256
|
dsh plugin --profile web remove dsh-remote-mobile
|
|
@@ -272,6 +303,8 @@ dsh-remote-mobile:
|
|
|
272
303
|
|
|
273
304
|
## 📂 本地文件存储位置
|
|
274
305
|
|
|
306
|
+
> **💡 路径提示**:在 macOS / Linux 下根目录为 `~/.dsh/`;在 Windows 下对应为 `C:\Users\<你的用户名>\.dsh\`(可在文件资源管理器地址栏直接输入 `%USERPROFILE%\.dsh` 直达)。
|
|
307
|
+
|
|
275
308
|
| 文件路径 | 说明 | 安全级别 |
|
|
276
309
|
|---|---|---|
|
|
277
310
|
| `~/.dsh/settings.yaml` | 全局安全策略与免密开关配置 | 用户级读写 |
|
|
@@ -289,9 +322,14 @@ dsh-remote-mobile:
|
|
|
289
322
|
|
|
290
323
|
**答**:这是 **3080 端口被其他进程占用**(绝大多数是上一个 `dsh web` 实例尚未完全退出,例如桌面快捷方式拉起的隐藏实例、或重启时新旧进程交叠),**与安装了哪个插件无关**。排查步骤:
|
|
291
324
|
|
|
292
|
-
1.
|
|
293
|
-
|
|
294
|
-
|
|
325
|
+
1. **查找占用端口的进程**:
|
|
326
|
+
* **macOS / Linux**:`lsof -nP -iTCP:3080`
|
|
327
|
+
* **Windows**:`netstat -ano | findstr 3080`(最后一列为 PID)
|
|
328
|
+
2. **结束旧实例**:
|
|
329
|
+
* **macOS / Linux**:`kill <PID>`
|
|
330
|
+
* **Windows**:`taskkill /F /PID <PID>`(或在任务管理器中结束对应 Node 进程)
|
|
331
|
+
3. 重新启动 `dsh web` 即可。
|
|
332
|
+
4. **注意**:桌面快捷方式(dsh-desktop-launcher 生成的后台实例)与终端手动启动的实例不能同时运行。
|
|
295
333
|
|
|
296
334
|
另:若日志显示的是 `service "remoteWebUiPairing" has been registered` 类错误,请升级本插件至最新版本——新版已内置通用共存保护,与其他远程接入类插件并存时可正常启动并自动让出服务,并在设置面板顶部提示冲突详情。
|
|
297
335
|
</details>
|
|
@@ -299,10 +337,17 @@ dsh-remote-mobile:
|
|
|
299
337
|
<details>
|
|
300
338
|
<summary><b>Q1: 手机扫码后提示「连接被拒绝」或无法打开页面?</b></summary>
|
|
301
339
|
|
|
302
|
-
|
|
303
|
-
1.
|
|
304
|
-
2.
|
|
305
|
-
3.
|
|
340
|
+
**答**:请按以下步骤逐一排查:
|
|
341
|
+
1. **配置检查**:确保电脑上的 `cordis.patch.yml` 中已配置 `host: '0.0.0.0'`,且 DSH 已经重启;
|
|
342
|
+
2. **同一局域网**:局域网访问时,确保手机与电脑连接在同一个 Wi-Fi / 路由器下,且未开启手机端的独立代理/VPN(避免流量绕过局域网);
|
|
343
|
+
3. **Windows 防火墙排查(Windows 用户常见原因)**:
|
|
344
|
+
* 启动 DSH 时如弹出「Windows Defender 防火墙」警报,请务必勾选 **「专用网络」** 和 **「公用网络」** 并允许访问;
|
|
345
|
+
* 若错过弹窗或依然无法连通,可使用**管理员权限打开 PowerShell** 执行以下命令一键放行端口:
|
|
346
|
+
```powershell
|
|
347
|
+
New-NetFirewallRule -DisplayName "DSH Web 3080" -Direction Inbound -LocalPort 3080 -Protocol TCP -Action Allow
|
|
348
|
+
```
|
|
349
|
+
* **检查 Wi-Fi 网络类型**:在 Windows「设置 -> 网络和 Internet -> Wi-Fi」中,确保当前 Wi-Fi 网络配置文件类型已设为 **「专用网络」**(若为「公用网络」,Windows 防火墙会默认拦截局域网入站请求);
|
|
350
|
+
4. **多网卡环境(WSL / 虚拟机)**:Windows 如安装了 WSL2 或 Hyper-V,可能会生成虚拟网卡 IP(如 `172.x.x.x`)。请在插件设置面板中确认使用的是物理无线网卡(WLAN / Wi-Fi)对应的局域网 IP 或 Tailscale 二维码。
|
|
306
351
|
</details>
|
|
307
352
|
|
|
308
353
|
<details>
|
package/README_EN.md
CHANGED
|
@@ -22,7 +22,7 @@ English Documentation · [简体中文](./README.md)
|
|
|
22
22
|
<a href="#config">Required Config</a> •
|
|
23
23
|
<a href="#preview">UI Preview</a> •
|
|
24
24
|
<a href="#features">Features</a> •
|
|
25
|
-
<a href="#install">Installation</a> •
|
|
25
|
+
<a href="#install">Installation & Update</a> •
|
|
26
26
|
<a href="#faq">FAQ</a>
|
|
27
27
|
</p>
|
|
28
28
|
|
|
@@ -69,7 +69,7 @@ dsh plugin --profile web add dsh-remote-mobile
|
|
|
69
69
|
<span id="config"></span>
|
|
70
70
|
### 2. Configuration (Open External Listening)
|
|
71
71
|
|
|
72
|
-
Because DSH defaults to `127.0.0.1`, ensure your `~/.dsh/profiles/web/cordis.patch.yml` includes the following configuration to allow external connectivity:
|
|
72
|
+
Because DSH defaults to `127.0.0.1`, ensure your `~/.dsh/profiles/web/cordis.patch.yml` (on Windows: `C:\Users\<username>\.dsh\profiles\web\cordis.patch.yml` or enter `%USERPROFILE%\.dsh` in File Explorer) includes the following configuration to allow external connectivity:
|
|
73
73
|
|
|
74
74
|
```yaml
|
|
75
75
|
# 1. Allow webserver to listen for external connections (Required)
|
|
@@ -89,7 +89,7 @@ Because DSH defaults to `127.0.0.1`, ensure your `~/.dsh/profiles/web/cordis.pat
|
|
|
89
89
|
disabled: true
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
> **💡 Note**: Plugin self-registration is automatically handled by the DSH Bundle system. You do **not** need to add `id: remote-mobile` manually.
|
|
92
|
+
> **💡 Note**: Plugin self-registration is automatically handled by the DSH Bundle system. You do **not** need to add `id: remote-mobile` manually. Windows users can press `Win + R` and enter `%USERPROFILE%\.dsh\profiles\web` to quickly jump to the configuration folder.
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
@@ -175,7 +175,7 @@ The DSH web UI still carries many desktop-oriented styles on phones. This plugin
|
|
|
175
175
|
---
|
|
176
176
|
|
|
177
177
|
<span id="install"></span>
|
|
178
|
-
## 📦
|
|
178
|
+
## 📦 Installation & Update
|
|
179
179
|
|
|
180
180
|
<details>
|
|
181
181
|
<summary><b>Expand to view all 4 installation methods</b></summary>
|
|
@@ -202,6 +202,7 @@ pnpm add dsh-remote-mobile
|
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
### Method 4: Local Source Development (Instant Symlink Sync)
|
|
205
|
+
|
|
205
206
|
```bash
|
|
206
207
|
# 1. Clone source code
|
|
207
208
|
git clone https://github.com/IceApriler/dsh-remote-mobile.git
|
|
@@ -210,15 +211,45 @@ cd dsh-remote-mobile
|
|
|
210
211
|
# 2. Install dependencies & build
|
|
211
212
|
npm install
|
|
212
213
|
npm run build
|
|
213
|
-
|
|
214
|
-
# 3. Create symlink to DSH runtime (changes take effect instantly on npm run build)
|
|
215
|
-
rm -rf ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
216
|
-
ln -s $(pwd) ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
217
214
|
```
|
|
218
215
|
|
|
216
|
+
**Create symlink to DSH runtime (changes take effect instantly on `npm run build`):**
|
|
217
|
+
|
|
218
|
+
* **macOS / Linux**:
|
|
219
|
+
```bash
|
|
220
|
+
rm -rf ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
221
|
+
ln -s $(pwd) ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
* **Windows (PowerShell)**:
|
|
225
|
+
```powershell
|
|
226
|
+
Remove-Item -Recurse -Force "$HOME\.dsh\profiles\web\node_modules\dsh-remote-mobile"
|
|
227
|
+
New-Item -ItemType Junction -Path "$HOME\.dsh\profiles\web\node_modules\dsh-remote-mobile" -Target (Get-Location)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
* **Windows (CMD)**:
|
|
231
|
+
```cmd
|
|
232
|
+
rmdir /s /q %USERPROFILE%\.dsh\profiles\web\node_modules\dsh-remote-mobile
|
|
233
|
+
mklink /J %USERPROFILE%\.dsh\profiles\web\node_modules\dsh-remote-mobile %CD%
|
|
234
|
+
```
|
|
235
|
+
|
|
219
236
|
</details>
|
|
220
237
|
|
|
221
|
-
###
|
|
238
|
+
### 🔄 Updating Plugin
|
|
239
|
+
|
|
240
|
+
Run the update command in your terminal and restart DSH:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Method 1: DSH CLI One-Command Update (Recommended)
|
|
244
|
+
dsh plugin --profile web update dsh-remote-mobile
|
|
245
|
+
|
|
246
|
+
# Method 2: Update via Package Manager in Profile Directory
|
|
247
|
+
cd ~/.dsh/profiles/web && pnpm update dsh-remote-mobile
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
> **💡 Tip**: You can also click the update button in the Web console under **Settings ⚙️ -> Plugins -> Plugin Management**, or run `dsh plugin --profile web add dsh-remote-mobile@latest`.
|
|
251
|
+
|
|
252
|
+
### 🗑️ Uninstalling
|
|
222
253
|
|
|
223
254
|
```bash
|
|
224
255
|
dsh plugin --profile web remove dsh-remote-mobile
|
|
@@ -271,6 +302,8 @@ Custom snippets (style mini-plugins) and their enabled states are persisted in `
|
|
|
271
302
|
|
|
272
303
|
## 📂 Local File Storage Locations
|
|
273
304
|
|
|
305
|
+
> **💡 Path Note**: On macOS / Linux, the base path is `~/.dsh/`; on Windows, it resolves to `C:\Users\<username>\.dsh\` (you can directly paste `%USERPROFILE%\.dsh` into the File Explorer address bar).
|
|
306
|
+
|
|
274
307
|
| Path | Description | Security Level |
|
|
275
308
|
|---|---|---|
|
|
276
309
|
| `~/.dsh/settings.yaml` | Global security policies & bypass toggles | User R/W |
|
|
@@ -288,9 +321,14 @@ Custom snippets (style mini-plugins) and their enabled states are persisted in `
|
|
|
288
321
|
|
|
289
322
|
**Answer**: This means **port 3080 is held by another process** (in most cases a previous `dsh web` instance has not fully exited — e.g. a hidden instance launched by a desktop shortcut, or overlapping old/new processes during restart). It is **unrelated to which plugins are installed**. Troubleshooting:
|
|
290
323
|
|
|
291
|
-
1. Find the process holding the port
|
|
292
|
-
|
|
293
|
-
|
|
324
|
+
1. **Find the process holding the port**:
|
|
325
|
+
* **macOS / Linux**: `lsof -nP -iTCP:3080`
|
|
326
|
+
* **Windows**: `netstat -ano | findstr 3080` (PID is in the rightmost column)
|
|
327
|
+
2. **Terminate the old instance**:
|
|
328
|
+
* **macOS / Linux**: `kill <PID>`
|
|
329
|
+
* **Windows**: `taskkill /F /PID <PID>` (or kill the Node process in Task Manager)
|
|
330
|
+
3. Start `dsh web` again.
|
|
331
|
+
4. **Note**: An instance launched via the desktop shortcut (dsh-desktop-launcher) and one started manually in a terminal cannot run simultaneously.
|
|
294
332
|
|
|
295
333
|
If your log instead shows `service "remoteWebUiPairing" has been registered`, please upgrade this plugin to the latest version — newer versions ship with generic coexistence protection and can start normally alongside other remote-access plugins by yielding the service automatically, with a banner explaining the details in the settings panel.
|
|
296
334
|
</details>
|
|
@@ -298,10 +336,17 @@ If your log instead shows `service "remoteWebUiPairing" has been registered`, pl
|
|
|
298
336
|
<details>
|
|
299
337
|
<summary><b>Q1: Getting "Connection Refused" or cannot open page when scanning on mobile?</b></summary>
|
|
300
338
|
|
|
301
|
-
**Answer**: Please verify the following
|
|
302
|
-
1. Ensure `host: '0.0.0.0'` is properly configured in `cordis.patch.yml` and DSH has been restarted;
|
|
303
|
-
2. For LAN access, ensure your mobile phone and computer are connected to the exact same Wi-Fi router;
|
|
304
|
-
3.
|
|
339
|
+
**Answer**: Please verify the following items step by step:
|
|
340
|
+
1. **Configuration**: Ensure `host: '0.0.0.0'` is properly configured in `cordis.patch.yml` and DSH has been restarted;
|
|
341
|
+
2. **Same Network**: For LAN access, ensure your mobile phone and computer are connected to the exact same Wi-Fi router, and disable standalone VPN/proxy apps on your phone;
|
|
342
|
+
3. **Windows Defender Firewall (Common for Windows users)**:
|
|
343
|
+
* When prompted by the Windows Firewall popup on startup, ensure both **"Private networks"** and **"Public networks"** are checked before allowing access;
|
|
344
|
+
* If you missed the prompt or still cannot connect, run the following command in **PowerShell as Administrator** to allow inbound traffic on port 3080:
|
|
345
|
+
```powershell
|
|
346
|
+
New-NetFirewallRule -DisplayName "DSH Web 3080" -Direction Inbound -LocalPort 3080 -Protocol TCP -Action Allow
|
|
347
|
+
```
|
|
348
|
+
* **Check Wi-Fi Network Profile**: Under Windows "Settings -> Network & Internet -> Wi-Fi", make sure your current Wi-Fi profile is set to **"Private network"** (Windows "Public network" blocks inbound LAN connections by default);
|
|
349
|
+
4. **Virtual / WSL Network Adapters**: If WSL2 or Hyper-V is installed on Windows, virtual network adapters (e.g. `172.x.x.x`) may be present. Make sure you use the physical WLAN / Wi-Fi LAN IP or the Tailscale QR code shown in the plugin settings panel.
|
|
305
350
|
</details>
|
|
306
351
|
|
|
307
352
|
<details>
|
package/lib/bridge/compat.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ export declare const CLIPBOARD_POLYFILL_SNIPPET = "\n(function() {\n if (typeof
|
|
|
51
51
|
* 注入到 index.html 的移动端悬浮入口拖拽与位置记忆脚本
|
|
52
52
|
* 允许用户在移动端上下随心拖动左上角入口把手,避免遮挡聊天内容,并自动保存位置
|
|
53
53
|
*/
|
|
54
|
-
export declare const DRAGGABLE_NAV_SNIPPET = "\n(function() {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n /* ===== \u9632\u8BEF\u6536\u8D77\u5B88\u536B =====\n * \u7B2C\u4E09\u65B9\u751F\u6001\u63D2\u4EF6\uFF08\u5982 @linxin666/dsh-web-ui-all \u7684\u79FB\u52A8\u7AEF\u62BD\u5C49\u589E\u5F3A\uFF09\u4F1A\u5728\u7528\u6237\u70B9\u51FB\n * \u4FA7\u8FB9\u680F\u6761\u76EE\uFF08role=treeitem\uFF09\u540E\uFF0C\u4E8E\u4E0B\u4E00\u5E27\u7A0B\u5E8F\u5316\u70B9\u51FB\u300C\u6536\u8D77\u4FA7\u8FB9\u680F\u300D\u6309\u94AE\u81EA\u52A8\u6536\u56DE\u62BD\u5C49\u3002\n * \u8BE5\u5224\u5B9A\u65E0\u6CD5\u533A\u5206\u300C\u9009\u4E2D\u6761\u76EE\u56DE\u4E3B\u533A\u300D\u4E0E\u300C\u70B9\u51FB\u6761\u76EE\u5185\u7684\u6B21\u7EA7\u64CD\u4F5C\u56FE\u6807\u300D\uFF08\u66F4\u591A\u64CD\u4F5C \u22EF /\n * \u5C55\u5F00\u7BAD\u5934\u7B49\uFF09\uFF0C\u5BFC\u81F4\u540E\u8005\u62BD\u5C49\u88AB\u8BEF\u5173\u3002\n * \u8FD9\u91CC\u8BB0\u5F55\u6700\u8FD1\u4E00\u6B21\u5BF9\u6761\u76EE\u5185\
|
|
54
|
+
export declare const DRAGGABLE_NAV_SNIPPET = "\n(function() {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n /* ===== \u9632\u8BEF\u6536\u8D77\u5B88\u536B =====\n * \u7B2C\u4E09\u65B9\u751F\u6001\u63D2\u4EF6\uFF08\u5982 @linxin666/dsh-web-ui-all \u7684\u79FB\u52A8\u7AEF\u62BD\u5C49\u589E\u5F3A\uFF09\u4F1A\u5728\u7528\u6237\u70B9\u51FB\n * \u4FA7\u8FB9\u680F\u6761\u76EE\uFF08role=treeitem\uFF09\u540E\uFF0C\u4E8E\u4E0B\u4E00\u5E27\u7A0B\u5E8F\u5316\u70B9\u51FB\u300C\u6536\u8D77\u4FA7\u8FB9\u680F\u300D\u6309\u94AE\u81EA\u52A8\u6536\u56DE\u62BD\u5C49\u3002\n * \u8BE5\u5224\u5B9A\u65E0\u6CD5\u533A\u5206\u300C\u9009\u4E2D\u6761\u76EE\u56DE\u4E3B\u533A\u300D\u4E0E\u300C\u70B9\u51FB\u6761\u76EE\u5185\u7684\u6B21\u7EA7\u64CD\u4F5C\u56FE\u6807\u300D\uFF08\u66F4\u591A\u64CD\u4F5C \u22EF /\n * \u5C55\u5F00\u7BAD\u5934\u7B49\uFF09\uFF0C\u5BFC\u81F4\u540E\u8005\u62BD\u5C49\u88AB\u8BEF\u5173\u3002\n * \u8FD9\u91CC\u8BB0\u5F55\u6700\u8FD1\u4E00\u6B21\u5BF9\u6761\u76EE\u5185\u4EFB\u610F\u90E8\u4F4D\uFF08\u9879\u76EE\u540D\u79F0\u4E3B\u4F53 / \u6B21\u7EA7\u6309\u94AE / \u7BAD\u5934\u56FE\u6807\uFF09\u7684\u89E6\u6478\u65F6\u95F4\uFF0C\n * \u5E76\u5305\u88C5 HTMLButtonElement.prototype.click\uFF1A\u77ED\u65F6\u95F4\u7A97\u53E3\u5185\u7684\u7A0B\u5E8F\u5316\u6536\u8D77\u8C03\u7528\u76F4\u63A5\u5FFD\u7565\u3002\n * \u8986\u76D6\u6761\u76EE\u4E3B\u4F53\u662F\u4E3A\u4E86\u8BA9\u9009\u4E2D\u9AD8\u4EAE\u540E\u6D6E\u73B0\u7684\u5C55\u5F00/\u6536\u8D77\u7BAD\u5934\u4E0E\u65B0\u589E/\u66F4\u591A\u64CD\u4F5C\u56FE\u6807\u6709\u8DB3\u591F\u7684\n * \u505C\u7559\u64CD\u4F5C\u65F6\u95F4\uFF1B\u7528\u6237\u771F\u5B9E\u70B9\u51FB\u6536\u8D77\u6309\u94AE\uFF08\u6D4F\u89C8\u5668\u5408\u6210\u4E8B\u4EF6\u4E0D\u8D70 prototype.click\uFF09\u4E0E\n * \u70B9\u51FB\u62BD\u5C49\u5916\u6697\u5904\u6536\u8D77\u7684\u5B98\u65B9\u884C\u4E3A\u5747\u4E0D\u53D7\u5F71\u54CD\u3002 */\n if (!window.__dshRmAntiCollapseInstalled__) {\n window.__dshRmAntiCollapseInstalled__ = true;\n var lastEntryTapAt = 0;\n document.addEventListener('pointerdown', function (e) {\n try {\n var t = e.target;\n if (!t || !t.closest) return;\n if (!t.closest('[data-pane=\"sidebar\"], [class*=\"_sidebarCol\"]')) return;\n var entry = t.closest('[role=\"treeitem\"], [data-dsh-part=\"sidebar-entry\"]');\n if (!entry) return;\n lastEntryTapAt = Date.now();\n } catch (err) {}\n }, { capture: true, passive: true });\n\n var protoClick = HTMLButtonElement.prototype.click;\n HTMLButtonElement.prototype.click = function () {\n try {\n var isSidebarToggle =\n this.matches('[data-dsh-responsive-part=\"sidebar-toggle\"]') ||\n /\u6536\u8D77\u4FA7\u8FB9\u680F|Collapse sidebar|Open sidebar/i.test(this.getAttribute('aria-label') || '');\n if (isSidebarToggle && Date.now() - lastEntryTapAt < 900) {\n return; // \u541E\u6389\u7D27\u968F\u6761\u76EE\u4EFB\u610F\u90E8\u4F4D\u70B9\u51FB\u4E4B\u540E\u7684\u7A0B\u5E8F\u5316\u6536\u8D77\n }\n } catch (err) {}\n return protoClick.apply(this, arguments);\n };\n }\n\n function initDraggableNav() {\n var logoRow = document.querySelector('[data-pane=\"sidebar\"] [class*=\"_logoRow\"], [class*=\"_sidebarCol\"] [class*=\"_logoRow\"]');\n if (!logoRow || logoRow.__dsh_drag_init__) return;\n logoRow.__dsh_drag_init__ = true;\n\n var savedTop = localStorage.getItem('dsh_mobile_nav_top');\n if (savedTop && !isNaN(Number(savedTop))) {\n var topVal = Math.max(10, Math.min(window.innerHeight - 60, Number(savedTop)));\n logoRow.style.setProperty('top', topVal + 'px', 'important');\n }\n\n var startY = 0;\n var initialTop = 0;\n var isDragging = false;\n var hasMoved = false;\n\n function onTouchStart(e) {\n var sidebar = document.querySelector('[data-pane=\"sidebar\"], [class*=\"_sidebarCol\"]');\n if (sidebar && !sidebar.querySelector('[class*=\"_collapsed\"]')) return;\n\n var touch = e.touches ? e.touches[0] : e;\n startY = touch.clientY;\n var rect = logoRow.getBoundingClientRect();\n initialTop = rect.top;\n isDragging = true;\n hasMoved = false;\n }\n\n function onTouchMove(e) {\n if (!isDragging) return;\n var touch = e.touches ? e.touches[0] : e;\n var deltaY = touch.clientY - startY;\n\n if (!hasMoved && Math.abs(deltaY) > 5) {\n hasMoved = true;\n }\n\n if (hasMoved) {\n if (e.cancelable) e.preventDefault();\n var newTop = initialTop + deltaY;\n var minTop = 10;\n var maxTop = window.innerHeight - 56;\n newTop = Math.max(minTop, Math.min(maxTop, newTop));\n logoRow.style.setProperty('top', newTop + 'px', 'important');\n }\n }\n\n function onTouchEnd(e) {\n if (!isDragging) return;\n isDragging = false;\n if (hasMoved) {\n e.preventDefault();\n e.stopPropagation();\n var currentRect = logoRow.getBoundingClientRect();\n try {\n localStorage.setItem('dsh_mobile_nav_top', String(Math.round(currentRect.top)));\n } catch (err) {}\n }\n }\n\n logoRow.addEventListener('touchstart', onTouchStart, { passive: true });\n window.addEventListener('touchmove', onTouchMove, { passive: false });\n window.addEventListener('touchend', onTouchEnd, { capture: true });\n\n logoRow.addEventListener('mousedown', onTouchStart);\n window.addEventListener('mousemove', onTouchMove);\n window.addEventListener('mouseup', onTouchEnd, { capture: true });\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initDraggableNav);\n } else {\n initDraggableNav();\n }\n setInterval(initDraggableNav, 800);\n})();\n";
|
|
55
55
|
/**
|
|
56
56
|
* 注入到 index.html 的移动端抽屉「点外部收起」脚本
|
|
57
57
|
*
|
|
@@ -63,7 +63,7 @@ export declare const DRAGGABLE_NAV_SNIPPET = "\n(function() {\n if (typeof wind
|
|
|
63
63
|
* 后缀稳定),不依赖 web-ui 注入的 data-pane / data-dsh-frame 属性,因此装/不装 web-ui
|
|
64
64
|
* 两种环境行为一致。折叠状态沿用官方写入的 data-sidebar-collapsed 属性。
|
|
65
65
|
*/
|
|
66
|
-
export declare const MOBILE_DISMISS_SNIPPET = "\n(function() {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n var frameSelector = '[class*=\"_frame\"]';\n var sidebarSelector = '[class*=\"_sidebarCol\"]';\n\n function webUiOwnsDrawer() {\n return !!document.querySelector('style[data-dsh-compat=\"responsive\"]');\n }\n\n function findToggle(frame) {\n return frame.querySelector('[class*=\"_toggle\"]') ||\n Array.prototype.filter.call(frame.querySelectorAll('button'), function (b) {\n return /\u6536\u8D77\u4FA7\u8FB9\u680F|Collapse sidebar|Open sidebar/i.test(b.getAttribute('aria-label') || '');\n })[0] || null;\n }\n\n function install(frame) {\n if (frame.__dshRmDismissInstalled__) return;\n frame.__dshRmDismissInstalled__ = true;\n var raf = 0;\n\n frame.addEventListener('click', function (event) {\n try {\n // web-ui \u53EF\u80FD\u8FD0\u884C\u4E2D\u624D\u6CE8\u5165 responsive style\uFF1A\u6BCF\u6B21\u4E8B\u4EF6\u90FD\u590D\u67E5\uFF0C\u52A8\u6001\u8BA9\u4F4D\n if (webUiOwnsDrawer()) return;\n var target = event.target;\n if (!target || !(target instanceof Element)) return;\n if (typeof window.matchMedia !== 'function' || !window.matchMedia('(max-width: 900px)').matches) return;\n var sidebar = frame.querySelector(sidebarSelector);\n var toggle = findToggle(frame);\n if (!sidebar || !toggle) return;\n\n // \u62BD\u5C49\u5C55\u5F00\u65F6\u70B9\u51FB\u6B63\u6587\uFF08sidebar \u5916\uFF09\u2192 \u89E6\u53D1\u5B98\u65B9\u6536\u8D77\u6309\u94AE\uFF0C\u5E76\u62E6\u622A\u88AB\u541E\u6389\u7684\u70B9\u51FB\uFF1B\n // \u627E\u4E0D\u5230\u6536\u8D77\u6309\u94AE\u65F6\u4E0A\u9762\u5DF2 return\uFF0C\u7EDD\u4E0D\u8BEF\u62E6\u6B63\u6587\u4EA4\u4E92\n if (!frame.hasAttribute('data-sidebar-collapsed') && !sidebar.contains(target)) {\n event.preventDefault();\n event.stopPropagation();\n toggle.click();\n return;\n }\n // \u70B9\u51FB\u4FA7\u8FB9\u680F\u6761\u76EE\uFF08\u9009\u4E2D\u540E\u56DE\u4E3B\u533A\uFF09\u2192 \u4E0B\u4E00\u5E27\u7A0B\u5E8F\u5316\u6536\u8D77\u3002\n // \u65E2\u6709\u9632\u8BEF\u6536\u8D77\u5B88\u536B\uFF08dsh-draggable-nav \u5305\u88C5 HTMLButtonElement.prototype.click\n // + 900ms \u7A97\u53E3\uFF09\u4F1A\u62E6\u622A\u300C\u70B9\u6761\u76EE\
|
|
66
|
+
export declare const MOBILE_DISMISS_SNIPPET = "\n(function() {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n var frameSelector = '[class*=\"_frame\"]';\n var sidebarSelector = '[class*=\"_sidebarCol\"]';\n\n function webUiOwnsDrawer() {\n return !!document.querySelector('style[data-dsh-compat=\"responsive\"]');\n }\n\n function findToggle(frame) {\n return frame.querySelector('[class*=\"_toggle\"]') ||\n Array.prototype.filter.call(frame.querySelectorAll('button'), function (b) {\n return /\u6536\u8D77\u4FA7\u8FB9\u680F|Collapse sidebar|Open sidebar/i.test(b.getAttribute('aria-label') || '');\n })[0] || null;\n }\n\n function install(frame) {\n if (frame.__dshRmDismissInstalled__) return;\n frame.__dshRmDismissInstalled__ = true;\n var raf = 0;\n\n frame.addEventListener('click', function (event) {\n try {\n // web-ui \u53EF\u80FD\u8FD0\u884C\u4E2D\u624D\u6CE8\u5165 responsive style\uFF1A\u6BCF\u6B21\u4E8B\u4EF6\u90FD\u590D\u67E5\uFF0C\u52A8\u6001\u8BA9\u4F4D\n if (webUiOwnsDrawer()) return;\n var target = event.target;\n if (!target || !(target instanceof Element)) return;\n if (typeof window.matchMedia !== 'function' || !window.matchMedia('(max-width: 900px)').matches) return;\n var sidebar = frame.querySelector(sidebarSelector);\n var toggle = findToggle(frame);\n if (!sidebar || !toggle) return;\n\n // \u62BD\u5C49\u5C55\u5F00\u65F6\u70B9\u51FB\u6B63\u6587\uFF08sidebar \u5916\uFF09\u2192 \u89E6\u53D1\u5B98\u65B9\u6536\u8D77\u6309\u94AE\uFF0C\u5E76\u62E6\u622A\u88AB\u541E\u6389\u7684\u70B9\u51FB\uFF1B\n // \u627E\u4E0D\u5230\u6536\u8D77\u6309\u94AE\u65F6\u4E0A\u9762\u5DF2 return\uFF0C\u7EDD\u4E0D\u8BEF\u62E6\u6B63\u6587\u4EA4\u4E92\n if (!frame.hasAttribute('data-sidebar-collapsed') && !sidebar.contains(target)) {\n event.preventDefault();\n event.stopPropagation();\n toggle.click();\n return;\n }\n // \u70B9\u51FB\u4FA7\u8FB9\u680F\u6761\u76EE\uFF08\u9009\u4E2D\u540E\u56DE\u4E3B\u533A\uFF09\u2192 \u4E0B\u4E00\u5E27\u7A0B\u5E8F\u5316\u6536\u8D77\u3002\n // \u65E2\u6709\u9632\u8BEF\u6536\u8D77\u5B88\u536B\uFF08dsh-draggable-nav \u5305\u88C5 HTMLButtonElement.prototype.click\n // + 900ms \u7A97\u53E3\uFF09\u4F1A\u62E6\u622A\u300C\u70B9\u6761\u76EE\u4EFB\u610F\u90E8\u4F4D\uFF08\u542B\u9879\u76EE\u540D\u79F0\u4E3B\u4F53\uFF09\u300D\u540E\u7684\u8BEF\u6536\u8D77\uFF0C\n // \u4FDD\u8BC1\u9009\u4E2D\u9AD8\u4EAE\u540E\u6D6E\u73B0\u7684\u5C55\u5F00/\u6536\u8D77\u7BAD\u5934\u4E0E\u65B0\u589E/\u66F4\u591A\u64CD\u4F5C\u56FE\u6807\u53EF\u64CD\u4F5C\uFF0C\u884C\u4E3A\u4E0E web-ui \u4E00\u81F4\u3002\n if (target.closest('[class*=\"_toggle\"]')) return;\n if (!target.closest('[role=\"treeitem\"], [data-dsh-part=\"sidebar-entry\"]')) return;\n if (raf !== 0) cancelAnimationFrame(raf);\n raf = requestAnimationFrame(function () {\n raf = 0;\n if (!frame.hasAttribute('data-sidebar-collapsed')) toggle.click();\n });\n } catch (err) {}\n }, true);\n }\n\n function ensure() {\n if (webUiOwnsDrawer()) return;\n var frame = document.querySelector(frameSelector);\n if (frame) install(frame);\n }\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', ensure);\n } else {\n ensure();\n }\n setInterval(ensure, 800);\n})();\n";
|
|
67
67
|
/**
|
|
68
68
|
* 挂载底层 http.Server 门禁劫持与回环上下文虚拟化代理
|
|
69
69
|
*
|
package/lib/bridge/compat.js
CHANGED
|
@@ -113,13 +113,14 @@ export const DRAGGABLE_NAV_SNIPPET = `
|
|
|
113
113
|
* 侧边栏条目(role=treeitem)后,于下一帧程序化点击「收起侧边栏」按钮自动收回抽屉。
|
|
114
114
|
* 该判定无法区分「选中条目回主区」与「点击条目内的次级操作图标」(更多操作 ⋯ /
|
|
115
115
|
* 展开箭头等),导致后者抽屉被误关。
|
|
116
|
-
*
|
|
117
|
-
* HTMLButtonElement.prototype.click
|
|
118
|
-
*
|
|
119
|
-
*
|
|
116
|
+
* 这里记录最近一次对条目内任意部位(项目名称主体 / 次级按钮 / 箭头图标)的触摸时间,
|
|
117
|
+
* 并包装 HTMLButtonElement.prototype.click:短时间窗口内的程序化收起调用直接忽略。
|
|
118
|
+
* 覆盖条目主体是为了让选中高亮后浮现的展开/收起箭头与新增/更多操作图标有足够的
|
|
119
|
+
* 停留操作时间;用户真实点击收起按钮(浏览器合成事件不走 prototype.click)与
|
|
120
|
+
* 点击抽屉外暗处收起的官方行为均不受影响。 */
|
|
120
121
|
if (!window.__dshRmAntiCollapseInstalled__) {
|
|
121
122
|
window.__dshRmAntiCollapseInstalled__ = true;
|
|
122
|
-
var
|
|
123
|
+
var lastEntryTapAt = 0;
|
|
123
124
|
document.addEventListener('pointerdown', function (e) {
|
|
124
125
|
try {
|
|
125
126
|
var t = e.target;
|
|
@@ -127,10 +128,7 @@ export const DRAGGABLE_NAV_SNIPPET = `
|
|
|
127
128
|
if (!t.closest('[data-pane="sidebar"], [class*="_sidebarCol"]')) return;
|
|
128
129
|
var entry = t.closest('[role="treeitem"], [data-dsh-part="sidebar-entry"]');
|
|
129
130
|
if (!entry) return;
|
|
130
|
-
|
|
131
|
-
!!t.closest('button, [role="button"]') ||
|
|
132
|
-
!!t.closest('[class*="_arrow"]');
|
|
133
|
-
if (isSecondaryControl) lastSecondaryTapAt = Date.now();
|
|
131
|
+
lastEntryTapAt = Date.now();
|
|
134
132
|
} catch (err) {}
|
|
135
133
|
}, { capture: true, passive: true });
|
|
136
134
|
|
|
@@ -140,8 +138,8 @@ export const DRAGGABLE_NAV_SNIPPET = `
|
|
|
140
138
|
var isSidebarToggle =
|
|
141
139
|
this.matches('[data-dsh-responsive-part="sidebar-toggle"]') ||
|
|
142
140
|
/收起侧边栏|Collapse sidebar|Open sidebar/i.test(this.getAttribute('aria-label') || '');
|
|
143
|
-
if (isSidebarToggle && Date.now() -
|
|
144
|
-
return; //
|
|
141
|
+
if (isSidebarToggle && Date.now() - lastEntryTapAt < 900) {
|
|
142
|
+
return; // 吞掉紧随条目任意部位点击之后的程序化收起
|
|
145
143
|
}
|
|
146
144
|
} catch (err) {}
|
|
147
145
|
return protoClick.apply(this, arguments);
|
|
@@ -280,7 +278,8 @@ export const MOBILE_DISMISS_SNIPPET = `
|
|
|
280
278
|
}
|
|
281
279
|
// 点击侧边栏条目(选中后回主区)→ 下一帧程序化收起。
|
|
282
280
|
// 既有防误收起守卫(dsh-draggable-nav 包装 HTMLButtonElement.prototype.click
|
|
283
|
-
// + 900ms
|
|
281
|
+
// + 900ms 窗口)会拦截「点条目任意部位(含项目名称主体)」后的误收起,
|
|
282
|
+
// 保证选中高亮后浮现的展开/收起箭头与新增/更多操作图标可操作,行为与 web-ui 一致。
|
|
284
283
|
if (target.closest('[class*="_toggle"]')) return;
|
|
285
284
|
if (!target.closest('[role="treeitem"], [data-dsh-part="sidebar-entry"]')) return;
|
|
286
285
|
if (raf !== 0) cancelAnimationFrame(raf);
|
package/lib/client.js
CHANGED
|
@@ -3464,8 +3464,8 @@ function StylesCard({ lang, showToast }) {
|
|
|
3464
3464
|
}
|
|
3465
3465
|
|
|
3466
3466
|
// src/client/version.js
|
|
3467
|
-
var PLUGIN_VERSION = "v1.4.
|
|
3468
|
-
var BUILD_TIME = "2026-
|
|
3467
|
+
var PLUGIN_VERSION = "v1.4.3";
|
|
3468
|
+
var BUILD_TIME = "2026-09-03 21:12:49";
|
|
3469
3469
|
|
|
3470
3470
|
// src/client/components/MainSection.jsx
|
|
3471
3471
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
@@ -50,8 +50,11 @@ const PRESET_SIDEBAR_CSS = `
|
|
|
50
50
|
/* 1. 最外层三栏布局:在移动端主工作区占满 100% 全宽,消除侧边栏强制占位。
|
|
51
51
|
选择器全部基于官方 CSS Modules 稳定后缀(_frame/_sidebarCol/_centerCol,
|
|
52
52
|
前缀 hash 随机、后缀稳定),不依赖 @linxin666/dsh-web-ui-all 注入的
|
|
53
|
-
data-pane / data-dsh-frame 属性,安装与否均生效。
|
|
54
|
-
|
|
53
|
+
data-pane / data-dsh-frame 属性,安装与否均生效。
|
|
54
|
+
注意:_frame 后缀同样命中「提问卡片」(Mbwy4a_frame 等非三栏布局元素),
|
|
55
|
+
故用 :has([class*="_sidebarCol"]) 把规则精确锁定到真正承载三栏布局的
|
|
56
|
+
外层 frame,避免提问弹窗被强制 100vw 撑满、被遮罩盖住。 */
|
|
57
|
+
[class*="_frame"]:has([class*="_sidebarCol"]) {
|
|
55
58
|
grid-template-columns: 0px minmax(0px, 1fr) 0px !important;
|
|
56
59
|
width: 100vw !important;
|
|
57
60
|
max-width: 100vw !important;
|
|
@@ -59,7 +62,7 @@ const PRESET_SIDEBAR_CSS = `
|
|
|
59
62
|
position: relative !important;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
[class*="_centerCol"] {
|
|
65
|
+
[class*="_frame"]:has([class*="_sidebarCol"]) [class*="_centerCol"] {
|
|
63
66
|
width: 100vw !important;
|
|
64
67
|
max-width: 100vw !important;
|
|
65
68
|
}
|
|
@@ -97,13 +100,15 @@ const PRESET_SIDEBAR_CSS = `
|
|
|
97
100
|
拦截全部点击。压到 899:低于抽屉、仍高于正文(≤100),「点抽屉外暗处
|
|
98
101
|
自动收回」的能力保留。
|
|
99
102
|
- 装了 web-ui 时:它生成 [data-dsh-frame]:not([data-sidebar-collapsed])::after
|
|
100
|
-
(z-index:1050),由下方
|
|
101
|
-
- 未装 web-ui 时:官方无遮罩,由下方 :not([data-sidebar-collapsed]) 规则补齐。
|
|
102
|
-
|
|
103
|
+
(z-index:1050),由下方 :has 锁定布局帧的 ::after 的 !important 统一压到 899。
|
|
104
|
+
- 未装 web-ui 时:官方无遮罩,由下方 :not([data-sidebar-collapsed]) 规则补齐。
|
|
105
|
+
遮罩必须挂在三栏布局帧上(:has([class*="_sidebarCol"])),否则 _frame 后缀
|
|
106
|
+
也会命中提问卡片等内层元素,把全屏黑纱盖到弹窗上面。 */
|
|
107
|
+
[class*="_frame"]:has([class*="_sidebarCol"])::after {
|
|
103
108
|
z-index: 899 !important;
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
[class*="_frame"]:not([data-sidebar-collapsed])::after {
|
|
111
|
+
[class*="_frame"]:has([class*="_sidebarCol"]):not([data-sidebar-collapsed])::after {
|
|
107
112
|
content: "";
|
|
108
113
|
position: fixed;
|
|
109
114
|
inset: 0;
|
|
@@ -566,6 +571,30 @@ const PRESET_MAIN_CSS = `
|
|
|
566
571
|
max-height: 12px !important;
|
|
567
572
|
flex: none !important;
|
|
568
573
|
}
|
|
574
|
+
|
|
575
|
+
/* 6. 提问卡片(Mbwy4a_frame,data-question-key 为官方稳定属性锚点):
|
|
576
|
+
收窄左右外边距(官方 padding: calc(composer-side-clearance + 16px) 偏大),
|
|
577
|
+
选项文案字号跟随正文(正文 12.5px,选项标题 13px、说明 12.5px),
|
|
578
|
+
行高同步收敛,保持卡片整体与对话紧凑排版一致。 */
|
|
579
|
+
[data-question-key] {
|
|
580
|
+
padding-left: 8px !important;
|
|
581
|
+
padding-right: 8px !important;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
[data-question-key] [class*="_optionLabel"] {
|
|
585
|
+
font-size: 13px !important;
|
|
586
|
+
line-height: 20px !important;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
[data-question-key] [class*="_description"] {
|
|
590
|
+
font-size: 12.5px !important;
|
|
591
|
+
line-height: 20px !important;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
[data-question-key] [class*="_title"] {
|
|
595
|
+
font-size: 15px !important;
|
|
596
|
+
line-height: 21px !important;
|
|
597
|
+
}
|
|
569
598
|
`;
|
|
570
599
|
/**
|
|
571
600
|
* 内置官方预设:按界面区域划分的三段预设。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-mobile",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "DeepSeek Harness 远程与移动端安全网关插件:零修改 DSH 底层代码安全开放局域网与 Tailscale 连接 | DeepSeek Harness (DSH) Remote & Mobile Security Guard: safely opens Tailscale/LAN with zero core modifications, QR scan auth, RSA encryption & brute-force defense.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|