dsh-notify-me 1.9.0 → 1.9.1
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 +14 -0
- package/README.en.md +3 -3
- package/README.md +3 -3
- package/lib/client.js +94 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to **dsh-notify-me** are documented here.
|
|
4
4
|
|
|
5
|
+
## [1.9.1] — 2026-10-20
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
|
|
9
|
+
- **设置左侧导航行换成品牌铃铛**:DSH 的设置外壳按分区 id 硬编码导航图标,`settings.section` 没有图标字段,所以插件改为面板渲染后打补丁——按本地化标签找到自己那一行的导航按钮,把宿主生成的 `<svg>` 换成品牌线稿(形状与 `docs/brand/icon-outline.svg` 一致),沿用宿主给的 icon class,并用 MutationObserver 跟随面板重渲染与重开。
|
|
10
|
+
- 宿主改结构时补丁静默放弃,显示回默认齿轮,其他功能不受影响。
|
|
11
|
+
|
|
12
|
+
### 变更
|
|
13
|
+
|
|
14
|
+
- README(中英)与 `docs/brand/README.md` 的旧口径「导航行图标换不了」改成实际做法与失效条件;`screenshots.json` 补上 1.8.0 / 1.9.0 的截图并修正已删除的 `.jpg` 路径;徽章 bundle 尺寸更新为 ~161 KiB。
|
|
15
|
+
|
|
16
|
+
### 测试
|
|
17
|
+
|
|
18
|
+
- `npm test` 两套件通过;另用真 bundle + 合成宿主面板(`data-shortcut-modal="settings"`、`button.navCell > svg + span.navLabel`)在无头 Chromium 里验证:三行导航里只有「通知提醒」变成铃铛(`data-dnm-nav="1"`、三条 shape),另外两行保持齿轮,图标 class 未丢。
|
|
5
19
|
## [Unreleased]
|
|
6
20
|
|
|
7
21
|
### 兼容性
|
package/README.en.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
[](https://www.npmjs.com/package/dsh-notify-me)
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](#installation)
|
|
16
|
-
[](lib/client.js)
|
|
17
17
|
[](#compatibility)
|
|
18
18
|
[](https://awesome-dsh-plugin.com)
|
|
19
19
|
|
|
@@ -193,7 +193,7 @@ The last block inside Advanced. The page protocol is detected automatically to t
|
|
|
193
193
|
|
|
194
194
|
</details>
|
|
195
195
|
|
|
196
|
-
> The settings sidebar icon is rendered by the DSH settings shell: it hard-codes icons per section id (account / models / agent-presets / plugins / archived-sessions) and
|
|
196
|
+
> The settings sidebar icon is rendered by the DSH settings shell: it hard-codes icons per section id (account / models / agent-presets / plugins / archived-sessions) and `settings.section` has no icon field. The plugin therefore patches that row after the panel renders: it finds its own entry by the localised label text, swaps the host `<svg>` for the brand bell (keeping the host icon class), and follows re-renders with a MutationObserver; if the host changes its markup the patch quietly gives up and the default gear stays.
|
|
197
197
|
|
|
198
198
|
> Notification permission is required: click once on the page → **Allow** (or address-bar lock → Site settings → Notifications → Allow → reload). On macOS, also allow the browser under System Settings → Notifications.
|
|
199
199
|
|
|
@@ -322,7 +322,7 @@ Verified on the real shell (DSH Desktop 0.2.0-rc.2, three rounds of retesting in
|
|
|
322
322
|
- "Stay quiet for the conversation on screen" is judged by `document.hidden`: a window fully covered by other apps still counts as visible, so waits in the current conversation stay quiet there too.
|
|
323
323
|
- External notification forwarding is subject to browser CORS rules: an endpoint that does not allow cross-origin requests falls back to a "sent but unverifiable" delivery (no-cors) and is reported honestly as such; Discord webhooks do allow cross-origin, so delivery to them is confirmed. HTTP errors are recorded as failures and never blindly retried. Forwarding runs only after the local alert has decided to fire, so anything the rules silence is never sent out.
|
|
324
324
|
|
|
325
|
-
- **The settings sidebar
|
|
325
|
+
- **The settings sidebar glyph relies on a DOM patch**: the shell hard-codes icons per section id and `settings.section` exposes no icon field, so the plugin can only swap the `<svg>` in its own row after the panel renders. It depends on the current panel structure (`data-shortcut-modal="settings"` plus a label `<span>` inside each nav button); if DSH changes that markup the patch silently stops working and the default gear shows instead — nothing else is affected.
|
|
326
326
|
|
|
327
327
|
## Development
|
|
328
328
|
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
[](https://www.npmjs.com/package/dsh-notify-me)
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](#安装)
|
|
16
|
-
[](lib/client.js)
|
|
17
17
|
[](#兼容性)
|
|
18
18
|
[](https://awesome-dsh-plugin.com)
|
|
19
19
|
|
|
@@ -189,7 +189,7 @@ Windows 的系统通知横幅固定画在主屏上,系统没有设置项、浏
|
|
|
189
189
|
|
|
190
190
|
</details>
|
|
191
191
|
|
|
192
|
-
> 左侧导航行的图标由 DSH 设置外壳统一渲染:外壳按分区 id 硬编码(只认 account / models / agent-presets / plugins / archived-sessions),其他分区一律给默认齿轮,`settings.section`
|
|
192
|
+
> 左侧导航行的图标由 DSH 设置外壳统一渲染:外壳按分区 id 硬编码(只认 account / models / agent-presets / plugins / archived-sessions),其他分区一律给默认齿轮,`settings.section` 也没有图标字段。插件的做法是在设置面板渲染后替换那一行:按本地化标签文本找到自己的入口,把宿主的 `<svg>` 换成品牌铃铛(保留宿主给的 icon class),并用 MutationObserver 跟随重渲染;宿主改结构时会自动放弃、回落到齿轮。
|
|
193
193
|
|
|
194
194
|
> 需要浏览器通知权限:页面上点一下 → 允许;或地址栏锁 → 站点设置 → 通知 → 允许 → 刷新。macOS 还要在 系统设置 → 通知 里允许该浏览器。
|
|
195
195
|
|
|
@@ -318,7 +318,7 @@ DSH Desktop 是一层 Electron 壳,页面跑在 `dsh-app://app` 下:DOM 的
|
|
|
318
318
|
- 「当前对话不弹通知」按 `document.hidden` 判定:窗口被别的应用完全盖住时仍算「页面可见」,此时当前对话的等待照样静默。
|
|
319
319
|
- 外部通知转发受浏览器跨域(CORS)限制:端点不放行时自动降级为「送出但不可确认」(no-cors),如实标为「已送出不可确认」;Discord Webhook 官方放行跨域,可直接确认送达。HTTP 错误如实记失败、不重试。转发在本地提醒决定要发之后才触发,所以被「当前对话不弹通知」等规则静音的提醒也不会外发。
|
|
320
320
|
|
|
321
|
-
-
|
|
321
|
+
- **设置左侧导航行图标靠 DOM 补丁**:外壳按分区 id 硬编码图标且 `settings.section` 没有图标字段,插件只能在面板渲染后把那一行的 `<svg>` 换成铃铛。命中依赖宿主当前的面板结构(`data-shortcut-modal="settings"` + 导航按钮里的标签 `<span>`);如果 DSH 改了这套结构,补丁会静默失效、显示回默认齿轮,其他功能不受影响。
|
|
322
322
|
|
|
323
323
|
## 开发自检
|
|
324
324
|
|
package/lib/client.js
CHANGED
|
@@ -1937,7 +1937,7 @@
|
|
|
1937
1937
|
});
|
|
1938
1938
|
} catch (e) {}
|
|
1939
1939
|
// keep in sync with package.json "version" on every release
|
|
1940
|
-
api.version = "1.9.
|
|
1940
|
+
api.version = "1.9.1";
|
|
1941
1941
|
api.setConfig = function (patch) { return setConfigLocal(patch); };
|
|
1942
1942
|
api.resetConfig = function () {
|
|
1943
1943
|
try {
|
|
@@ -2311,6 +2311,94 @@
|
|
|
2311
2311
|
offHint: "Reminders are off: enable them first, then test.",
|
|
2312
2312
|
versionLine: "Plugin version: dsh-notify-me v"
|
|
2313
2313
|
};
|
|
2314
|
+
// ─────────────────── sidebar row glyph ───────────────────────────
|
|
2315
|
+
// The settings shell picks the nav glyph from a table keyed by section id
|
|
2316
|
+
// (account / models / agent-presets / plugins / archived-sessions) and hands
|
|
2317
|
+
// every other section the settings gear; settings.section carries no icon
|
|
2318
|
+
// field, so there is no supported way to give our row the bell. Patch the
|
|
2319
|
+
// rendered cell instead: find the nav button whose label is ours and swap
|
|
2320
|
+
// its <svg> for the brand bell. The panel is portaled fresh on every open,
|
|
2321
|
+
// so this re-applies itself; if a host updates its markup the label lookup
|
|
2322
|
+
// simply finds nothing and the gear stays.
|
|
2323
|
+
function bellNavSvg() {
|
|
2324
|
+
var NS = "http://www.w3.org/2000/svg";
|
|
2325
|
+
var svg = document.createElementNS(NS, "svg");
|
|
2326
|
+
var attrs = {
|
|
2327
|
+
viewBox: "0 0 24 24", width: "16", height: "16", fill: "none",
|
|
2328
|
+
stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round",
|
|
2329
|
+
"stroke-linejoin": "round", "aria-hidden": "true", "data-dnm-nav": "1"
|
|
2330
|
+
};
|
|
2331
|
+
for (var k in attrs) if (Object.prototype.hasOwnProperty.call(attrs, k)) svg.setAttribute(k, attrs[k]);
|
|
2332
|
+
var shapes = [
|
|
2333
|
+
["path", { d: "M12 3.4a5.1 5.1 0 0 0-5.1 5.1v3.1c0 .9-.3 1.7-.9 2.4l-1.1 1.3c-.5.6-.1 1.5.7 1.5h12.8c.8 0 1.2-.9.7-1.5l-1.1-1.3a3.8 3.8 0 0 1-.9-2.4V8.5A5.1 5.1 0 0 0 12 3.4Z" }],
|
|
2334
|
+
["path", { d: "M9.8 19.2a2.4 2.4 0 0 0 4.4 0" }],
|
|
2335
|
+
["circle", { cx: "18.3", cy: "5.3", r: "2.35", fill: "currentColor", stroke: "none" }]
|
|
2336
|
+
];
|
|
2337
|
+
for (var i = 0; i < shapes.length; i++) {
|
|
2338
|
+
var el = document.createElementNS(NS, shapes[i][0]);
|
|
2339
|
+
for (var a in shapes[i][1]) if (Object.prototype.hasOwnProperty.call(shapes[i][1], a)) el.setAttribute(a, shapes[i][1][a]);
|
|
2340
|
+
svg.appendChild(el);
|
|
2341
|
+
}
|
|
2342
|
+
return svg;
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
function installNavBell(labelOf) {
|
|
2346
|
+
if (typeof document === "undefined" || !document.body || typeof MutationObserver !== "function") {
|
|
2347
|
+
return function () {};
|
|
2348
|
+
}
|
|
2349
|
+
var PANEL = '[data-shortcut-modal="settings"]';
|
|
2350
|
+
var observed = null;
|
|
2351
|
+
var watching = null;
|
|
2352
|
+
|
|
2353
|
+
function patchPanel(panel) {
|
|
2354
|
+
try {
|
|
2355
|
+
var label = String(labelOf() || "").trim();
|
|
2356
|
+
if (!label || !panel) return;
|
|
2357
|
+
var cells = panel.querySelectorAll("button");
|
|
2358
|
+
for (var i = 0; i < cells.length; i++) {
|
|
2359
|
+
var cell = cells[i];
|
|
2360
|
+
var spans = cell.querySelectorAll("span");
|
|
2361
|
+
var hit = false;
|
|
2362
|
+
for (var s = 0; s < spans.length; s++) {
|
|
2363
|
+
if (String(spans[s].textContent || "").trim() === label) { hit = true; break; }
|
|
2364
|
+
}
|
|
2365
|
+
if (!hit) continue;
|
|
2366
|
+
var svg = cell.querySelector("svg");
|
|
2367
|
+
if (!svg || svg.getAttribute("data-dnm-nav") === "1") continue;
|
|
2368
|
+
var bell = bellNavSvg();
|
|
2369
|
+
// Keep the shell's own icon class so the box size and color match.
|
|
2370
|
+
var cls = svg.getAttribute("class");
|
|
2371
|
+
if (cls) bell.setAttribute("class", cls);
|
|
2372
|
+
if (svg.parentNode) svg.parentNode.replaceChild(bell, svg);
|
|
2373
|
+
}
|
|
2374
|
+
} catch (e) {}
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
function watchPanel(panel) {
|
|
2378
|
+
if (!panel || panel === observed) return;
|
|
2379
|
+
observed = panel;
|
|
2380
|
+
patchPanel(panel);
|
|
2381
|
+
if (watching) { try { watching.disconnect(); } catch (e) {} }
|
|
2382
|
+
watching = new MutationObserver(function () { patchPanel(observed); });
|
|
2383
|
+
watching.observe(panel, { childList: true, subtree: true });
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
// The panel is portaled onto <body>, so a body-level childList observer is
|
|
2387
|
+
// enough to notice it opening without watching the whole page.
|
|
2388
|
+
var opener = new MutationObserver(function () {
|
|
2389
|
+
var panel = document.querySelector(PANEL);
|
|
2390
|
+
if (panel) watchPanel(panel);
|
|
2391
|
+
else if (watching) { try { watching.disconnect(); } catch (e) {} watching = null; observed = null; }
|
|
2392
|
+
});
|
|
2393
|
+
opener.observe(document.body, { childList: true });
|
|
2394
|
+
var existing = document.querySelector(PANEL);
|
|
2395
|
+
if (existing) watchPanel(existing);
|
|
2396
|
+
return function () {
|
|
2397
|
+
try { opener.disconnect(); } catch (e) {}
|
|
2398
|
+
if (watching) { try { watching.disconnect(); } catch (e) {} }
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2314
2402
|
// Small element helper to keep the hand-written page readable.
|
|
2315
2403
|
function h(tag, props) {
|
|
2316
2404
|
var args = [tag, props || null];
|
|
@@ -2932,6 +3020,11 @@
|
|
|
2932
3020
|
return React.createElement(NotifySettingsView, { ctx: ctx, t: t });
|
|
2933
3021
|
});
|
|
2934
3022
|
});
|
|
3023
|
+
// Same page, different layer: give the sidebar row the bell instead of
|
|
3024
|
+
// the gear the shell falls back to for unknown section ids.
|
|
3025
|
+
ctx.effect(function () {
|
|
3026
|
+
return installNavBell(function () { return t("nav"); });
|
|
3027
|
+
}, "dsh-notify-me: sidebar glyph");
|
|
2935
3028
|
}
|
|
2936
3029
|
} catch (e) {
|
|
2937
3030
|
try { console.error("[dsh-notify-me] settings page unavailable", e); } catch (e2) {}
|
package/package.json
CHANGED