@zaclinley/dsh-mailharbor 0.21.0 → 0.22.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 +14 -0
- package/lib/client.js +71 -17
- 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,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 696333f: Virtualized conversation list.
|
|
8
|
+
|
|
9
|
+
- The grouped list renders only the visible window (plus a 600px overscan)
|
|
10
|
+
once there are more than 30 groups, using cumulative height estimates and
|
|
11
|
+
top/bottom spacers.
|
|
12
|
+
- Scrolling near the bottom loads the next 40 messages automatically while
|
|
13
|
+
preserving the scroll position; the manual 加载更多 button remains.
|
|
14
|
+
- Expanded conversations are measured into the virtual height so they do not
|
|
15
|
+
overlap the following groups.
|
|
16
|
+
|
|
3
17
|
## 0.21.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/lib/client.js
CHANGED
|
@@ -2758,6 +2758,10 @@ function MailPanel() {
|
|
|
2758
2758
|
const [selectedKeys, setSelectedKeys] = (0, import_react9.useState)([]);
|
|
2759
2759
|
const searchRef = (0, import_react9.useRef)(null);
|
|
2760
2760
|
const threadCache = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
2761
|
+
const rowsRef = (0, import_react9.useRef)(null);
|
|
2762
|
+
const autoLoadRef = (0, import_react9.useRef)(0);
|
|
2763
|
+
const [listScroll, setListScroll] = (0, import_react9.useState)(0);
|
|
2764
|
+
const [listViewport, setListViewport] = (0, import_react9.useState)(800);
|
|
2761
2765
|
const [projectOptions, setProjectOptions] = (0, import_react9.useState)([]);
|
|
2762
2766
|
const [targetProject, setTargetProject] = (0, import_react9.useState)("");
|
|
2763
2767
|
const [extraction, setExtraction] = (0, import_react9.useState)(null);
|
|
@@ -3144,6 +3148,10 @@ ${projectPicker.subject}`,
|
|
|
3144
3148
|
setAiInfo(null);
|
|
3145
3149
|
setSearch("");
|
|
3146
3150
|
}, [accountScope, source]);
|
|
3151
|
+
(0, import_react9.useEffect)(() => {
|
|
3152
|
+
if (rowsRef.current !== null) rowsRef.current.scrollTop = 0;
|
|
3153
|
+
setListScroll(0);
|
|
3154
|
+
}, [accountScope, mailbox, search, unreadOnly, fromFilter, sinceFilter, beforeFilter, attachmentOnly]);
|
|
3147
3155
|
(0, import_react9.useEffect)(() => {
|
|
3148
3156
|
if (selected === null) {
|
|
3149
3157
|
setThreadItems([]);
|
|
@@ -3686,6 +3694,28 @@ ${projectPicker.subject}`,
|
|
|
3686
3694
|
};
|
|
3687
3695
|
const isSent = isSentFolder(mailbox);
|
|
3688
3696
|
const groups = groupMessages(items);
|
|
3697
|
+
const virtualEnabled = !selectMode && !showingDrafts && groups.length > 30;
|
|
3698
|
+
const offsets = [];
|
|
3699
|
+
let virtualTotal = 0;
|
|
3700
|
+
for (const group of groups) {
|
|
3701
|
+
offsets.push(virtualTotal);
|
|
3702
|
+
const expanded = expandedGroups.includes(group.key);
|
|
3703
|
+
virtualTotal += 64 + (expanded ? Math.max(0, group.items.length - 1) * 64 : 0);
|
|
3704
|
+
}
|
|
3705
|
+
let virtualStart = 0;
|
|
3706
|
+
let virtualEnd = groups.length;
|
|
3707
|
+
if (virtualEnabled) {
|
|
3708
|
+
const top = Math.max(0, listScroll - 600);
|
|
3709
|
+
const bottom = listScroll + listViewport + 600;
|
|
3710
|
+
virtualStart = 0;
|
|
3711
|
+
while (virtualStart < groups.length && (offsets[virtualStart] ?? 0) < top) virtualStart += 1;
|
|
3712
|
+
virtualEnd = virtualStart;
|
|
3713
|
+
while (virtualEnd < groups.length && (offsets[virtualEnd] ?? 0) < bottom) virtualEnd += 1;
|
|
3714
|
+
virtualStart = Math.max(0, virtualStart - 3);
|
|
3715
|
+
virtualEnd = Math.min(groups.length, virtualEnd + 3);
|
|
3716
|
+
}
|
|
3717
|
+
const topSpacer = virtualEnabled ? offsets[virtualStart] ?? 0 : 0;
|
|
3718
|
+
const bottomSpacer = virtualEnabled ? virtualTotal - (offsets[virtualEnd] ?? virtualTotal) : 0;
|
|
3689
3719
|
const renderMessage = (item, meta = {}) => {
|
|
3690
3720
|
const sent = isSent && item.to.length > 0;
|
|
3691
3721
|
const first = sent ? item.to[0] : item.from;
|
|
@@ -3758,6 +3788,21 @@ ${projectPicker.subject}`,
|
|
|
3758
3788
|
item.snippet === "" ? null : (0, import_react9.createElement)("span", { className: "snippet" }, highlight(item.snippet, aiInfo?.keywords[0] ?? search))
|
|
3759
3789
|
);
|
|
3760
3790
|
};
|
|
3791
|
+
const renderGroup = (group) => {
|
|
3792
|
+
const latest = group.items[0];
|
|
3793
|
+
if (latest === void 0) return null;
|
|
3794
|
+
const expanded = expandedGroups.includes(group.key);
|
|
3795
|
+
return (0, import_react9.createElement)(
|
|
3796
|
+
"div",
|
|
3797
|
+
{ className: "mailharbor-thread", key: group.key },
|
|
3798
|
+
renderMessage(latest, {
|
|
3799
|
+
groupCount: group.items.length,
|
|
3800
|
+
groupKey: group.key,
|
|
3801
|
+
expanded
|
|
3802
|
+
}),
|
|
3803
|
+
expanded ? group.items.slice(1).map((item) => renderMessage(item, { compact: true })) : null
|
|
3804
|
+
);
|
|
3805
|
+
};
|
|
3761
3806
|
return (0, import_react9.createElement)(
|
|
3762
3807
|
"div",
|
|
3763
3808
|
{ className: narrow ? "mailharbor mailharbor-narrow" : "mailharbor" },
|
|
@@ -4283,7 +4328,20 @@ ${projectPicker.subject}`,
|
|
|
4283
4328
|
) : null,
|
|
4284
4329
|
(0, import_react9.createElement)(
|
|
4285
4330
|
"div",
|
|
4286
|
-
{
|
|
4331
|
+
{
|
|
4332
|
+
className: "mailharbor-rows",
|
|
4333
|
+
ref: rowsRef,
|
|
4334
|
+
onScroll: (event) => {
|
|
4335
|
+
const target = event.currentTarget;
|
|
4336
|
+
setListScroll(target.scrollTop);
|
|
4337
|
+
setListViewport(target.clientHeight);
|
|
4338
|
+
const now = Date.now();
|
|
4339
|
+
if (now - autoLoadRef.current > 800 && target.scrollTop + target.clientHeight > target.scrollHeight - 220 && page.total > items.length && !loading && aiInfo === null) {
|
|
4340
|
+
autoLoadRef.current = now;
|
|
4341
|
+
setLimit((current) => current + 40);
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
},
|
|
4287
4345
|
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
4346
|
"div",
|
|
4289
4347
|
{ className: "mailharbor-empty" },
|
|
@@ -4376,21 +4434,17 @@ ${projectPicker.subject}`,
|
|
|
4376
4434
|
},
|
|
4377
4435
|
"\u6E05\u9664\u641C\u7D22"
|
|
4378
4436
|
) : 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
|
-
})
|
|
4437
|
+
) : selectMode ? items.map((item) => renderMessage(item)) : virtualEnabled ? [
|
|
4438
|
+
(0, import_react9.createElement)("div", {
|
|
4439
|
+
key: "virtual-top",
|
|
4440
|
+
style: { height: `${String(topSpacer)}px` }
|
|
4441
|
+
}),
|
|
4442
|
+
...groups.slice(virtualStart, virtualEnd).map(renderGroup),
|
|
4443
|
+
(0, import_react9.createElement)("div", {
|
|
4444
|
+
key: "virtual-bottom",
|
|
4445
|
+
style: { height: `${String(bottomSpacer)}px` }
|
|
4446
|
+
})
|
|
4447
|
+
] : groups.map(renderGroup)
|
|
4394
4448
|
),
|
|
4395
4449
|
!showingDrafts && items.length > 0 ? (0, import_react9.createElement)(
|
|
4396
4450
|
"div",
|
|
@@ -6314,7 +6368,7 @@ function TaskEditor({
|
|
|
6314
6368
|
}
|
|
6315
6369
|
|
|
6316
6370
|
// src/client/index.tsx
|
|
6317
|
-
var VERSION = "0.
|
|
6371
|
+
var VERSION = "0.22.0";
|
|
6318
6372
|
var inject = ["slots"];
|
|
6319
6373
|
var PANEL_ID = "mailharbor";
|
|
6320
6374
|
var TASKS_PANEL_ID = "mailharbor-tasks";
|