@zaclinley/dsh-mailharbor 0.21.0 → 0.22.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 +24 -0
- package/lib/client.js +78 -22
- package/lib/client.js.map +2 -2
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.22.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2a996e5: Hide empty recipient lines in the reader.
|
|
8
|
+
|
|
9
|
+
- Expanded conversation cards only render the 收件人/抄送 block when addresses
|
|
10
|
+
exist, and fall back to the loaded detail when the summary has none.
|
|
11
|
+
- The single-message reader no longer prints "收件人:—" either.
|
|
12
|
+
|
|
13
|
+
## 0.22.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 696333f: Virtualized conversation list.
|
|
18
|
+
|
|
19
|
+
- The grouped list renders only the visible window (plus a 600px overscan)
|
|
20
|
+
once there are more than 30 groups, using cumulative height estimates and
|
|
21
|
+
top/bottom spacers.
|
|
22
|
+
- Scrolling near the bottom loads the next 40 messages automatically while
|
|
23
|
+
preserving the scroll position; the manual 加载更多 button remains.
|
|
24
|
+
- Expanded conversations are measured into the virtual height so they do not
|
|
25
|
+
overlap the following groups.
|
|
26
|
+
|
|
3
27
|
## 0.21.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/lib/client.js
CHANGED
|
@@ -2410,10 +2410,10 @@ function Reader({
|
|
|
2410
2410
|
(0, import_react8.createElement)(Icon, { name: detailOpen ? "chevronLeft" : "chevronRight", size: 12 })
|
|
2411
2411
|
)
|
|
2412
2412
|
),
|
|
2413
|
-
threaded || !detailOpen ? null : (0, import_react8.createElement)(
|
|
2413
|
+
threaded || !detailOpen || detail.to.length === 0 && detail.cc.length === 0 ? null : (0, import_react8.createElement)(
|
|
2414
2414
|
"div",
|
|
2415
2415
|
{ className: "mailharbor-reader-recipients" },
|
|
2416
|
-
(0, import_react8.createElement)("span", null, `\u6536\u4EF6\u4EBA\uFF1A${addressLine(detail.to)
|
|
2416
|
+
detail.to.length === 0 ? null : (0, import_react8.createElement)("span", null, `\u6536\u4EF6\u4EBA\uFF1A${addressLine(detail.to)}`),
|
|
2417
2417
|
detail.cc.length === 0 ? null : (0, import_react8.createElement)("span", null, `\u6284\u9001\uFF1A${addressLine(detail.cc)}`)
|
|
2418
2418
|
),
|
|
2419
2419
|
(0, import_react8.createElement)(
|
|
@@ -2534,6 +2534,8 @@ function Reader({
|
|
|
2534
2534
|
const sentItem = isSentMailbox(mailbox) && item.to.length > 0;
|
|
2535
2535
|
const who = sentItem ? item.to[0] ?? item.from : item.from;
|
|
2536
2536
|
const selectedItem = item.id === detail.id;
|
|
2537
|
+
const toLine = addressLine(item.to) || (itemDetail === void 0 ? "" : addressLine(itemDetail.to));
|
|
2538
|
+
const ccLine = itemDetail === void 0 ? "" : addressLine(itemDetail.cc);
|
|
2537
2539
|
return (0, import_react8.createElement)(
|
|
2538
2540
|
"div",
|
|
2539
2541
|
{
|
|
@@ -2568,11 +2570,11 @@ function Reader({
|
|
|
2568
2570
|
expandedItem ? (0, import_react8.createElement)(
|
|
2569
2571
|
"div",
|
|
2570
2572
|
{ className: "mailharbor-thread-body" },
|
|
2571
|
-
(0, import_react8.createElement)(
|
|
2573
|
+
toLine === "" && ccLine === "" ? null : (0, import_react8.createElement)(
|
|
2572
2574
|
"div",
|
|
2573
2575
|
{ className: "mailharbor-thread-recipients small muted" },
|
|
2574
|
-
(0, import_react8.createElement)("span", null, `\u6536\u4EF6\u4EBA\uFF1A${
|
|
2575
|
-
|
|
2576
|
+
toLine === "" ? null : (0, import_react8.createElement)("span", null, `\u6536\u4EF6\u4EBA\uFF1A${toLine}`),
|
|
2577
|
+
ccLine === "" ? null : (0, import_react8.createElement)("span", null, `\u6284\u9001\uFF1A${ccLine}`)
|
|
2576
2578
|
),
|
|
2577
2579
|
itemDetail === void 0 ? (0, import_react8.createElement)(
|
|
2578
2580
|
"div",
|
|
@@ -2758,6 +2760,10 @@ function MailPanel() {
|
|
|
2758
2760
|
const [selectedKeys, setSelectedKeys] = (0, import_react9.useState)([]);
|
|
2759
2761
|
const searchRef = (0, import_react9.useRef)(null);
|
|
2760
2762
|
const threadCache = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
2763
|
+
const rowsRef = (0, import_react9.useRef)(null);
|
|
2764
|
+
const autoLoadRef = (0, import_react9.useRef)(0);
|
|
2765
|
+
const [listScroll, setListScroll] = (0, import_react9.useState)(0);
|
|
2766
|
+
const [listViewport, setListViewport] = (0, import_react9.useState)(800);
|
|
2761
2767
|
const [projectOptions, setProjectOptions] = (0, import_react9.useState)([]);
|
|
2762
2768
|
const [targetProject, setTargetProject] = (0, import_react9.useState)("");
|
|
2763
2769
|
const [extraction, setExtraction] = (0, import_react9.useState)(null);
|
|
@@ -3144,6 +3150,10 @@ ${projectPicker.subject}`,
|
|
|
3144
3150
|
setAiInfo(null);
|
|
3145
3151
|
setSearch("");
|
|
3146
3152
|
}, [accountScope, source]);
|
|
3153
|
+
(0, import_react9.useEffect)(() => {
|
|
3154
|
+
if (rowsRef.current !== null) rowsRef.current.scrollTop = 0;
|
|
3155
|
+
setListScroll(0);
|
|
3156
|
+
}, [accountScope, mailbox, search, unreadOnly, fromFilter, sinceFilter, beforeFilter, attachmentOnly]);
|
|
3147
3157
|
(0, import_react9.useEffect)(() => {
|
|
3148
3158
|
if (selected === null) {
|
|
3149
3159
|
setThreadItems([]);
|
|
@@ -3686,6 +3696,28 @@ ${projectPicker.subject}`,
|
|
|
3686
3696
|
};
|
|
3687
3697
|
const isSent = isSentFolder(mailbox);
|
|
3688
3698
|
const groups = groupMessages(items);
|
|
3699
|
+
const virtualEnabled = !selectMode && !showingDrafts && groups.length > 30;
|
|
3700
|
+
const offsets = [];
|
|
3701
|
+
let virtualTotal = 0;
|
|
3702
|
+
for (const group of groups) {
|
|
3703
|
+
offsets.push(virtualTotal);
|
|
3704
|
+
const expanded = expandedGroups.includes(group.key);
|
|
3705
|
+
virtualTotal += 64 + (expanded ? Math.max(0, group.items.length - 1) * 64 : 0);
|
|
3706
|
+
}
|
|
3707
|
+
let virtualStart = 0;
|
|
3708
|
+
let virtualEnd = groups.length;
|
|
3709
|
+
if (virtualEnabled) {
|
|
3710
|
+
const top = Math.max(0, listScroll - 600);
|
|
3711
|
+
const bottom = listScroll + listViewport + 600;
|
|
3712
|
+
virtualStart = 0;
|
|
3713
|
+
while (virtualStart < groups.length && (offsets[virtualStart] ?? 0) < top) virtualStart += 1;
|
|
3714
|
+
virtualEnd = virtualStart;
|
|
3715
|
+
while (virtualEnd < groups.length && (offsets[virtualEnd] ?? 0) < bottom) virtualEnd += 1;
|
|
3716
|
+
virtualStart = Math.max(0, virtualStart - 3);
|
|
3717
|
+
virtualEnd = Math.min(groups.length, virtualEnd + 3);
|
|
3718
|
+
}
|
|
3719
|
+
const topSpacer = virtualEnabled ? offsets[virtualStart] ?? 0 : 0;
|
|
3720
|
+
const bottomSpacer = virtualEnabled ? virtualTotal - (offsets[virtualEnd] ?? virtualTotal) : 0;
|
|
3689
3721
|
const renderMessage = (item, meta = {}) => {
|
|
3690
3722
|
const sent = isSent && item.to.length > 0;
|
|
3691
3723
|
const first = sent ? item.to[0] : item.from;
|
|
@@ -3758,6 +3790,21 @@ ${projectPicker.subject}`,
|
|
|
3758
3790
|
item.snippet === "" ? null : (0, import_react9.createElement)("span", { className: "snippet" }, highlight(item.snippet, aiInfo?.keywords[0] ?? search))
|
|
3759
3791
|
);
|
|
3760
3792
|
};
|
|
3793
|
+
const renderGroup = (group) => {
|
|
3794
|
+
const latest = group.items[0];
|
|
3795
|
+
if (latest === void 0) return null;
|
|
3796
|
+
const expanded = expandedGroups.includes(group.key);
|
|
3797
|
+
return (0, import_react9.createElement)(
|
|
3798
|
+
"div",
|
|
3799
|
+
{ className: "mailharbor-thread", key: group.key },
|
|
3800
|
+
renderMessage(latest, {
|
|
3801
|
+
groupCount: group.items.length,
|
|
3802
|
+
groupKey: group.key,
|
|
3803
|
+
expanded
|
|
3804
|
+
}),
|
|
3805
|
+
expanded ? group.items.slice(1).map((item) => renderMessage(item, { compact: true })) : null
|
|
3806
|
+
);
|
|
3807
|
+
};
|
|
3761
3808
|
return (0, import_react9.createElement)(
|
|
3762
3809
|
"div",
|
|
3763
3810
|
{ className: narrow ? "mailharbor mailharbor-narrow" : "mailharbor" },
|
|
@@ -4283,7 +4330,20 @@ ${projectPicker.subject}`,
|
|
|
4283
4330
|
) : null,
|
|
4284
4331
|
(0, import_react9.createElement)(
|
|
4285
4332
|
"div",
|
|
4286
|
-
{
|
|
4333
|
+
{
|
|
4334
|
+
className: "mailharbor-rows",
|
|
4335
|
+
ref: rowsRef,
|
|
4336
|
+
onScroll: (event) => {
|
|
4337
|
+
const target = event.currentTarget;
|
|
4338
|
+
setListScroll(target.scrollTop);
|
|
4339
|
+
setListViewport(target.clientHeight);
|
|
4340
|
+
const now = Date.now();
|
|
4341
|
+
if (now - autoLoadRef.current > 800 && target.scrollTop + target.clientHeight > target.scrollHeight - 220 && page.total > items.length && !loading && aiInfo === null) {
|
|
4342
|
+
autoLoadRef.current = now;
|
|
4343
|
+
setLimit((current) => current + 40);
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
},
|
|
4287
4347
|
loading && items.length === 0 && drafts.length === 0 ? (0, import_react9.createElement)("div", { className: "mailharbor-empty" }, "\u6B63\u5728\u8BFB\u53D6\u2026") : showingDrafts ? drafts.length === 0 ? (0, import_react9.createElement)(
|
|
4288
4348
|
"div",
|
|
4289
4349
|
{ className: "mailharbor-empty" },
|
|
@@ -4376,21 +4436,17 @@ ${projectPicker.subject}`,
|
|
|
4376
4436
|
},
|
|
4377
4437
|
"\u6E05\u9664\u641C\u7D22"
|
|
4378
4438
|
) : null
|
|
4379
|
-
) : selectMode ? items.map((item) => renderMessage(item)) :
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
}),
|
|
4391
|
-
expanded ? group.items.slice(1).map((item) => renderMessage(item, { compact: true })) : null
|
|
4392
|
-
);
|
|
4393
|
-
})
|
|
4439
|
+
) : selectMode ? items.map((item) => renderMessage(item)) : virtualEnabled ? [
|
|
4440
|
+
(0, import_react9.createElement)("div", {
|
|
4441
|
+
key: "virtual-top",
|
|
4442
|
+
style: { height: `${String(topSpacer)}px` }
|
|
4443
|
+
}),
|
|
4444
|
+
...groups.slice(virtualStart, virtualEnd).map(renderGroup),
|
|
4445
|
+
(0, import_react9.createElement)("div", {
|
|
4446
|
+
key: "virtual-bottom",
|
|
4447
|
+
style: { height: `${String(bottomSpacer)}px` }
|
|
4448
|
+
})
|
|
4449
|
+
] : groups.map(renderGroup)
|
|
4394
4450
|
),
|
|
4395
4451
|
!showingDrafts && items.length > 0 ? (0, import_react9.createElement)(
|
|
4396
4452
|
"div",
|
|
@@ -6314,7 +6370,7 @@ function TaskEditor({
|
|
|
6314
6370
|
}
|
|
6315
6371
|
|
|
6316
6372
|
// src/client/index.tsx
|
|
6317
|
-
var VERSION = "0.
|
|
6373
|
+
var VERSION = "0.22.1";
|
|
6318
6374
|
var inject = ["slots"];
|
|
6319
6375
|
var PANEL_ID = "mailharbor";
|
|
6320
6376
|
var TASKS_PANEL_ID = "mailharbor-tasks";
|