dsh-conversation-navigator 0.1.15 → 0.1.16

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.
Files changed (2) hide show
  1. package/lib/client.js +101 -50
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -163,6 +163,19 @@ window.__ModuleLoader__.load({
163
163
  flex: none; color: var(--dsw-alias-label-secondary, #888); font-size: 10px; opacity: .8;
164
164
  }
165
165
  .cnvnav-empty { padding: 18px 10px; text-align: center; color: var(--dsw-alias-label-secondary, #888); }
166
+ .cnvnav-filter-row { padding: 6px 6px 0; }
167
+ .cnvnav-filter {
168
+ width: 100%; box-sizing: border-box;
169
+ height: 28px; padding: 0 8px;
170
+ border: 1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35));
171
+ border-radius: 8px;
172
+ background: var(--dsw-alias-bg-layer-1, rgba(128,128,128,.06));
173
+ color: var(--dsw-alias-label-primary, #222);
174
+ font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif);
175
+ font-size: 12px; outline: none;
176
+ }
177
+ .cnvnav-filter::placeholder { color: var(--dsw-alias-label-secondary, #888); }
178
+ .cnvnav-filter:focus { border-color: var(--dsw-alias-brand-primary, #4f46e5); }
166
179
  .cnvnav-topbar { display: flex; gap: 6px; margin: 6px 6px 0; }
167
180
  .cnvnav-footer { display: flex; gap: 6px; margin: 0 6px 6px; }
168
181
  .cnvnav-bar-btn { flex: 1; display: block; }
@@ -467,6 +480,7 @@ window.__ModuleLoader__.load({
467
480
  /* ---------- floating navigator panel ---------- */
468
481
  function Panel() {
469
482
  const snap = useStore();
483
+ const [filter, setFilter] = React.useState("");
470
484
 
471
485
  React.useEffect(() => {
472
486
  if (!snap.open) return;
@@ -531,35 +545,77 @@ window.__ModuleLoader__.load({
531
545
  const groups = snap.outline !== null ? snap.outline.groups : [];
532
546
  const count = snap.outline !== null ? snap.outline.count : 0;
533
547
 
534
- const groupNodes = groups.map((g) => {
535
- const expanded = snap.expanded[g.gid] === true;
536
- const isTurnGroup = g.turn !== null;
537
- const stepItems = isTurnGroup ? (g.headIsUser ? g.items.slice(1) : g.items) : [];
538
- const hasSteps = stepItems.length > 0;
539
- const groupActive = g.items.some((it) => it.key === snap.activeKey);
540
- return React.createElement("div", { key: g.gid, className: "cnvnav-group" },
541
- React.createElement("div", {
542
- ref: (el) => { groupEls[g.gid] = el; },
543
- className: "cnvnav-group-row" + (groupActive ? " cnvnav-group-row-active" : ""),
548
+ const kw = filter.trim().toLowerCase();
549
+ const filtering = kw !== "";
550
+ function hit(text) {
551
+ return typeof text === "string" && text !== "" && text.toLowerCase().indexOf(kw) !== -1;
552
+ }
553
+ function renderItem(item) {
554
+ return React.createElement("button", {
555
+ key: item.key,
556
+ type: "button",
557
+ ref: (el) => { itemEls[item.key] = el; },
558
+ className: "cnvnav-item" + (item.key === snap.activeKey ? " cnvnav-item-active" : ""),
559
+ onClick: () => jumpTo(item.key),
560
+ },
561
+ React.createElement("span", { className: "cnvnav-badge cnvnav-badge-" + item.cls }, item.label),
562
+ item.preview !== null && item.preview !== ""
563
+ ? React.createElement("span", { className: "cnvnav-item-preview" }, item.preview)
564
+ : null,
565
+ item.time !== ""
566
+ ? React.createElement("span", { className: "cnvnav-item-time" }, item.time)
567
+ : null,
568
+ );
569
+ }
570
+ function renderGroupHead(g, groupActive) {
571
+ return React.createElement("div", {
572
+ ref: (el) => { groupEls[g.gid] = el; },
573
+ className: "cnvnav-group-row" + (groupActive ? " cnvnav-group-row-active" : ""),
574
+ },
575
+ React.createElement(Tooltip, {
576
+ label: "跳转到此位置",
577
+ side: "top",
578
+ delayMs: 500,
544
579
  },
545
- React.createElement(Tooltip, {
546
- label: "跳转到此位置",
547
- side: "top",
548
- delayMs: 500,
549
- },
550
- React.createElement("span", { className: "cnvnav-group-head-wrap" },
551
- React.createElement("button", {
552
- type: "button",
553
- className: "cnvnav-group-head",
554
- onClick: () => jumpTo(g.headKey),
555
- },
556
- React.createElement("span", { className: "cnvnav-group-title" }, g.title),
557
- g.subtitle !== ""
558
- ? React.createElement("span", { className: "cnvnav-group-sub" }, g.subtitle)
559
- : null,
560
- ),
580
+ React.createElement("span", { className: "cnvnav-group-head-wrap" },
581
+ React.createElement("button", {
582
+ type: "button",
583
+ className: "cnvnav-group-head",
584
+ onClick: () => jumpTo(g.headKey),
585
+ },
586
+ React.createElement("span", { className: "cnvnav-group-title" }, g.title),
587
+ g.subtitle !== ""
588
+ ? React.createElement("span", { className: "cnvnav-group-sub" }, g.subtitle)
589
+ : null,
561
590
  ),
562
591
  ),
592
+ ),
593
+ );
594
+ }
595
+
596
+ let groupNodes;
597
+ if (filtering) {
598
+ groupNodes = [];
599
+ for (const g of groups) {
600
+ const subtitleHit = hit(g.subtitle);
601
+ const hitItems = g.items.filter((it) => hit(it.preview) || hit(it.label));
602
+ if (!subtitleHit && hitItems.length === 0) continue;
603
+ const rows = subtitleHit ? g.items : hitItems;
604
+ const groupActive = g.items.some((it) => it.key === snap.activeKey);
605
+ groupNodes.push(React.createElement("div", { key: g.gid, className: "cnvnav-group" },
606
+ renderGroupHead(g, groupActive),
607
+ rows.map(renderItem),
608
+ ));
609
+ }
610
+ } else {
611
+ groupNodes = groups.map((g) => {
612
+ const expanded = snap.expanded[g.gid] === true;
613
+ const isTurnGroup = g.turn !== null;
614
+ const stepItems = isTurnGroup ? (g.headIsUser ? g.items.slice(1) : g.items) : [];
615
+ const hasSteps = stepItems.length > 0;
616
+ const groupActive = g.items.some((it) => it.key === snap.activeKey);
617
+ return React.createElement("div", { key: g.gid, className: "cnvnav-group" },
618
+ renderGroupHead(g, groupActive),
563
619
  hasSteps
564
620
  ? React.createElement(Tooltip, {
565
621
  label: expanded ? "折叠步次" : "展开步次",
@@ -581,28 +637,12 @@ window.__ModuleLoader__.load({
581
637
  ),
582
638
  )
583
639
  : null,
584
- ),
585
- expanded && hasSteps
586
- ? stepItems.map((item) =>
587
- React.createElement("button", {
588
- key: item.key,
589
- type: "button",
590
- ref: (el) => { itemEls[item.key] = el; },
591
- className: "cnvnav-item" + (item.key === snap.activeKey ? " cnvnav-item-active" : ""),
592
- onClick: () => jumpTo(item.key),
593
- },
594
- React.createElement("span", { className: "cnvnav-badge cnvnav-badge-" + item.cls }, item.label),
595
- item.preview !== null && item.preview !== ""
596
- ? React.createElement("span", { className: "cnvnav-item-preview" }, item.preview)
597
- : null,
598
- item.time !== ""
599
- ? React.createElement("span", { className: "cnvnav-item-time" }, item.time)
600
- : null,
601
- ),
602
- )
603
- : null,
604
- );
605
- });
640
+ expanded && hasSteps
641
+ ? stepItems.map(renderItem)
642
+ : null,
643
+ );
644
+ });
645
+ }
606
646
 
607
647
  return React.createElement("div", {
608
648
  ref: (el) => { panelEl = el; },
@@ -612,7 +652,7 @@ window.__ModuleLoader__.load({
612
652
  },
613
653
  React.createElement("div", { className: "cnvnav-head" },
614
654
  React.createElement("span", { className: "cnvnav-title" }, "会话导航"),
615
- React.createElement("span", { className: "cnvnav-count" }, String(count) + " 条"),
655
+ React.createElement("span", { className: "cnvnav-count" }, (filtering ? groupNodes.length + " / " : "") + String(count) + " 条"),
616
656
  React.createElement(Tooltip, {
617
657
  label: "收起面板",
618
658
  side: "bottom",
@@ -628,6 +668,15 @@ window.__ModuleLoader__.load({
628
668
  ),
629
669
  ),
630
670
  ),
671
+ React.createElement("div", { className: "cnvnav-filter-row" },
672
+ React.createElement("input", {
673
+ type: "text",
674
+ className: "cnvnav-filter",
675
+ placeholder: "过滤提问 / 回复…",
676
+ value: filter,
677
+ onChange: (e) => setFilter(e.target.value),
678
+ }),
679
+ ),
631
680
  React.createElement("div", { className: "cnvnav-topbar" },
632
681
  React.createElement(Tooltip, {
633
682
  label: "加载更早的一批轮次",
@@ -670,7 +719,9 @@ window.__ModuleLoader__.load({
670
719
  },
671
720
  groups.length === 0
672
721
  ? React.createElement("div", { className: "cnvnav-empty" }, "当前会话暂无对话节点")
673
- : groupNodes,
722
+ : (filtering && groupNodes.length === 0
723
+ ? React.createElement("div", { className: "cnvnav-empty" }, "无匹配结果")
724
+ : groupNodes),
674
725
  ),
675
726
  React.createElement("div", { className: "cnvnav-footer" },
676
727
  React.createElement(Tooltip, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-conversation-navigator",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Codex 风格的 DSH(DeepSeek Harness)会话导航插件:按轮折叠的对话大纲面板,支持节点点击跳转、滚动位置高亮与轨迹视图同款配色。",
5
5
  "keywords": [
6
6
  "dsh",