dsh-remote-web 0.7.6-beta.8 → 0.7.6
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/lib/client.js +102 -10
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -98,7 +98,7 @@ window.__ModuleLoader__.load({
|
|
|
98
98
|
// 绝不写 :root / body —— 否则会污染整个 GUI。JS 解析出主题后往根节点写
|
|
99
99
|
// data-dru-theme="dark|light",下面按属性切换;末一条 `:not([data-dru-theme])`
|
|
100
100
|
// 是 JS 尚未执行时的纯 CSS 兜底(一旦 JS 写过属性就不再参与,不会打架)。
|
|
101
|
-
".dru-settings-section,.dru-popup,.dru-nav-remote{",
|
|
101
|
+
".dru-settings-section,.dru-popup,.dru-nav-remote,.dru-standalone-card{",
|
|
102
102
|
" color-scheme:light;",
|
|
103
103
|
" --dru-surface:#f6f8fa;", // 卡片底
|
|
104
104
|
" --dru-surface-2:#ffffff;", // 抬升面(输入框/行/弹窗卡)
|
|
@@ -149,10 +149,11 @@ window.__ModuleLoader__.load({
|
|
|
149
149
|
// 深色:JS 写的 data-dru-theme 优先;宿主属性作 JS 未执行时的兜底。
|
|
150
150
|
// 取值跟着宿主的深色基色走(body 实测 #151517 / 层 1 #232324 / 层 2 #2c2c2e / 层 3 #353638),
|
|
151
151
|
// 语义色**在深底上重新取值**,不是沿用亮色值(亮色的 #1a7f37 / #cf222e 在深底对比度不足)。
|
|
152
|
-
".dru-settings-section[data-dru-theme=\"dark\"],.dru-popup[data-dru-theme=\"dark\"],.dru-nav-remote[data-dru-theme=\"dark\"],",
|
|
152
|
+
".dru-settings-section[data-dru-theme=\"dark\"],.dru-popup[data-dru-theme=\"dark\"],.dru-nav-remote[data-dru-theme=\"dark\"],.dru-standalone-card[data-dru-theme=\"dark\"],",
|
|
153
153
|
"body[data-ds-dark-theme] .dru-settings-section:not([data-dru-theme]),",
|
|
154
154
|
"body[data-ds-dark-theme] .dru-popup:not([data-dru-theme]),",
|
|
155
|
-
"body[data-ds-dark-theme] .dru-nav-remote:not([data-dru-theme])
|
|
155
|
+
"body[data-ds-dark-theme] .dru-nav-remote:not([data-dru-theme]),",
|
|
156
|
+
"body[data-ds-dark-theme] .dru-standalone-card:not([data-dru-theme]){",
|
|
156
157
|
" color-scheme:dark;",
|
|
157
158
|
" --dru-surface:#232324;",
|
|
158
159
|
" --dru-surface-2:#2c2c2e;",
|
|
@@ -202,6 +203,15 @@ window.__ModuleLoader__.load({
|
|
|
202
203
|
"}",
|
|
203
204
|
// 设置页栏目容器(nav 选中后渲染在 settings.section 内容区)
|
|
204
205
|
".dru-settings-section{max-width:720px;display:flex;flex-direction:column;gap:14px;padding-top:2px;color:var(--dru-fg)}",
|
|
206
|
+
// 📱 独立「远程访问」弹层(2026-10-25):入口点击不再去"猜"官方设置面板的 DOM,
|
|
207
|
+
// 直接弹我们自己的一份设置页 —— 宿主改版也影响不到它。
|
|
208
|
+
".dru-standalone-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--dru-overlay)}",
|
|
209
|
+
".dru-standalone-card{width:min(760px,100%);max-height:88vh;overflow:auto;box-sizing:border-box;padding:18px 20px 22px;border:1px solid var(--dru-border);border-radius:14px;background:var(--dru-surface-2);color:var(--dru-fg);box-shadow:0 18px 60px var(--dru-shadow)}",
|
|
210
|
+
".dru-standalone-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:8px}",
|
|
211
|
+
".dru-standalone-title{font-size:16px;font-weight:700}",
|
|
212
|
+
".dru-standalone-close{appearance:none;border:1px solid var(--dru-border-ctl);background:var(--dru-surface-2);color:var(--dru-fg-muted);width:30px;height:30px;border-radius:8px;font-size:18px;line-height:1;cursor:pointer}",
|
|
213
|
+
".dru-standalone-close:hover{background:var(--dru-hover);color:var(--dru-fg)}",
|
|
214
|
+
"@media (max-width:640px){.dru-standalone-overlay{padding:8px}.dru-standalone-card{max-height:94vh;border-radius:12px;padding:14px 14px 18px}}",
|
|
205
215
|
".dru-settings-head{display:flex;align-items:center;gap:10px;padding:6px 2px 2px}",
|
|
206
216
|
".dru-settings-icon{font-size:24px;line-height:1;flex:none}",
|
|
207
217
|
// 标题/副标题优先沿用宿主语义令牌(自带深浅两套),取不到再退回本插件令牌
|
|
@@ -1117,6 +1127,61 @@ window.__ModuleLoader__.load({
|
|
|
1117
1127
|
0.2 实测该槽就在侧栏底部、且**当前是空的**)—— 位置、宽度、折叠态全由宿主负责。
|
|
1118
1128
|
所以这里不再注入任何 DOM,直接注册进槽位。id 仍保留 `dru-nav-remote`:
|
|
1119
1129
|
公告徽标 / 首次红点那套按 id 取节点的既有逻辑因此不用改。 */
|
|
1130
|
+
/* 📱 独立「远程访问」弹层(2026-10-25 用户拍板):
|
|
1131
|
+
桌面端点击侧栏入口时,不再去"点官方设置/找栏目"(宿主一改版就点错或没反应,
|
|
1132
|
+
实测会点到左上角「更多→浏览插件」),而是弹出我们自己的一份设置页。
|
|
1133
|
+
「设置 → 远程访问」栏目保留,正常从官方设置页进入的用户仍走那条路。
|
|
1134
|
+
实现上用 shell.overlay 槽(宿主最上层,不受侧栏容器裁剪),组件常驻、按事件开关。 */
|
|
1135
|
+
var standaloneOverlayMounted = false;
|
|
1136
|
+
function openRemoteStandalonePanel() {
|
|
1137
|
+
try { window.dispatchEvent(new CustomEvent("dsh-remote:open-standalone")); } catch (e) { /* 忽略 */ }
|
|
1138
|
+
}
|
|
1139
|
+
function RemoteStandaloneOverlay() {
|
|
1140
|
+
var st = useState(false);
|
|
1141
|
+
var open = st[0];
|
|
1142
|
+
var setOpen = st[1];
|
|
1143
|
+
useEffect(function () {
|
|
1144
|
+
standaloneOverlayMounted = true;
|
|
1145
|
+
function onOpen() { try { setOpen(true); } catch (e) { /* 忽略 */ } }
|
|
1146
|
+
function onKey(e) {
|
|
1147
|
+
if (!e) return;
|
|
1148
|
+
if (e.key === "Escape" || e.keyCode === 27) { try { setOpen(false); } catch (e2) { /* 忽略 */ } }
|
|
1149
|
+
}
|
|
1150
|
+
try {
|
|
1151
|
+
window.addEventListener("dsh-remote:open-standalone", onOpen);
|
|
1152
|
+
window.addEventListener("keydown", onKey);
|
|
1153
|
+
} catch (e3) { /* 忽略 */ }
|
|
1154
|
+
return function () {
|
|
1155
|
+
standaloneOverlayMounted = false;
|
|
1156
|
+
try {
|
|
1157
|
+
window.removeEventListener("dsh-remote:open-standalone", onOpen);
|
|
1158
|
+
window.removeEventListener("keydown", onKey);
|
|
1159
|
+
} catch (e4) { /* 忽略 */ }
|
|
1160
|
+
};
|
|
1161
|
+
}, []);
|
|
1162
|
+
if (!open) return null;
|
|
1163
|
+
var dark = false;
|
|
1164
|
+
try { dark = !!document.body && document.body.hasAttribute("data-ds-dark-theme"); } catch (e5) { /* 忽略 */ }
|
|
1165
|
+
return h("div", {
|
|
1166
|
+
className: "dru-standalone-overlay",
|
|
1167
|
+
role: "dialog",
|
|
1168
|
+
"aria-modal": "true",
|
|
1169
|
+
"aria-label": "远程访问",
|
|
1170
|
+
onClick: function (e) { if (e && e.target === e.currentTarget) setOpen(false); }
|
|
1171
|
+
},
|
|
1172
|
+
h("div", { className: "dru-standalone-card", "data-dru-theme": dark ? "dark" : "light" },
|
|
1173
|
+
h("div", { className: "dru-standalone-head" },
|
|
1174
|
+
h("b", { className: "dru-standalone-title" }, "📱 远程访问"),
|
|
1175
|
+
h("button", {
|
|
1176
|
+
type: "button",
|
|
1177
|
+
className: "dru-standalone-close",
|
|
1178
|
+
"aria-label": "关闭",
|
|
1179
|
+
onClick: function () { setOpen(false); }
|
|
1180
|
+
}, "×")),
|
|
1181
|
+
h(RemoteControlSection, { standalone: true })
|
|
1182
|
+
));
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1120
1185
|
function RemoteNavEntry(props) {
|
|
1121
1186
|
var wide = !(props && props.wide === false);
|
|
1122
1187
|
var seenArr = useState(false);
|
|
@@ -1133,12 +1198,15 @@ window.__ModuleLoader__.load({
|
|
|
1133
1198
|
try { e.preventDefault(); } catch (err) { /* 忽略 */ }
|
|
1134
1199
|
setClicked(true);
|
|
1135
1200
|
dotMarkSeen(); // 用过入口 = 已了解位置 → 收起首次红点
|
|
1136
|
-
// 2026-10-25
|
|
1137
|
-
//
|
|
1138
|
-
// 打开链内部自带兜底:侧栏候选 → 官方快捷键 → 更多/账号菜单 → 栏目点击。
|
|
1201
|
+
// 2026-10-25(用户拍板):优先弹**我们自己的独立设置页**(不再依赖官方设置面板 DOM);
|
|
1202
|
+
// 只有宿主没有 shell.overlay 槽(极老版本)时才退回旧的"打开官方设置栏目"链路。
|
|
1139
1203
|
try {
|
|
1140
|
-
|
|
1141
|
-
|
|
1204
|
+
openRemoteStandalonePanel();
|
|
1205
|
+
setTimeout(function () {
|
|
1206
|
+
if (!standaloneOverlayMounted) {
|
|
1207
|
+
try { openRemoteSettings(); } catch (e2) { /* 忽略 */ }
|
|
1208
|
+
}
|
|
1209
|
+
}, 150);
|
|
1142
1210
|
} catch (errOpen) { /* 绝不因打开失败抛到宿主 */ }
|
|
1143
1211
|
}
|
|
1144
1212
|
}, [
|
|
@@ -1198,6 +1266,7 @@ window.__ModuleLoader__.load({
|
|
|
1198
1266
|
* 之所以是模块级的:拉取发生在 apply() 里(组件还没挂载),而消费方有两个
|
|
1199
1267
|
* (设置面板的卡片 / shell.overlay 上的弹窗),模块级 store 才能让两边看到同一份数据。
|
|
1200
1268
|
*/
|
|
1269
|
+
var annRetryCount = 0; // 公告首次拉取瞬态失败的有界重试计数(成功即清零)
|
|
1201
1270
|
var annState = {
|
|
1202
1271
|
ok: false, // 拉取成功且结构是我们认识的那一种(老服务端 404 / 结构不符 → 一直是 false)
|
|
1203
1272
|
bubble: false, // bubble_enabled === true 才置真(字段缺失一律当 false = fail closed)
|
|
@@ -1360,6 +1429,7 @@ window.__ModuleLoader__.load({
|
|
|
1360
1429
|
var norm = annNormalize(b);
|
|
1361
1430
|
if (!norm) { annState.ok = false; annState.bubble = false; annState.items = []; annState.unread = 0; annEmit(); return false; }
|
|
1362
1431
|
annState.ok = true;
|
|
1432
|
+
annRetryCount = 0;
|
|
1363
1433
|
annState.bubble = norm.bubble;
|
|
1364
1434
|
annState.items = norm.items;
|
|
1365
1435
|
annState.unread = norm.unread;
|
|
@@ -1368,13 +1438,24 @@ window.__ModuleLoader__.load({
|
|
|
1368
1438
|
}
|
|
1369
1439
|
annEmit();
|
|
1370
1440
|
return true;
|
|
1371
|
-
}).catch(function () {
|
|
1441
|
+
}).catch(function (err) {
|
|
1372
1442
|
// 404(老服务端)/ 不可达 / 超时:fail closed —— 不显示入口、不弹窗,**绝不抛**
|
|
1373
1443
|
annState.ok = false;
|
|
1374
1444
|
annState.bubble = false;
|
|
1375
1445
|
annState.items = [];
|
|
1376
1446
|
annState.unread = 0;
|
|
1377
1447
|
annEmit();
|
|
1448
|
+
// 2026-10-25(用户反馈「公告板块没了」):dsh 重启后页面常常比插件宿主路由先就绪,
|
|
1449
|
+
// 首次拉取失败一次,整页(sessionStorage 一次性标记)就再也没有公告入口。
|
|
1450
|
+
// 这里只对**瞬态失败**做有界重试(最多 2 次、间隔 1.5s/3s);404 明确是老服务端,不重试。
|
|
1451
|
+
// 注意:这只发生在**失败后**,成功路径仍然严格"每次页面加载只拉一次"。
|
|
1452
|
+
var st = Number(err && (err.status || err.statusCode));
|
|
1453
|
+
if (st !== 404 && annRetryCount < 2) {
|
|
1454
|
+
annRetryCount += 1;
|
|
1455
|
+
try {
|
|
1456
|
+
setTimeout(function () { annFetch({ openPopup: false }); }, 1500 * annRetryCount);
|
|
1457
|
+
} catch (e2) { /* 忽略 */ }
|
|
1458
|
+
}
|
|
1378
1459
|
return false;
|
|
1379
1460
|
});
|
|
1380
1461
|
}
|
|
@@ -5264,8 +5345,12 @@ window.__ModuleLoader__.load({
|
|
|
5264
5345
|
function renderAnnouncementsCard() {
|
|
5265
5346
|
if (!annState.ok || !annState.bubble) return null;
|
|
5266
5347
|
var items = annState.items;
|
|
5267
|
-
if (!items.length) return null;
|
|
5268
5348
|
var unread = annState.unread;
|
|
5349
|
+
// 2026-10-25:列表为空时**保留板块**(显示「暂无公告」)而不是整卡消失 ——
|
|
5350
|
+
// 板块本身是用户确认"公告功能还在"的锚点,静默消失会被当成功能坏了。
|
|
5351
|
+
if (!items.length) {
|
|
5352
|
+
return card("📣 公告", [h("div", { className: "dru-hint" }, "暂无公告")]);
|
|
5353
|
+
}
|
|
5269
5354
|
return card("📣 公告" + (unread > 0 ? "(" + unread + " 条未读)" : ""), [
|
|
5270
5355
|
h("div", { className: "dru-ann-list" }, items.map(function (it) {
|
|
5271
5356
|
return h("button", {
|
|
@@ -6136,6 +6221,13 @@ window.__ModuleLoader__.load({
|
|
|
6136
6221
|
// 公告是锦上添花,**没有任何资格**把门关上 —— 任何异常都只是"这次没有弹窗"。
|
|
6137
6222
|
}
|
|
6138
6223
|
|
|
6224
|
+
// 📱 独立「远程访问」弹层(入口点击用;见 RemoteStandaloneOverlay 注释)
|
|
6225
|
+
try {
|
|
6226
|
+
ctx.slots.inject("shell.overlay", function () {
|
|
6227
|
+
return ctx.slots.register({ name: "shell.overlay", id: "dsh-remote-standalone", order: 95 }, RemoteStandaloneOverlay);
|
|
6228
|
+
});
|
|
6229
|
+
} catch (eStand) { /* 老宿主没有 shell.overlay:入口会在 150ms 后回退到官方设置栏目链路 */ }
|
|
6230
|
+
|
|
6139
6231
|
// 📣 公告:每次页面加载**只拉一次**(sessionStorage 一次性标记,见 annPullOnce)。
|
|
6140
6232
|
// 放在 apply() 里是刻意的:apply 跑在 app mount **之前**,所以这里**绝不能碰产品 DOM**
|
|
6141
6233
|
// (那时还没有),只做数据拉取;UI 全部交给上面那个槽位与面板卡片。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-web",
|
|
3
|
-
"version": "0.7.6
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "公网远程控制 DeepSeek Harness(dsh web):安装即得专属加密地址,人在外面也能用手机访问电脑上的 dsh——无需同一局域网/WiFi、无需公网 IP 与内网穿透,全程加密;手机端 100% 还原电脑体验(对话/工具/审批/设置)。技术用户可选自建服务,流量走自己的服务器。Remote control DeepSeek Harness (dsh web) from anywhere over the public internet — install, get an encrypted URL, use it from your phone on any network (dual-half cordis plugin: Settings panel + same-origin /dsh-remote routes). (2026-09 由 dsh-remote-ui 更名 / renamed from dsh-remote-ui; dsh-remote 的 dsh web 插件半,不是纯 UI/皮肤插件)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|