dsh-notify-me 1.10.0 → 1.10.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 CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to **dsh-notify-me** are documented here.
4
4
 
5
+ ## [1.10.1] — 2026-10-21
6
+
7
+ ### 变更
8
+
9
+ - **悬浮提示的触发区收窄到标题文字本身**:行标题是 flex 列里的子项,会被 blockify 撑满整列,之前鼠标停在标题右侧的空白处也会弹说明。改用 width:fit-content,实测标题宽 52px、文本列 437px,只有压在字上才弹。
10
+ - **「浮层位置」「音量」改成点标题展开**:这两项以前跟着上开关立刻出现,页面会突然长出一段缩进区。现在标题后面带 ▸ / ▾,点一下才展开,标题上同时显示当前值(如「右下」「50%」)。
11
+ - **提醒停留时间缩到 5 秒档**:普通提醒 5 秒自动收起(浮层「需要你」「回复完成」同档),带「同意 / 拒绝」的审批卡片 12 秒;原来最长的那张一直占屏。
12
+
13
+ ### 测试
14
+
15
+ - 冒烟:角落下拉折叠后才出现、展开后默认值正确、改值落盘;带按钮卡片 12 秒自收的定时器断言同步更新。
16
+ - npm test 两套件通过(ALL SMOKE TESTS PASSED / cordis-host-test passed)。
17
+
5
18
  ## [1.10.0] — 2026-10-21
6
19
 
7
20
  ### 新增
package/README.en.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![npm total downloads](https://img.shields.io/npm/dt/dsh-notify-me?style=flat-square&label=total%20downloads&color=1F883D)](https://www.npmjs.com/package/dsh-notify-me)
14
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)
15
15
  [![DSH Web and Desktop](https://img.shields.io/badge/DSH-Web%20%7C%20Desktop-blue?style=flat-square)](#installation)
16
- [![Client bundle size](https://img.shields.io/badge/client-%7E168%20KiB-green?style=flat-square)](lib/client.js)
16
+ [![Client bundle size](https://img.shields.io/badge/client-%7E172%20KiB-green?style=flat-square)](lib/client.js)
17
17
  [![DSH Compatibility](https://img.shields.io/badge/DSH-tested%200.2.1--rc.2-6366f1.svg?style=flat-square)](#compatibility)
18
18
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
19
19
 
@@ -40,14 +40,14 @@ A notification plugin for DSH Web / Desktop, so you can keep full access off wit
40
40
 
41
41
  ![Three overlay cards in the bottom-right corner of the DSH page: question, approval request with Approve / Reject, and reply finished](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-en.png)
42
42
 
43
- *In-page overlay (1.8.0) · the real plugin rendered on a demo page · for when system notifications cannot reach the secondary display; cards appear on whichever display the DSH window is on.* [View full size](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-en.png)
43
+ *In-page overlay · the real plugin rendered on a demo page · for when system notifications cannot reach the secondary display; cards appear on whichever display the DSH window is on.* [View full size](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-en.png)
44
44
 
45
45
  <details>
46
46
  <summary>See the settings interface</summary>
47
47
 
48
48
  ![The Notify me settings page: header, how you get told, when to alert, try it, and the collapsed Advanced block](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/settings-en.png)
49
49
 
50
- The real settings component (v1.10.0 defaults) rendered in a standalone demo shell. The alert channel is a single choice, and row explanations live in a hover tooltip that appears when the pointer rests on a title, which is why only the titles show here.
50
+ The real settings component (v1.10.1 defaults) rendered in a standalone demo shell. The alert channel is a single choice, and row explanations live in a hover tooltip that appears when the pointer rests on a title, which is why only the titles show here.
51
51
  </details>
52
52
 
53
53
  ## Installation
@@ -116,15 +116,15 @@ dsh-notify-me decouples **supervision** from **sitting in front of the screen**:
116
116
 
117
117
  ## Configure it from DSH Settings
118
118
 
119
- Open **Settings → Notify me**. The page runs as how you get told, when to alert, and a try-it block; the knobs you rarely touch fold into **Advanced** at the bottom. Rows show titles only — the explanation pops up next to the pointer once it rests on the title text (hovering a switch does nothing), with a hidden copy kept for screen readers.
119
+ Open **Settings → Notify me**. The page runs as how you get told, when to alert, and a try-it block; the knobs you rarely touch fold into **Advanced** at the bottom. Rows show titles only — the explanation pops up next to the pointer once it rests on the title text (hovering a switch does nothing), with a hidden copy kept for screen readers. Rows marked with ▸ open a sub-item when clicked.
120
120
 
121
121
  ### How you get told
122
122
 
123
123
  - **Enable reminders**: master switch — off means no toasts, no sounds, and the tab title is left alone;
124
124
  - **How you get told (pick one)**: system notifications or the in-page overlay — a single choice, so turning one on turns the other off;
125
125
  - **System notifications** (default): native toasts landing in the Windows / macOS notification center; needs notification permission;
126
- - **In-page overlay**: cards drawn in the page corner, on whichever display the window sits on — system notifications only land on the primary display. No permission needed, and the Desktop shell can Approve / Reject right on the card. Pick one of four corners when it is the chosen channel. See [Secondary displays and the overlay](#secondary-displays-and-the-overlay);
127
- - **Sound / Volume**: master cue switch and a volume slider; what it plays comes from Advanced → Alert sound;
126
+ - **In-page overlay**: cards drawn in the page corner, on whichever display the window sits on — system notifications only land on the primary display. No permission needed, and the Desktop shell can Approve / Reject right on the card. Click the row open to pick one of four corners when it is the chosen channel. See [Secondary displays and the overlay](#secondary-displays-and-the-overlay);
127
+ - **Sound / Volume**: the switch is direct; the slider folds into that row — click the title (▸ turns into ▾) to reveal it. What it plays comes from Advanced → Alert sound;
128
128
  - **Decide approvals from the toast** (on by default): approval toasts carry Approve / Reject that settle the request in place. **Desktop notifications have no buttons** (`dsh-app://` cannot register a Service Worker) — pick the in-page overlay as the channel instead; the page states plainly which channel can carry buttons right now.
129
129
 
130
130
  ### Secondary displays and the overlay
@@ -133,7 +133,7 @@ Windows draws system notification banners on the primary display only. There is
133
133
 
134
134
  The **in-page overlay** skips the notification center and draws the card inside the DSH page instead: wherever the window is, the card is there too.
135
135
 
136
- - **Position** — top right / bottom right / top left / bottom left, default bottom right; changes apply immediately;
136
+ - **Position** — click the In-page overlay row open (▸ turns into ▾), then pick top right / bottom right / top left / bottom left; the row shows the current value. Default bottom right, changes apply immediately;
137
137
  - **No notification permission needed** — it works when permission was never granted, and on the Desktop shell where buttonless toasts are all the OS channel can do;
138
138
  - **Approval cards carry Approve / Reject** — the same decision as Allow once / Reject on the approval card, and they work on the Desktop too (no Service Worker involved). Clicking the card body opens its conversation;
139
139
  - **Lifetime** — "needs you" cards retire after 12s, "reply finished" after 6s, and an approval card with buttons after 18s; a card or its close button retires one earlier. At most 4 cards stack at once;
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![npm total downloads](https://img.shields.io/npm/dt/dsh-notify-me?style=flat-square&label=total%20downloads&color=1F883D)](https://www.npmjs.com/package/dsh-notify-me)
14
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)
15
15
  [![DSH Web and Desktop](https://img.shields.io/badge/DSH-Web%20%7C%20Desktop-blue?style=flat-square)](#安装)
16
- [![Client bundle size](https://img.shields.io/badge/client-%7E168%20KiB-green?style=flat-square)](lib/client.js)
16
+ [![Client bundle size](https://img.shields.io/badge/client-%7E172%20KiB-green?style=flat-square)](lib/client.js)
17
17
  [![DSH Compatibility](https://img.shields.io/badge/DSH-%E5%B7%B2%E9%80%82%E9%85%8D%200.2.1--rc.2-6366f1.svg?style=flat-square)](#兼容性)
18
18
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
19
19
 
@@ -40,14 +40,14 @@ DSH Web / Desktop 的通知插件,让你敢不开完整访问,也不必一
40
40
 
41
41
  ![DSH 页面右下角的三张浮层提醒:提问、审批请求(带「同意 / 拒绝」按钮)、回复完成](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-zh.png)
42
42
 
43
- *页面浮层提醒(1.8.0)· 真实插件在独立演示页里渲染 · 系统通知画不到副屏时用它,卡片落在 DSH 窗口所在的那块屏。* [查看原图](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-zh.png)
43
+ *页面浮层提醒 · 真实插件在独立演示页里渲染 · 系统通知画不到副屏时用它,卡片落在 DSH 窗口所在的那块屏。* [查看原图](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-zh.png)
44
44
 
45
45
  <details>
46
46
  <summary>展开设置界面预览</summary>
47
47
 
48
48
  ![通知提醒设置页:页眉、提醒方式、什么时候提醒、试一试与折叠的高级设置](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/settings-zh.png)
49
49
 
50
- 真实插件设置组件(v1.10.0 默认配置)在独立演示环境里渲染;提醒方式是一组单选,每行的说明在鼠标停在标题文字上时才出现,所以这里只看到标题。
50
+ 真实插件设置组件(v1.10.1 默认配置)在独立演示环境里渲染;提醒方式是一组单选,每行的说明在鼠标停在标题文字上时才出现,所以这里只看到标题。
51
51
  </details>
52
52
 
53
53
  ## 安装
@@ -112,15 +112,15 @@ dsh-notify-me 把「监督」和「守在屏幕前」解耦:只在真的出现
112
112
 
113
113
  ## 在 DSH 设置里改配置
114
114
 
115
- 打开 **设置 → 通知提醒**。页面按「提醒方式 → 什么时候提醒 → 试一试」三段排开,不常改的收进底部「高级设置」,点一下展开。每行只写标题,具体说明在鼠标移上去时弹出的小方框里(触屏或键盘操作时留一份隐藏文本给读屏)。
115
+ 打开 **设置 → 通知提醒**。页面按「提醒方式 → 什么时候提醒 → 试一试」三段排开,不常改的收进底部「高级设置」,点一下展开。每行只写标题,具体说明在鼠标停在标题文字上时弹出的小方框里(只有标题本身触发布局,整行空白处不会弹;触屏或键盘操作时留一份隐藏文本给读屏)。带 ▸ 的行点一下展开子项。
116
116
 
117
117
  ### 提醒方式
118
118
 
119
119
  - **启用提醒** 总开关:关闭后不弹通知、不响提示音,也不改标签页标题;
120
120
  - **提醒方式(二选一)**:系统通知 / 页面浮层,单选,开了这个就不再弹那个;
121
121
  - **系统通知**(默认):进 Windows / macOS 通知中心,需要通知权限;
122
- - **页面浮层**:在 DSH 页面角落画提醒卡片,窗口在哪块屏它就在哪块屏——系统通知只会画在主屏,主屏不看时用它;不需要通知权限,桌面端也能在卡片上直接「同意 / 拒绝」。选中后可选四个角落的位置,见[副屏与浮层提醒](#副屏与浮层提醒);
123
- - **提示音 / 音量**:提示音开关与音量滑块;具体播什么由「高级设置 → 音效来源」决定;
122
+ - **页面浮层**:在 DSH 页面角落画提醒卡片,窗口在哪块屏它就在哪块屏——系统通知只会画在主屏,主屏不看时用它;不需要通知权限,桌面端也能在卡片上直接「同意 / 拒绝」。选中后可在该行点开选四个角落的位置,见[副屏与浮层提醒](#副屏与浮层提醒);
123
+ - **提示音 / 音量**:开关直接切;音量滑块收在该行里,点一下标题(▸ 变成 ▾)展开。具体播什么由「高级设置 → 音效来源」决定;
124
124
  - **审批通知上直接裁决**(默认开):审批通知带「同意 / 拒绝」,点一下即完成裁决,不用切回页面。**桌面端的通知没有按钮**(`dsh-app://` 页面无法注册 Service Worker),需要按钮就打开「页面浮层提醒」,改在浮层上裁决;设置页会如实说明当前哪种渠道能给按钮。
125
125
 
126
126
  ### 副屏与浮层提醒
@@ -129,10 +129,10 @@ Windows 的系统通知横幅固定画在主屏上,系统没有设置项、浏
129
129
 
130
130
  「页面浮层提醒」绕开系统通知中心,直接在 DSH 页面里画一张卡片:窗口在哪块屏,卡片就出现在哪块屏。
131
131
 
132
- - **位置**:设置里选右上 / 右下 / 左上 / 左下,默认右下;改完立刻生效;
132
+ - **位置**:点开「页面浮层提醒」那一行(▸ 变 ▾)再选右上 / 右下 / 左上 / 左下,默认右下,行上直接显示当前值;改完立刻生效;
133
133
  - **不需要通知权限**:通知权限没给、或桌面端弹不出带按钮的通知时,浮层照常工作;
134
134
  - **审批卡片带「同意 / 拒绝」**:与审批卡片的「允许一次 / 拒绝」等价,桌面端也能用(不依赖 Service Worker);点卡片正文则切回对应对话;
135
- - **停留时间**:「需要你」12 秒,「回复完成」6 秒,带按钮的审批卡片 18 秒,都会自动收起;也可以点卡片或右上角叉提前关掉。最多同时叠 4 张;
135
+ - **停留时间**:普通提醒 5 秒自动收起,带「同意 / 拒绝」的审批卡片 12 秒,系统通知同档(普通 5 秒、带按钮 12 秒);也可以点卡片或右上角叉提前关掉。最多同时叠 4 张;
136
136
  - **与系统通知的关系**:二选一。以前两个开关可以同开,结果同一条提醒弹两遍、还互相挡住,1.10.0 起改成单选。老配置里开着浮层的,升级后自动落到浮层。
137
137
 
138
138
  浮层只知道窗口在哪块屏,不知道你人在看哪块屏。窗口留在主屏、人却盯着副屏时,它同样看不见。
package/lib/client.js CHANGED
@@ -782,7 +782,7 @@
782
782
  }
783
783
  // Longer for an actionable toast so there is time to click it, shorter
784
784
  // for a plain one: a notification that just sits there is noise.
785
- setTimeout(function () { n.close(); }, quick ? 20000 : 10000);
785
+ setTimeout(function () { n.close(); }, quick ? 12000 : 5000);
786
786
  } catch (e) {}
787
787
  }
788
788
 
@@ -801,7 +801,7 @@
801
801
  // How long a card stays. "needs you" deserves a longer look than a finished
802
802
  // reply; actionable cards get the longest window but still fade, because a
803
803
  // card that never leaves is just clutter once the user has moved on.
804
- var OVERLAY_TTL = { attention: 12000, done: 6000, action: 18000 };
804
+ var OVERLAY_TTL = { attention: 5000, done: 5000, action: 12000 };
805
805
  var OVERLAY_CORNERS = ["bottom-right", "bottom-left", "top-right", "top-left"];
806
806
  var OVERLAY_CSS = "" +
807
807
  ".dnm-ov-layer{position:fixed;z-index:2147483000;display:flex;flex-direction:column;gap:10px;pointer-events:none;max-width:calc(100vw - 24px)}" +
@@ -1964,7 +1964,7 @@
1964
1964
  });
1965
1965
  } catch (e) {}
1966
1966
  // keep in sync with package.json "version" on every release
1967
- api.version = "1.10.0";
1967
+ api.version = "1.10.1";
1968
1968
  api.setConfig = function (patch) { return setConfigLocal(patch); };
1969
1969
  api.resetConfig = function () {
1970
1970
  try {
@@ -2481,7 +2481,12 @@
2481
2481
  ".dnm-advToggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#3b82f6);outline-offset:2px}" +
2482
2482
  ".dnm-advRight{display:flex;align-items:center;gap:8px;flex:none;font-weight:400;color:var(--dsw-alias-label-tertiary,rgba(120,120,120,.9))}" +
2483
2483
  ".dnm-advChev{font-size:10px;translate:0 1px;transition:transform .15s ease}" +
2484
- ".dnm-rowLabel.dnm-rowTip{cursor:help}" +
2484
+ // A flex item is blockified, so display:inline-block would still stretch to the
2485
+ // column width; fit-content is what actually hugs the glyphs.
2486
+ ".dnm-rowLabel.dnm-rowTip{width:fit-content;max-width:100%;cursor:help}" +
2487
+ ".dnm-rowLabelBtn{cursor:pointer}" +
2488
+ ".dnm-rowLabelBtn.dnm-rowTip{display:inline-flex;align-items:center;gap:6px;width:fit-content;cursor:pointer}" +
2489
+ ".dnm-chev{font-size:10px;line-height:1;color:var(--dsw-alias-label-tertiary,rgba(120,120,120,.9))}" +
2485
2490
  ".dnm-rowValue{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,rgba(120,120,120,.9))}" +
2486
2491
  // The long explanation lives in a tooltip next to the pointer, so a
2487
2492
  // row is one line tall. Screen readers still get the text.
@@ -2936,6 +2941,42 @@
2936
2941
  var advState = React.useState(false);
2937
2942
  var advancedOpen = advState[0];
2938
2943
  var setAdvancedOpen = advState[1];
2944
+ // Dependent controls (overlay corner, volume) stay folded away until the
2945
+ // row they belong to is clicked open.
2946
+ var subStateHook = React.useState({});
2947
+ var subState = subStateHook[0];
2948
+ var setSubState = subStateHook[1];
2949
+ function discloseRow(opts) {
2950
+ var open = !!(subState && subState[opts.key]);
2951
+ var toggle = function () {
2952
+ setSubState(function (prev) {
2953
+ var next = {};
2954
+ for (var k in prev) next[k] = prev[k];
2955
+ next[opts.key] = !prev[opts.key];
2956
+ return next;
2957
+ });
2958
+ };
2959
+ var label = h("div", {
2960
+ className: "dnm-rowLabel dnm-rowLabelBtn",
2961
+ role: "button",
2962
+ tabIndex: 0,
2963
+ "aria-expanded": open ? "true" : "false",
2964
+ "data-dnm-expand": opts.key,
2965
+ onClick: toggle,
2966
+ onKeyDown: function (e) {
2967
+ if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggle(); }
2968
+ }
2969
+ }, [
2970
+ opts.labelText,
2971
+ opts.valueText ? h("span", { className: "dnm-rowValue" }, opts.valueText) : null,
2972
+ h("span", { className: "dnm-chev" }, open ? "▾" : "▸")
2973
+ ]);
2974
+ var row = tipRow(opts.rowClass || "dnm-row", opts.hintText, [
2975
+ h("div", { className: "dnm-rowText" }, [label, srOnly(opts.hintText)]),
2976
+ opts.control
2977
+ ]);
2978
+ return open ? [row, opts.sub] : [row];
2979
+ }
2939
2980
  var testRow = tipRow("dnm-row dnm-rowStack", t("testHint"), [
2940
2981
  h("div", { className: "dnm-rowText" }, [
2941
2982
  h("div", { className: "dnm-rowLabel" }, t("testTitle")),
@@ -2964,39 +3005,67 @@
2964
3005
  if (!v && attentionActive > 0) { attentionActive = 0; applyTitle(); }
2965
3006
  }),
2966
3007
  rowRadio(t("toast"), toastHintText(), cfg.channel !== "overlay", function () { patch({ channel: "toast" }); }),
2967
- rowRadio(t("overlay"), t("overlayHint"), cfg.channel === "overlay", function () { patch({ channel: "overlay" }); }),
2968
- cfg.channel === "overlay" ? tipRow("dnm-row dnm-rowSub", t("overlayCornerHint"), [
2969
- h("div", { className: "dnm-rowText" }, [
2970
- h("div", { className: "dnm-rowLabel" }, t("overlayCorner")),
2971
- srOnly(t("overlayCornerHint"))
2972
- ]),
2973
- h("select", {
2974
- className: "dnm-select",
2975
- value: overlayCorner(),
2976
- "aria-label": t("overlayCorner"),
2977
- onChange: function (e) { patch({ overlayCorner: e.currentTarget.value }); }
2978
- }, [
2979
- h("option", { value: "top-right" }, t("overlayPosTR")),
2980
- h("option", { value: "bottom-right" }, t("overlayPosBR")),
2981
- h("option", { value: "top-left" }, t("overlayPosTL")),
2982
- h("option", { value: "bottom-left" }, t("overlayPosBL"))
3008
+ cfg.channel === "overlay" ? discloseRow({
3009
+ key: "overlayCorner",
3010
+ rowClass: "dnm-row dnm-rowRadio",
3011
+ labelText: t("overlay"),
3012
+ hintText: t("overlayHint"),
3013
+ valueText: t("overlayPos" + ({ "top-right": "TR", "bottom-right": "BR", "top-left": "TL", "bottom-left": "BL" })[overlayCorner()] || "BR"),
3014
+ control: h("input", {
3015
+ type: "radio",
3016
+ className: "dnm-radio",
3017
+ name: "dnm-alert-channel",
3018
+ checked: true,
3019
+ "aria-label": t("overlay") + " " + t("overlayCorner"),
3020
+ onChange: function () {},
3021
+ onClick: function () {}
3022
+ }),
3023
+ sub: tipRow("dnm-row dnm-rowSub", t("overlayCornerHint"), [
3024
+ h("div", { className: "dnm-rowText" }, [
3025
+ h("div", { className: "dnm-rowLabel" }, t("overlayCorner")),
3026
+ srOnly(t("overlayCornerHint"))
3027
+ ]),
3028
+ h("select", {
3029
+ className: "dnm-select",
3030
+ value: overlayCorner(),
3031
+ "aria-label": t("overlayCorner"),
3032
+ onChange: function (e) { patch({ overlayCorner: e.currentTarget.value }); }
3033
+ }, [
3034
+ h("option", { value: "top-right" }, t("overlayPosTR")),
3035
+ h("option", { value: "bottom-right" }, t("overlayPosBR")),
3036
+ h("option", { value: "top-left" }, t("overlayPosTL")),
3037
+ h("option", { value: "bottom-left" }, t("overlayPosBL"))
3038
+ ])
2983
3039
  ])
2984
- ]) : null,
2985
- rowSwitch("sound", t("sound"), t("soundHint"), cfg.sound, function (v) { patch({ sound: v }); }),
2986
- cfg.sound ? h("div", { className: "dnm-row dnm-rowSub" }, [
2987
- h("div", { className: "dnm-rowText" }, [
2988
- h("div", { className: "dnm-rowLabel" }, t("volume")),
2989
- h("div", { className: "dnm-rowHint" }, String(Math.round(cfg.volume * 100)) + "%")
2990
- ]),
2991
- h("input", {
2992
- type: "range",
2993
- className: "dnm-range",
2994
- min: 0, max: 100, step: 5,
2995
- value: Math.round(cfg.volume * 100),
2996
- "aria-label": t("volume"),
2997
- onChange: function (e) { patch({ volume: Number(e.currentTarget.value) / 100 }); }
2998
- })
2999
- ]) : null,
3040
+ }) : rowRadio(t("overlay"), t("overlayHint"), false, function () { patch({ channel: "overlay" }); }),
3041
+ cfg.sound ? discloseRow({
3042
+ key: "volume",
3043
+ labelText: t("sound"),
3044
+ hintText: t("soundHint"),
3045
+ valueText: String(Math.round(cfg.volume * 100)) + "%",
3046
+ control: h("button", {
3047
+ type: "button",
3048
+ role: "switch",
3049
+ "aria-checked": "true",
3050
+ "aria-label": t("sound"),
3051
+ className: "dnm-switch on",
3052
+ onClick: function () { patch({ sound: false }); }
3053
+ }, h("span", { className: "dnm-knob" })),
3054
+ sub: h("div", { className: "dnm-row dnm-rowSub" }, [
3055
+ h("div", { className: "dnm-rowText" }, [
3056
+ h("div", { className: "dnm-rowLabel" }, t("volume")),
3057
+ h("div", { className: "dnm-rowHint" }, String(Math.round(cfg.volume * 100)) + "%")
3058
+ ]),
3059
+ h("input", {
3060
+ type: "range",
3061
+ className: "dnm-range",
3062
+ min: 0, max: 100, step: 5,
3063
+ value: Math.round(cfg.volume * 100),
3064
+ "aria-label": t("volume"),
3065
+ onChange: function (e) { patch({ volume: Number(e.currentTarget.value) / 100 }); }
3066
+ })
3067
+ ])
3068
+ }) : rowSwitch("sound", t("sound"), t("soundHint"), false, function (v) { patch({ sound: v }); }),
3000
3069
  rowSwitch("quickActions", t("quickActions"), t("quickActionsHint"), cfg.quickActions, function (v) {
3001
3070
  patch({ quickActions: v });
3002
3071
  if (v) ensureActionBridge();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-notify-me",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "离开 DSH 页面也能收到提醒:需要你操作 / 后台回复完成时发系统通知、标题标记与可选页面浮层(副屏也能看见),支持审批快捷裁决与外部推送。Brand icon and a reworked settings page in 1.9.0.",
5
5
  "license": "MIT",
6
6
  "type": "module",