dsh-mobile 0.3.10 → 0.3.11
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 +5 -0
- package/README.en.md +7 -7
- package/README.md +7 -7
- package/lib/client.js +104 -5
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +31 -2
- package/lib/index.mjs +91 -5
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-layout.js +8 -0
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
Notable changes to DSH Mobile are recorded here. GitHub Releases remain the source for downloadable packages and complete generated commit notes.
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
## 0.3.11 - 2026-09-07
|
|
7
|
+
|
|
8
|
+
- Sync the browser tab title with the current session on the dedicated layout, matching the stock behavior (thanks @idoall for reporting #45).
|
|
9
|
+
- Allow installed plugins' WebSocket endpoints through the gateway via admin-approved exact paths (e.g. `/sidebar/ws/terminal`), managed in the remote panel behind local-admin trust; built-in DSH paths keep working and everything else stays blocked (thanks @idoall for reporting #47).
|
|
10
|
+
|
|
6
11
|
## 0.3.10 - 2026-09-07
|
|
7
12
|
|
|
8
13
|
- Keep the workspace sidebar open on desktop-sized viewports (≥900px): the dedicated layout docks it as a persistent panel that survives reconnects and no longer auto-closes after selecting a session, and the dimming scrim only covers the narrow overlay drawer and details panel. Narrow screens keep the overlay drawer behavior unchanged (thanks @idoall for reporting #42).
|
package/README.en.md
CHANGED
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
|
|
20
20
|
> DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
|
|
21
21
|
>
|
|
22
|
-
> **0.3.
|
|
22
|
+
> **0.3.11 update**: remote pages follow the current session in the browser tab (#45); third-party plugin WebSockets can be approved by the admin (e.g. terminals, #47). Thanks @idoall for reporting. [Details](CHANGELOG.md).
|
|
23
23
|
>
|
|
24
|
-
> **Upgrade reminder**: Windows DSH Desktop users should update to plugin 0.3.
|
|
24
|
+
> **Upgrade reminder**: Windows DSH Desktop users should update to plugin 0.3.11. Existing 0.3.3-0.3.10 apps and paired devices remain compatible without re-pairing. [Compatibility notes](#compatibility).
|
|
25
25
|
|
|
26
26
|
<p align="center">
|
|
27
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
28
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
29
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.
|
|
27
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.11/dsh-mobile-android-v0.3.11.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
|
|
28
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.11/dsh-mobile-android-v0.3.11.apk"><strong>Download Android app 0.3.11</strong></a><br>
|
|
29
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.11">Release notes and checksums</a></sub>
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
32
|
DSH Mobile is a DeepSeek Harness plugin that lets a mobile browser or the Android app connect over a protected LAN or an optional Tailscale Funnel, cpolar, or self-hosted FRP remote path. Local and remote access keep the same sessions, Workspaces, messages, and tools while using separate switches and paired-device stores without modifying DeepSeek Harness source.
|
|
@@ -198,14 +198,14 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
|
|
|
198
198
|
|
|
199
199
|
| DSH Mobile plugin | Verified DeepSeek Harness version |
|
|
200
200
|
| --- | --- |
|
|
201
|
-
| `0.3.10` | `0.1.3-alpha.1` |
|
|
201
|
+
| `0.3.10`, `0.3.11` | `0.1.3-alpha.1` |
|
|
202
202
|
| `0.3.9` | `0.1.3-alpha.1` |
|
|
203
203
|
| `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
|
|
204
204
|
| `0.3.4`, `0.3.5` | `0.1.2-alpha.2` |
|
|
205
205
|
| `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
|
|
206
206
|
| `0.1.4`, `0.2.x` | `0.1.1-rc.2` |
|
|
207
207
|
|
|
208
|
-
Existing 0.3.3-0.3.
|
|
208
|
+
Existing 0.3.3-0.3.10 apps do not need re-pairing. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
|
|
209
209
|
|
|
210
210
|
## Uninstall
|
|
211
211
|
|
package/README.md
CHANGED
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
|
|
27
27
|
> DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
|
|
28
28
|
>
|
|
29
|
-
> **0.3.
|
|
29
|
+
> **0.3.11 更新**:远程页浏览器标签页跟随当前会话标题(#45);第三方插件 WebSocket 可经管理员批准放行(如终端,#47)。感谢 @idoall 反馈。[详细记录](CHANGELOG.md)。
|
|
30
30
|
>
|
|
31
|
-
> **升级提醒**:Windows DSH Desktop 用户请更新至插件 0.3.
|
|
31
|
+
> **升级提醒**:Windows DSH Desktop 用户请更新至插件 0.3.11;现有 0.3.3-0.3.10 App 可继续使用,无需重新配对。[兼容说明](#兼容性)。
|
|
32
32
|
|
|
33
33
|
<p align="center">
|
|
34
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
35
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
36
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.
|
|
34
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.11/dsh-mobile-android-v0.3.11.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
|
|
35
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.11/dsh-mobile-android-v0.3.11.apk"><strong>下载 Android App 0.3.11</strong></a><br>
|
|
36
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.11">版本说明与校验文件</a></sub>
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
39
|
DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
|
|
@@ -207,14 +207,14 @@ flowchart LR
|
|
|
207
207
|
|
|
208
208
|
| DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
|
|
209
209
|
| --- | --- |
|
|
210
|
-
| `0.3.10` | `0.1.3-alpha.1` |
|
|
210
|
+
| `0.3.10`、`0.3.11` | `0.1.3-alpha.1` |
|
|
211
211
|
| `0.3.9` | `0.1.3-alpha.1` |
|
|
212
212
|
| `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
|
|
213
213
|
| `0.3.4`、`0.3.5` | `0.1.2-alpha.2` |
|
|
214
214
|
| `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
|
|
215
215
|
| `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
|
|
216
216
|
|
|
217
|
-
现有 0.3.3-0.3.
|
|
217
|
+
现有 0.3.3-0.3.10 App 无需重新配对;更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
|
|
218
218
|
|
|
219
219
|
## 卸载
|
|
220
220
|
|
package/lib/client.js
CHANGED
|
@@ -151,7 +151,14 @@ window.__ModuleLoader__.load({
|
|
|
151
151
|
remoteQrReady: "Remote pairing QR code generated. Scan it from “Remote access” in the app.",
|
|
152
152
|
resetCpolarConfirm: "Disable the cpolar remote channel and remove all remote paired devices? Your cpolar account and other tunnels are unchanged.",
|
|
153
153
|
resetTailscaleConfirm: "Sign out of Tailscale on this computer and remove all remote paired devices? Local network configuration is unchanged.",
|
|
154
|
-
requestFailed: "Request failed: {error}"
|
|
154
|
+
requestFailed: "Request failed: {error}",
|
|
155
|
+
wsPathsTitle: "Third-party WebSocket paths",
|
|
156
|
+
wsPathsIntro: "Let installed plugins’ WebSocket endpoints (exact paths such as /sidebar/ws/terminal) work through the gateway. Built-in DSH paths always work; everything else stays blocked.",
|
|
157
|
+
wsPathsPlaceholder: "/sidebar/ws/terminal",
|
|
158
|
+
wsPathsAdd: "Allow path",
|
|
159
|
+
wsPathsRemove: "Remove",
|
|
160
|
+
wsPathsEmpty: "No extra paths allowed.",
|
|
161
|
+
wsPathsInvalid: "Enter an exact path starting with / (no query string)."
|
|
155
162
|
},
|
|
156
163
|
it: {
|
|
157
164
|
mobileAccess: "Accesso mobile",
|
|
@@ -297,7 +304,14 @@ window.__ModuleLoader__.load({
|
|
|
297
304
|
remoteQrReady: "QR di abbinamento remoto generato. Scansionalo da “Accesso remoto” nell’app.",
|
|
298
305
|
resetCpolarConfirm: "Disattivare il canale remoto cpolar e rimuovere tutti i dispositivi remoti? Account cpolar e altri tunnel restano invariati.",
|
|
299
306
|
resetTailscaleConfirm: "Uscire da Tailscale su questo computer e rimuovere tutti i dispositivi remoti? La configurazione della rete locale resta invariata.",
|
|
300
|
-
requestFailed: "Richiesta non riuscita: {error}"
|
|
307
|
+
requestFailed: "Richiesta non riuscita: {error}",
|
|
308
|
+
wsPathsTitle: "Percorsi WebSocket di terze parti",
|
|
309
|
+
wsPathsIntro: "Consenti agli endpoint WebSocket dei plugin installati (percorsi esatti come /sidebar/ws/terminal) di passare dal gateway. I percorsi DSH integrati funzionano sempre; tutto il resto resta bloccato.",
|
|
310
|
+
wsPathsPlaceholder: "/sidebar/ws/terminal",
|
|
311
|
+
wsPathsAdd: "Consenti percorso",
|
|
312
|
+
wsPathsRemove: "Rimuovi",
|
|
313
|
+
wsPathsEmpty: "Nessun percorso aggiuntivo consentito.",
|
|
314
|
+
wsPathsInvalid: "Inserisci un percorso esatto che inizi con / (senza query)."
|
|
301
315
|
},
|
|
302
316
|
zh: {}
|
|
303
317
|
};
|
|
@@ -445,7 +459,14 @@ window.__ModuleLoader__.load({
|
|
|
445
459
|
remoteQrReady: "远程配对二维码已生成。请在 App 的“远程访问”中扫描。",
|
|
446
460
|
resetCpolarConfirm: "关闭 cpolar 远程通道并移除所有远程配对设备?不会修改你的 cpolar 账号或其他隧道。",
|
|
447
461
|
resetTailscaleConfirm: "退出电脑上的 Tailscale 登录并移除所有远程配对设备?局域网配置不会改变。",
|
|
448
|
-
requestFailed: "请求失败:{error}"
|
|
462
|
+
requestFailed: "请求失败:{error}",
|
|
463
|
+
wsPathsTitle: "第三方 WebSocket 路径",
|
|
464
|
+
wsPathsIntro: "允许已装插件的 WebSocket 端点(确切路径,如 /sidebar/ws/terminal)经网关通行。DSH 内置路径始终可用,其余一律拦截。",
|
|
465
|
+
wsPathsPlaceholder: "/sidebar/ws/terminal",
|
|
466
|
+
wsPathsAdd: "允许该路径",
|
|
467
|
+
wsPathsRemove: "移除",
|
|
468
|
+
wsPathsEmpty: "暂无额外允许的路径。",
|
|
469
|
+
wsPathsInvalid: "请输入以 / 开头的确切路径(不带 query)。"
|
|
449
470
|
});
|
|
450
471
|
Object.assign(MOBILE_CONTROL_MESSAGES.en, {
|
|
451
472
|
selfHostedConnections: "Self-hosted connection",
|
|
@@ -2527,8 +2548,85 @@ window.__ModuleLoader__.load({
|
|
|
2527
2548
|
remoteManageRow.append(remoteDevices, remoteReset);
|
|
2528
2549
|
const remoteDevicePanel = element("div", "dsh-mobile-control__devices");
|
|
2529
2550
|
remoteDevicePanel.hidden = true;
|
|
2551
|
+
const wsPathsSection = element("section", "dsh-mobile-control__ws-paths");
|
|
2552
|
+
const wsPathsTitle = element("h3", "dsh-mobile-control__section-title");
|
|
2553
|
+
wsPathsTitle.textContent = t("wsPathsTitle");
|
|
2554
|
+
const wsPathsIntro = element("p", "dsh-mobile-control__intro");
|
|
2555
|
+
wsPathsIntro.textContent = t("wsPathsIntro");
|
|
2556
|
+
const wsPathsList = element("ul", "dsh-mobile-control__ws-paths-list");
|
|
2557
|
+
const wsPathsRow = element("div", "dsh-mobile-control__ws-paths-row");
|
|
2558
|
+
const wsPathsInput = element("input", "dsh-mobile-control__ws-paths-input");
|
|
2559
|
+
wsPathsInput.type = "text";
|
|
2560
|
+
wsPathsInput.placeholder = t("wsPathsPlaceholder");
|
|
2561
|
+
wsPathsInput.setAttribute("aria-label", t("wsPathsTitle"));
|
|
2562
|
+
const wsPathsAdd = element("button", "dsh-mobile-control__secondary");
|
|
2563
|
+
wsPathsAdd.type = "button";
|
|
2564
|
+
wsPathsAdd.textContent = t("wsPathsAdd");
|
|
2565
|
+
const wsPathsStatus = element("p", "dsh-mobile-control__status");
|
|
2566
|
+
wsPathsStatus.hidden = true;
|
|
2567
|
+
wsPathsStatus.setAttribute("aria-live", "polite");
|
|
2568
|
+
wsPathsRow.append(wsPathsInput, wsPathsAdd);
|
|
2569
|
+
wsPathsSection.append(wsPathsTitle, wsPathsIntro, wsPathsList, wsPathsRow, wsPathsStatus);
|
|
2570
|
+
let wsPathsCurrent = [];
|
|
2571
|
+
let wsPathsLoaded = false;
|
|
2572
|
+
const renderWsPaths = (paths) => {
|
|
2573
|
+
wsPathsCurrent = [...paths];
|
|
2574
|
+
wsPathsList.replaceChildren();
|
|
2575
|
+
if (paths.length === 0) {
|
|
2576
|
+
const empty = element("li", "dsh-mobile-control__ws-paths-empty");
|
|
2577
|
+
empty.textContent = t("wsPathsEmpty");
|
|
2578
|
+
wsPathsList.append(empty);
|
|
2579
|
+
}
|
|
2580
|
+
for (const path of paths) {
|
|
2581
|
+
const item = element("li", "dsh-mobile-control__ws-paths-item");
|
|
2582
|
+
const label = element("code");
|
|
2583
|
+
label.textContent = path;
|
|
2584
|
+
const remove = element("button", "dsh-mobile-control__ws-paths-remove");
|
|
2585
|
+
remove.type = "button";
|
|
2586
|
+
remove.textContent = t("wsPathsRemove");
|
|
2587
|
+
remove.setAttribute("aria-label", `${t("wsPathsRemove")}: ${path}`);
|
|
2588
|
+
remove.addEventListener("click", () => {
|
|
2589
|
+
saveWsPaths(wsPathsCurrent.filter((entry) => entry !== path));
|
|
2590
|
+
});
|
|
2591
|
+
item.append(label, remove);
|
|
2592
|
+
wsPathsList.append(item);
|
|
2593
|
+
}
|
|
2594
|
+
};
|
|
2595
|
+
const loadWsPaths = () => {
|
|
2596
|
+
controlRequestJson("/api/mobile-access/remote/websocket-paths").then((data) => {
|
|
2597
|
+
wsPathsLoaded = true;
|
|
2598
|
+
wsPathsStatus.hidden = true;
|
|
2599
|
+
renderWsPaths(Array.isArray(data.paths) ? data.paths.filter((entry) => typeof entry === "string") : []);
|
|
2600
|
+
}, (error) => {
|
|
2601
|
+
wsPathsStatus.hidden = false;
|
|
2602
|
+
wsPathsStatus.textContent = t("requestFailed", { error: String(error) });
|
|
2603
|
+
});
|
|
2604
|
+
};
|
|
2605
|
+
const saveWsPaths = (paths) => {
|
|
2606
|
+
wsPathsStatus.hidden = true;
|
|
2607
|
+
controlRequestJson("/api/mobile-access/remote/websocket-paths", {
|
|
2608
|
+
method: "POST",
|
|
2609
|
+
body: JSON.stringify({ paths })
|
|
2610
|
+
}).then((data) => {
|
|
2611
|
+
wsPathsLoaded = true;
|
|
2612
|
+
renderWsPaths(Array.isArray(data.paths) ? data.paths.filter((entry) => typeof entry === "string") : []);
|
|
2613
|
+
}, (error) => {
|
|
2614
|
+
wsPathsStatus.hidden = false;
|
|
2615
|
+
wsPathsStatus.textContent = t("requestFailed", { error: String(error) });
|
|
2616
|
+
});
|
|
2617
|
+
};
|
|
2618
|
+
wsPathsAdd.addEventListener("click", () => {
|
|
2619
|
+
const value = wsPathsInput.value.trim();
|
|
2620
|
+
if (value === "") {
|
|
2621
|
+
wsPathsStatus.hidden = false;
|
|
2622
|
+
wsPathsStatus.textContent = t("wsPathsInvalid");
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
wsPathsInput.value = "";
|
|
2626
|
+
saveWsPaths([...wsPathsCurrent, value]);
|
|
2627
|
+
});
|
|
2530
2628
|
const remoteWorkspace = element("section", "dsh-mobile-control__remote-workspace");
|
|
2531
|
-
remoteWorkspace.append(providerSetupHeader, remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteActions, remoteQr, remoteManageRow, remoteDevicePanel);
|
|
2629
|
+
remoteWorkspace.append(providerSetupHeader, remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteActions, remoteQr, remoteManageRow, remoteDevicePanel, wsPathsSection);
|
|
2532
2630
|
const diagnosticsView = element("div", "dsh-mobile-control__view is-diagnostics");
|
|
2533
2631
|
diagnosticsView.hidden = true;
|
|
2534
2632
|
const diagnosticsIntro = element("p", "dsh-mobile-control__intro");
|
|
@@ -2669,6 +2767,7 @@ window.__ModuleLoader__.load({
|
|
|
2669
2767
|
remoteTab.addEventListener("click", () => {
|
|
2670
2768
|
selectView("remote");
|
|
2671
2769
|
loadRemote();
|
|
2770
|
+
if (!wsPathsLoaded) loadWsPaths();
|
|
2672
2771
|
});
|
|
2673
2772
|
const setOpen = (open) => {
|
|
2674
2773
|
panel.hidden = !open;
|
|
@@ -5003,7 +5102,7 @@ window.__ModuleLoader__.load({
|
|
|
5003
5102
|
.dsh-mobile-control__actions{display:flex;flex-wrap:nowrap;gap:6px}.dsh-mobile-control__actions button{flex:1 1 0;min-width:0;min-height:40px;padding:8px 4px;border-radius:10px;font:12px/1.2 system-ui;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}
|
|
5004
5103
|
.dsh-mobile-control button:focus-visible,.dsh-mobile-control a:focus-visible,.dsh-mobile-control input:focus-visible,.dsh-mobile-control summary:focus-visible{outline:3px solid rgb(37 99 235 / 28%);outline-offset:2px}
|
|
5005
5104
|
.dsh-mobile-control__trigger{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:8px;width:calc(100% + 4px);height:42px;margin:4px -2px;padding:0 10px 0 8px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font-family:inherit;font-size:14px;line-height:22px;cursor:pointer;overflow:hidden}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger:active,.dsh-mobile-control__trigger[aria-expanded="true"]{background:var(--dsw-alias-interactive-bg-active,#e8ebf0)}.dsh-mobile-control__trigger:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:2px}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;gap:0;border-radius:50%}.dsh-mobile-control__trigger-icon{display:block;flex:none}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
|
|
5006
|
-
.dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}
|
|
5105
|
+
.dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__ws-paths{margin:10px 0 0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__ws-paths-list{margin:0 0 8px;padding:0;list-style:none}.dsh-mobile-control__ws-paths-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px}.dsh-mobile-control__ws-paths-item{display:flex;align-items:center;gap:8px;padding:6px 0}.dsh-mobile-control__ws-paths-item + .dsh-mobile-control__ws-paths-item{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__ws-paths-item code{flex:1 1 0;min-width:0;overflow:hidden;font:11px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__ws-paths-remove{flex:none;min-height:28px;padding:4px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:8px;background:transparent;color:inherit;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__ws-paths-row{display:flex;gap:8px}.dsh-mobile-control__ws-paths-row input{flex:1 1 0;min-width:0;box-sizing:border-box;min-height:40px;padding:8px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:14px/1.4 system-ui}.dsh-mobile-control__ws-paths-row button{flex:none}
|
|
5007
5106
|
@media (max-width:359px){.dsh-mobile-control__provider-choices{grid-template-columns:1fr}.dsh-mobile-control__provider{min-height:68px}}@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}.dsh-mobile-control__diagnostic-summary.is-running .dsh-mobile-control__diagnostic-summary-icon::before,.dsh-mobile-control__diagnostic-checks{animation:none}}
|
|
5008
5107
|
`;
|
|
5009
5108
|
/** Mount the desktop control or mobile feature enhancements. */
|