dsh-email 0.16.3 → 0.17.0

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
@@ -4,6 +4,10 @@
4
4
 
5
5
  [历史英文记录](docs/CHANGELOG.en.md)
6
6
 
7
+ ## 0.17.0(2026-10-17)
8
+
9
+ - 设置面板顶部新增「首次使用」分步引导:一次只讲一步,支持上一步/下一步/跳过,看完记在本机不再出现。
10
+ - 引导内容与该插件的实际用法一致;可在开发者工具里清掉 `dsh-first-run:dsh-email:v1` 重新查看。
7
11
  ## 0.16.3 (2026-10-17)
8
12
 
9
13
  - 修复未配置邮箱时,服务商示例列表被凭据脱敏器误隐藏的问题;保留真实凭据的原有脱敏规则。
package/lib/client.js CHANGED
@@ -9,6 +9,71 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const React = require("react");
10
10
  const { useState, useEffect, useCallback, useRef } = React;
11
11
  const h = React.createElement;
12
+ const __FR_KEY = 'dsh-first-run:dsh-email:v1';
13
+ const __FR_TITLE = '邮件 · 首次使用(4 步)';
14
+ const __FR_STEPS = [
15
+ { title: '先把账号填上', body: '下面填 IMAP / SMTP 地址与授权码(QQ 邮箱用「授权码」,不是登录密码)。保存后这里会显示连接状态。' },
16
+ { title: '看一眼收件箱', body: '连接成功后,下方会列出最近邮件的标题与发件人;点开任意一封可读正文。' },
17
+ { title: '让它替你整理', body: '在对话里直接说你要做的事,比在页面里逐个点更快。', tryIt: '把今天的未读邮件按主题归纳一下' },
18
+ { title: '发信前一定先看草稿', body: '涉及发信时默认先生成草稿给你确认,确认后才真正发送;收件人规则在下方「发信规则」里配。' },
19
+ ];
20
+
21
+ // ---- first-run guide (shared snippet, keep in sync across plugins) ----
22
+ const __FR_STYLE_ID = 'dsh-first-run-css';
23
+ const __FR_CSS = [
24
+ '.fr-card{border:1px solid var(--dsw-border,rgba(0,0,0,.10));border-radius:12px;padding:14px 16px;margin:0 0 14px;background:linear-gradient(180deg,rgba(59,130,246,.06),rgba(59,130,246,.02))}',
25
+ '.fr-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}',
26
+ '.fr-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-accent,#3b82f6)}',
27
+ '.fr-title{font-weight:650;font-size:13.5px}',
28
+ '.fr-count{margin-left:auto;font-size:11px;color:var(--dsw-text-weak,#6b7280);font-variant-numeric:tabular-nums}',
29
+ '.fr-step{font-weight:600;font-size:13px;margin:2px 0 4px}',
30
+ '.fr-body{color:var(--dsw-text-weak,#4b5563);font-size:12.5px;line-height:1.65}',
31
+ '.fr-try{margin-top:8px;padding:7px 9px;border-radius:8px;background:rgba(59,130,246,.09);font-size:12px;display:flex;gap:8px}',
32
+ '.fr-try code{font-family:ui-monospace,monospace;white-space:pre-wrap;word-break:break-word}',
33
+ '.fr-bar{display:flex;gap:8px;align-items:center;margin-top:12px}',
34
+ '.fr-progress{display:flex;gap:4px;margin-right:auto}',
35
+ '.fr-seg{width:16px;height:3px;border-radius:2px;background:var(--dsw-border,rgba(0,0,0,.12))}',
36
+ '.fr-seg.on{background:var(--dsw-accent,#3b82f6)}',
37
+ '.fr-btn{border:1px solid var(--dsw-border,rgba(0,0,0,.14));background:transparent;color:inherit;border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer}',
38
+ '.fr-btn:hover{background:rgba(0,0,0,.04)}',
39
+ '.fr-btn.primary{background:var(--dsw-accent,#3b82f6);border-color:transparent;color:#fff}',
40
+ '.fr-btn.ghost{border-color:transparent;color:var(--dsw-text-weak,#6b7280)}',
41
+ ].join('\n');
42
+ function __frEnsureCss() {
43
+ if (document.getElementById(__FR_STYLE_ID)) return;
44
+ const el = document.createElement('style');
45
+ el.id = __FR_STYLE_ID;
46
+ el.textContent = __FR_CSS;
47
+ document.head.appendChild(el);
48
+ }
49
+ function __frRead() { try { return localStorage.getItem(__FR_KEY) === 'done'; } catch { return false; } }
50
+ function __frWrite() { try { localStorage.setItem(__FR_KEY, 'done'); } catch {} }
51
+ function __FirstRunCard() {
52
+ const [done, setDone] = React.useState(__frRead);
53
+ const [index, setIndex] = React.useState(0);
54
+ React.useEffect(() => { __frEnsureCss(); }, []);
55
+ if (done) return null;
56
+ const step = __FR_STEPS[index];
57
+ const last = index >= __FR_STEPS.length - 1;
58
+ const close = () => { __frWrite(); setDone(true); };
59
+ return h('div', { className: 'fr-card' },
60
+ h('div', { className: 'fr-head' }, h('span', { className: 'fr-dot' }), h('span', { className: 'fr-title' }, __FR_TITLE), h('span', { className: 'fr-count' }, (index + 1) + ' / ' + __FR_STEPS.length)),
61
+ h('div', { className: 'fr-step' }, step.title),
62
+ h('div', { className: 'fr-body' }, step.body),
63
+ step.tryIt ? h('div', { className: 'fr-try' }, h('span', null, '可以直接说'), h('code', null, '「' + step.tryIt + '」')) : null,
64
+ h('div', { className: 'fr-bar' },
65
+ h('div', { className: 'fr-progress' }, __FR_STEPS.map((_, i) => h('span', { key: i, className: 'fr-seg' + (i <= index ? ' on' : '') }))),
66
+ h('button', { className: 'fr-btn ghost', type: 'button', onClick: close }, '跳过'),
67
+ index > 0 ? h('button', { className: 'fr-btn', type: 'button', onClick: () => setIndex(index - 1) }, '上一步') : null,
68
+ h('button', { className: 'fr-btn primary', type: 'button', onClick: () => { if (last) close(); else setIndex(index + 1); } }, last ? '开始使用' : '下一步')));
69
+ }
70
+ function __withFirstRun(Component) {
71
+ return function FirstRunWrapped(props) {
72
+ return h(React.Fragment, null, h(__FirstRunCard, null), h(Component, props));
73
+ };
74
+ }
75
+ // ---- end first-run guide ----
76
+
12
77
 
13
78
  // Harness supplies document.baseURI for reverse-proxy mounts and in-page navigation.
14
79
  const ROUTE = "_dsh/dsh-email/settings";
@@ -2857,9 +2922,10 @@ function apply(ctx) {
2857
2922
  return UI[lang]["nav.title"];
2858
2923
  },
2859
2924
  inject: () => ({}),
2860
- }, EmailSettingsSection));
2925
+ }, __withFirstRun(EmailSettingsSection)));
2861
2926
  }
2862
2927
 
2928
+ exports.__firstRunCard = __FirstRunCard;
2863
2929
  exports.apply = apply;
2864
2930
  exports.inject = inject;
2865
2931
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-email",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "在 DSH 中收发、搜索和整理邮件,支持多个邮箱账号。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",