dsh-m 0.9.59 → 0.9.60
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.md +16 -0
- package/lib/client.js +73 -22
- package/package.json +1 -1
- package/registry.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,14 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
8
8
|
|
|
9
9
|
## 中文
|
|
10
10
|
|
|
11
|
+
### 0.9.60 修复:截图灯箱窗口态无导航/无法退出——createPortal 逃出面板包含块 + 控件常驻
|
|
12
|
+
|
|
13
|
+
- **根因**:灯箱 `position:fixed` 是 `.dshm-panel`(`backdrop-filter` + `overflow:hidden`)的后代,面板盒成了它的包含块——图片按视口单位放大(旧 94vw/80vh),在 ≤680px 高的窗口态面板里必然溢出,in-flow 的 ‹›/圆点被裁出屏外,又没有 ✕;全屏态面板恰为视口才「碰巧」可见(即「只有全屏才有导航按钮,窗口态图片占满小屏且无法退出」)。
|
|
14
|
+
- **v2 修复(`b89af18`)**:① 灯箱 `createPortal` 挂 `document.body`——逃出包含块,窗口/全屏/窄屏任何状态都按真实视口定位(SSR/无 document 回退原树,冒烟测试照常渲染);② 控件全部绝对定位贴边,构造上不可能被图片挤出屏——右上 ✕ 常驻、两侧 ‹› 大热区、底部「计数+圆点+操作提示」pill,图片降为 74vh 给控件留位;③ 退出路径四条:点图即关(zoom-out 光标)、点遮罩关、Esc 关、✕ 关——键盘 ←→/Esc 语义不变(DetailModal 文档级监听不受 portal 影响);④ 单图不渲染 ‹›/计数/圆点(无死控件),圆点热区 `background-clip:content-box` 扩到 18px,开灯箱即聚焦 ✕(对齐 DetailModal U8 先例)。
|
|
15
|
+
- **配套**:环形步进抽纯函数 `lbStep`(`lightbox.js`,组件与键盘共用,单测覆盖回绕/单图/非有限输入);新增 `client-lightbox.test.mjs` 结构守卫(portal/✕/点图关/单图收敛/CSS 绝对定位/内联取模退役),SSR 冒烟补灯箱多图/单图结构断言。
|
|
16
|
+
- **评审吸收轮(独立 subagent 评审,发布前落码)**:R1 CSS 级联——`.dsvm-btn` 基础规则源顺序靠后,实测反杀 ✕/‹› 的 `padding:0/font-size:26px/radius:10px`(‹› 字形实渲 13px),改复合选择器 `.dsvm-btn.dsvm-lb*`(特异性 0,2,0,顺序免疫);R2 Windows Desktop 拖拽带——灯箱 `top:var(--dsh-windows-titlebar-height,0px)` 让带(0.9.4 先例,Web 无变量回落 0px 行为不变),✕ 不再落进壳顶 `-webkit-app-region:drag` 吞点击带;R3 焦点还原——关闭灯箱把焦点归还触发的截图缩略图(捕获 effect 声明于聚焦 ✕ 之前,`isConnected` 防已卸载元素);R4 灯箱圆点与缩略图条 key 改序号(URL 重复不撞车);R5 无头探针固化为 `scripts/verify-lightbox.mjs` 入库(手动跑,需 playwright-core),结构断言收敛为 includes 级锚(逐字正则红灯语义是「文本变了」非「行为变了」),SSR 冒烟补 `role=dialog/aria-modal` 与重复 URL 圆点断言。
|
|
17
|
+
- **验证**:1236 项测试全绿、typecheck 零错误;`scripts/verify-lightbox.mjs` 复刻 `.dshm-overlay > .dshm-panel` 真实语境 19/19 断言——面板内 fixed 探针盒=面板盒(包含块实证)、灯箱盒=全视口、✕/‹›/pill 全程在视口内、**计算样式级联正确(R1 回归门)**、›/圆点/‹/←→ 导航与 Esc/点图关闭正确、**关闭后焦点还原缩略图(R3)**、**拖拽带 40px 避让(R2)**、全屏态回归、500px 矮窗口控件仍常驻(旧版此处必裁)。
|
|
18
|
+
|
|
11
19
|
### 0.9.59 优化:分类行左缘内缩 8px + 全屏下空转 ⌃ 收起钮按行数派生隐藏
|
|
12
20
|
|
|
13
21
|
- **分类行内缩(`f42e5be`)**:分类 chips 行与搜索框/卡片左缘齐平,小颗粒胶囊贴着大元素左缘视觉憋仄;分类行整体右移 8px 留出呼吸空间。仅作用分类行(ZoneChips),上方分区 chips 行不随动。`offsetLeft` 与 absolute 定位同以 `.dshm-chips` 的 padding 盒为原点 → `+N` 跟随、右侧筛选钉位、`offsetTop` 裁剪几何均不受影响。
|
|
@@ -438,6 +446,14 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
438
446
|
|
|
439
447
|
## English
|
|
440
448
|
|
|
449
|
+
### Fixed in 0.9.60 — screenshot lightbox unusable when windowed: portal out of the panel containing block + always-visible controls
|
|
450
|
+
|
|
451
|
+
- **Root cause**: the lightbox was a `position:fixed` descendant of `.dshm-panel` (`backdrop-filter` + `overflow:hidden`), so the panel box became its containing block. The image sized in viewport units (old 94vw/80vh) inevitably overflows the ≤680px-tall windowed panel and the in-flow ‹›/dots row gets clipped off-screen, with no close button at all; fullscreen only worked because the panel then equals the viewport (the reported "nav buttons appear only in fullscreen; windowed fills the small screen and cannot exit").
|
|
452
|
+
- **v2 fix (`b89af18`)**: ① portal the lightbox to `document.body` — it escapes the containing block and is positioned against the real viewport in every panel state (SSR/no-document falls back to the plain tree so the smoke test still renders it); ② every control is absolutely positioned to the edges and can never be pushed off-screen by an image — persistent top-right ✕, large side ‹ › arrows, a bottom counter+dots+hint pill, and the image capped at 74vh; ③ four ways out: click the image (zoom-out cursor), click the backdrop, Esc, or ✕ — keyboard ←→/Esc semantics unchanged (DetailModal document-level listeners are unaffected by the portal); ④ single-image shots hide ‹›/counter/dots (no dead controls), dot hit areas grow to 18px via `background-clip:content-box`, and the close button is focused on open (same pattern as DetailModal U8).
|
|
453
|
+
- **Supporting changes**: the ring step is extracted as the pure `lbStep` helper (`lightbox.js`, shared by the component and the keyboard handler; unit-tested for wrap-around, single image and non-finite input); new `client-lightbox.test.mjs` structural guards (portal/✕/click-image-close/single-image/CSS absolutes/inline-modulo retired); SSR smoke extended with multi- and single-image lightbox assertions.
|
|
454
|
+
- **Review absorption round (independent subagent review, landed pre-release)**: R1 CSS cascade — the base `.dsvm-btn` rule sits later in source order and measurably overrode the ✕/‹› `padding:0/font-size:26px/radius:10px` (arrows actually rendered a 13px glyph); switched to compound selectors `.dsvm-btn.dsvm-lb*` (specificity 0,2,0, order-immune). R2 Windows Desktop drag band — the lightbox now yields the top band via `top:var(--dsh-windows-titlebar-height,0px)` (the 0.9.4 precedent; web falls back to 0px with zero drift) so ✕ never lands in the shell's `-webkit-app-region:drag` strip that swallows clicks. R3 focus restore — closing the lightbox returns focus to the triggering screenshot thumbnail (capture effect declared before the focus-✕ effect; `isConnected` guard). R4 lightbox dots and the thumbnail strip now key by index (duplicate URLs no longer collide). R5 the headless probe is persisted as `scripts/verify-lightbox.mjs` (manual run, needs playwright-core); structural assertions converged to includes-level anchors (verbatim regex red lights mean "text changed", not "behavior changed"); SSR smoke gains `role=dialog/aria-modal` and duplicate-URL dots assertions.
|
|
455
|
+
- **Verification**: 1236 tests pass and typecheck is clean; `scripts/verify-lightbox.mjs` reproducing the real `.dshm-overlay > .dshm-panel` context passed 19/19 assertions — a fixed probe inside the panel equals the panel box (containing block proven), the lightbox box equals the viewport, ✕/‹›/pill stay within the viewport at all times, **computed cascade styles correct (R1 regression gate)**, ›/dot/‹/←→ navigation plus Esc/click-image close behave correctly, **focus restored to the thumbnail on close (R3)**, **40px titlebar band avoided (R2)**, fullscreen regresses nothing, and controls remain present in a 500px-tall window (always clipped before).
|
|
456
|
+
|
|
441
457
|
### Improved in 0.9.59 — 8px category-row inset and a derived visibility for the no-op collapse toggle
|
|
442
458
|
|
|
443
459
|
- **Category-row inset (`f42e5be`)**: the category chip row sat flush with the search box and card grid, and small pills hugging large elements felt cramped; the row now starts 8px further right for breathing room. Only the category row (ZoneChips) moves — the zone chip row above stays put. `offsetLeft` and absolute positioning share the `.dshm-chips` padding-box origin, so `+N` tracking, the pinned Filter trigger and `offsetTop`-based clip geometry are all unaffected.
|
package/lib/client.js
CHANGED
|
@@ -463,6 +463,21 @@ var init_backdrop = __esm({
|
|
|
463
463
|
}
|
|
464
464
|
});
|
|
465
465
|
|
|
466
|
+
// src/client/lightbox.js
|
|
467
|
+
var lightbox_exports = {};
|
|
468
|
+
__export(lightbox_exports, {
|
|
469
|
+
lbStep: () => lbStep
|
|
470
|
+
});
|
|
471
|
+
function lbStep(index, step, length) {
|
|
472
|
+
if (!Number.isFinite(index) || !Number.isFinite(step) || !Number.isInteger(length) || length <= 1) return index;
|
|
473
|
+
return ((index + step) % length + length) % length;
|
|
474
|
+
}
|
|
475
|
+
var init_lightbox = __esm({
|
|
476
|
+
"src/client/lightbox.js"() {
|
|
477
|
+
"use strict";
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
466
481
|
// src/client/markdown.js
|
|
467
482
|
var markdown_exports = {};
|
|
468
483
|
__export(markdown_exports, {
|
|
@@ -1576,6 +1591,7 @@ var API = "/dshm";
|
|
|
1576
1591
|
var { DEFAULT_PAGE_SIZE: DEFAULT_PAGE_SIZE2, MARKET_PAGE_SIZES: MARKET_PAGE_SIZES2, pageItems: pageItems2, createZoneState: createZoneState2, normalizeMarketQuery: normalizeMarketQuery2, resetPageOnFilterChange: resetPageOnFilterChange2, normalizeMarketResponse: normalizeMarketResponse2, registryNotice: registryNotice2, zoneChips: zoneChips2, marketNotice: marketNotice2, searchSourceOf: searchSourceOf2, mergeLatestFields: mergeLatestFields2, chipRows: chipRows2, countBeyondRows: countBeyondRows2, clipTopOf: clipTopOf2, visibleRowTop: visibleRowTop2, autoExpandDecision: autoExpandDecision2 } = (init_market_state(), __toCommonJS(market_state_exports));
|
|
1577
1592
|
var { readMarketSnapshot: readMarketSnapshot2, writeMarketSnapshot: writeMarketSnapshot2, isDefaultFirstPageQuery: isDefaultFirstPageQuery2 } = (init_market_snapshot(), __toCommonJS(market_snapshot_exports));
|
|
1578
1593
|
var { backdropCloseHandlers: backdropCloseHandlers2 } = (init_backdrop(), __toCommonJS(backdrop_exports));
|
|
1594
|
+
var { lbStep: lbStep2 } = (init_lightbox(), __toCommonJS(lightbox_exports));
|
|
1579
1595
|
var { createMarkdown: createMarkdown2 } = (init_markdown(), __toCommonJS(markdown_exports));
|
|
1580
1596
|
var { ExtLink, MdImg, renderMarkdown } = createMarkdown2(h);
|
|
1581
1597
|
var { installedViewModel: installedViewModel2, registrySourceKey: registrySourceKey2 } = (init_installed_view(), __toCommonJS(installed_view_exports));
|
|
@@ -1752,6 +1768,10 @@ var ZH = {
|
|
|
1752
1768
|
"pager.jump.ph": "\u9875\u53F7",
|
|
1753
1769
|
"panel.fullscreen": "\u5168\u5C4F",
|
|
1754
1770
|
"panel.restore": "\u8FD8\u539F",
|
|
1771
|
+
"lb.title": "\u63D2\u4EF6\u622A\u56FE\u9884\u89C8",
|
|
1772
|
+
"lb.prev": "\u4E0A\u4E00\u5F20\uFF08\u2190\uFF09",
|
|
1773
|
+
"lb.next": "\u4E0B\u4E00\u5F20\uFF08\u2192\uFF09",
|
|
1774
|
+
"lb.hint": "\u70B9\u56FE\u6216\u7A7A\u767D\u5904\u5173\u95ED \xB7 \u2190\u2192 \u5207\u6362",
|
|
1755
1775
|
"filter.title": "\u7B5B\u9009",
|
|
1756
1776
|
"filter.sortfield": "\u6392\u5E8F\u5B57\u6BB5",
|
|
1757
1777
|
"filter.sortdir": "\u6392\u5217\u65B9\u5411",
|
|
@@ -2026,6 +2046,10 @@ var EN = {
|
|
|
2026
2046
|
"pager.jump.ph": "Page",
|
|
2027
2047
|
"panel.fullscreen": "Fullscreen",
|
|
2028
2048
|
"panel.restore": "Restore",
|
|
2049
|
+
"lb.title": "Plugin screenshot preview",
|
|
2050
|
+
"lb.prev": "Previous (\u2190)",
|
|
2051
|
+
"lb.next": "Next (\u2192)",
|
|
2052
|
+
"lb.hint": "Click image or backdrop to close \xB7 \u2190\u2192 to switch",
|
|
2029
2053
|
"filter.title": "Filter",
|
|
2030
2054
|
"filter.sortfield": "Sort by",
|
|
2031
2055
|
"filter.sortdir": "Direction",
|
|
@@ -2260,13 +2284,27 @@ var CSS = `
|
|
|
2260
2284
|
.dsvm-shotrow{display:flex;gap:6px;overflow-x:auto;padding:2px 0}
|
|
2261
2285
|
.dsvm-shotbox{min-width:120px;min-height:84px;display:flex;align-items:center;justify-content:center;background:rgba(127,127,127,.08);border-radius:6px;cursor:zoom-in;border:1px solid var(--dsw-alias-border-l2,rgba(127,127,127,.25))}
|
|
2262
2286
|
.dsvm-shot{max-width:220px;max-height:130px;border-radius:6px;display:block}
|
|
2263
|
-
.
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
.dsvm-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2287
|
+
/* \u706F\u7BB1 v2\uFF080.9.60\uFF09\uFF1A\u7EC4\u4EF6 createPortal \u6302 body\uFF08\u9003\u51FA\u9762\u677F backdrop-filter \u5305\u542B\u5757\uFF09\uFF0C
|
|
2288
|
+
\u63A7\u4EF6\u5168\u90E8\u7EDD\u5BF9\u5B9A\u4F4D\u8D34\u89C6\u53E3\u8FB9\u2014\u2014\u2715 \u5E38\u9A7B\u53F3\u4E0A\u3001\u2039\u203A \u4E24\u4FA7\u5C45\u4E2D\u3001\u5E95\u90E8\u8BA1\u6570+\u5706\u70B9 pill\uFF0C
|
|
2289
|
+
\u4EFB\u4F55\u9762\u677F\u72B6\u6001/\u4EFB\u610F\u56FE\u7247\u9AD8\u5EA6\u4E0B\u90FD\u4E0D\u4F1A\u88AB\u6324\u51FA\u5C4F\u5E55\uFF1B\u56FE\u7247\u964D\u5230 74vh \u7ED9\u5E95\u90E8\u63A7\u4EF6\u7559\u4F4D\u3002
|
|
2290
|
+
\u8BC4\u5BA1 R1\uFF1A\u2715/\u2039\u203A \u7528 .dsvm-btn.dsvm-lb* \u590D\u5408\u9009\u62E9\u5668\u2014\u2014\u57FA\u7840 .dsvm-btn \u89C4\u5219\u6E90\u987A\u5E8F\u9760\u540E
|
|
2291
|
+
\uFF08padding:5px 14px/font-size:13px/radius:8px\uFF09\uFF0C\u540C\u7279\u5F02\u6027\u4E0B\u4F1A\u53CD\u6740\u5355\u7C7B\u89C4\u5219\uFF08\u5B9E\u6D4B\u5B57\u5F62 13px\u226026px\uFF09\u3002
|
|
2292
|
+
\u8BC4\u5BA1 R2\uFF1Atop \u8BA9\u51FA Windows Desktop \u62D6\u62FD\u5E26 var(--dsh-windows-titlebar-height)\uFF080.9.4 \u5148\u4F8B\uFF0C
|
|
2293
|
+
\u58F3\u9876 -webkit-app-region:drag \u541E\u70B9\u51FB\u3001\u65E0\u89C6 z-index\uFF09\uFF1BWeb \u65E0\u6B64\u53D8\u91CF\u56DE\u843D 0px \u884C\u4E3A\u4E0D\u53D8\u3002 */
|
|
2294
|
+
.dsvm-lightbox{position:fixed;top:var(--dsh-windows-titlebar-height,0px);left:0;right:0;bottom:0;z-index:2147483200;background:rgba(0,0,0,.88);display:flex;align-items:center;justify-content:center}
|
|
2295
|
+
.dsvm-lightbox img{max-width:min(92vw,1500px);max-height:74vh;border-radius:8px;cursor:zoom-out;box-shadow:0 10px 44px rgba(0,0,0,.55);display:block}
|
|
2296
|
+
.dsvm-btn:focus-visible{outline:2px solid rgba(255,255,255,.75);outline-offset:2px}
|
|
2297
|
+
.dsvm-btn.dsvm-lbclose{position:absolute;top:12px;right:12px;width:38px;height:38px;padding:0;border-radius:10px;display:flex;align-items:center;justify-content:center}
|
|
2298
|
+
.dsvm-btn.dsvm-lbarrow{position:absolute;top:50%;transform:translateY(-50%);width:46px;height:60px;padding:0;font-size:26px;line-height:1;border-radius:10px}
|
|
2299
|
+
.dsvm-lbarrow.prev{left:12px}
|
|
2300
|
+
.dsvm-lbarrow.next{right:12px}
|
|
2301
|
+
.dsvm-lbbar{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);display:flex;align-items:center;gap:12px;max-width:94vw;background:rgba(15,23,42,.62);border:1px solid rgba(255,255,255,.16);border-radius:999px;padding:7px 16px;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
|
|
2302
|
+
.dsvm-lbcount{color:rgba(255,255,255,.82);font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
2303
|
+
.dsvm-lbhint{color:rgba(255,255,255,.55);font-size:11px;white-space:nowrap}
|
|
2304
|
+
.dsvm-lbdots{display:flex;gap:2px}
|
|
2305
|
+
.dsvm-lbdot{box-sizing:content-box;width:8px;height:8px;padding:5px;border-radius:50%;background:rgba(255,255,255,.32);background-clip:content-box;cursor:pointer}
|
|
2306
|
+
.dsvm-lbdot.on{background:#fff;background-clip:content-box}
|
|
2307
|
+
@media (max-width:640px){.dsvm-lbhint{display:none}.dsvm-btn.dsvm-lbarrow{width:40px;height:54px}}
|
|
2270
2308
|
.dsvm-card-clickable, .dshm-card{cursor:pointer}
|
|
2271
2309
|
.dshm-card:hover{border-color:var(--dsw-alias-interactive-bg-selected,#4f46e5)}
|
|
2272
2310
|
.dsvm-btn{border:1px solid rgba(255,255,255,.35);background:rgba(255,255,255,.14);color:#fff;border-radius:8px;padding:5px 14px;font:inherit;font-size:13px;cursor:pointer}
|
|
@@ -2965,23 +3003,36 @@ function Shot({ src, onClick }) {
|
|
|
2965
3003
|
);
|
|
2966
3004
|
}
|
|
2967
3005
|
function Lightbox({ shots, index, onNav, onClose }) {
|
|
2968
|
-
|
|
3006
|
+
const single = shots.length <= 1;
|
|
3007
|
+
const closeRef = useRef(null);
|
|
3008
|
+
const prevFocusRef = useRef(null);
|
|
3009
|
+
useEffect(() => {
|
|
3010
|
+
prevFocusRef.current = document.activeElement;
|
|
3011
|
+
return () => {
|
|
3012
|
+
const el = prevFocusRef.current;
|
|
3013
|
+
if (el && el.isConnected) el.focus();
|
|
3014
|
+
};
|
|
3015
|
+
}, []);
|
|
3016
|
+
useEffect(() => {
|
|
3017
|
+
if (closeRef.current) closeRef.current.focus();
|
|
3018
|
+
}, []);
|
|
3019
|
+
const node = h(
|
|
2969
3020
|
"div",
|
|
2970
|
-
{ className: "dsvm-lightbox", ...backdropCloseHandlers2(onClose) },
|
|
2971
|
-
h("img", { src: shots[index], alt: "", onClick:
|
|
2972
|
-
h(
|
|
3021
|
+
{ className: "dsvm-lightbox", role: "dialog", "aria-modal": "true", "aria-label": lookup("lb.title"), ...backdropCloseHandlers2(onClose) },
|
|
3022
|
+
h("img", { src: shots[index], alt: "", onClick: onClose, referrerPolicy: "no-referrer" }),
|
|
3023
|
+
h("button", { ref: closeRef, className: "dsvm-btn dsvm-lbclose", "aria-label": lookup("common.close"), title: lookup("common.close"), onClick: onClose }, h(XIcon)),
|
|
3024
|
+
single ? null : h("button", { className: "dsvm-btn dsvm-lbarrow prev", "aria-label": lookup("lb.prev"), title: lookup("lb.prev"), onClick: () => onNav(lbStep2(index, -1, shots.length)) }, "\u2039"),
|
|
3025
|
+
single ? null : h("button", { className: "dsvm-btn dsvm-lbarrow next", "aria-label": lookup("lb.next"), title: lookup("lb.next"), onClick: () => onNav(lbStep2(index, 1, shots.length)) }, "\u203A"),
|
|
3026
|
+
single ? null : h(
|
|
2973
3027
|
"div",
|
|
2974
|
-
{ className: "dsvm-
|
|
2975
|
-
h("button", { className: "dsvm-btn", onClick: () => onNav((index - 1 + shots.length) % shots.length) }, "\u2039"),
|
|
3028
|
+
{ className: "dsvm-lbbar" },
|
|
2976
3029
|
h("span", { className: "dsvm-lbcount" }, `${index + 1} / ${shots.length}`),
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
"div",
|
|
2981
|
-
{ className: "dsvm-lbdots", onClick: (e) => e.stopPropagation() },
|
|
2982
|
-
...shots.map((s, i) => h("span", { key: s, className: `dsvm-lbdot${i === index ? " on" : ""}`, onClick: () => onNav(i) }))
|
|
3030
|
+
// 评审 R4:key 用序号而非 URL——safeScreenshots 不去重,同一 URL 两次出现即 key 撞车
|
|
3031
|
+
h("div", { className: "dsvm-lbdots" }, ...shots.map((s, i) => h("span", { key: i, className: `dsvm-lbdot${i === index ? " on" : ""}`, onClick: () => onNav(i) }))),
|
|
3032
|
+
h("span", { className: "dsvm-lbhint" }, lookup("lb.hint"))
|
|
2983
3033
|
)
|
|
2984
3034
|
);
|
|
3035
|
+
return typeof document !== "undefined" && document.body && typeof rd.createPortal === "function" ? rd.createPortal(node, document.body) : node;
|
|
2985
3036
|
}
|
|
2986
3037
|
var dsvmModalDepth = 0;
|
|
2987
3038
|
function useModalDepth(active) {
|
|
@@ -3010,8 +3061,8 @@ function DetailModal({ it, labels, busy, onClose, onInstall, onUpgrade, upgradeB
|
|
|
3010
3061
|
else onClose();
|
|
3011
3062
|
}
|
|
3012
3063
|
if (lb !== null && shots.length > 1) {
|
|
3013
|
-
if (e.key === "ArrowLeft") setLb((i) => (i -
|
|
3014
|
-
if (e.key === "ArrowRight") setLb((i) => (i
|
|
3064
|
+
if (e.key === "ArrowLeft") setLb((i) => lbStep2(i, -1, shots.length));
|
|
3065
|
+
if (e.key === "ArrowRight") setLb((i) => lbStep2(i, 1, shots.length));
|
|
3015
3066
|
}
|
|
3016
3067
|
};
|
|
3017
3068
|
document.addEventListener("keydown", onKey);
|
|
@@ -3088,7 +3139,7 @@ function DetailModal({ it, labels, busy, onClose, onInstall, onUpgrade, upgradeB
|
|
|
3088
3139
|
shots.length ? h(
|
|
3089
3140
|
"div",
|
|
3090
3141
|
{ className: "dsvm-shotrow" },
|
|
3091
|
-
...shots.map((src, i) => h(Shot, { key: src
|
|
3142
|
+
...shots.map((src, i) => h(Shot, { key: `${i}:${src}`, src, onClick: () => setLb(i) }))
|
|
3092
3143
|
) : null,
|
|
3093
3144
|
it.community === true ? h(
|
|
3094
3145
|
"details",
|
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -66,7 +66,8 @@
|
|
|
66
66
|
"id": "dsh-context",
|
|
67
67
|
"name": "DSH Context",
|
|
68
68
|
"description": "上下文透视:Context 仪表盘、侧栏面板与 /context 命令,查看上下文组成、演进趋势与压缩剪枝等事件,支持跨会话用量统计。",
|
|
69
|
-
"category": "
|
|
69
|
+
"category": "essentials",
|
|
70
|
+
"alsoCategories": ["cui-picks"],
|
|
70
71
|
"tags": ["上下文", "Token 统计", "可视化", "仪表盘"],
|
|
71
72
|
"source": "npm",
|
|
72
73
|
"npm": "dsh-context",
|