dsh-quick-toc 0.7.6 → 0.7.8
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.en.md +17 -6
- package/CHANGELOG.md +17 -6
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/lib/client.js +128 -16
- package/package.json +3 -2
package/CHANGELOG.en.md
CHANGED
|
@@ -2,20 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to **dsh-quick-toc** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
|
|
4
4
|
|
|
5
|
+
## [0.7.8] - 2026-09-27
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **DSH 0.1.7-rc.2 is supported**: it shares the whole plugin interface with rc.1 (the configuration card still registers into `plugins.item`, `plugins.bundle.config` and the rc line's `settings.plugin.item`, the settings service is still `configForms`, and the Plugins page's slot contract is byte-for-byte rc.1's), so no code change was needed; it was exercised point by point in an isolated environment (host boot, plugin status, the Plugins page's entry and card, a card write landing in the settings document, sessions, panel and curtain).
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Opening the curtain's search column no longer re-lays out the outline every frame**: the column used to transition its own width, and because the outline is the flex item next to it, every frame re-laid out the whole rendered list (measured on a 34-row list: one width step per frame, ~18ms frames and a 76ms first hitch; the cost grows with the list). The layout now flips once and the movement rides on a transform (the column slides in from off the right edge while the outline is flipped back to where it sat and released), which measured under 32ms for the first frame, with the resting geometry unchanged.
|
|
12
|
+
|
|
13
|
+
## [0.7.7] - 2026-09-27
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **On the 0.1.7 line the Plugins page had no configuration entry for this plugin**: 0.1.7 removed the whole Settings → Plugins → Plugin configuration page, leaving the configuration card on the bundle page alone (`plugins.bundle.config`, keyed on the npm package name), with no entry for this plugin in the Plugins page's Official group — the settings were unreachable from there. The package now also registers `plugins.item` (`id` `quick-toc`, `order` 50, titled after the panel), and opening that entry shows the card already expanded (both 0.1.7 seats render it with a `view`, so the card starts open there; the rc line's Plugin configuration cell passes no props and keeps the collapsed card list).
|
|
17
|
+
- **Opening the curtain could play its whole drop animation before any of it was seen**: opening the curtain re-lays out the list at the curtain's width, and on a long session that commit is itself a long task, so an animation clock started together with it had already run its 0.46s by the first painted frame (0.7.4 fixed another cause of the same failure: the auto-loader pulling the whole session in at once). The animation is now re-armed once the open state is in the DOM — that layout finishes first, the clock starts after it.
|
|
18
|
+
|
|
5
19
|
## [0.7.6] - 2026-09-24
|
|
6
20
|
|
|
7
21
|
### Fixed
|
|
8
|
-
- **On the 0.1.7 line the settings card's writes only reached the browser**: on a profile whose entry id differs from the
|
|
22
|
+
- **On the 0.1.7 line the settings card's writes only reached the browser**: before the host's settings document had arrived (on a profile whose entry id differs from the candidate names) the plugin bound a form that does not exist — the card opened and took clicks, but every write fell back to the browser mirror with the settings document untouched and no console error. It now waits for the document, and a host that never serves one still gets the card after 4 seconds (the browser mirror, its documented fallback layer).
|
|
9
23
|
|
|
10
24
|
## [0.7.5] - 2026-09-24
|
|
11
25
|
|
|
12
26
|
### Changed
|
|
13
|
-
- **DSH 0.1.7-rc.1 is supported**: it is the 0.1.7 interface set moved onto the rc channel
|
|
27
|
+
- **DSH 0.1.7-rc.1 is supported**: it is the 0.1.7 interface set moved onto the rc channel and shares its settings service and configuration-card slots with 0.1.7-alpha.x, so no code change was needed; it was exercised point by point in an isolated environment (host boot, panel, curtain, Esc, dock switch and collapse).
|
|
14
28
|
- **The declared compatibility floor moved to 0.1.5-rc.3**: the older 0.1.5-rc.1 and 0.1.5-rc.2 are no longer declared (`engines.dsh` and both peer ranges follow), and the README's compatibility table matches.
|
|
15
|
-
- **The loader row id
|
|
16
|
-
|
|
17
|
-
### Fixed
|
|
18
|
-
- **A binding fallback for the settings scope**: the host's settings document can still be loading when a plugin applies (0.1.7-rc.1 answers `status: "loading"` for that form), and the code used to accept only a one-shot "ready" snapshot; it now falls back to the first candidate form that EXISTS and lets the subscription take over once the document arrives.
|
|
29
|
+
- **The loader row id now equals the settings namespace** (`quick-toc` to `dsh-quick-toc`): from DSH 0.1.7 on, settings are addressed by profile entry id, and an id that does not match the namespace the plugin registered leaves an existing installation's saved preferences unreadable in the import file. With matching names this package can also live in the profile's `dsh.profile.bundles` (0.1.7's plugin manager only offers a configuration page for packages listed there), but **never together with a profile-patch `insert:` of the same name** (that makes the host refuse to boot).
|
|
19
30
|
|
|
20
31
|
## [0.7.4] - 2026-09-23
|
|
21
32
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,20 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
**dsh-quick-toc** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
|
|
4
4
|
|
|
5
|
+
## [0.7.8] - 2026-09-27
|
|
6
|
+
|
|
7
|
+
### 变更
|
|
8
|
+
- **支持 DSH 0.1.7-rc.2**:与 rc.1 共用同一套插件接口(配置卡片仍挂在 `plugins.item`、`plugins.bundle.config` 与 rc 线的 `settings.plugin.item` 上,设置服务仍是 `configForms`,插件管理页的槽位契约与 rc.1 逐字节相同),代码无需改动;隔离环境里逐项实测通过(宿主启动、插件运行状态、插件页条目与卡片、卡片写入落到设置文档、会话、面板与幕布)。
|
|
9
|
+
|
|
10
|
+
### 修复
|
|
11
|
+
- **幕布打开搜索栏时不再逐帧重排大纲**:搜索栏原本过渡自己的宽度,而大纲是与它同行的伸缩项,于是每一帧都要重排整个已渲染列表(34 行的列表实测:每帧一次宽度步进、约 18ms 一帧、首帧卡顿 76ms;列表越长越重)。现在布局只翻转一次,位移交给 transform(搜索栏从右缘外滑入,大纲反向翻转回原位置再释放),实测首帧卡顿降到 32ms 以内,静止时的几何与之前完全一致。
|
|
12
|
+
|
|
13
|
+
## [0.7.7] - 2026-09-27
|
|
14
|
+
|
|
15
|
+
### 修复
|
|
16
|
+
- **0.1.7 线上插件页缺少本插件的配置入口**:0.1.7 移除了「设置 → 插件 → 插件配置」整页,配置卡片只剩组合包页面上的 `plugins.bundle.config`(以 npm 包名为键)一处,插件页「官方」分组里没有本插件的条目,读者在那里找不到设置入口。现在同时注册 `plugins.item`(`id` 为 `quick-toc`、`order` 50、标题取面板名),点开该条目即见已展开的卡片(0.1.7 的两处座位渲染时都带 `view`,卡片因此默认展开;rc 线「插件配置」里那处不带 props,仍是收拢的卡片列表)。
|
|
17
|
+
- **打开幕布时展开动画可能整段播完才被看到**:打开幕布会让列表按幕布的宽度整体重排,长会话里这次提交本身就是一段长任务,动画时钟若与这次提交同时开始,0.46 秒会在首帧绘制之前走完(0.7.4 修的是同一类问题的另一种成因:当时是自动加载把整段会话一次性拉了进来)。现在动画在打开状态写入 DOM 之后重新点火一次,先完成这次布局再开始计时。
|
|
18
|
+
|
|
5
19
|
## [0.7.6] - 2026-09-24
|
|
6
20
|
|
|
7
21
|
### 修复
|
|
8
|
-
- **0.1.7
|
|
22
|
+
- **0.1.7 线上配置卡片的写入只落在浏览器里**:宿主设置文档还没到位时(入口 id 与候选名不一致的 profile 上)插件绑到了一个并不存在的表单——卡片能开能点,但写入都退回本地镜像、设置文档不动,控制台也没有报错。现在等文档到位再绑定,宿主始终不给文档时 4 秒后仍提供卡片(退回本地镜像这个既有降级层)。
|
|
9
23
|
|
|
10
24
|
## [0.7.5] - 2026-09-24
|
|
11
25
|
|
|
12
26
|
### 变更
|
|
13
|
-
- **支持 DSH 0.1.7-rc.1**:它是 0.1.7 那套接口搬到 rc
|
|
27
|
+
- **支持 DSH 0.1.7-rc.1**:它是 0.1.7 那套接口搬到 rc 通道,与 0.1.7-alpha.x 共用同一套设置服务与配置卡片槽位,代码无需改动;隔离环境里逐项实测通过(宿主启动、面板、幕布、Esc、停靠切换与收起)。
|
|
14
28
|
- **声明的兼容下限收到 0.1.5-rc.3**:更早的 0.1.5-rc.1、0.1.5-rc.2 不再声明(`engines.dsh` 与两条 peer 区间同步收紧),README 兼容表跟上。
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
### 修复
|
|
18
|
-
- **设置作用域的绑定兜底**:宿主设置文档在插件加载时可能仍在载入(0.1.7-rc.1 实测该表单的 `status` 为 `loading`),原先只认一次「就绪」快照;现在会退到第一个存在的候选表单,由订阅在文档到位后接续。
|
|
29
|
+
- **加载行 id 与设置命名空间对齐**(`quick-toc` → `dsh-quick-toc`):DSH 0.1.7 起设置按入口 id 寻址,名字与插件注册的命名空间不一致时,已保存的偏好会留在导入文件里读不到。同名之后本插件也可以放进 profile 的 `dsh.profile.bundles`(0.1.7 的插件管理页只在 bundles 里的包上给出配置页),但**不能与 profile patch 里的同名 `insert:` 并存**(会让宿主启动失败)。
|
|
19
30
|
|
|
20
31
|
## [0.7.4] - 2026-09-23
|
|
21
32
|
|
package/README.en.md
CHANGED
|
@@ -42,7 +42,7 @@ A conversation TOC plugin for [DeepSeek Harness](https://github.com/deepseek-ai/
|
|
|
42
42
|
|
|
43
43
|
| Plugin | Supported DSH |
|
|
44
44
|
| --- | --- |
|
|
45
|
-
| **0.7.x** (latest, 0.7.
|
|
45
|
+
| **0.7.x** (latest, 0.7.8) | 0.1.5-rc.3, 0.1.7-alpha.1, 0.1.7-alpha.2, 0.1.7-rc.1, 0.1.7-rc.2 |
|
|
46
46
|
| 0.6.x (0.6.3) | 0.1.5-rc.1, 0.1.5-rc.2 |
|
|
47
47
|
| 0.5.x (0.5.1) | 0.1.5-rc.1, 0.1.5-rc.2 |
|
|
48
48
|
| 0.4.x (0.4.1) | 0.1.5-rc.1, 0.1.5-rc.2 |
|
|
@@ -115,7 +115,7 @@ A missing `turnOutline` means the host has no such projection, and the staged `j
|
|
|
115
115
|
- Interface text lives in one string table at the top of `lib/client.js` (`DICTS`, one Chinese and one English copy) and the language setting picks between them: on `follow the host` the host's translate function (`ctx.locale.bind("dsh-quick-toc")`, fed by the same `DICTS` tables) is asked first and the built-in table is only the fallback. The two tables must stay key-aligned; the only Chinese-only entry is `time.beforeYesterday` (English carries the date for anything older than yesterday), while `time.yesterday` exists in both (`yesterday`).
|
|
116
116
|
- Preferences sit in two layers behind one module-level store: the Host settings document (language, docked edge, levels, scale, handle position, remembered reading position, fuzzy, hover and diagnostic; authoritative on a loopback page) and `localStorage` (the mirror, plus the real storage for top offset / width / height, which describe this screen and are saved per browser). **The host layer itself is one of two dialects, whichever the running host offers**: on 0.1.5-rc.3 it is `ctx.settingsScope.bind({ namespace: "dsh-quick-toc" })` (addressed by namespace), while on either 0.1.7 line (alpha and rc) it is `ctx.configForms.get(<profile entry id>)` (addressed by profile entry id, the client recognising its own entry by the schema the host serves). Both expose the same methods over the same snapshot fields, so the store stays one. Writes are routed per field: host fields go through `scope.mutate` (folded in locally, reconciled when the host answers), everything else goes to `localStorage`; a value that IS the field's default is written by removing that entry from the user layer instead (the same thing as "not customized"). On a non-loopback page DSH marks settings read-only, so those nine preferences fall back to the mirror and behave exactly as in 0.5.x; values left by a 0.5.x install are imported into the host layer once, the first time it answers (and only while the user layer is empty). Once the host has answered, that layer is authoritative — which is why a local key such as `localStorage['dsh-quick-toc.debug']` no longer takes effect on a loopback page: use the switch in the card.
|
|
117
117
|
- The curtain and the docked panel **share one list DOM**: the curtain only moves the panel itself into a full-width container that drops from the lower edge of the tab strip (in curtain mode the panel swaps to a different geometry — relative positioning, 100% width and height, no panel scale), and that container stays mounted as a zero-size pass-through while the curtain is up, so opening or closing it never rebuilds the list or loses the scroll position. Cross-session search goes through the client `ctx.get("sessions")` service's `search(query, signal)` (the host's session full-text index, at most 20 hits per search); each session's reading position lives in this browser (`dsh-quick-toc.readPos.v1`, valid for half an hour).
|
|
118
|
-
- The configuration card is registered into
|
|
118
|
+
- The configuration card is registered into all three seats at once, and which one it lands in is the running host's business: on 0.1.5-rc.3 it is `settings.plugin.item` (keyed on the plugin's namespace; the slot is dispatched only for namespaces the Host actually serves, so a deployment without the host half simply shows no card and the panel is unaffected); on either 0.1.7 line (alpha and rc) it is two places on the sidebar's Plugins page — the plugin's own entry in the Official group (`plugins.item`, `id` `quick-toc`, `label` from "Conversation Outline", `order` 50) and the configuration area of its bundle page (`plugins.bundle.config`, keyed on the npm package name). Both 0.1.7 seats hand the card a `view`, so it starts expanded there (opening the entry or the bundle page IS the expansion gesture); the rc line's configuration cell passes no props at all and keeps the collapsed list shape. Every registration happens only once a settings scope has bound, and the card and the panel share the store above, which is what makes the two live in both directions.
|
|
119
119
|
- Changes to `lib/client.js` show up after a page refresh (client modules are served under a content hash and DSH's client HMR pushes reloads); changes to `lib/index.js` (the host half) need a DSH restart
|
|
120
120
|
|
|
121
121
|
## License
|
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
| 插件版本 | 支持的 DSH 版本 |
|
|
44
44
|
| --- | --- |
|
|
45
|
-
| **0.7.x**(最新,0.7.
|
|
45
|
+
| **0.7.x**(最新,0.7.8) | 0.1.5-rc.3、0.1.7-alpha.1、0.1.7-alpha.2、0.1.7-rc.1、0.1.7-rc.2 |
|
|
46
46
|
| 0.6.x(0.6.3) | 0.1.5-rc.1、0.1.5-rc.2 |
|
|
47
47
|
| 0.5.x(0.5.1) | 0.1.5-rc.1、0.1.5-rc.2 |
|
|
48
48
|
| 0.4.x(0.4.1) | 0.1.5-rc.1、0.1.5-rc.2 |
|
|
@@ -115,7 +115,7 @@ dsh plugin --profile web add <插件目录路径>
|
|
|
115
115
|
- 界面文字来自 `lib/client.js` 顶部的一张字符串表(`DICTS`,中英各一份),语言设置决定用哪一份:`跟随宿主` 时优先问宿主的翻译函数(`ctx.locale.bind("dsh-quick-toc")`,注册的表就来自 `DICTS`),拿不到才回退到内置表。中英两份表的键必须对齐(仅 `time.beforeYesterday`(前天)是中文独有——英文对更早的时间直接用日期;`time.yesterday` 两语言都有,英文作 `yesterday`)。
|
|
116
116
|
- 偏好存储分两层,由一个模块级 store 统一读出:宿主设置文档(语言/停靠边/层级/缩放/把手位置/记住阅读位置/模糊/悬停/诊断九项,回环页面上是权威层)与 `localStorage`(镜像 + 顶边距/宽度/高度三项的正式存储——它们描述"这一块屏幕",按浏览器保存)。**宿主那一层按运行中的宿主二选一**:0.1.5-rc.3 上是 `ctx.settingsScope.bind({ namespace: "dsh-quick-toc" })`(按命名空间寻址),0.1.7 两条线(alpha 与 rc)上改成 `ctx.configForms.get(<profile entry id>)`(按 profile 条目 id 寻址,客户端按宿主实际服务的 schema 认出自己那一条);两者暴露的方法与快照字段相同,所以 store 只有一套。写入按字段路由:宿主字段走 `scope.mutate`(本地同步折叠、宿主应答后对账),其余写 `localStorage`;写入的值若正好是该字段的默认值,则改为把用户层里的这一项删掉(等同于"未自定义")。非回环页面 DSH 将设置标记为只读,此时这九项偏好退回本地镜像,行为与 0.5.x 一致;0.5.x 留下的本地值会在宿主层首次应答时导入一次(仅当用户层为空)。宿主应答之后宿主层就是权威层,因此 `localStorage['dsh-quick-toc.debug']` 这类本地键在回环页面上不再生效——诊断开关请用卡片里那一条。
|
|
117
117
|
- 幕布与停靠面板**共用同一份列表 DOM**:幕布只是把面板本体搬进一个从标签条下沿落下的整宽容器(面板在幕布态换一套几何:相对定位、宽高 100%、不套用面板缩放),容器本身常驻挂载、收起时是一个 0×0 的直通盒,所以开关幕布不会重建列表、也不会丢掉滚动位置。跨会话检索走客户端 `ctx.get("sessions")` 的 `search(query, signal)`(走宿主的会话全文索引,一次最多 20 条);每个会话的阅读位置存在浏览器本地(`dsh-quick-toc.readPos.v1`,半小时内有效)。
|
|
118
|
-
-
|
|
118
|
+
- 插件配置卡片按宿主实际提供的槽位注册,三处一起挂、装上哪一处由宿主决定:0.1.5-rc.3 上是 `settings.plugin.item`(`key` 为插件命名空间,该槽按宿主实际服务的命名空间派发,宿主半未加载时卡片自然不出现,面板不受影响);0.1.7 两条线(alpha 与 rc)上是侧边栏「插件」页的两处——「官方」分组里插件自己的条目(`plugins.item`,`id` 为 `quick-toc`,`label` 取「对话大纲」,`order` 50)与该 bundle 页面上的配置区(`plugins.bundle.config`,`key` 为 npm 包名)。0.1.7 的插件页渲染这两处时都会带上 `view`,卡片因此默认展开(点进条目或 bundle 页本身就是展开动作);rc 线的配置单元不带任何 props,卡片保持收拢的列表形态。所有注册都只在设置作用域绑定成功后才做,卡片与面板共享上面那个 store,因此两边实时互通。
|
|
119
119
|
- 修改 `lib/client.js` 后刷新页面即可看到变化(客户端模块按内容哈希发版,DSH 的客户端 HMR 也会推送重载);改 `lib/index.js`(宿主半)需重启 DSH
|
|
120
120
|
|
|
121
121
|
## License
|
package/lib/client.js
CHANGED
|
@@ -2174,6 +2174,21 @@ window.__ModuleLoader__.load({
|
|
|
2174
2174
|
setSheetOpen(true);
|
|
2175
2175
|
}
|
|
2176
2176
|
};
|
|
2177
|
+
// The drop is armed by the class the open commit writes, so its clock starts inside
|
|
2178
|
+
// that commit. On a long outline the commit is a long task of its own (the whole list
|
|
2179
|
+
// re-laid out at the curtain's width), and an animation whose 0.46s runs while its own
|
|
2180
|
+
// first frame is still being laid out is over before anything is painted — the failure
|
|
2181
|
+
// 0.7.4 fixed for the host-driven load, and the same shape of failure when the cost is
|
|
2182
|
+
// ours. Re-arming it here, with the open state already in the DOM and before the
|
|
2183
|
+
// browser paints it, puts the layout and the animation on the same frame.
|
|
2184
|
+
react.useLayoutEffect(function () {
|
|
2185
|
+
if (!sheetOpen) return;
|
|
2186
|
+
var node = sheetRef.current;
|
|
2187
|
+
if (!node || !node.style) return;
|
|
2188
|
+
node.style.animation = "none";
|
|
2189
|
+
void node.offsetWidth; // pay the commit's layout HERE, before the drop starts
|
|
2190
|
+
node.style.animation = "";
|
|
2191
|
+
}, [sheetOpen]);
|
|
2177
2192
|
// "return" only needs to exist for one painted frame: the panel renders at
|
|
2178
2193
|
// its collapsed spot, and releasing it lets the left/clip transition carry
|
|
2179
2194
|
// it back open. The tuck must NOT be released here — it is held until the
|
|
@@ -2399,6 +2414,75 @@ window.__ModuleLoader__.load({
|
|
|
2399
2414
|
try { searchRef.current.focus({ preventScroll: true }); }
|
|
2400
2415
|
catch (e) { searchRef.current.focus(); }
|
|
2401
2416
|
}, [searchOpen]);
|
|
2417
|
+
// ---- the curtain's search column: its own box, and the motion that moves it --------
|
|
2418
|
+
// `sheetColW` is how much of the curtain's row the search column claims, and it is
|
|
2419
|
+
// computed HERE (not where the column is built) so the flip effect below keeps a stable
|
|
2420
|
+
// hook list on an empty conversation too — the panel bails out further down, and a hook
|
|
2421
|
+
// added after that point would change the hook count between renders (React #310).
|
|
2422
|
+
var searchColRef = react.useRef(null);
|
|
2423
|
+
var searchGeomRef = react.useRef(null);
|
|
2424
|
+
var sheetColW = (searchOpen || searchAnim === "out") ? SHEET_SEARCH_W : 0;
|
|
2425
|
+
// The column used to animate its own WIDTH, and because the outline is the flex sibling
|
|
2426
|
+
// that grows into the rest of the row, every frame of that re-laid out every rendered row
|
|
2427
|
+
// (measured on a 34-row list: a width step per frame, ~18ms frames and a 76ms first hitch;
|
|
2428
|
+
// the cost grows with the list, which is what made opening search on a long session feel
|
|
2429
|
+
// stuck). The layout now flips in ONE commit — that single reflow is unavoidable, the text
|
|
2430
|
+
// has to re-wrap — and the movement rides on transforms, which the compositor owns:
|
|
2431
|
+
// * opening: the column starts parked off the right edge and slides home, while the list
|
|
2432
|
+
// is flipped back to where it sat before the flip and released, so the outline still
|
|
2433
|
+
// travels left into place instead of jumping there;
|
|
2434
|
+
// * closing: the column keeps its box for the exit and slides off first (the box only
|
|
2435
|
+
// collapses when the exit state ends), then the list is flipped back to full width the
|
|
2436
|
+
// same way.
|
|
2437
|
+
// Both elements are measured, never derived: the flip is the previous box minus the new one.
|
|
2438
|
+
react.useLayoutEffect(function () {
|
|
2439
|
+
var list = listRef.current;
|
|
2440
|
+
var col = searchColRef.current;
|
|
2441
|
+
if (!sheetOpen || !list || !col) { searchGeomRef.current = null; return undefined; }
|
|
2442
|
+
// `offsetLeft` is the box's own position: layout, never a transform. A rect here would
|
|
2443
|
+
// read back the very transform this effect applies, and the next commit would "flip"
|
|
2444
|
+
// from the parked position it just created (measured: the list swung 110px past its
|
|
2445
|
+
// resting spot and eased back).
|
|
2446
|
+
var layoutLeft = list.offsetLeft;
|
|
2447
|
+
var colLayout = sheetColW > 0; // the layout currently on screen
|
|
2448
|
+
var wantOpen = !!searchOpen && searchAnim !== "out"; // "out" is the exit in flight
|
|
2449
|
+
var colWidth = col.getBoundingClientRect().width;
|
|
2450
|
+
var prev = searchGeomRef.current;
|
|
2451
|
+
if (prev && prev.colLayout !== colLayout) {
|
|
2452
|
+
// the layout flipped under the reader: put the list back where it was, then release it
|
|
2453
|
+
var dx = prev.layoutLeft - layoutLeft;
|
|
2454
|
+
if (dx !== 0) {
|
|
2455
|
+
list.style.transition = "none";
|
|
2456
|
+
list.style.transform = "translateX(" + dx + "px)";
|
|
2457
|
+
requestAnimationFrame(function () {
|
|
2458
|
+
list.style.transition = "transform 0.24s " + EASE;
|
|
2459
|
+
list.style.transform = "";
|
|
2460
|
+
setTimeout(function () { list.style.transition = ""; }, 320);
|
|
2461
|
+
});
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
if (prev && prev.wantOpen !== wantOpen) {
|
|
2465
|
+
if (wantOpen) {
|
|
2466
|
+
// parked just off the row's right edge, then slid home by the transition
|
|
2467
|
+
col.style.transition = "none";
|
|
2468
|
+
col.style.transform = "translateX(" + (colWidth || SHEET_SEARCH_W) + "px)";
|
|
2469
|
+
requestAnimationFrame(function () {
|
|
2470
|
+
col.style.transition = "transform 0.24s " + EASE;
|
|
2471
|
+
col.style.transform = "";
|
|
2472
|
+
});
|
|
2473
|
+
} else {
|
|
2474
|
+
// out it goes while its box is still there; the box collapses when the exit ends
|
|
2475
|
+
col.style.transition = "transform 0.24s " + EASE;
|
|
2476
|
+
col.style.transform = "translateX(" + (colWidth || SHEET_SEARCH_W) + "px)";
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
if (colWidth === 0) {
|
|
2480
|
+
col.style.transition = "none";
|
|
2481
|
+
col.style.transform = "";
|
|
2482
|
+
}
|
|
2483
|
+
searchGeomRef.current = { colLayout: colLayout, layoutLeft: layoutLeft, wantOpen: wantOpen };
|
|
2484
|
+
return undefined;
|
|
2485
|
+
}, [sheetOpen, sheetColW, searchOpen, searchAnim]);
|
|
2402
2486
|
var onQueryChange = function (v) {
|
|
2403
2487
|
setQuery(v);
|
|
2404
2488
|
setMatchIdx(0);
|
|
@@ -5521,12 +5605,11 @@ window.__ModuleLoader__.load({
|
|
|
5521
5605
|
});
|
|
5522
5606
|
// ---- curtain search column: pushed in from the right edge -----------------
|
|
5523
5607
|
// The panel's own search box and its two buttons, then the hits below them.
|
|
5524
|
-
//
|
|
5525
|
-
//
|
|
5526
|
-
//
|
|
5527
|
-
// curtain is up so both directions animate.
|
|
5528
|
-
var sheetColW = (searchOpen || searchAnim === "out") ? SHEET_SEARCH_W : 0;
|
|
5608
|
+
// The column's WIDTH is what makes room (see `sheetColW` above), an inner box keeps the
|
|
5609
|
+
// full width so the content never squashes while the column narrows, and the column is
|
|
5610
|
+
// always mounted while the curtain is up so both directions animate.
|
|
5529
5611
|
var sheetSearchColEl = sheetOpen ? react_jsx_runtime.jsx("div", {
|
|
5612
|
+
ref: searchColRef,
|
|
5530
5613
|
className: "dqt-sheet-search",
|
|
5531
5614
|
"data-sheet-search": sheetColW > 0 ? "on" : undefined,
|
|
5532
5615
|
style: {
|
|
@@ -5534,8 +5617,7 @@ window.__ModuleLoader__.load({
|
|
|
5534
5617
|
width: sheetColW,
|
|
5535
5618
|
overflow: "hidden",
|
|
5536
5619
|
minHeight: 0,
|
|
5537
|
-
borderLeft: sheetColW > 0 ? "1px solid " + C.panelBorder : "none"
|
|
5538
|
-
transition: "width 0.24s " + EASE + ", border-color 0.24s " + EASE
|
|
5620
|
+
borderLeft: sheetColW > 0 ? "1px solid " + C.panelBorder : "none"
|
|
5539
5621
|
},
|
|
5540
5622
|
children: react_jsx_runtime.jsx("div", {
|
|
5541
5623
|
style: { width: SHEET_SEARCH_W, height: "100%", display: "flex", flexDirection: "column", minHeight: 0 },
|
|
@@ -6963,13 +7045,17 @@ window.__ModuleLoader__.load({
|
|
|
6963
7045
|
// live in both directions. The chrome mirrors the section's own card (radii,
|
|
6964
7046
|
// borders, spacing, tokens) because a plugin bundle cannot import the section's
|
|
6965
7047
|
// CSS module.
|
|
6966
|
-
function TocSettingsCard() {
|
|
7048
|
+
function TocSettingsCard(props) {
|
|
6967
7049
|
var prefs = usePrefs();
|
|
6968
7050
|
setLanguage(prefs.lang, hostLanguage());
|
|
6969
7051
|
var snap = prefsStore.host();
|
|
6970
7052
|
var writable = !!snap && snap.writable === true;
|
|
6971
7053
|
var user = snap && snap.user && typeof snap.user === "object" ? snap.user : {};
|
|
6972
|
-
|
|
7054
|
+
// Start open where the seat already opened the section: the 0.1.7 plugin pages hand the
|
|
7055
|
+
// card a `view` (the reader clicked into the entry or the bundle page to get here), so
|
|
7056
|
+
// making them click the card's own header after that was a second expansion for nothing.
|
|
7057
|
+
// The rc line's configuration cell passes no props and keeps the collapsed list shape.
|
|
7058
|
+
var openState = react.useState(!!(props && (props.defaultOpen === true || props.view === "page")));
|
|
6973
7059
|
var open = openState[0];
|
|
6974
7060
|
var setOpen = openState[1];
|
|
6975
7061
|
var commit = function (patch) { prefsStore.set(patch); };
|
|
@@ -7184,6 +7270,16 @@ window.__ModuleLoader__.load({
|
|
|
7184
7270
|
});
|
|
7185
7271
|
}
|
|
7186
7272
|
|
|
7273
|
+
// The 0.1.7 Plugins page's own entry for this plugin (`plugins.item`). That seat asks one
|
|
7274
|
+
// component for two views: a one-line `summary` for the entry in its Official group, and
|
|
7275
|
+
// the `page` body once the entry is opened. The summary answers with the card's own
|
|
7276
|
+
// description and every other view is the card itself, already open — the click that
|
|
7277
|
+
// opened the entry IS the expansion gesture.
|
|
7278
|
+
function TocCardPage(props) {
|
|
7279
|
+
if (props && props.view === "summary") return T("settings.desc");
|
|
7280
|
+
return react_jsx_runtime.jsx(TocSettingsCard, { defaultOpen: true });
|
|
7281
|
+
}
|
|
7282
|
+
|
|
7187
7283
|
// Declared client services only. `slots` and `locale` exist on every supported line;
|
|
7188
7284
|
// the settings service is looked up with `ctx.get` instead (see `pickSettingsScope`),
|
|
7189
7285
|
// because declaring a name a host does not provide parks the whole package.
|
|
@@ -7396,6 +7492,21 @@ window.__ModuleLoader__.load({
|
|
|
7396
7492
|
locale: "dsh-quick-toc"
|
|
7397
7493
|
}, TocSettingsCard);
|
|
7398
7494
|
});
|
|
7495
|
+
// 0.1.7's Plugins page lists one entry per plugin in its Official group
|
|
7496
|
+
// (`plugins.item`), which is where the reader looks for our settings there — the
|
|
7497
|
+
// earlier line's keyed configuration cell (`settings.plugin.item`) no longer exists
|
|
7498
|
+
// on that host, so without this seat the card had nowhere to appear. `id` names the
|
|
7499
|
+
// entry, `label` is its line in the group, and `order` places it after the host's
|
|
7500
|
+
// own pages (shell 10 / agent loop 20 / subagent 30 / web search 40).
|
|
7501
|
+
ctx.slots.inject("plugins.item", function () {
|
|
7502
|
+
return ctx.slots.register({
|
|
7503
|
+
name: "plugins.item",
|
|
7504
|
+
id: "quick-toc",
|
|
7505
|
+
order: 50,
|
|
7506
|
+
label: function () { return T("panel.title"); },
|
|
7507
|
+
locale: "dsh-quick-toc"
|
|
7508
|
+
}, TocCardPage);
|
|
7509
|
+
});
|
|
7399
7510
|
ctx.slots.inject("settings.plugin.item", function () {
|
|
7400
7511
|
return ctx.slots.register({
|
|
7401
7512
|
name: "settings.plugin.item",
|
|
@@ -7444,13 +7555,14 @@ window.__ModuleLoader__.load({
|
|
|
7444
7555
|
// The plugin-configuration card, in whichever seat the running host offers:
|
|
7445
7556
|
// * up to rc.2 it is a keyed `settings.plugin.item` cell under
|
|
7446
7557
|
// Settings → Plugins → Plugin configuration, keyed by the settings namespace;
|
|
7447
|
-
// * on the
|
|
7448
|
-
//
|
|
7449
|
-
// (`plugins.bundle.config
|
|
7450
|
-
// `<package>#<row id>`) exists too, but a
|
|
7451
|
-
// page in 0.1.7-alpha.1 while the bundle
|
|
7452
|
-
// plugin's, not one row's, so the
|
|
7453
|
-
//
|
|
7558
|
+
// * on 0.1.7 the Plugins page's Official group lists one entry per plugin
|
|
7559
|
+
// (`plugins.item`) and the bundle page carries the bundle's own configuration
|
|
7560
|
+
// (`plugins.bundle.config`, keyed by the npm package name). A row-level cell
|
|
7561
|
+
// (`plugins.row.config`, keyed `<package>#<row id>`) exists too, but a
|
|
7562
|
+
// registration there did not reach that page in 0.1.7-alpha.1 while the bundle
|
|
7563
|
+
// cell did — and these preferences are the plugin's, not one row's, so the
|
|
7564
|
+
// bundle page is the right seat for them.
|
|
7565
|
+
// Registering into a slot a given host never declares is inert, so all three are
|
|
7454
7566
|
// offered together, once the host layer bound (or the fallback timer fired).
|
|
7455
7567
|
}
|
|
7456
7568
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-quick-toc",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.8",
|
|
4
4
|
"description": "Conversation TOC for DeepSeek Harness (DSH): a whole-session, turn-grouped Markdown outline with hover previews, a level filter, a full-width curtain, jump-to-end buttons, title/full-text/cross-session search and a Chinese/English interface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"0.1.5-rc.3": "compatible",
|
|
39
39
|
"0.1.7-alpha.1": "compatible",
|
|
40
40
|
"0.1.7-alpha.2": "compatible",
|
|
41
|
-
"0.1.7-rc.1": "compatible"
|
|
41
|
+
"0.1.7-rc.1": "compatible",
|
|
42
|
+
"0.1.7-rc.2": "compatible"
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
},
|