dsh-quick-toc 0.10.1 → 0.10.2
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 +12 -0
- package/CHANGELOG.md +12 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/client.js +153 -38
- package/package.json +1 -1
package/CHANGELOG.en.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to **dsh-quick-toc** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
|
|
4
4
|
|
|
5
|
+
## [0.10.2] - 2026-10-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **A bookmarks panel on the curtain**: the curtain's toolbar has a bookmarks button on the left, beside the settings button; it slides in from the right in the same drawer the search uses, and the outline stays where it is instead of being replaced.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **The theme colour reaches more places**: hovering an entry paints its hierarchy guide in the theme colour, the search box takes it as a focus border, the hover preview card carries a theme-coloured bar on its reading side, and a pinned card's ring gets a filled core in the same colour.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **The theme colour came out black in a light theme**: with blue chosen, the plugin borrowed the host's accent colour, which is near-black ink in a light theme — so the guides, the search border, the card's bar and the pin's core all turned black. All six colours now use values of the plugin's own.
|
|
15
|
+
- **The curtain's landing bounce opened an unblurred seam along its top edge**: the settle now stretches downward from the top edge, so the top never leaves the line it hangs from.
|
|
16
|
+
|
|
5
17
|
## [0.10.1] - 2026-10-21
|
|
6
18
|
|
|
7
19
|
### Fixed
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
**dsh-quick-toc** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
|
|
4
4
|
|
|
5
|
+
## [0.10.2] - 2026-10-22
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
- **幕布的书签栏**:幕布的工具行左侧(设置按钮右边)新增一个书签按钮,点开后书签从右侧滑出,与搜索共用同一个抽屉;大纲原地保留,不再被整块替换。
|
|
9
|
+
|
|
10
|
+
### 变更
|
|
11
|
+
- **主题色覆盖更多位置**:悬停条目时它的层级引导线转为主题色,搜索框聚焦时边框转为主题色,悬停预览卡片的左侧有一条主题色竖条,钉住后的圆环核心也是主题色。
|
|
12
|
+
|
|
13
|
+
### 修复
|
|
14
|
+
- **浅色主题下主题色显示为黑色**:主题色选蓝色时,插件取用的是宿主界面的强调色,而浅色主题里那个值是近黑色,于是引导线、搜索框描边、卡片竖条与钉住圆环都变黑了;现在六种颜色都使用插件自己的色值。
|
|
15
|
+
- **幕布落下回弹时顶部露出一条没有模糊的缝隙**:回弹改为从顶边向下伸展,顶部不再离开它悬挂的那条线。
|
|
16
|
+
|
|
5
17
|
## [0.10.1] - 2026-10-21
|
|
6
18
|
|
|
7
19
|
### 修复
|
package/README.en.md
CHANGED
|
@@ -44,7 +44,7 @@ A conversation TOC plugin for [DeepSeek Harness](https://github.com/deepseek-ai/
|
|
|
44
44
|
|
|
45
45
|
| Plugin | Supported DSH |
|
|
46
46
|
| --- | --- |
|
|
47
|
-
| **0.10.x** (latest, 0.10.
|
|
47
|
+
| **0.10.x** (latest, 0.10.2) | 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, 0.2.0-rc.1, 0.2.0-rc.2, 0.2.1-alpha.1, 0.2.1-alpha.2, 0.2.1-alpha.3, 0.2.1-alpha.4, 0.2.1-alpha.5, 0.2.1-rc.1, 0.2.1-rc.2 |
|
|
48
48
|
| **0.9.x** (0.9.5) | 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, 0.2.0-rc.1, 0.2.0-rc.2, 0.2.1-alpha.1, 0.2.1-alpha.2, 0.2.1-alpha.3, 0.2.1-alpha.4, 0.2.1-alpha.5 |
|
|
49
49
|
| 0.8.x (0.8.2) | 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, 0.2.0-rc.1, 0.2.0-rc.2 |
|
|
50
50
|
| 0.7.x (0.7.14) | 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, 0.2.0-rc.1, 0.2.0-rc.2 |
|
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
| 插件版本 | 支持的 DSH 版本 |
|
|
46
46
|
| --- | --- |
|
|
47
|
-
| **0.10.x**(最新,0.10.
|
|
47
|
+
| **0.10.x**(最新,0.10.2) | 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、0.2.0-rc.1、0.2.0-rc.2、0.2.1-alpha.1、0.2.1-alpha.2、0.2.1-alpha.3、0.2.1-alpha.4、0.2.1-alpha.5、0.2.1-rc.1、0.2.1-rc.2 |
|
|
48
48
|
| **0.9.x**(0.9.5) | 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、0.2.0-rc.1、0.2.0-rc.2、0.2.1-alpha.1、0.2.1-alpha.2、0.2.1-alpha.3、0.2.1-alpha.4、0.2.1-alpha.5 |
|
|
49
49
|
| 0.8.x(0.8.2) | 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、0.2.0-rc.1、0.2.0-rc.2 |
|
|
50
50
|
| 0.7.x(0.7.14) | 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、0.2.0-rc.1、0.2.0-rc.2 |
|
package/lib/client.js
CHANGED
|
@@ -179,6 +179,8 @@ window.__ModuleLoader__.load({
|
|
|
179
179
|
"marks.tip.only": "只看书签({n})",
|
|
180
180
|
"marks.tip.all": "显示全部大纲(书签 {n})",
|
|
181
181
|
"marks.empty": "还没有书签。右键任意条目,选「加入书签」即可。",
|
|
182
|
+
"marks.title": "书签",
|
|
183
|
+
"marks.tip.col": "书签栏({n})",
|
|
182
184
|
"menu.goto": "跳到这一节",
|
|
183
185
|
"menu.mark": "加入书签",
|
|
184
186
|
"menu.unmark": "移出书签",
|
|
@@ -309,6 +311,8 @@ window.__ModuleLoader__.load({
|
|
|
309
311
|
"marks.tip.only": "Show bookmarks only ({n})",
|
|
310
312
|
"marks.tip.all": "Show the whole outline ({n} bookmarked)",
|
|
311
313
|
"marks.empty": "No bookmarks yet. Right-click any entry and choose \u201cAdd bookmark\u201d.",
|
|
314
|
+
"marks.title": "Bookmarks",
|
|
315
|
+
"marks.tip.col": "Bookmarks panel ({n})",
|
|
312
316
|
"menu.goto": "Jump to this section",
|
|
313
317
|
"menu.mark": "Add bookmark",
|
|
314
318
|
"menu.unmark": "Remove bookmark",
|
|
@@ -470,7 +474,12 @@ window.__ModuleLoader__.load({
|
|
|
470
474
|
// triplet with a solid that stays legible on both light and dark surfaces
|
|
471
475
|
// (the dot shows the vivid hue; the solid is the readable one).
|
|
472
476
|
var ACCENTS = {
|
|
473
|
-
|
|
477
|
+
// Every option is SELF-CONTAINED, blue included. Blue used to borrow the host's
|
|
478
|
+
// `--dsw-alias-brand-primary`; in a light theme that token is near-black ink, so
|
|
479
|
+
// picking "blue" painted the hierarchy guides, the search ring, the preview
|
|
480
|
+
// card's bar and the pin's core BLACK. The theme colour is the plugin's own
|
|
481
|
+
// decision, so it does not defer to the host's brand token at all.
|
|
482
|
+
blue: { rgb: "79, 140, 255", solid: "#4F8CFF", dot: "#4f8cff" },
|
|
474
483
|
red: { rgb: "245, 72, 77", solid: "#F5484D", dot: "#F5484D" },
|
|
475
484
|
yellow: { rgb: "232, 162, 12", solid: "#D99300", dot: "#FFB020" },
|
|
476
485
|
green: { rgb: "48, 164, 108", solid: "#2FA36B", dot: "#2FA36B" },
|
|
@@ -496,10 +505,13 @@ window.__ModuleLoader__.load({
|
|
|
496
505
|
// injected base, which keeps today's values as its fallback.
|
|
497
506
|
var accentCssText = function (id) {
|
|
498
507
|
var t = ACCENTS[normAccent(id)] || ACCENTS.blue;
|
|
499
|
-
var solid = t.solid || "
|
|
508
|
+
var solid = t.solid || "#4F8CFF";
|
|
500
509
|
return ".dqt-nav{box-shadow:inset 0 0 0 1px " + solid + ";background:rgba(" + t.rgb + ",0.10)}"
|
|
501
510
|
+ ".dqt-phead:focus-visible{outline-color:" + solid + "}"
|
|
502
|
-
+ ".dqt-slider{accent-color:" + solid + "}"
|
|
511
|
+
+ ".dqt-slider{accent-color:" + solid + "}"
|
|
512
|
+
// the search pill takes the theme colour the moment the caret is in it, so the
|
|
513
|
+
// box and the hit marks below it agree on which search is running
|
|
514
|
+
+ ".dqt-search-pill:focus-within{background:rgba(" + t.rgb + ",0.12);box-shadow:inset 0 0 0 1px " + solid + "}";
|
|
503
515
|
};
|
|
504
516
|
var applyAccentCss = function (id) {
|
|
505
517
|
if (typeof document === "undefined") return;
|
|
@@ -2165,7 +2177,10 @@ window.__ModuleLoader__.load({
|
|
|
2165
2177
|
panelBorder: "var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25))",
|
|
2166
2178
|
text: "var(--dsw-alias-label-primary, #e8eaee)",
|
|
2167
2179
|
muted: "var(--dsw-alias-label-secondary, #9aa0ab)",
|
|
2168
|
-
|
|
2180
|
+
// the plugin's own blue, NOT the host's brand token: that token is near-black
|
|
2181
|
+
// in light themes, and every accent piece (guides, search ring, preview bar,
|
|
2182
|
+
// pin core) turned black with it
|
|
2183
|
+
accent: "#4F8CFF",
|
|
2169
2184
|
// the selection triplet, for callers that paint their own alphas (search
|
|
2170
2185
|
// hit marks): same hue as every tint above, in one place
|
|
2171
2186
|
accentRgb: "79,140,255",
|
|
@@ -3235,6 +3250,8 @@ window.__ModuleLoader__.load({
|
|
|
3235
3250
|
sheetTimerRef.current = setTimeout(function () {
|
|
3236
3251
|
sheetTimerRef.current = null;
|
|
3237
3252
|
setSheetOpen(false);
|
|
3253
|
+
// the column only exists across the curtain: a later drop starts closed
|
|
3254
|
+
setMarksCol(false);
|
|
3238
3255
|
// the panel was open before the curtain: slide it back in instead of
|
|
3239
3256
|
// letting it pop into place (the reader saw that pop as a flash)
|
|
3240
3257
|
if (open) setPanelAside("return");
|
|
@@ -3658,9 +3675,24 @@ window.__ModuleLoader__.load({
|
|
|
3658
3675
|
return function () { clearTimeout(timer); };
|
|
3659
3676
|
}, [dock, panelY, panelW, panelH, levels, fuzzy]);
|
|
3660
3677
|
|
|
3678
|
+
// ---- the curtain's bookmarks column --------------------------------------
|
|
3679
|
+
// ONE drawer, two tenants. The search column is measured and slid from the
|
|
3680
|
+
// right edge (see the flip effect above); the bookmarks ride the very same box,
|
|
3681
|
+
// motion and width, so the curtain needs no second mechanism. Opening either
|
|
3682
|
+
// tenant takes the other's place, and the docked panel keeps its star button
|
|
3683
|
+
// and full-view overlay — there the outline has no column to share.
|
|
3684
|
+
var _sMarksCol = react.useState(false);
|
|
3685
|
+
var marksCol = _sMarksCol[0];
|
|
3686
|
+
var setMarksCol = _sMarksCol[1];
|
|
3687
|
+
var toggleMarksCol = function () {
|
|
3688
|
+
if (marksCol) { setMarksCol(false); return; }
|
|
3689
|
+
setMarksCol(true);
|
|
3690
|
+
if (searchOpen) closeSearch();
|
|
3691
|
+
};
|
|
3661
3692
|
var openSearch = function () {
|
|
3662
3693
|
setSearchOpen(true);
|
|
3663
3694
|
setSearchAnim("enter");
|
|
3695
|
+
if (marksCol) setMarksCol(false);
|
|
3664
3696
|
};
|
|
3665
3697
|
var closeSearch = function () {
|
|
3666
3698
|
setSearchAnim("out");
|
|
@@ -3692,7 +3724,7 @@ window.__ModuleLoader__.load({
|
|
|
3692
3724
|
// added after that point would change the hook count between renders (React #310).
|
|
3693
3725
|
var searchColRef = react.useRef(null);
|
|
3694
3726
|
var searchGeomRef = react.useRef(null);
|
|
3695
|
-
var sheetColW = (searchOpen || searchAnim === "out") ? SHEET_SEARCH_W : 0;
|
|
3727
|
+
var sheetColW = (searchOpen || marksCol || searchAnim === "out") ? SHEET_SEARCH_W : 0;
|
|
3696
3728
|
// The column used to animate its own WIDTH, and because the outline is the flex sibling
|
|
3697
3729
|
// that grows into the rest of the row, every frame of that re-laid out every rendered row
|
|
3698
3730
|
// (measured on a 34-row list: a width step per frame, ~18ms frames and a 76ms first hitch;
|
|
@@ -3716,7 +3748,7 @@ window.__ModuleLoader__.load({
|
|
|
3716
3748
|
// resting spot and eased back).
|
|
3717
3749
|
var layoutLeft = list.offsetLeft;
|
|
3718
3750
|
var colLayout = sheetColW > 0; // the layout currently on screen
|
|
3719
|
-
var wantOpen = !!searchOpen && searchAnim !== "out"; // "out" is the exit in flight
|
|
3751
|
+
var wantOpen = (!!searchOpen && searchAnim !== "out") || !!marksCol; // "out" is the exit in flight
|
|
3720
3752
|
var colWidth = col.getBoundingClientRect().width;
|
|
3721
3753
|
var prev = searchGeomRef.current;
|
|
3722
3754
|
if (prev && prev.colLayout !== colLayout) {
|
|
@@ -3753,7 +3785,7 @@ window.__ModuleLoader__.load({
|
|
|
3753
3785
|
}
|
|
3754
3786
|
searchGeomRef.current = { colLayout: colLayout, layoutLeft: layoutLeft, wantOpen: wantOpen };
|
|
3755
3787
|
return undefined;
|
|
3756
|
-
}, [sheetOpen, sheetColW, searchOpen, searchAnim]);
|
|
3788
|
+
}, [sheetOpen, sheetColW, searchOpen, searchAnim, marksCol]);
|
|
3757
3789
|
var onQueryChange = function (v) {
|
|
3758
3790
|
setQuery(v);
|
|
3759
3791
|
setMatchIdx(0);
|
|
@@ -6524,6 +6556,23 @@ window.__ModuleLoader__.load({
|
|
|
6524
6556
|
// twenty-pixel star, and a squeezed digit is worse than none). The count lives
|
|
6525
6557
|
// in the tooltip a moment later, where it has a line of its own.
|
|
6526
6558
|
var markCount = marks.length > 99 ? "99+" : String(marks.length);
|
|
6559
|
+
// the star, drawn once: the docked header's 15px face and the curtain's larger
|
|
6560
|
+
// one are the same glyph at two sizes
|
|
6561
|
+
var starIcon = function (size) {
|
|
6562
|
+
return react_jsx_runtime.jsx("svg", {
|
|
6563
|
+
width: size, height: size, viewBox: "0 0 24 24",
|
|
6564
|
+
style: { display: "block" },
|
|
6565
|
+
children: react_jsx_runtime.jsx("path", {
|
|
6566
|
+
// rounded joins (a stroke in the same colour as the fill) soften the
|
|
6567
|
+
// five points; without it the star reads as a spiky asterisk at this size
|
|
6568
|
+
d: "M12 3.1l2.72 5.52 6.09.89-4.4 4.29 1.04 6.06L12 16.9l-5.45 2.86 1.04-6.06-4.4-4.29 6.09-.89z",
|
|
6569
|
+
fill: "currentColor",
|
|
6570
|
+
stroke: "currentColor",
|
|
6571
|
+
strokeWidth: 2.4,
|
|
6572
|
+
strokeLinejoin: "round"
|
|
6573
|
+
})
|
|
6574
|
+
});
|
|
6575
|
+
};
|
|
6527
6576
|
var marksTip = onlyMarks
|
|
6528
6577
|
? Tp("marks.tip.all", { n: markCount })
|
|
6529
6578
|
: Tp("marks.tip.only", { n: markCount });
|
|
@@ -6548,21 +6597,14 @@ window.__ModuleLoader__.load({
|
|
|
6548
6597
|
padding: 0,
|
|
6549
6598
|
transition: "background 0.18s ease, color 0.18s ease"
|
|
6550
6599
|
},
|
|
6551
|
-
children:
|
|
6552
|
-
key: "star",
|
|
6553
|
-
width: 15, height: 15, viewBox: "0 0 24 24",
|
|
6554
|
-
style: { display: "block" },
|
|
6555
|
-
children: react_jsx_runtime.jsx("path", {
|
|
6556
|
-
// rounded joins (a stroke in the same colour as the fill) soften the
|
|
6557
|
-
// five points; without it the star reads as a spiky asterisk at this size
|
|
6558
|
-
d: "M12 3.1l2.72 5.52 6.09.89-4.4 4.29 1.04 6.06L12 16.9l-5.45 2.86 1.04-6.06-4.4-4.29 6.09-.89z",
|
|
6559
|
-
fill: "currentColor",
|
|
6560
|
-
stroke: "currentColor",
|
|
6561
|
-
strokeWidth: 2.4,
|
|
6562
|
-
strokeLinejoin: "round"
|
|
6563
|
-
})
|
|
6564
|
-
})
|
|
6600
|
+
children: starIcon(15)
|
|
6565
6601
|
}, "marks-btn");
|
|
6602
|
+
// the curtain's way into the bookmarks: the docked header's star, at the
|
|
6603
|
+
// curtain's own scale (toolBtn), sliding the drawer in from the right exactly
|
|
6604
|
+
// like the magnifier does. It sits in the LEFT pair, right of the settings
|
|
6605
|
+
// button (the docked header's arrangement), not next to the search
|
|
6606
|
+
var sheetMarksBtnEl = toolBtn("marks", "dqt-sheet-marks-btn", toggleMarksCol,
|
|
6607
|
+
Tp("marks.tip.col", { n: markCount }), marksCol, false, starIcon(tbIconLg));
|
|
6566
6608
|
// the curtain keeps its own entry point: the water-drop handle on the top
|
|
6567
6609
|
// edge (sheet.openHandle). The toolbar's curtain button is gone — the header
|
|
6568
6610
|
// is four controls now.
|
|
@@ -6584,8 +6626,10 @@ window.__ModuleLoader__.load({
|
|
|
6584
6626
|
cursor: "pointer"
|
|
6585
6627
|
},
|
|
6586
6628
|
onMouseEnter: function (e) {
|
|
6587
|
-
|
|
6588
|
-
|
|
6629
|
+
// C.chip / C.accent, not the host's brand variables: this button used to stay
|
|
6630
|
+
// blue whatever theme colour the reader picked
|
|
6631
|
+
e.currentTarget.style.background = C.chip;
|
|
6632
|
+
e.currentTarget.style.color = C.accent;
|
|
6589
6633
|
},
|
|
6590
6634
|
onMouseLeave: function (e) {
|
|
6591
6635
|
e.currentTarget.style.background = "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.16))";
|
|
@@ -6698,7 +6742,10 @@ window.__ModuleLoader__.load({
|
|
|
6698
6742
|
children: [
|
|
6699
6743
|
react_jsx_runtime.jsx("div", {
|
|
6700
6744
|
style: { position: "relative", display: "flex", alignItems: "center", gap: 8, flex: "none" },
|
|
6701
|
-
|
|
6745
|
+
// settings first, then the bookmarks: the LEFT pair is "what the outline
|
|
6746
|
+
// holds", the right pair is "how you look through it" (search) and the way
|
|
6747
|
+
// out — the same split the docked header uses
|
|
6748
|
+
children: [settingsBtnEl, sheetMarksBtnEl]
|
|
6702
6749
|
}),
|
|
6703
6750
|
react_jsx_runtime.jsx("div", { style: { flex: "1 1 auto", minWidth: 0 } }),
|
|
6704
6751
|
searchBtnEl,
|
|
@@ -6806,6 +6853,7 @@ window.__ModuleLoader__.load({
|
|
|
6806
6853
|
// input with a custom animated placeholder: the box stays static,
|
|
6807
6854
|
// only the placeholder text fades when the scope switches
|
|
6808
6855
|
react_jsx_runtime.jsx("div", {
|
|
6856
|
+
className: "dqt-search-pill",
|
|
6809
6857
|
style: {
|
|
6810
6858
|
position: "relative",
|
|
6811
6859
|
flex: 1,
|
|
@@ -7017,7 +7065,7 @@ window.__ModuleLoader__.load({
|
|
|
7017
7065
|
// target lookup, the keyboard cursor, the follow). A saved place needs a label
|
|
7018
7066
|
// and a click — nothing else.
|
|
7019
7067
|
var markRowsEl = null;
|
|
7020
|
-
if (onlyMarks && !resultsEl) {
|
|
7068
|
+
if ((onlyMarks || marksCol) && !resultsEl) {
|
|
7021
7069
|
// `dense` is a local of the row renderers, not of this component: read the
|
|
7022
7070
|
// preference here instead (referencing the other one threw and took the
|
|
7023
7071
|
// whole panel down with it).
|
|
@@ -7111,7 +7159,7 @@ window.__ModuleLoader__.load({
|
|
|
7111
7159
|
// the moment the shorter list rendered, and putting the offset back afterwards
|
|
7112
7160
|
// was a race the browser usually won.
|
|
7113
7161
|
var marksOverlayEl = null;
|
|
7114
|
-
if (onlyMarks && !resultsEl) {
|
|
7162
|
+
if (onlyMarks && !resultsEl && !marksCol) {
|
|
7115
7163
|
marksOverlayEl = react_jsx_runtime.jsx("div", {
|
|
7116
7164
|
className: "dqt-marks-overlay",
|
|
7117
7165
|
style: {
|
|
@@ -7145,8 +7193,9 @@ window.__ModuleLoader__.load({
|
|
|
7145
7193
|
"aria-label": T("a11y.list"),
|
|
7146
7194
|
style: {
|
|
7147
7195
|
// hidden rather than unmounted while the bookmark view is up (see above):
|
|
7148
|
-
// it keeps its height and therefore its scroll offset
|
|
7149
|
-
|
|
7196
|
+
// it keeps its height and therefore its scroll offset. In the curtain the
|
|
7197
|
+
// bookmarks live in their own column, so the outline stays visible.
|
|
7198
|
+
visibility: onlyMarks && !resultsEl && !marksCol ? "hidden" : undefined,
|
|
7150
7199
|
overflowY: "auto",
|
|
7151
7200
|
// We are the only thing that holds the reader's place in this list (see the
|
|
7152
7201
|
// paging block): the browser's own scroll anchoring would also adjust
|
|
@@ -7203,6 +7252,7 @@ window.__ModuleLoader__.load({
|
|
|
7203
7252
|
ref: searchColRef,
|
|
7204
7253
|
className: "dqt-sheet-search",
|
|
7205
7254
|
"data-sheet-search": sheetColW > 0 ? "on" : undefined,
|
|
7255
|
+
"data-sheet-marks": marksCol ? "on" : undefined,
|
|
7206
7256
|
style: {
|
|
7207
7257
|
flex: "none",
|
|
7208
7258
|
width: sheetColW,
|
|
@@ -7212,14 +7262,45 @@ window.__ModuleLoader__.load({
|
|
|
7212
7262
|
},
|
|
7213
7263
|
children: react_jsx_runtime.jsx("div", {
|
|
7214
7264
|
style: { width: SHEET_SEARCH_W, height: "100%", display: "flex", flexDirection: "column", minHeight: 0 },
|
|
7215
|
-
children: [
|
|
7265
|
+
children: marksCol ? [
|
|
7266
|
+
// the same column, the other tenant: a quiet title line with the count,
|
|
7267
|
+
// then the saved rows. No controls — the star in the chrome closes it.
|
|
7268
|
+
react_jsx_runtime.jsx("div", {
|
|
7269
|
+
key: "col-marks-head",
|
|
7270
|
+
style: {
|
|
7271
|
+
flex: "none",
|
|
7272
|
+
display: "flex",
|
|
7273
|
+
alignItems: "center",
|
|
7274
|
+
gap: 8,
|
|
7275
|
+
padding: "10px 12px 9px",
|
|
7276
|
+
borderBottom: "1px solid " + C.panelBorder,
|
|
7277
|
+
fontSize: 12.5,
|
|
7278
|
+
fontWeight: 600,
|
|
7279
|
+
color: C.text
|
|
7280
|
+
},
|
|
7281
|
+
children: [
|
|
7282
|
+
react_jsx_runtime.jsx("span", { key: "t", children: T("marks.title") }, "mh-t"),
|
|
7283
|
+
react_jsx_runtime.jsx("span", {
|
|
7284
|
+
key: "n",
|
|
7285
|
+
style: { fontSize: 11, fontWeight: 400, color: C.muted },
|
|
7286
|
+
children: markCount
|
|
7287
|
+
}, "mh-n")
|
|
7288
|
+
]
|
|
7289
|
+
}),
|
|
7290
|
+
react_jsx_runtime.jsx("div", {
|
|
7291
|
+
key: "col-marks-body",
|
|
7292
|
+
className: "dqt-sheet-marks-body",
|
|
7293
|
+
style: { flex: "1 1 auto", minHeight: 0, overflowY: "auto", padding: "2px 6px 8px" },
|
|
7294
|
+
children: markRowsEl
|
|
7295
|
+
})
|
|
7296
|
+
] : [
|
|
7216
7297
|
searchRowEl,
|
|
7217
7298
|
// empty until something is typed — no placeholder note in the way
|
|
7218
7299
|
react_jsx_runtime.jsx("div", {
|
|
7219
7300
|
className: "dqt-sheet-results",
|
|
7220
7301
|
style: { flex: "1 1 auto", minHeight: 0, overflowY: "auto", padding: "0 8px 8px", direction: "ltr" },
|
|
7221
7302
|
children: resultsEl
|
|
7222
|
-
})
|
|
7303
|
+
}, "col-results")
|
|
7223
7304
|
]
|
|
7224
7305
|
})
|
|
7225
7306
|
}) : null;
|
|
@@ -7974,7 +8055,30 @@ window.__ModuleLoader__.load({
|
|
|
7974
8055
|
fontSize: 11,
|
|
7975
8056
|
lineHeight: "20px"
|
|
7976
8057
|
},
|
|
7977
|
-
|
|
8058
|
+
// A ring with a FILLED core, drawn rather than typed: the ◉/○ glyphs
|
|
8059
|
+
// could only be one colour, and the pin's filled state is exactly the
|
|
8060
|
+
// place the theme colour should show. Outline only when it is not pinned.
|
|
8061
|
+
children: [react_jsx_runtime.jsx("svg", {
|
|
8062
|
+
key: "pin-ico",
|
|
8063
|
+
width: 13,
|
|
8064
|
+
height: 13,
|
|
8065
|
+
viewBox: "0 0 16 16",
|
|
8066
|
+
style: { display: "block" },
|
|
8067
|
+
fill: "none",
|
|
8068
|
+
children: [
|
|
8069
|
+
react_jsx_runtime.jsx("circle", {
|
|
8070
|
+
key: "ring",
|
|
8071
|
+
cx: 8, cy: 8, r: 5.4,
|
|
8072
|
+
stroke: "currentColor",
|
|
8073
|
+
strokeWidth: 1.4
|
|
8074
|
+
}),
|
|
8075
|
+
opts.pinned ? react_jsx_runtime.jsx("circle", {
|
|
8076
|
+
key: "core",
|
|
8077
|
+
cx: 8, cy: 8, r: 2.9,
|
|
8078
|
+
fill: P.accent
|
|
8079
|
+
}) : null
|
|
8080
|
+
]
|
|
8081
|
+
})]
|
|
7978
8082
|
}, "hc-pin")
|
|
7979
8083
|
]
|
|
7980
8084
|
}, "hc-head")
|
|
@@ -8023,7 +8127,12 @@ window.__ModuleLoader__.load({
|
|
|
8023
8127
|
WebkitBackdropFilter: P.glassOn ? P.panelBlur : undefined,
|
|
8024
8128
|
color: P.text,
|
|
8025
8129
|
border: "1px solid " + P.panelBorder,
|
|
8026
|
-
|
|
8130
|
+
// An inset accent bar on the reading side says "this card belongs to that
|
|
8131
|
+
// row" without a second border: a shadow cannot move the box, and it
|
|
8132
|
+
// respects the corner radius. It stays while the card is pinned — that is
|
|
8133
|
+
// when the link matters most.
|
|
8134
|
+
boxShadow: "inset 2px 0 0 " + P.accent
|
|
8135
|
+
+ (P.glassOn ? ", " + rimInset() + ", 0 8px 24px rgba(0,0,0,0.28)" : ", 0 8px 24px rgba(0,0,0,0.28)"),
|
|
8027
8136
|
// above the panel and the curtain — it is a sibling of both in this
|
|
8028
8137
|
// portal, and both sit below it in the layer band we claim
|
|
8029
8138
|
zIndex: Z_HOVER + (opts.pinned ? 1 : 0),
|
|
@@ -8304,6 +8413,10 @@ window.__ModuleLoader__.load({
|
|
|
8304
8413
|
// old content-box the bottom pair sat below it and the clip cut them
|
|
8305
8414
|
// away, which is why the bottom edge had no visible line
|
|
8306
8415
|
boxSizing: "border-box",
|
|
8416
|
+
// the landing sag stretches the box DOWNWARD only, so its top edge never
|
|
8417
|
+
// leaves the clip it hangs from (see the dqt-sheet-in keyframes: a
|
|
8418
|
+
// translated top edge opened a slit that showed the transcript unblurred)
|
|
8419
|
+
transformOrigin: "top center",
|
|
8307
8420
|
display: "flex",
|
|
8308
8421
|
flexDirection: "column",
|
|
8309
8422
|
// The curtain is the transient surface (Windows' "Acrylic" case): the
|
|
@@ -8609,7 +8722,9 @@ window.__ModuleLoader__.load({
|
|
|
8609
8722
|
// that the text never looks like it jumped
|
|
8610
8723
|
e.currentTarget.style.transform = "translateX(1px)";
|
|
8611
8724
|
var gd = e.currentTarget.querySelector("[data-dqt-guide]");
|
|
8612
|
-
|
|
8725
|
+
// the guide column takes the theme colour while its row is the one being
|
|
8726
|
+
// read: a hairline's worth of colour is enough to say "these belong here"
|
|
8727
|
+
if (gd) { gd.style.transform = "translateX(-1px)"; gd.style.background = C.accent; }
|
|
8613
8728
|
if (extra && extra.hoverStart) extra.hoverStart(hoverInfo, e.currentTarget);
|
|
8614
8729
|
},
|
|
8615
8730
|
onMouseLeave: function (e) {
|
|
@@ -8619,7 +8734,7 @@ window.__ModuleLoader__.load({
|
|
|
8619
8734
|
if (b) b.style.opacity = "0";
|
|
8620
8735
|
e.currentTarget.style.transform = "translateX(0)";
|
|
8621
8736
|
var gd2 = e.currentTarget.querySelector("[data-dqt-guide]");
|
|
8622
|
-
if (gd2) gd2.style.transform = "translateX(0)";
|
|
8737
|
+
if (gd2) { gd2.style.transform = "translateX(0)"; gd2.style.background = C.panelBorder; }
|
|
8623
8738
|
if (extra && extra.hoverEnd) extra.hoverEnd();
|
|
8624
8739
|
},
|
|
8625
8740
|
onContextMenu: function (e) {
|
|
@@ -9973,7 +10088,7 @@ window.__ModuleLoader__.load({
|
|
|
9973
10088
|
// ease-out is fast at a segment's start, it read as a snap back into place.
|
|
9974
10089
|
// At the turning point the velocity is zero, so that leg eases IN as well as
|
|
9975
10090
|
// out — that is what makes it a settle instead of a bounce.
|
|
9976
|
-
"@keyframes dqt-sheet-in{from{transform:translateY(calc(-100% - 24px));animation-timing-function:cubic-bezier(0.22, 0.9, 0.3, 1)}62%{transform:translateY(
|
|
10091
|
+
"@keyframes dqt-sheet-in{from{transform:translateY(calc(-100% - 24px));animation-timing-function:cubic-bezier(0.22, 0.9, 0.3, 1)}62%{transform:translateY(0) scaleY(1.014);animation-timing-function:cubic-bezier(0.45, 0, 0.25, 1)}to{transform:translateY(0) scaleY(1)}}" +
|
|
9977
10092
|
// The retract has to clear the shadow too, not just the sheet: the sheet is
|
|
9978
10093
|
// 24px shorter than its shell (that strip is where the drop shadow lands),
|
|
9979
10094
|
// so `translateY(-100%)` parked its own shadow exactly at the shell's top
|
|
@@ -10013,7 +10128,7 @@ window.__ModuleLoader__.load({
|
|
|
10013
10128
|
// keyboard cursor: an INSET outline plus a whisper of fill, so it never
|
|
10014
10129
|
// reflows the row and stays distinct from the reading position's blue box
|
|
10015
10130
|
// (which keeps the 3px left accent bar and the pastel fill)
|
|
10016
|
-
".dqt-nav{box-shadow:inset 0 0 0 1px
|
|
10131
|
+
".dqt-nav{box-shadow:inset 0 0 0 1px #4F8CFF;background:rgba(79,140,255,0.10);border-radius:6px}" +
|
|
10017
10132
|
".dqt-nav:focus{outline:none}" +
|
|
10018
10133
|
// the list itself never draws a focus ring — the cursor row is the indicator
|
|
10019
10134
|
".dqt-list:focus-visible{outline:none}" +
|
|
@@ -10045,7 +10160,7 @@ window.__ModuleLoader__.load({
|
|
|
10045
10160
|
".dqt-pcard:hover{border-color:var(--dsw-alias-label-dimmed)}" +
|
|
10046
10161
|
".dqt-pcardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}" +
|
|
10047
10162
|
".dqt-phead{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}" +
|
|
10048
|
-
".dqt-phead:focus-visible{outline:2px solid
|
|
10163
|
+
".dqt-phead:focus-visible{outline:2px solid #4F8CFF;outline-offset:-2px}" +
|
|
10049
10164
|
".dqt-pheadText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}" +
|
|
10050
10165
|
".dqt-pname{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}" +
|
|
10051
10166
|
".dqt-pdesc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}" +
|
|
@@ -10079,7 +10194,7 @@ window.__ModuleLoader__.load({
|
|
|
10079
10194
|
".dqt-segOn{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-sidebar-nav-item-active)}" +
|
|
10080
10195
|
// scale slider — the fonttune card's slider shape (track, readout, end labels)
|
|
10081
10196
|
".dqt-sliderRow{align-items:center;gap:10px;margin-top:10px;display:flex}" +
|
|
10082
|
-
".dqt-slider{flex:1;min-width:0;height:20px;accent-color
|
|
10197
|
+
".dqt-slider{flex:1;min-width:0;height:20px;accent-color:#4F8CFF}" +
|
|
10083
10198
|
".dqt-slider:disabled{opacity:.4;cursor:default}" +
|
|
10084
10199
|
".dqt-sliderValue{flex:none;min-width:56px;text-align:right;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;font-variant-numeric:tabular-nums}" +
|
|
10085
10200
|
".dqt-sliderScale{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;display:flex;justify-content:space-between}";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-quick-toc",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Conversation TOC for DeepSeek Harness (DSH): a whole-session, turn-grouped Markdown outline with hover previews, heading-level preferences, a full-width curtain, jump-to-end buttons, title/prompts/full-text/cross-session search and a Chinese/English interface.",
|
|
5
5
|
"icon": "./icon.svg",
|
|
6
6
|
"type": "module",
|