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 +4 -0
- package/lib/client.js +67 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
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
|
|