dsh-quick-toc 0.2.2 → 0.3.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/README.en.md +17 -6
- package/README.md +17 -6
- package/lib/client.js +108 -49
- package/package.json +17 -2
package/README.en.md
CHANGED
|
@@ -2,18 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
> **English** | [中文](README.md)
|
|
4
4
|
|
|
5
|
-
A quick conversation TOC plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH): extracts Markdown headings (H1–H6) from AI replies into a navigable outline panel, grouped by conversation turn, with auto-follow highlighting.
|
|
5
|
+
A quick conversation TOC plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH): extracts Markdown headings (H1–H6) from AI replies into a navigable outline panel, grouped by conversation turn, with auto-follow highlighting, keyword search and in-chat match highlighting.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- **Turn-grouped outline** — each user message + its AI replies form one group, with the group's end time as the header
|
|
9
|
+
- **Turn-grouped outline** — each user message + its AI replies form one group, with the group's end time as the header (plus the turn's first-line preview; click it to jump to the turn start)
|
|
10
|
+
- **Keyword search** — a magnifier in the header opens the search box; Enter cycles matches (n/N counter), Esc closes; toggle between **title / full-text** scope
|
|
11
|
+
- **In-chat highlighting** — matched keywords are highlighted in the conversation; the current match gets a distinct highlight and is scrolled to the upper-middle of the viewport; every occurrence counts toward n/N
|
|
10
12
|
- **Auto-follow highlight** — as you scroll the conversation, the turns visible in the viewport light up in the outline (multiple at once); the outline auto-loads and scrolls to keep them visible
|
|
11
13
|
- **Smooth jump** — click a heading to glide to the exact heading position in the conversation
|
|
12
14
|
- **Dockable & resizable** — dock left or right (drag the top bar), resize from the edges/corner, collapse to a draggable edge handle; panel size/position remembered
|
|
13
|
-
- **Scrollbar follows the dock** — scrollbar sits on the left when docked left, right when docked right
|
|
14
15
|
- **Paged rendering** — shows the latest groups first; scrolling to the top of the outline loads older ones
|
|
15
16
|
- **Markdown-aware titles** — inline `**bold**`, *italic*, `` `code` ``, `[links](url)`, `~~strike~~` are stripped from heading text
|
|
16
|
-
- Auto-hides when the conversation has no headings; works in light/dark themes
|
|
17
|
+
- Auto-hides when the conversation has no headings; works in light/dark themes; the inner-shadow card look adapts to the theme (white bevel in dark)
|
|
18
|
+
|
|
19
|
+
## Compatibility
|
|
20
|
+
|
|
21
|
+
| Plugin | DSH |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| **0.3.0** | **≥ 0.1.2-rc.1** (new slot architecture) |
|
|
24
|
+
| 0.2.2 | DSH versions before 0.1.2-rc.1 |
|
|
25
|
+
|
|
26
|
+
0.3.0 re-targeted the host integration (new slot architecture + `useChat` session data) and **only supports DSH 0.1.2-rc.1 and above**; for older DSH builds install 0.2.2. On install/update the DSH market pre-flights host compatibility from `dsh.compatibility.dshReleases` and `peerDependencies` in package.json and warns on a mismatch.
|
|
17
27
|
|
|
18
28
|
## Install
|
|
19
29
|
|
|
@@ -47,9 +57,10 @@ Restart DSH (double-click `restart-dsh.bat` on Windows) and open the Web UI. The
|
|
|
47
57
|
## Development
|
|
48
58
|
|
|
49
59
|
- `lib/client.js` — all UI logic (browser side)
|
|
50
|
-
- `lib/index.js` — host-side no-op entry
|
|
60
|
+
- `lib/index.js` — host-side no-op entry (extend with a version gate if needed)
|
|
51
61
|
- `cordis.patch.yml` — loader patch (official DSH bundle format)
|
|
52
|
-
-
|
|
62
|
+
- **Since 0.3.0 the plugin targets the new plugin model**: the panel registers into the session-scoped `conversation.input.overlay` slot (session hooks are contributed via `ctx.uiSession.provide`, `useChat` by ui-chat), and the panel body `createPortal`s to `document.body` as a fixed floating dock; data comes from `props.useChat` (`ChatSnapshot.order` + `nodes`; node shape: `kind: user/assistant-step`, `location.turn`, `data.blocks`)
|
|
63
|
+
- Client changes need a DSH restart (boot rev is content-based)
|
|
53
64
|
|
|
54
65
|
## License
|
|
55
66
|
|
package/README.md
CHANGED
|
@@ -2,18 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
> [English](README.en.md) | **中文**
|
|
4
4
|
|
|
5
|
-
**DeepSeek Harness(DSH)对话大纲插件**:把 AI 回复中的 Markdown 标题(H1–H6
|
|
5
|
+
**DeepSeek Harness(DSH)对话大纲插件**:把 AI 回复中的 Markdown 标题(H1–H6)提取成可导航的大纲面板,按对话回合分组,自动跟随阅读位置,支持关键字搜索与对话内高亮定位。
|
|
6
6
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
|
-
- **按回合分组** —— 每条用户消息 + 其后续 AI
|
|
9
|
+
- **按回合分组** —— 每条用户消息 + 其后续 AI 回复为一组,组头显示该组最后一条消息的结束时间(附带该回合首行预览,点击可跳到回合开头)
|
|
10
|
+
- **关键字搜索** —— 标题栏放大镜打开搜索框,回车逐个定位(n/N 计数),Esc 关闭;支持 **标题 / 全文** 范围切换
|
|
11
|
+
- **对话内高亮** —— 命中关键字在对话中高亮,当前命中单独标亮并滚动到视口上方约 1/3 处;同一条消息内的多次命中都计入 n/N
|
|
10
12
|
- **自动跟随高亮** —— 滚动对话框时,视口内可见的回合在大纲中自动点亮(多组可同时点亮);大纲自动加载并滚动,保证正在读的组始终可见
|
|
11
13
|
- **平滑跳转** —— 点击标题平滑滚动到对话中该标题的准确位置
|
|
12
14
|
- **可停靠、可缩放** —— 左右停靠(拖顶部横条移动)、边缘/角部拖拽调整大小、收起成可拖动的边缘把手;大小与位置自动记忆
|
|
13
|
-
- **滚动条跟随停靠方向** —— 停靠左侧时滚动条在左,停靠右侧时在右
|
|
14
15
|
- **分页渲染** —— 默认显示最近几组,大纲滚动到顶部自动加载更早的组
|
|
15
16
|
- **Markdown 清理** —— 标题中的 `**加粗**`、*斜体*、`` `代码` ``、`[链接](url)`、`~~删除线~~` 等行内标记自动剥离
|
|
16
|
-
- 对话无标题时自动隐藏;适配深色 /
|
|
17
|
+
- 对话无标题时自动隐藏;适配深色 / 浅色主题;内阴影卡片质感随主题切换(深色为白色高光)
|
|
18
|
+
|
|
19
|
+
## 兼容性
|
|
20
|
+
|
|
21
|
+
| 插件版本 | DSH 版本 |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| **0.3.0** | **≥ 0.1.2-rc.1**(新 slot 架构) |
|
|
24
|
+
| 0.2.2 | 0.1.2-rc.1 之前的旧版 DSH |
|
|
25
|
+
|
|
26
|
+
0.3.0 重写了与宿主的对接(新版 slot 架构 + `useChat` 会话数据),**只支持 DSH 0.1.2-rc.1 及以上**;旧版 DSH 请安装 0.2.2。安装/更新时 DSH 市场会根据 package.json 的 `dsh.compatibility.dshReleases` 与 `peerDependencies` 做 host 兼容预检,版本不符会给出提示。
|
|
17
27
|
|
|
18
28
|
## 安装
|
|
19
29
|
|
|
@@ -47,9 +57,10 @@ dsh plugin --profile web add <本目录路径>
|
|
|
47
57
|
## 开发
|
|
48
58
|
|
|
49
59
|
- `lib/client.js` —— 全部 UI 逻辑(浏览器端)
|
|
50
|
-
- `lib/index.js` ——
|
|
60
|
+
- `lib/index.js` —— 宿主端空入口(版本守卫可在此扩展)
|
|
51
61
|
- `cordis.patch.yml` —— loader patch(符合官方 bundle 规范)
|
|
52
|
-
-
|
|
62
|
+
- **0.3.0 起对接新版插件模型**:面板注册进会话级 `conversation.input.overlay` 槽(会话级 hook 由 `ctx.uiSession.provide` 贡献,`useChat` 由 ui-chat 贡献),面板本体 `createPortal` 到 `document.body` 渲染成固定浮层;数据入口为 `props.useChat`(`ChatSnapshot.order` + `nodes`,节点形状:`kind: user/assistant-step`、`location.turn`、`data.blocks`)
|
|
63
|
+
- 改 client.js 后需重启 DSH(boot rev 按内容算)
|
|
53
64
|
|
|
54
65
|
## License
|
|
55
66
|
|
package/lib/client.js
CHANGED
|
@@ -6,11 +6,19 @@ window.__ModuleLoader__.load({
|
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
-
require("
|
|
9
|
+
let react_dom = require("react-dom"); // createPortal -> panel stays a top-level overlay (highest pointer priority)
|
|
10
|
+
// DSH 0.1.2-rc.1: the old @deepseek-ai/dsh-client-runtime package is gone.
|
|
11
|
+
// Runtime hooks (useChat etc.) now arrive as session-scope slot props —
|
|
12
|
+
// no runtime package to require here anymore.
|
|
10
13
|
|
|
11
14
|
// ---------- constants ----------
|
|
12
15
|
var PANEL_WIDTH = 288;
|
|
13
|
-
|
|
16
|
+
// Very high base so the portal-rendered panel (top-level stacking context)
|
|
17
|
+
// always sits above DSH content and its transcript width handles.
|
|
18
|
+
// Panel layer: above the app's popovers (z 100) and the transcript width
|
|
19
|
+
// handles (z 8), but BELOW DSH's modal layer (settings/image viewer, z 1000)
|
|
20
|
+
// so opening settings covers the panel instead of the panel floating on top.
|
|
21
|
+
var Z_BASE = 500;
|
|
14
22
|
var EASE = "cubic-bezier(0.22, 0.9, 0.3, 1)"; // smooth non-linear slide
|
|
15
23
|
|
|
16
24
|
// ---------- markdown helpers ----------
|
|
@@ -223,6 +231,42 @@ window.__ModuleLoader__.load({
|
|
|
223
231
|
chip: "rgba(79, 140, 255, 0.18)"
|
|
224
232
|
};
|
|
225
233
|
|
|
234
|
+
// ---- theme scheme detection (for the panel's 3D inner shadow) ----
|
|
235
|
+
// Prefer a positive dark signal from the OS preference, then DSH's theme
|
|
236
|
+
// attribute/class, then the --dsw-alias-bg-base luminance as a last resort.
|
|
237
|
+
// Failed-open to light so a light card never gets a dark inner shadow by
|
|
238
|
+
// mistake; the caller flips to the white bevel only on a confident dark read.
|
|
239
|
+
function isDarkScheme() {
|
|
240
|
+
try {
|
|
241
|
+
// DSH's authoritative dark marker: <body data-ds-dark-theme> is set when
|
|
242
|
+
// the dark scheme is active (system OR manual). Check it first.
|
|
243
|
+
var body = document.body;
|
|
244
|
+
if (body) {
|
|
245
|
+
if (body.hasAttribute && body.hasAttribute("data-ds-dark-theme")) return true;
|
|
246
|
+
var cls = body.className || "";
|
|
247
|
+
if (/dark|theme-dark/i.test(cls)) return true;
|
|
248
|
+
var attr = (body.getAttribute("data-theme") || body.getAttribute("data-color-scheme") || "").toLowerCase();
|
|
249
|
+
if (attr === "dark" || /dark/.test(attr)) return true;
|
|
250
|
+
}
|
|
251
|
+
if (typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: dark)").matches) return true;
|
|
252
|
+
var root = body || document.documentElement;
|
|
253
|
+
var cs = getComputedStyle(root).colorScheme;
|
|
254
|
+
if (typeof cs === "string" && /dark/i.test(cs)) return true;
|
|
255
|
+
var v = getComputedStyle(root).getPropertyValue("--dsw-alias-bg-base");
|
|
256
|
+
var m = /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/.exec(v);
|
|
257
|
+
if (m) return (Number(m[1]) + Number(m[2]) + Number(m[3])) < 384;
|
|
258
|
+
} catch (e) {}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
// Inner shadow: computed per-render (not once) so it follows the live theme.
|
|
262
|
+
// Dark scheme -> soft WHITE bevel (recessed card highlight); light -> soft
|
|
263
|
+
// dark shade. Outer shadow stays off (clip-path would clip it).
|
|
264
|
+
function innerShadow() {
|
|
265
|
+
return isDarkScheme()
|
|
266
|
+
? "inset 0 0 0 1px rgba(255,255,255,0.16), inset 0 1px 0 rgba(255,255,255,0.12), inset 0 -10px 16px rgba(255,255,255,0.08)"
|
|
267
|
+
: "inset 0 0 0 1px rgba(0,0,0,0.08), inset 0 2px 10px rgba(0,0,0,0.18)";
|
|
268
|
+
}
|
|
269
|
+
|
|
226
270
|
// ---------- error boundary ----------
|
|
227
271
|
var ErrorBoundary = (function () {
|
|
228
272
|
if (!react.Component) return function (p) { return p.children; };
|
|
@@ -262,13 +306,17 @@ window.__ModuleLoader__.load({
|
|
|
262
306
|
|
|
263
307
|
// ---------- component ----------
|
|
264
308
|
function OutlinePanel(props) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
309
|
+
// DSH 0.1.2-rc.1: the conversation moved out of the session snapshot —
|
|
310
|
+
// it is now the session-scope `chat` hook (ChatSnapshot: order + nodes
|
|
311
|
+
// map + legacy projection), contributed by dsh-client-ui-chat. Same node
|
|
312
|
+
// shape as before (kind user/assistant-step, location.turn, data.blocks).
|
|
313
|
+
var useChat = props.useChat;
|
|
314
|
+
if (!useChat) {
|
|
315
|
+
console.warn("[dsh-quick-toc] useChat prop missing (requires DSH >= 0.1.2-rc.1)");
|
|
268
316
|
return null;
|
|
269
317
|
}
|
|
270
|
-
var order =
|
|
271
|
-
var nodes =
|
|
318
|
+
var order = useChat(function (s) { return s.order; });
|
|
319
|
+
var nodes = useChat(function (s) { return s.nodes; });
|
|
272
320
|
|
|
273
321
|
// ---- hooks (ALL before any conditional return) ----
|
|
274
322
|
// collapsed by default; user expands via the edge handle (default dock: left)
|
|
@@ -793,24 +841,20 @@ window.__ModuleLoader__.load({
|
|
|
793
841
|
// ---- geometry: always position by `left` (px) so dock-switch & slide share one animated transition
|
|
794
842
|
var dockRight = dock === "right";
|
|
795
843
|
var panelLeft;
|
|
796
|
-
if (
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
844
|
+
if (dockRight) {
|
|
845
|
+
// RIGHT dock: keep the panel's VISIBLE right edge pinned at the SAME
|
|
846
|
+
// line when collapsed as when expanded (the expand edge is correct).
|
|
847
|
+
// open: left = openRight, visible right edge = openRight+panelW
|
|
848
|
+
// closed: left = openRight + panelW, clip-right panelW hides it fully,
|
|
849
|
+
// so the visible right edge stays at openRight+panelW -> the
|
|
850
|
+
// collapse shrinks toward that line and vanishes exactly there.
|
|
851
|
+
var openRight = window.innerWidth - (viewport ? viewport.right + 48 : 60) - panelW;
|
|
852
|
+
panelLeft = open ? openRight : (openRight + panelW);
|
|
853
|
+
} else if (open) {
|
|
854
|
+
// LEFT dock open (left dock is the confirmed-correct reference — untouched)
|
|
855
|
+
panelLeft = (viewport ? viewport.left + 8 : 8);
|
|
800
856
|
} else {
|
|
801
|
-
|
|
802
|
-
// left dock -> slide just past the left sidebar edge (stop there)
|
|
803
|
-
// right dock -> boundary is the right sidebar when it is open,
|
|
804
|
-
// otherwise the screen's right edge
|
|
805
|
-
if (dockRight) {
|
|
806
|
-
// with the right sidebar open, slide INTO the sidebar area (covered
|
|
807
|
-
// by the cover wall); otherwise fly off the screen's right edge
|
|
808
|
-
panelLeft = (viewport && viewport.right > 80)
|
|
809
|
-
? (window.innerWidth - viewport.right)
|
|
810
|
-
: window.innerWidth + 24;
|
|
811
|
-
} else {
|
|
812
|
-
panelLeft = (viewport ? viewport.left - panelW - 8 : -(panelW + 48));
|
|
813
|
-
}
|
|
857
|
+
panelLeft = (viewport ? viewport.left - panelW - 8 : -(panelW + 48));
|
|
814
858
|
}
|
|
815
859
|
var vMaxH = viewport ? Math.max(200, viewport.height - 28) : "72vh";
|
|
816
860
|
var baseTopPx = (viewport ? viewport.top + 14 : window.innerHeight * 0.12) + panelY;
|
|
@@ -919,6 +963,7 @@ window.__ModuleLoader__.load({
|
|
|
919
963
|
alignItems: "center",
|
|
920
964
|
justifyContent: "center",
|
|
921
965
|
borderRadius: "50%",
|
|
966
|
+
cornerShape: "round",
|
|
922
967
|
background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.16))",
|
|
923
968
|
border: "none",
|
|
924
969
|
color: C.muted,
|
|
@@ -962,9 +1007,12 @@ window.__ModuleLoader__.load({
|
|
|
962
1007
|
// like being covered by the sidebar (the sidebar stays untouched):
|
|
963
1008
|
// left dock -> clipped from the left up to the sidebar line
|
|
964
1009
|
// right dock -> clipped from the right at the screen/sidebar line
|
|
1010
|
+
// LEFT dock keeps its original clip (collapse left). RIGHT dock clips the
|
|
1011
|
+
// LEFT side so the panel closes toward its right (dock) edge in place.
|
|
965
1012
|
var panelClip = "inset(0 0 0 0px)";
|
|
966
1013
|
if (!open) {
|
|
967
1014
|
if (dockRight) {
|
|
1015
|
+
// mirror of LEFT: clip the RIGHT side (panel flies right, shrinking from its right)
|
|
968
1016
|
panelClip = "inset(0 " + panelW + "px 0 0)";
|
|
969
1017
|
} else {
|
|
970
1018
|
panelClip = "inset(0 0 0 " + (panelW + 8) + "px)";
|
|
@@ -985,13 +1033,15 @@ window.__ModuleLoader__.load({
|
|
|
985
1033
|
background: C.panelBg,
|
|
986
1034
|
border: "none",
|
|
987
1035
|
borderRadius: 12,
|
|
988
|
-
boxShadow: "0 2px 10px rgba(0,0,0,0.18)",
|
|
989
1036
|
zIndex: Z_BASE,
|
|
990
1037
|
overflow: "hidden",
|
|
991
1038
|
color: C.text,
|
|
992
1039
|
opacity: panelOpacity,
|
|
993
1040
|
clipPath: panelClip,
|
|
994
|
-
|
|
1041
|
+
// inner shadow only (no outer): theme-aware (white bevel in dark mode,
|
|
1042
|
+
// soft shade in light) — outer shadow would be clipped by the collapse
|
|
1043
|
+
// clip-path and the panel edges.
|
|
1044
|
+
boxShadow: innerShadow(),
|
|
995
1045
|
transition: panelTransition,
|
|
996
1046
|
pointerEvents: "auto"
|
|
997
1047
|
},
|
|
@@ -1027,6 +1077,7 @@ window.__ModuleLoader__.load({
|
|
|
1027
1077
|
width: 56,
|
|
1028
1078
|
height: 5,
|
|
1029
1079
|
borderRadius: 999,
|
|
1080
|
+
cornerShape: "round",
|
|
1030
1081
|
background: "var(--dsw-alias-border-l2, rgba(128,128,128,0.55))",
|
|
1031
1082
|
opacity: 0.35,
|
|
1032
1083
|
transition: "opacity 0.2s ease",
|
|
@@ -1075,6 +1126,7 @@ window.__ModuleLoader__.load({
|
|
|
1075
1126
|
alignItems: "center",
|
|
1076
1127
|
justifyContent: "center",
|
|
1077
1128
|
borderRadius: "50%",
|
|
1129
|
+
cornerShape: "round",
|
|
1078
1130
|
background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.16))",
|
|
1079
1131
|
border: "none",
|
|
1080
1132
|
color: C.muted,
|
|
@@ -1118,6 +1170,7 @@ window.__ModuleLoader__.load({
|
|
|
1118
1170
|
alignItems: "center",
|
|
1119
1171
|
justifyContent: "center",
|
|
1120
1172
|
borderRadius: "50%",
|
|
1173
|
+
cornerShape: "round",
|
|
1121
1174
|
background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.16))",
|
|
1122
1175
|
border: "none",
|
|
1123
1176
|
color: C.muted,
|
|
@@ -1188,6 +1241,7 @@ window.__ModuleLoader__.load({
|
|
|
1188
1241
|
alignItems: "center",
|
|
1189
1242
|
background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.14))",
|
|
1190
1243
|
borderRadius: 999,
|
|
1244
|
+
cornerShape: "round",
|
|
1191
1245
|
padding: "6px 12px"
|
|
1192
1246
|
},
|
|
1193
1247
|
children: [
|
|
@@ -1274,6 +1328,7 @@ window.__ModuleLoader__.load({
|
|
|
1274
1328
|
alignItems: "center",
|
|
1275
1329
|
justifyContent: "center",
|
|
1276
1330
|
borderRadius: "50%",
|
|
1331
|
+
cornerShape: "round",
|
|
1277
1332
|
fontSize: 11,
|
|
1278
1333
|
color: searchScope === "full" ? "var(--dsw-alias-brand-primary, #4f8cff)" : C.muted,
|
|
1279
1334
|
background: searchScope === "full" ? "rgba(79,140,255,0.18)" : "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.14))",
|
|
@@ -1306,6 +1361,7 @@ window.__ModuleLoader__.load({
|
|
|
1306
1361
|
// the scrollbar follows the dock side (rtl flips it to the left)
|
|
1307
1362
|
react_jsx_runtime.jsx("div", {
|
|
1308
1363
|
ref: listRef,
|
|
1364
|
+
className: "dqt-list",
|
|
1309
1365
|
style: {
|
|
1310
1366
|
overflowY: "auto",
|
|
1311
1367
|
padding: "6px 8px",
|
|
@@ -1395,6 +1451,7 @@ window.__ModuleLoader__.load({
|
|
|
1395
1451
|
width: 12,
|
|
1396
1452
|
height: 80,
|
|
1397
1453
|
borderRadius: 999,
|
|
1454
|
+
cornerShape: "round",
|
|
1398
1455
|
background: "var(--dsw-alias-border-l2, rgba(160,160,160,0.55))",
|
|
1399
1456
|
opacity: handleShown ? 0.5 : 0,
|
|
1400
1457
|
transition: "opacity 0.35s ease, background 0.25s ease",
|
|
@@ -1419,9 +1476,10 @@ window.__ModuleLoader__.load({
|
|
|
1419
1476
|
})
|
|
1420
1477
|
}) : null;
|
|
1421
1478
|
|
|
1422
|
-
return
|
|
1423
|
-
children: [panelEl, edgeEl]
|
|
1424
|
-
|
|
1479
|
+
return react_dom.createPortal(
|
|
1480
|
+
react_jsx_runtime.jsx(ErrorBoundary, { children: [panelEl, edgeEl] }),
|
|
1481
|
+
document.body
|
|
1482
|
+
);
|
|
1425
1483
|
}
|
|
1426
1484
|
|
|
1427
1485
|
function renderItem(n, depth, jump, C, uid) {
|
|
@@ -1540,15 +1598,6 @@ window.__ModuleLoader__.load({
|
|
|
1540
1598
|
return out;
|
|
1541
1599
|
}
|
|
1542
1600
|
|
|
1543
|
-
function OutlineOverlay(props) {
|
|
1544
|
-
var SessionProvider = props.SessionProvider;
|
|
1545
|
-
var renderSlot = props.renderSlot;
|
|
1546
|
-
return react_jsx_runtime.jsx(SessionProvider, {
|
|
1547
|
-
empty: function () { return null; },
|
|
1548
|
-
children: function () { return renderSlot("quick-toc.panel", {}); }
|
|
1549
|
-
});
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
1601
|
var zh = {
|
|
1553
1602
|
"panel.title": "对话大纲"
|
|
1554
1603
|
};
|
|
@@ -1556,38 +1605,48 @@ window.__ModuleLoader__.load({
|
|
|
1556
1605
|
"panel.title": "Conversation Outline"
|
|
1557
1606
|
};
|
|
1558
1607
|
|
|
1559
|
-
var inject = ["slots", "
|
|
1608
|
+
var inject = ["slots", "locale"];
|
|
1560
1609
|
|
|
1561
1610
|
function apply(ctx) {
|
|
1562
1611
|
ctx.effect(function () {
|
|
1563
1612
|
return ctx.locale.register("dsh-quick-toc", { zh: zh, en: en });
|
|
1564
1613
|
}, "dsh-quick-toc: dictionaries");
|
|
1565
|
-
|
|
1614
|
+
// DSH 0.1.2-rc.1: session-scoped hooks (useChat/useSession/sessionId) only arrive
|
|
1615
|
+
// inside a declared session slot. Register the panel into the session-scoped
|
|
1616
|
+
// conversation.input.overlay (list/additive) so it receives useChat; the panel
|
|
1617
|
+
// itself renders a fixed, frame-floating dock, so the overlay seat is just the
|
|
1618
|
+
// hook source (it is NOT the panel's visual container).
|
|
1619
|
+
ctx.slots.inject("conversation.input.overlay", function () {
|
|
1566
1620
|
return ctx.slots.register({
|
|
1567
|
-
name: "
|
|
1621
|
+
name: "conversation.input.overlay",
|
|
1568
1622
|
id: "quick-toc",
|
|
1569
1623
|
order: 90,
|
|
1570
|
-
children: { "quick-toc.panel": { kind: "single", scope: "session" } }
|
|
1571
|
-
}, OutlineOverlay);
|
|
1572
|
-
});
|
|
1573
|
-
ctx.slots.inject("quick-toc.panel", function () {
|
|
1574
|
-
return ctx.slots.register({
|
|
1575
|
-
name: "quick-toc.panel",
|
|
1576
1624
|
locale: "dsh-quick-toc"
|
|
1577
1625
|
}, OutlinePanel);
|
|
1578
1626
|
});
|
|
1579
1627
|
}
|
|
1580
1628
|
|
|
1629
|
+
exports.name = "dsh-quick-toc"; // runner attributes slot entries to this registrant
|
|
1581
1630
|
exports.apply = apply;
|
|
1582
1631
|
exports.inject = inject;
|
|
1583
1632
|
|
|
1584
|
-
// inject the small keyframe stylesheet once
|
|
1633
|
+
// inject the small keyframe + panel-scrollbar stylesheet once
|
|
1585
1634
|
(function () {
|
|
1586
1635
|
if (typeof document === "undefined") return;
|
|
1587
1636
|
if (document.getElementById("dsh-quick-toc-css")) return;
|
|
1588
1637
|
var s = document.createElement("style");
|
|
1589
1638
|
s.id = "dsh-quick-toc-css";
|
|
1590
|
-
s.textContent = "@keyframes dqt-spin{to{transform:rotate(360deg)}}@keyframes dqt-fade-in{from{opacity:0}to{opacity:1}}@keyframes dqt-fade-out{from{opacity:1}to{opacity:0}}"
|
|
1639
|
+
s.textContent = "@keyframes dqt-spin{to{transform:rotate(360deg)}}@keyframes dqt-fade-in{from{opacity:0}to{opacity:1}}@keyframes dqt-fade-out{from{opacity:1}to{opacity:0}}" +
|
|
1640
|
+
// Hide the native scrollbar entirely (no arrow buttons, no grey bar) —
|
|
1641
|
+
// custom webkit scrollbar styling was not reliably suppressing the
|
|
1642
|
+
// default arrows, so a hidden native bar + the panel's inner shadow gives
|
|
1643
|
+
// the cleanest look. Scrolling still works (auto-follow + wheel-load-older).
|
|
1644
|
+
".dqt-list{scrollbar-width:none;-ms-overflow-style:none}" +
|
|
1645
|
+
".dqt-list::-webkit-scrollbar{display:none;width:0;height:0}" +
|
|
1646
|
+
".dqt-list::-webkit-scrollbar-button{display:none;height:0;width:0}" +
|
|
1647
|
+
".dqt-list::-webkit-scrollbar-track{background:transparent}" +
|
|
1648
|
+
".dqt-list::-webkit-scrollbar-thumb{background:transparent}" +
|
|
1649
|
+
".dqt-list::-webkit-scrollbar-corner{background:transparent}";
|
|
1591
1650
|
document.head.appendChild(s);
|
|
1592
1651
|
})();
|
|
1593
1652
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-quick-toc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Quick conversation TOC for DeepSeek Harness: markdown heading outline grouped by turn, with auto-follow highlight and smooth jump navigation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
"lib",
|
|
9
9
|
"cordis.patch.yml",
|
|
10
10
|
"README.md",
|
|
11
|
+
"README.en.md",
|
|
11
12
|
"LICENSE"
|
|
12
13
|
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"dsh": ">=0.1.2-rc.1"
|
|
16
|
+
},
|
|
13
17
|
"exports": {
|
|
14
18
|
".": "./lib/index.js",
|
|
15
19
|
"./client": "./lib/client.js",
|
|
@@ -21,13 +25,24 @@
|
|
|
21
25
|
},
|
|
22
26
|
"client": {
|
|
23
27
|
"inject": [
|
|
24
|
-
"@deepseek-ai/dsh-client-
|
|
28
|
+
"@deepseek-ai/dsh-client-ui-chat",
|
|
25
29
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
26
30
|
"@deepseek-ai/dsh-client-ui-layout"
|
|
27
31
|
],
|
|
28
32
|
"platform": "web"
|
|
33
|
+
},
|
|
34
|
+
"compatibility": {
|
|
35
|
+
"dshReleases": {
|
|
36
|
+
"0.1.2-rc.1": "compatible",
|
|
37
|
+
"0.1.5-rc.1": "compatible"
|
|
38
|
+
}
|
|
29
39
|
}
|
|
30
40
|
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"react": "^18.2.0",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-chat": ">=0.1.2-rc.1",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.2-rc.1"
|
|
45
|
+
},
|
|
31
46
|
"license": "MIT",
|
|
32
47
|
"keywords": [
|
|
33
48
|
"dsh",
|