dsh-conversation-navigator 0.1.18 → 0.1.19
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/README.md +2 -0
- package/lib/client.js +73 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ Codex 风格的 **DeepSeek Harness(DSH)Web 端会话导航面板**:在对话页*
|
|
|
9
9
|
- **按轮折叠大纲**:默认只显示"第 N 轮 + 你的问题"列表,长对话一目了然
|
|
10
10
|
- **关键词过滤**:点击左上角搜索图标呼出输入框,只按「你的提问 + 助手实际回复文本」过滤(上下文、工具、命令、压缩、推理等不参与匹配),命中词高亮,列表文本自动定位到关键词处
|
|
11
11
|
- **展开/折叠步次**:点击轮次行右侧的箭头按钮(`▸ N`,展开时旋转为 `▾`)平滑展开/折叠该轮的步次明细(助手回复、工具调用、命令、压缩点等)
|
|
12
|
+
- **悬停查看全文**:鼠标在轮次行停留片刻,气泡显示该轮用户提问的完整原文,不再被单行截断
|
|
13
|
+
- **显示 / 隐藏轮次**:头部切换按钮一键切换两种风格——「显示轮次」为经典分组视图(压缩等系统事件与轮次同级加粗展示);「隐藏轮次」为极简视图,每一行统一为轨迹徽标 + 文本(用户 = 业务蓝、助手 = 紫罗兰、压缩 = 中性灰),搜索框展开时按钮自动让位
|
|
12
14
|
- **丝滑动效**:面板开合淡入淡出、步次展开/折叠高度过渡、过滤结果逐条级联淡入、折叠箭头旋转——全部纯 CSS 实现,零依赖
|
|
13
15
|
- **点击定位**:点击轮次主体或步次条目,平滑滚动跳转到对话中对应位置(不改变折叠状态)
|
|
14
16
|
- **加载更早 / 加载全部**:面板顶部两个按钮——「加载更早」向后翻一页、「加载全部」一键把所有历史轮次载入导航,之后可任意跳转(页面默认仍懒加载,只有点按钮才补载)
|
package/lib/client.js
CHANGED
|
@@ -65,6 +65,16 @@ window.__ModuleLoader__.load({
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
function SwitchTurnsIcon() {
|
|
69
|
+
return React.createElement("svg", {
|
|
70
|
+
viewBox: "0 0 1024 1024", width: 14, height: 14, fill: "currentColor",
|
|
71
|
+
"aria-hidden": true,
|
|
72
|
+
},
|
|
73
|
+
React.createElement("path", { d: "M168 454c-8.837 0-16-7.163-16-16v-48c0-8.837 7.163-16 16-16h531.572L519.63 191.225c-9.858-10.014-2.934-26.883 10.978-27.22l0.424-0.005h70a16 16 0 0 1 11.402 4.775l254 258C876.392 436.89 869.226 454 855.032 454H168z m642-61.741v0.032L855 438h0.032L810 392.259zM601.032 180H601l190.992 194h0.032L601.032 180z" }),
|
|
74
|
+
React.createElement("path", { d: "M855.064 570c8.837 0 16 7.163 16 16l0 48c0 8.837-7.163 16-16 16l-531.572 0L503.434 832.775c9.858 10.014 2.934 26.884-10.978 27.22l-0.424 0.005-70 0a16 16 0 0 1-11.402-4.775l-254-258C146.672 587.11 153.838 570 168.032 570L855.064 570z m-642 61.741l0-0.032L168.064 586l-0.032 0L213.064 631.741zM422.032 844H422.064l-190.992-194-0.032 0L422.032 844z" }),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
/* ---------- own stylesheet (static packages have no styles builtin) ---------- */
|
|
69
79
|
const CSS = `
|
|
70
80
|
.cnvnav-panel {
|
|
@@ -89,6 +99,7 @@ window.__ModuleLoader__.load({
|
|
|
89
99
|
}
|
|
90
100
|
.cnvnav-count { color: var(--dsw-alias-label-secondary, #888); font-size: 11px; }
|
|
91
101
|
.cnvnav-search { flex: none; display: flex; }
|
|
102
|
+
.cnvnav-turns-toggle { flex: none; display: flex; }
|
|
92
103
|
.cnvnav-close { margin-left: auto; }
|
|
93
104
|
.cnvnav-list {
|
|
94
105
|
overflow-y: auto; padding: 6px; min-height: 0;
|
|
@@ -113,6 +124,7 @@ window.__ModuleLoader__.load({
|
|
|
113
124
|
color: var(--dsw-alias-label-primary, #222);
|
|
114
125
|
}
|
|
115
126
|
.cnvnav-group-title { font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif); font-size: 14px; font-weight: 700; line-height: 20px; white-space: nowrap; transition: color .16s ease; }
|
|
127
|
+
.cnvnav-group-head .cnvnav-badge { align-self: center; }
|
|
116
128
|
.cnvnav-group-sub {
|
|
117
129
|
color: var(--dsw-alias-label-secondary, #888);
|
|
118
130
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
@@ -303,7 +315,24 @@ window.__ModuleLoader__.load({
|
|
|
303
315
|
}
|
|
304
316
|
return null;
|
|
305
317
|
}
|
|
306
|
-
|
|
318
|
+
/* Full user question text (all text blocks) for the hover bubble. */
|
|
319
|
+
function fullDialogueText(node) {
|
|
320
|
+
const d = node && node.data;
|
|
321
|
+
if (!d || typeof d !== "object") return null;
|
|
322
|
+
if (node.kind !== "user") return null;
|
|
323
|
+
if (typeof d.content === "string") {
|
|
324
|
+
const t = d.content.trim();
|
|
325
|
+
return t === "" ? null : t;
|
|
326
|
+
}
|
|
327
|
+
if (!Array.isArray(d.content)) return null;
|
|
328
|
+
const parts = [];
|
|
329
|
+
for (const b of d.content) {
|
|
330
|
+
if (!b || typeof b !== "object") continue;
|
|
331
|
+
if ((b.type === "text" || b.kind === "text") && typeof b.text === "string" && b.text.trim() !== "") parts.push(b.text.trim());
|
|
332
|
+
}
|
|
333
|
+
return parts.length > 0 ? parts.join("\n") : null;
|
|
334
|
+
}
|
|
335
|
+
function previewFor(node) {
|
|
307
336
|
const d = node && node.data;
|
|
308
337
|
if (!d || typeof d !== "object") return null;
|
|
309
338
|
switch (node.kind) {
|
|
@@ -394,6 +423,7 @@ window.__ModuleLoader__.load({
|
|
|
394
423
|
cls: meta.cls,
|
|
395
424
|
preview: previewFor(node),
|
|
396
425
|
search: dialogueText(node),
|
|
426
|
+
full: fullDialogueText(node),
|
|
397
427
|
time: fmtTime(timeOf(node)),
|
|
398
428
|
};
|
|
399
429
|
const turn = turnOf(node);
|
|
@@ -521,6 +551,7 @@ window.__ModuleLoader__.load({
|
|
|
521
551
|
const snap = useStore();
|
|
522
552
|
const [filter, setFilter] = React.useState("");
|
|
523
553
|
const [searchOpen, setSearchOpen] = React.useState(false);
|
|
554
|
+
const [turnsHidden, setTurnsHidden] = React.useState(false);
|
|
524
555
|
function toggleSearch() {
|
|
525
556
|
if (searchOpen) setFilter("");
|
|
526
557
|
setSearchOpen(!searchOpen);
|
|
@@ -646,15 +677,37 @@ window.__ModuleLoader__.load({
|
|
|
646
677
|
}
|
|
647
678
|
function renderGroupHead(g, groupActive, chevron) {
|
|
648
679
|
const headSearch = g.items.length > 0 ? g.items[0].search : null;
|
|
680
|
+
const headFull = g.headIsUser && g.items.length > 0 ? g.items[0].full : null;
|
|
649
681
|
const useSnippet = filtering && hit(headSearch);
|
|
650
682
|
const sub = useSnippet ? snippetNodes(headSearch, kw, 15, 40) : g.subtitle;
|
|
651
683
|
const hasSub = sub !== "" && (!Array.isArray(sub) || sub.length > 0);
|
|
684
|
+
/* 标题策略:
|
|
685
|
+
显示轮次: 轮次行 = 加粗「第 N 轮」; 压缩等非轮次行 = 加粗类型标签, 视作轮次同级
|
|
686
|
+
隐藏轮次: 每行统一轨迹徽标 — 轮次头 = 「用户」业务蓝(助手开头则助手紫), 非轮次行 = 各自徽标(压缩=中性灰) */
|
|
687
|
+
let titleNode = null;
|
|
688
|
+
if (g.turn === null) {
|
|
689
|
+
if (turnsHidden && g.items.length > 0) {
|
|
690
|
+
const headItem = g.items[0];
|
|
691
|
+
titleNode = React.createElement("span", {
|
|
692
|
+
className: "cnvnav-badge cnvnav-badge-" + headItem.cls,
|
|
693
|
+
}, headItem.label);
|
|
694
|
+
} else {
|
|
695
|
+
titleNode = React.createElement("span", { className: "cnvnav-group-title" }, g.title);
|
|
696
|
+
}
|
|
697
|
+
} else if (!turnsHidden) {
|
|
698
|
+
titleNode = React.createElement("span", { className: "cnvnav-group-title" }, g.title);
|
|
699
|
+
} else if (g.items.length > 0) {
|
|
700
|
+
const headItem = g.items[0];
|
|
701
|
+
titleNode = React.createElement("span", {
|
|
702
|
+
className: "cnvnav-badge cnvnav-badge-" + headItem.cls,
|
|
703
|
+
}, headItem.kind === "user" ? "用户" : headItem.label);
|
|
704
|
+
}
|
|
652
705
|
return React.createElement("div", {
|
|
653
706
|
ref: (el) => { groupEls[g.gid] = el; },
|
|
654
707
|
className: "cnvnav-group-row" + (groupActive ? " cnvnav-group-row-active" : ""),
|
|
655
708
|
},
|
|
656
709
|
React.createElement(Tooltip, {
|
|
657
|
-
label: "跳转到此位置",
|
|
710
|
+
label: headFull !== null ? headFull : "跳转到此位置", maxWidth: 340,
|
|
658
711
|
side: "top",
|
|
659
712
|
delayMs: 500,
|
|
660
713
|
},
|
|
@@ -664,7 +717,7 @@ window.__ModuleLoader__.load({
|
|
|
664
717
|
className: "cnvnav-group-head",
|
|
665
718
|
onClick: () => jumpTo(g.headKey),
|
|
666
719
|
},
|
|
667
|
-
|
|
720
|
+
titleNode,
|
|
668
721
|
hasSub
|
|
669
722
|
? React.createElement("span", { className: "cnvnav-group-sub" }, sub)
|
|
670
723
|
: null,
|
|
@@ -776,6 +829,23 @@ window.__ModuleLoader__.load({
|
|
|
776
829
|
}),
|
|
777
830
|
),
|
|
778
831
|
),
|
|
832
|
+
searchOpen
|
|
833
|
+
? null
|
|
834
|
+
: React.createElement(Tooltip, {
|
|
835
|
+
label: turnsHidden ? "显示轮次" : "隐藏轮次",
|
|
836
|
+
side: "bottom",
|
|
837
|
+
delayMs: 500,
|
|
838
|
+
},
|
|
839
|
+
React.createElement("span", { className: "cnvnav-turns-toggle" },
|
|
840
|
+
React.createElement(Button, {
|
|
841
|
+
variant: turnsHidden ? "primary" : "ghost",
|
|
842
|
+
size: "sm",
|
|
843
|
+
icon: React.createElement(SwitchTurnsIcon),
|
|
844
|
+
"aria-pressed": turnsHidden,
|
|
845
|
+
onClick: () => setTurnsHidden(!turnsHidden),
|
|
846
|
+
}),
|
|
847
|
+
),
|
|
848
|
+
),
|
|
779
849
|
searchOpen
|
|
780
850
|
? React.createElement("input", {
|
|
781
851
|
type: "text",
|