dsh-m 0.9.63 → 0.9.65
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 +32 -0
- package/lib/client.js +207 -71
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,22 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
8
8
|
|
|
9
9
|
## 中文
|
|
10
10
|
|
|
11
|
+
### 0.9.65 优化:灯箱邻图预取 + 触屏滑动切换 + 焦点圈闭
|
|
12
|
+
|
|
13
|
+
- **邻图预取**:当前图加载完成(`useImgChain` settled)后静默预热左右邻——URL 用与灯箱真实请求**逐字节同形**的 `weservUrl(w=1600)`,翻页直接命中浏览器缓存近零等待。纯 best-effort:不碰赢家记忆/链状态,预取失败对真实链零影响(导航时照常走 weserv→原图双兜底);`prefetchedRef` Set 去重防来回翻页重复发起,Set 随灯箱挂载期生命周期(重开重新预热);单图由 `lbNeighbors` 空表自然短路。
|
|
14
|
+
- **触屏滑动切换**:touch 指针横向滑过阈值即翻页(`swipeDir` 纯函数判向:|dx| ≥ 48px 且 |dx| ≥ 2|dy|;不设时长门槛,慢拖也算;竖滑/斜滑归零——纵向手势与 pinch 缩放可达性留给原生,`touch-action:pan-y pinch-zoom`)。只认 `pointerType==="touch"`——鼠标拖拽维持原生语义(图=原生拖拽、遮罩=按下+点击才关,0.9.27 防拖拽误关守卫不破);滑动终结后 500ms 内根上 capture 吞掉合成 click(双保险:即便滑动止于 ✕/遮罩也不触发其点击语义)。判向/邻图两枚纯函数入 `lightbox.js`(`swipeDir`/`lbNeighbors`,Node 单测覆盖)。
|
|
15
|
+
- **焦点圈闭**:灯箱开着时 Tab/Shift+Tab 只在灯箱内可聚焦控件(按钮/链接:✕/‹›/失败态重试+打开原图)间回绕;焦点已逃出灯箱(如点击遮罩落在 body)时拉回首/尾。portal 挂 body 后 Tab 本会走到背景面板,此处收口;DetailModal 自身 U8 债(无圈闭)维持不变,Esc 仍只关最上层弹层。
|
|
16
|
+
- **验证**:1289 项测试全绿、typecheck 零错误;`client-lightbox.test.mjs` 新增 6 项(`lbNeighbors`/`swipeDir` 纯逻辑单测 + 预取/滑动/圈闭/touch-action 结构锚),0.9.60/0.9.62 批次既有锚全数保持。
|
|
17
|
+
|
|
18
|
+
### 0.9.64 优化:设置页双清单并排重排 + 操作记录整体搬迁设置 tab
|
|
19
|
+
|
|
20
|
+
- **设置页网格(mock 驱动终审)**:社区清单/精选清单两卡并排 **4:7**(社区卡只读五项 ~250px 足矣,宽度让给交互更多的精选卡);全屏态「关于」升入三卡行(`4fr 7fr 3fr`,不封顶——对齐市场「加列不加宽」哲学,设置页恰有三个卡片单元可用);视口 ≤760px 单列回落;关于卡常态通栏、操作记录恒通栏(`nth-child` 定位,与 `Section()` 签名解耦)。
|
|
21
|
+
- **社区卡清爽列表**:标题行回归纯标题(去 `from` 前缀);状态徽章降为绿/黄/红**小圆点**;行间发丝分隔线 + 数值右对齐等宽数字;「社区目录开关」入列表为末行(开关是目录属性,钉底反而脱离语境);关态 = 提示行 + 开关行(重开入口不丢)。中途方案「统计带」(白盒大数字)经实评否决——卡片中的卡片是视觉噪音。
|
|
22
|
+
- **精选卡减行**:说明行缩短(被删的「条目格式可参照下载的默认清单」与下载按钮 tooltip 重复,零信息损失);配置地址长 URL 单行省略 + `title` 悬浮全文。
|
|
23
|
+
- **操作记录搬迁(第二批)**:三 tab 共用的底部常驻区退役;`OperationsPanel` → `OperationsCard` 落位设置 tab 末位通宽卡——进行中组滚动区外常驻(进度不被滚走),已结束组进 220px 滚动区(展示上限 50 条防 DOM 无界,store/恢复校验不动),「清除已结束」钉底,空态 hint 卡常驻导览。
|
|
24
|
+
- **可见性补偿**:底部消失后失败/带警告终态无人主动发现 → 设置 tab 红点(复用 outdated 红点样式,清除/移除后随 syncOps 自灭);市场卡「进行中」徽章点击改道:切设置 tab + 滚动定位操作记录卡(文案「查看操作面板」→「查看操作记录」)。
|
|
25
|
+
- **验证**:构建 verify 通过、typecheck 零错误、全量 1283 项测试连续 4 轮全绿(首轮 1 例与改动无关的瞬时 flake 未复现);布局终稿经交互式 HTML mock 三宽度 × 三布局 × 多状态现场评审定稿(`docs/settings-layout-mock.html` 入库作设计记录)。
|
|
26
|
+
|
|
11
27
|
### 0.9.63 修复:点在加载转圈上不再无动作——转圈显式接 onClick=onClose
|
|
12
28
|
|
|
13
29
|
- **背景**:0.9.62 给灯箱加了走链转圈占位,但转圈是遮罩根的**子元素**,而 `backdropCloseHandlers`(0.9.27 防拖拽误关)只在 `mousedown` 与 `click` 都命中遮罩自身(`target === currentTarget`)时才关——点在 34px 转圈正中因此无动作。转圈显式接 `onClick: onClose`,与「点图即关」同语义:走链期间的任何一次点击都是有效的关闭逃生门。
|
|
@@ -466,6 +482,22 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
466
482
|
|
|
467
483
|
## English
|
|
468
484
|
|
|
485
|
+
### Added in 0.9.65 — lightbox: neighbor prefetch + touch swipe navigation + focus trap
|
|
486
|
+
|
|
487
|
+
- **Neighbor prefetch**: once the current image settles (`useImgChain` settled), the left/right neighbors are warmed silently - using a `weservUrl(w=1600)` URL **byte-identical** to the lightbox's real request, so a swipe/arrow navigation hits the browser cache with near-zero wait. Strictly best-effort: no winner-memory or chain-state mutation, a failed prefetch leaves the real chain untouched (navigation still runs the weserv→original dual fallback); a `prefetchedRef` Set dedupes repeated crossings (no re-issuing when bouncing back), the Set lives for the lightbox mount lifetime (a fresh open warms again); single-image boxes short-circuit naturally via `lbNeighbors` returning an empty list.
|
|
488
|
+
- **Touch swipe navigation**: a horizontal touch drag past the threshold flips images (`swipeDir` pure predicate: |dx| ≥ 48px and |dx| ≥ 2|dy|; no time gate - slow deliberate drags count; vertical/diagonal drags return 0 - vertical gestures and pinch-zoom accessibility stay native, via `touch-action:pan-y pinch-zoom`). Only `pointerType==="touch"` is recognized - mouse drags keep their native semantics (image = native drag, backdrop = press+click to close, the 0.9.27 drag-misfire guard intact); for 500ms after a recognized swipe the root's capture phase swallows the synthetic click (double belt: a swipe ending on ✕ or the backdrop triggers neither).
|
|
489
|
+
- **Focus trap**: while the lightbox is open, Tab/Shift+Tab cycles only among focusable controls inside it (buttons/links: ✕/‹›/failed-state retry + open-original); if focus has escaped (e.g. a backdrop click left it on body), the next Tab pulls it back to the first/last control. After the portal-to-body change, Tab used to walk into the background panel - this closes that gap; DetailModal's own U8 debt (no trap) is unchanged and Esc still closes only the topmost layer.
|
|
490
|
+
- **Verification**: 1289 tests green, typecheck clean; `client-lightbox.test.mjs` gains 6 items (`lbNeighbors`/`swipeDir` pure-logic units + prefetch/swipe/trap/touch-action structural anchors); all 0.9.60/0.9.62-era anchors retained.
|
|
491
|
+
|
|
492
|
+
### Changed in 0.9.64 — settings page: dual-catalog side-by-side layout + operations history moved into the settings tab
|
|
493
|
+
|
|
494
|
+
- **Settings grid (mock-driven final review)**: the Community and Curated cards now sit side by side at **4:7** (the read-only community card needs ~250px; width goes to the more interactive registry card); in fullscreen the About card joins a three-card row (`4fr 7fr 3fr`, uncapped — the same "add columns, don't stretch units" philosophy as the market tab); below a 760px viewport it falls back to a single column; About spans full width in normal mode, the operations card is always full width.
|
|
495
|
+
- **Community card, clean list**: the title row is a pure title again (`from` prefix dropped); the status badge becomes a small green/amber/red dot; hairline row separators + right-aligned tabular figures; the catalog toggle joins the list as its last row (the toggle is an attribute of the catalog — pinning it to the card bottom detached it from context); off state = hint line + toggle row (the re-entry control is preserved). The intermediate "stat band" design (boxed big numbers) was rejected in live review — cards inside a card are visual noise.
|
|
496
|
+
- **Curated card trim**: the note line is shortened (the removed clause duplicated the download button tooltip — zero information loss); long configured URLs render as a single ellipsized line with the full value on hover.
|
|
497
|
+
- **Operations history migration (batch 2)**: the bottom strip shared by all three tabs is retired; `OperationsPanel` becomes `OperationsCard` at the bottom of the settings tab — active rows stay outside the scroll area (progress never scrolls away), finished records live in a 220px scroll region (display cap 50 to bound the DOM; store/restore validation untouched), "Clear finished" is pinned below, and an empty-state hint card doubles as wayfinding.
|
|
498
|
+
- **Visibility compensation**: with the bottom strip gone, failed/warned records would go unnoticed — the settings tab now shows a red dot (reuses the outdated-dot style; clears on remove/clear); the market card's "running" badge now switches to the settings tab and scrolls to the operations card (label 查看操作面板 → 查看操作记录).
|
|
499
|
+
- **Verification**: build verify passes, typecheck clean, full 1283-test suite green in 4 consecutive runs (one transient unrelated flake in the first run did not reproduce); the final layout was settled via an interactive HTML mock across three widths × three layouts × multiple states (`docs/settings-layout-mock.html` committed as a design record).
|
|
500
|
+
|
|
469
501
|
### Fixed in 0.9.63 — clicking dead-center on the loading spinner no longer no-ops: spinner gets an explicit onClick=onClose
|
|
470
502
|
|
|
471
503
|
- **Background**: 0.9.62 added the chain-loading spinner, but the spinner is a **child** of the backdrop root, and `backdropCloseHandlers` (0.9.27 drag-misfire guard) closes only when both `mousedown` and `click` land on the backdrop itself (`target === currentTarget`) - so a click dead-center on the 34px spinner did nothing. The spinner now carries `onClick: onClose`, same semantics as click-image-to-close: during loading, any click is a valid escape hatch.
|
package/lib/client.js
CHANGED
|
@@ -466,12 +466,28 @@ var init_backdrop = __esm({
|
|
|
466
466
|
// src/client/lightbox.js
|
|
467
467
|
var lightbox_exports = {};
|
|
468
468
|
__export(lightbox_exports, {
|
|
469
|
-
|
|
469
|
+
lbNeighbors: () => lbNeighbors,
|
|
470
|
+
lbStep: () => lbStep,
|
|
471
|
+
swipeDir: () => swipeDir
|
|
470
472
|
});
|
|
471
473
|
function lbStep(index, step, length) {
|
|
472
474
|
if (!Number.isFinite(index) || !Number.isFinite(step) || !Number.isInteger(length) || length <= 1) return index;
|
|
473
475
|
return ((index + step) % length + length) % length;
|
|
474
476
|
}
|
|
477
|
+
function lbNeighbors(index, length) {
|
|
478
|
+
if (!Number.isFinite(index) || !Number.isInteger(length) || length <= 1) return [];
|
|
479
|
+
const out = [];
|
|
480
|
+
for (const n of [lbStep(index, 1, length), lbStep(index, -1, length)]) {
|
|
481
|
+
if (Number.isFinite(n) && !out.includes(n)) out.push(n);
|
|
482
|
+
}
|
|
483
|
+
return out;
|
|
484
|
+
}
|
|
485
|
+
function swipeDir(dx, dy, { threshold = 48, ratio = 2 } = {}) {
|
|
486
|
+
if (!Number.isFinite(dx) || !Number.isFinite(dy)) return 0;
|
|
487
|
+
const ax = Math.abs(dx);
|
|
488
|
+
if (ax < threshold || ax < ratio * Math.abs(dy)) return 0;
|
|
489
|
+
return dx > 0 ? 1 : -1;
|
|
490
|
+
}
|
|
475
491
|
var init_lightbox = __esm({
|
|
476
492
|
"src/client/lightbox.js"() {
|
|
477
493
|
"use strict";
|
|
@@ -1651,7 +1667,7 @@ var API = "/dshm";
|
|
|
1651
1667
|
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));
|
|
1652
1668
|
var { readMarketSnapshot: readMarketSnapshot2, writeMarketSnapshot: writeMarketSnapshot2, isDefaultFirstPageQuery: isDefaultFirstPageQuery2 } = (init_market_snapshot(), __toCommonJS(market_snapshot_exports));
|
|
1653
1669
|
var { backdropCloseHandlers: backdropCloseHandlers2 } = (init_backdrop(), __toCommonJS(backdrop_exports));
|
|
1654
|
-
var { lbStep: lbStep2 } = (init_lightbox(), __toCommonJS(lightbox_exports));
|
|
1670
|
+
var { lbStep: lbStep2, lbNeighbors: lbNeighbors2, swipeDir: swipeDir2 } = (init_lightbox(), __toCommonJS(lightbox_exports));
|
|
1655
1671
|
var { WESERV_TIMEOUT_MS: WESERV_TIMEOUT_MS2, weservUrl: weservUrl2, serviceBucketOf: serviceBucketOf2, tierOrder: tierOrder2, nextTier: nextTier2, needsTimeout: needsTimeout2, preferredTier: preferredTier2, rememberSuccess: rememberSuccess2 } = (init_img_chain(), __toCommonJS(img_chain_exports));
|
|
1656
1672
|
var { createMarkdown: createMarkdown2 } = (init_markdown(), __toCommonJS(markdown_exports));
|
|
1657
1673
|
var { ExtLink, MdImg, renderMarkdown } = createMarkdown2(h);
|
|
@@ -1705,7 +1721,7 @@ var ZH = {
|
|
|
1705
1721
|
"op.superseded.note": "{target} \u5DF2\u8DF3\u8FC7\uFF08\u524D\u63D0\u5DF2\u4E0D\u6210\u7ACB\u6216\u5DF2\u624B\u52A8\u5904\u7406\uFF09",
|
|
1706
1722
|
"op.cancelled": "\u7528\u6237\u653E\u5F03\u786E\u8BA4",
|
|
1707
1723
|
"op.remove": "\u79FB\u9664\u8BB0\u5F55",
|
|
1708
|
-
"op.panel.jump": "\u67E5\u770B\u64CD\u4F5C\
|
|
1724
|
+
"op.panel.jump": "\u67E5\u770B\u64CD\u4F5C\u8BB0\u5F55",
|
|
1709
1725
|
"op.kind.install": "\u5B89\u88C5",
|
|
1710
1726
|
"op.kind.upgrade": "\u5347\u7EA7",
|
|
1711
1727
|
"op.kind.uninstall": "\u5378\u8F7D",
|
|
@@ -1801,7 +1817,7 @@ var ZH = {
|
|
|
1801
1817
|
"src.custom.unavailable": "\u81EA\u5B9A\u4E49\u6E90\uFF08\u4E0D\u53EF\u7528\uFF09",
|
|
1802
1818
|
"settings.address": "Registry \u5730\u5740",
|
|
1803
1819
|
"settings.address.default": "\u5185\u7F6E\u9ED8\u8BA4\u6E05\u5355",
|
|
1804
|
-
"settings.note.custom": "\u81EA\u5B9A\u4E49\u6E90\u5C06\u6574\u4F53\u66FF\u6362\u300C\u7CBE\u9009\u6E05\u5355\u300D\uFF1B\
|
|
1820
|
+
"settings.note.custom": "\u81EA\u5B9A\u4E49\u6E90\u5C06\u6574\u4F53\u66FF\u6362\u300C\u7CBE\u9009\u6E05\u5355\u300D\uFF1B\u7559\u7A7A = \u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u6E05\u5355\u3002",
|
|
1805
1821
|
"settings.address.ph": "https://example.com/registry.json \u6216 /path/to/registry.json",
|
|
1806
1822
|
"settings.configured": "\u914D\u7F6E\u5730\u5740",
|
|
1807
1823
|
"settings.effective": "\u751F\u6548\u6765\u6E90",
|
|
@@ -1863,7 +1879,7 @@ var ZH = {
|
|
|
1863
1879
|
"guard.noforce": "\u5B88\u536B\u62E6\u622A\u65E0\u300C\u4ECD\u8981\u5B89\u88C5\u300D\u901A\u9053\uFF0C\u8BF7\u6309\u4FEE\u590D\u4F9D\u636E\u4EBA\u5DE5\u5904\u7406",
|
|
1864
1880
|
"detail.screenshots": "\u622A\u56FE",
|
|
1865
1881
|
"installed.check.incomplete": "\u68C0\u67E5\u672A\u5B8C\u6210",
|
|
1866
|
-
"settings.community": "\u793E\u533A\u6E05\u5355\
|
|
1882
|
+
"settings.community": "\u793E\u533A\u6E05\u5355\uFF08awesome-dsh-plugin\uFF09",
|
|
1867
1883
|
"settings.community.toggle": "\u793E\u533A\u76EE\u5F55\u5F00\u5173",
|
|
1868
1884
|
"settings.community.off": "\u793E\u533A\u76EE\u5F55\u5DF2\u5173\u95ED\uFF1A\u5E02\u573A\u4EC5\u663E\u793A\u7CBE\u9009\u6E05\u5355\uFF0C\u91CD\u65B0\u5F00\u542F\u5373\u65F6\u751F\u6548\u3002",
|
|
1869
1885
|
"settings.community.on.ok": "\u793E\u533A\u76EE\u5F55\u5DF2\u5F00\u542F\uFF08\u5373\u65F6\u751F\u6548\uFF09",
|
|
@@ -1877,6 +1893,11 @@ var ZH = {
|
|
|
1877
1893
|
"settings.community.count.v": "{n}\uFF08\u4E0A\u6E38 {up}\uFF09",
|
|
1878
1894
|
"settings.community.displaced": "\u4E0E\u7CBE\u9009\u91CD\u590D",
|
|
1879
1895
|
"settings.community.displaced.v": "{n} \u6761",
|
|
1896
|
+
"settings.ops": "\u64CD\u4F5C\u8BB0\u5F55",
|
|
1897
|
+
"settings.ops.empty": "\u6682\u65E0\u64CD\u4F5C\u8BB0\u5F55\u3002\u5B89\u88C5\u3001\u5347\u7EA7\u3001\u5378\u8F7D\u4E0E\u5F00\u5173\u64CD\u4F5C\u7684\u6267\u884C\u5386\u53F2\u5C06\u5728\u8FD9\u91CC\u663E\u793A\u3002",
|
|
1898
|
+
"settings.ops.group.active": "\u8FDB\u884C\u4E2D",
|
|
1899
|
+
"settings.ops.group.done": "\u5DF2\u7ED3\u675F",
|
|
1900
|
+
"settings.ops.reddot": "\u5B58\u5728\u5931\u8D25\u6216\u5E26\u8B66\u544A\u7684\u64CD\u4F5C\u8BB0\u5F55",
|
|
1880
1901
|
"registry.refreshed": "\u6536\u5F55\u6E05\u5355\u5DF2\u5F3A\u5236\u5237\u65B0",
|
|
1881
1902
|
"notify.installed": "\u5DF2\u5B89\u88C5 {pkg}{version}",
|
|
1882
1903
|
"notify.allowbuilds": "\uFF08\u6CE8\u610F\uFF1A\u8BE5\u63D2\u4EF6\u6267\u884C\u4E86\u6784\u5EFA\u811A\u672C\uFF0C\u5DF2\u6309\u7B56\u7565\u653E\u884C\uFF09",
|
|
@@ -1986,7 +2007,7 @@ var EN = {
|
|
|
1986
2007
|
"op.superseded.note": "{target} skipped (precondition gone or already handled)",
|
|
1987
2008
|
"op.cancelled": "user cancelled",
|
|
1988
2009
|
"op.remove": "Dismiss",
|
|
1989
|
-
"op.panel.jump": "Open operations
|
|
2010
|
+
"op.panel.jump": "Open operations card",
|
|
1990
2011
|
"op.kind.install": "Install",
|
|
1991
2012
|
"op.kind.upgrade": "Upgrade",
|
|
1992
2013
|
"op.kind.uninstall": "Uninstall",
|
|
@@ -2082,7 +2103,7 @@ var EN = {
|
|
|
2082
2103
|
"src.custom.unavailable": "Custom source (unavailable)",
|
|
2083
2104
|
"settings.address": "Registry address",
|
|
2084
2105
|
"settings.address.default": "Built-in default registry",
|
|
2085
|
-
"settings.note.custom": "A custom source replaces the whole Curated registry
|
|
2106
|
+
"settings.note.custom": "A custom source replaces the whole Curated registry. Leave empty for the built-in default.",
|
|
2086
2107
|
"settings.address.ph": "https://example.com/registry.json or /path/to/registry.json",
|
|
2087
2108
|
"settings.configured": "Configured address",
|
|
2088
2109
|
"settings.effective": "Effective source",
|
|
@@ -2144,7 +2165,7 @@ var EN = {
|
|
|
2144
2165
|
"guard.noforce": "Guard blocks have no force channel \u2014 repair manually per the basis above",
|
|
2145
2166
|
"detail.screenshots": "Screenshots",
|
|
2146
2167
|
"installed.check.incomplete": "Check incomplete",
|
|
2147
|
-
"settings.community": "Community catalog (
|
|
2168
|
+
"settings.community": "Community catalog (awesome-dsh-plugin)",
|
|
2148
2169
|
"settings.community.toggle": "Community catalog toggle",
|
|
2149
2170
|
"settings.community.off": "Community catalog is off: the market shows only the Curated registry. Toggle back on anytime \u2014 it applies live.",
|
|
2150
2171
|
"settings.community.on.ok": "Community catalog enabled (live)",
|
|
@@ -2158,6 +2179,11 @@ var EN = {
|
|
|
2158
2179
|
"settings.community.count.v": "{n} (upstream {up})",
|
|
2159
2180
|
"settings.community.displaced": "Displaced (duplicates)",
|
|
2160
2181
|
"settings.community.displaced.v": "{n}",
|
|
2182
|
+
"settings.ops": "Operations",
|
|
2183
|
+
"settings.ops.empty": "No operations yet. Install, upgrade, uninstall and toggle history will appear here.",
|
|
2184
|
+
"settings.ops.group.active": "Active",
|
|
2185
|
+
"settings.ops.group.done": "Finished",
|
|
2186
|
+
"settings.ops.reddot": "Failed or warned operations exist",
|
|
2161
2187
|
"registry.refreshed": "Registry force-refreshed",
|
|
2162
2188
|
"notify.installed": "Installed {pkg}{version}",
|
|
2163
2189
|
"notify.allowbuilds": " (note: this plugin ran build scripts, allowed by policy)",
|
|
@@ -2364,8 +2390,10 @@ var CSS = `
|
|
|
2364
2390
|
\u5728\u6D45\u5E95\u4E0A\u4E0D\u53EF\u89C1\uFF08\u7528\u6237\u53CC\u6A21\u5F0F\u5B9E\u62CD\uFF09\u3002\u53CC\u4FA7\u4FEE\u590D\u2014\u2014\u76AE\u80A4\u4FA7 :not(.dsvm-lightbox) \u8C41\u514D
|
|
2365
2391
|
\uFF08dsh-skins 1.5.1 \u8D77\uFF09\uFF1B\u672C\u4FA7 background !important \u81EA\u6301\uFF1Amarketplace \u793E\u533A\u76AE\u80A4\u4E0D\u53EF
|
|
2366
2392
|
\u679A\u4E3E\uFF0C\u5F71\u9662\u4E0D\u53D8\u91CF\u5FC5\u987B\u7531\u7EC4\u4EF6\u81EA\u5DF1\u515C\u5E95\u3002!important \u6E05\u5355\u5B9A\u957F\uFF08\u6CE8\u91CA\u63D0\u53CA\xD72 + \u672C\u89C4\u5219
|
|
2367
|
-
+ sidebar footer \u517C\u5BB9\u89C4\u5219\uFF09\uFF0C\u65B0\u589E\u987B\u6539 client-lightbox \u65AD\u8A00\u663E\u5F0F\u767B\u8BB0\uFF0C\u6CE8\u91CA\u5373\u5B88\u536B\u3002
|
|
2368
|
-
.
|
|
2393
|
+
+ sidebar footer \u517C\u5BB9\u89C4\u5219\uFF09\uFF0C\u65B0\u589E\u987B\u6539 client-lightbox \u65AD\u8A00\u663E\u5F0F\u767B\u8BB0\uFF0C\u6CE8\u91CA\u5373\u5B88\u536B\u3002
|
|
2394
|
+
0.9.65\uFF1Atouch-action:pan-y pinch-zoom\u2014\u2014\u6A2A\u6ED1\u5224\u5411\u4EA4\u7ED9\u706F\u7BB1\u6ED1\u52A8\u5207\u6362\uFF0C\u7EB5\u5411\u539F\u751F
|
|
2395
|
+
\u624B\u52BF\u4E0E pinch \u7F29\u653E\uFF08\u4F4E\u89C6\u529B\u53EF\u8FBE\u6027\uFF09\u4E0D\u88AB\u52AB\u6301\u3002 */
|
|
2396
|
+
.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)!important;display:flex;align-items:center;justify-content:center;touch-action:pan-y pinch-zoom}
|
|
2369
2397
|
.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}
|
|
2370
2398
|
.dsvm-btn:focus-visible{outline:2px solid rgba(255,255,255,.75);outline-offset:2px}
|
|
2371
2399
|
.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}
|
|
@@ -2403,7 +2431,11 @@ var CSS = `
|
|
|
2403
2431
|
.dshm-card:hover{border-color:var(--dsw-alias-interactive-bg-selected,#4f46e5)}
|
|
2404
2432
|
.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}
|
|
2405
2433
|
.dsvm-btn:hover{background:rgba(255,255,255,.24)}
|
|
2406
|
-
.dsvm-ops{
|
|
2434
|
+
.dsvm-ops-caption{font-size:11px;color:var(--dsw-alias-label-caption,#9ca3af);margin:2px 0 -3px}
|
|
2435
|
+
.dshm-ops-scroll{max-height:220px;overflow-y:auto;overscroll-behavior:contain}
|
|
2436
|
+
.dshm-ops-scroll::-webkit-scrollbar{width:8px}
|
|
2437
|
+
.dshm-ops-scroll::-webkit-scrollbar-thumb{background:rgba(127,127,127,.28);border-radius:4px}
|
|
2438
|
+
.dshm-ops-scroll::-webkit-scrollbar-thumb:hover{background:rgba(127,127,127,.45)}
|
|
2407
2439
|
.dsvm-opgroup{display:flex;flex-direction:column;gap:3px}
|
|
2408
2440
|
.dsvm-opgroup.done{opacity:.75}
|
|
2409
2441
|
.dsvm-oprow{display:flex;align-items:center;gap:8px;min-height:22px}
|
|
@@ -2447,6 +2479,23 @@ button.dshm-badge:hover{filter:brightness(.95)}
|
|
|
2447
2479
|
.dshm-row{display:flex;align-items:center;gap:8px}
|
|
2448
2480
|
.dshm-kv{display:grid;grid-template-columns:96px 1fr;gap:6px 10px;font-size:12px;align-items:baseline}
|
|
2449
2481
|
.dshm-kv .k{color:var(--dsw-alias-label-caption,#6b7280);font-size:11px}
|
|
2482
|
+
.dshm-settings-grid{display:grid;gap:10px;grid-template-columns:4fr 7fr;min-width:0}
|
|
2483
|
+
.dshm-settings-grid>.dshm-section{margin:0;min-width:0}
|
|
2484
|
+
.dshm-settings-grid>.dshm-section:nth-child(3){grid-column:1/-1}
|
|
2485
|
+
.dshm-settings-grid>.dshm-ops-card{grid-column:1/-1}
|
|
2486
|
+
.dshm-panel.full .dshm-settings-grid{grid-template-columns:4fr 7fr 3fr}
|
|
2487
|
+
.dshm-panel.full .dshm-settings-grid>.dshm-section:nth-child(3){grid-column:auto}
|
|
2488
|
+
@media (max-width:760px){.dshm-settings-grid,.dshm-panel.full .dshm-settings-grid{grid-template-columns:minmax(0,1fr)}.dshm-settings-grid>.dshm-section:nth-child(3),.dshm-settings-grid>.dshm-ops-card{grid-column:1/-1}}
|
|
2489
|
+
.dshm-kvlines{display:flex;flex-direction:column}
|
|
2490
|
+
.dshm-kvline-row{display:flex;justify-content:space-between;align-items:baseline;gap:10px;padding:5px 0;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(127,127,127,.14));min-width:0}
|
|
2491
|
+
.dshm-kvline-row:last-child{border-bottom:0}
|
|
2492
|
+
.dshm-kvline-row .rl{font-size:11px;color:var(--dsw-alias-label-caption,#6b7280);flex:none}
|
|
2493
|
+
.dshm-kvline-row .rv{font-size:12px;text-align:right;font-variant-numeric:tabular-nums;overflow-wrap:anywhere;min-width:0}
|
|
2494
|
+
.dshm-kvline-row .dshm-switch{margin-left:0;align-self:center}
|
|
2495
|
+
.dshm-dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:5px;vertical-align:1px;background:var(--dsw-alias-state-success-primary,#22c55e)}
|
|
2496
|
+
.dshm-dot.warn{background:var(--dsw-alias-state-warn-primary,#b45309)}
|
|
2497
|
+
.dshm-dot.err{background:var(--dsw-alias-state-error-primary,#b91c1c)}
|
|
2498
|
+
.dshm-code-1line{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
|
|
2450
2499
|
.dshm-section{background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.04));border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;padding:12px 14px;display:flex;flex-direction:column;gap:9px;margin:0 0 10px}
|
|
2451
2500
|
.dshm-section:last-child{margin-bottom:2px}
|
|
2452
2501
|
.dshm-section-title{display:flex;align-items:center;gap:7px;font-weight:700;font-size:12px;letter-spacing:.2px;color:var(--dsw-alias-label-primary,inherit)}
|
|
@@ -3160,9 +3209,40 @@ function Lightbox({ shots, index, onNav, onClose }) {
|
|
|
3160
3209
|
if (closeRef.current) closeRef.current.focus();
|
|
3161
3210
|
}, []);
|
|
3162
3211
|
const chain = useImgChain(shots[index], { w: 1600 });
|
|
3212
|
+
const prefetchedRef = useRef(null);
|
|
3213
|
+
if (prefetchedRef.current === null) prefetchedRef.current = /* @__PURE__ */ new Set();
|
|
3214
|
+
useEffect(() => {
|
|
3215
|
+
if (typeof Image === "undefined") return;
|
|
3216
|
+
if (!chain.settled || chain.failed) return;
|
|
3217
|
+
for (const n of lbNeighbors2(index, shots.length)) {
|
|
3218
|
+
const url = shots[n];
|
|
3219
|
+
if (typeof url !== "string" || url === "" || prefetchedRef.current.has(url)) continue;
|
|
3220
|
+
prefetchedRef.current.add(url);
|
|
3221
|
+
const img = new Image();
|
|
3222
|
+
img.decoding = "async";
|
|
3223
|
+
img.src = weservUrl2(url, { w: 1600 });
|
|
3224
|
+
}
|
|
3225
|
+
}, [chain.settled, chain.failed, index, shots]);
|
|
3226
|
+
const swipeRef = useRef(null);
|
|
3227
|
+
const swipedAtRef = useRef(0);
|
|
3228
|
+
const onPointerDown = (e) => {
|
|
3229
|
+
if (e.pointerType !== "touch") return;
|
|
3230
|
+
swipeRef.current = { x: e.clientX, y: e.clientY };
|
|
3231
|
+
};
|
|
3232
|
+
const onPointerUp = (e) => {
|
|
3233
|
+
if (e.pointerType !== "touch" || !swipeRef.current) return;
|
|
3234
|
+
const dir = swipeDir2(e.clientX - swipeRef.current.x, e.clientY - swipeRef.current.y);
|
|
3235
|
+
swipeRef.current = null;
|
|
3236
|
+
if (!dir || single) return;
|
|
3237
|
+
swipedAtRef.current = Date.now();
|
|
3238
|
+
onNav(lbStep2(index, dir, shots.length));
|
|
3239
|
+
};
|
|
3240
|
+
const onClickCapture = (e) => {
|
|
3241
|
+
if (Date.now() - swipedAtRef.current < 500) e.stopPropagation();
|
|
3242
|
+
};
|
|
3163
3243
|
const node = h(
|
|
3164
3244
|
"div",
|
|
3165
|
-
{ className: "dsvm-lightbox", role: "dialog", "aria-modal": "true", "aria-label": lookup("lb.title"), ...backdropCloseHandlers2(onClose) },
|
|
3245
|
+
{ className: "dsvm-lightbox", role: "dialog", "aria-modal": "true", "aria-label": lookup("lb.title"), onPointerDown, onPointerUp, onClickCapture, ...backdropCloseHandlers2(onClose) },
|
|
3166
3246
|
chain.failed ? h(
|
|
3167
3247
|
"div",
|
|
3168
3248
|
{ className: "dsvm-lbfail", onClick: (e) => e.stopPropagation() },
|
|
@@ -3252,6 +3332,19 @@ function DetailModal({ it, labels, busy, onClose, onInstall, onUpgrade, upgradeB
|
|
|
3252
3332
|
if (e.key === "ArrowLeft") setLb((i) => lbStep2(i, -1, visible.length));
|
|
3253
3333
|
if (e.key === "ArrowRight") setLb((i) => lbStep2(i, 1, visible.length));
|
|
3254
3334
|
}
|
|
3335
|
+
if (e.key === "Tab" && lb !== null) {
|
|
3336
|
+
const box = typeof document !== "undefined" ? document.querySelector(".dsvm-lightbox") : null;
|
|
3337
|
+
if (!box) return;
|
|
3338
|
+
const focusables = Array.from(box.querySelectorAll("button, a[href]")).filter((el) => el.offsetWidth > 0 && el.offsetHeight > 0);
|
|
3339
|
+
if (!focusables.length) return;
|
|
3340
|
+
const first = focusables[0];
|
|
3341
|
+
const last = focusables[focusables.length - 1];
|
|
3342
|
+
const active = document.activeElement;
|
|
3343
|
+
if (!box.contains(active) || (e.shiftKey ? active === first : active === last)) {
|
|
3344
|
+
e.preventDefault();
|
|
3345
|
+
(e.shiftKey ? last : first).focus();
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3255
3348
|
};
|
|
3256
3349
|
document.addEventListener("keydown", onKey);
|
|
3257
3350
|
return () => document.removeEventListener("keydown", onKey);
|
|
@@ -3379,7 +3472,7 @@ var ZONE_TABS = [
|
|
|
3379
3472
|
{ id: "primary", labelKey: "zone.primary" },
|
|
3380
3473
|
{ id: "favorites", labelKey: "zone.favorites" }
|
|
3381
3474
|
];
|
|
3382
|
-
function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind }) {
|
|
3475
|
+
function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind, onOpenOps }) {
|
|
3383
3476
|
const [zone, setZone] = useState("community");
|
|
3384
3477
|
const market = zone === "favorites" ? null : markets[zone];
|
|
3385
3478
|
const { data, loading, error, reload, query, updateQuery } = market || {};
|
|
@@ -3669,10 +3762,7 @@ function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind })
|
|
|
3669
3762
|
title: lookup("op.panel.jump"),
|
|
3670
3763
|
onClick: (e) => {
|
|
3671
3764
|
e.stopPropagation();
|
|
3672
|
-
if (typeof
|
|
3673
|
-
const el = document.querySelector(".dsvm-ops");
|
|
3674
|
-
if (el && el.scrollIntoView) el.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
3675
|
-
}
|
|
3765
|
+
if (typeof onOpenOps === "function") onOpenOps();
|
|
3676
3766
|
}
|
|
3677
3767
|
},
|
|
3678
3768
|
lookup("op.status.running")
|
|
@@ -4045,7 +4135,7 @@ function regSourceLabel(data) {
|
|
|
4045
4135
|
function configStatusLabel(status) {
|
|
4046
4136
|
return lookup(`settings.status.${status || "loading"}` || "settings.status.loading");
|
|
4047
4137
|
}
|
|
4048
|
-
function SettingsTab({ notify, onRegistryChanged, onForceMarket }) {
|
|
4138
|
+
function SettingsTab({ notify, onRegistryChanged, onForceMarket, opsRecords, onOpsClearFinished, onOpsRemove }) {
|
|
4049
4139
|
const reg = useAsync((force) => api("registry", force ? { force: true } : {}), []);
|
|
4050
4140
|
const cfgState = useAsync(() => api("registry-config"), []);
|
|
4051
4141
|
const [busy, setBusy] = useState(false);
|
|
@@ -4135,47 +4225,61 @@ function SettingsTab({ notify, onRegistryChanged, onForceMarket }) {
|
|
|
4135
4225
|
};
|
|
4136
4226
|
const communityLive = communitySummary && (communitySummary.status === "ready" || communitySummary.status === "stale");
|
|
4137
4227
|
const communityStatusBadge = !communityLive ? { cls: "err", label: lookup("settings.status.unavailable") } : communitySummary.status === "stale" ? { cls: "warn", label: lookup("settings.community.status.stale") } : { cls: "ok", label: lookup("settings.status.ready") };
|
|
4138
|
-
|
|
4228
|
+
const kvlineRow = (labelKey, valueNode) => h(
|
|
4229
|
+
"div",
|
|
4230
|
+
{ className: "dshm-kvline-row" },
|
|
4231
|
+
h("span", { className: "rl" }, lookup(labelKey)),
|
|
4232
|
+
h("span", { className: "rv" }, valueNode)
|
|
4233
|
+
);
|
|
4234
|
+
const communitySwitch = h(
|
|
4235
|
+
"label",
|
|
4236
|
+
{
|
|
4237
|
+
className: `dshm-switch${communityOn ? " on" : ""}${communityBusy || communityOn === null ? " locked" : ""}`,
|
|
4238
|
+
title: lookup("settings.community.toggle")
|
|
4239
|
+
},
|
|
4240
|
+
h("input", {
|
|
4241
|
+
type: "checkbox",
|
|
4242
|
+
checked: communityOn === true,
|
|
4243
|
+
disabled: communityBusy || communityOn === null,
|
|
4244
|
+
onChange: (e) => applyCommunity(e.target.checked)
|
|
4245
|
+
}),
|
|
4246
|
+
h("span", { className: "dshm-switch-slider" })
|
|
4247
|
+
);
|
|
4248
|
+
const communitySwitchRow = h(
|
|
4249
|
+
"div",
|
|
4250
|
+
{ className: "dshm-kvline-row" },
|
|
4251
|
+
h("span", { className: "rl" }, lookup("settings.community.toggle")),
|
|
4252
|
+
communitySwitch
|
|
4253
|
+
);
|
|
4254
|
+
const communityBody = communityOn === false ? h(
|
|
4139
4255
|
React.Fragment,
|
|
4140
4256
|
null,
|
|
4141
|
-
|
|
4257
|
+
h("div", { className: "dshm-hint" }, lookup("settings.community.off")),
|
|
4258
|
+
communitySwitchRow
|
|
4259
|
+
) : h(
|
|
4260
|
+
"div",
|
|
4261
|
+
{ className: "dshm-kvlines" },
|
|
4262
|
+
kvlineRow("settings.community.status", h(
|
|
4263
|
+
"span",
|
|
4264
|
+
null,
|
|
4265
|
+
h("span", { className: `dshm-dot${communityStatusBadge.cls === "ok" ? "" : ` ${communityStatusBadge.cls}`}` }),
|
|
4266
|
+
communityStatusBadge.label
|
|
4267
|
+
)),
|
|
4268
|
+
kvlineRow("settings.community.version", communityLive ? communitySummary.version || "\u2014" : "\u2014"),
|
|
4269
|
+
kvlineRow("settings.community.route", communityLive ? communitySummary.route || "\u2014" : "\u2014"),
|
|
4270
|
+
kvlineRow("settings.community.count", communityLive ? lookup("settings.community.count.v", { n: communitySummary.acceptedCount ?? 0, up: communitySummary.upstreamCount ?? "\u2014" }) : "\u2014"),
|
|
4271
|
+
kvlineRow("settings.community.displaced", communityLive ? lookup("settings.community.displaced.v", { n: communitySummary.displaced ?? 0 }) : "\u2014"),
|
|
4272
|
+
communitySwitchRow
|
|
4273
|
+
);
|
|
4274
|
+
return h(
|
|
4275
|
+
"div",
|
|
4276
|
+
{ className: "dshm-settings-grid" },
|
|
4277
|
+
// ① 社区清单(awesome-dsh-plugin):左卡;清爽列表 + 发丝分隔线,开关为列表末行
|
|
4142
4278
|
h(
|
|
4143
4279
|
"div",
|
|
4144
4280
|
{ className: "dshm-section" },
|
|
4145
|
-
h(
|
|
4146
|
-
|
|
4147
|
-
{ className: "dshm-section-title" },
|
|
4148
|
-
lookup("settings.community"),
|
|
4149
|
-
h("span", { className: "dshm-spacer" }),
|
|
4150
|
-
h(
|
|
4151
|
-
"label",
|
|
4152
|
-
{
|
|
4153
|
-
className: `dshm-switch${communityOn ? " on" : ""}${communityBusy || communityOn === null ? " locked" : ""}`,
|
|
4154
|
-
title: lookup("settings.community.toggle")
|
|
4155
|
-
},
|
|
4156
|
-
h("input", {
|
|
4157
|
-
type: "checkbox",
|
|
4158
|
-
checked: communityOn === true,
|
|
4159
|
-
disabled: communityBusy || communityOn === null,
|
|
4160
|
-
onChange: (e) => applyCommunity(e.target.checked)
|
|
4161
|
-
}),
|
|
4162
|
-
h("span", { className: "dshm-switch-slider" })
|
|
4163
|
-
)
|
|
4164
|
-
),
|
|
4165
|
-
communityOn === false ? h("div", { className: "dshm-hint" }, lookup("settings.community.off")) : h(
|
|
4166
|
-
"div",
|
|
4167
|
-
{ className: "dshm-kv" },
|
|
4168
|
-
h("span", { className: "k" }, lookup("settings.community.status")),
|
|
4169
|
-
h("span", null, h("span", { className: `dshm-badge ${communityStatusBadge.cls}` }, communityStatusBadge.label)),
|
|
4170
|
-
h("span", { className: "k" }, lookup("settings.community.version")),
|
|
4171
|
-
h("span", null, communityLive ? communitySummary.version || "\u2014" : "\u2014"),
|
|
4172
|
-
h("span", { className: "k" }, lookup("settings.community.route")),
|
|
4173
|
-
h("span", null, communityLive ? communitySummary.route || "\u2014" : "\u2014"),
|
|
4174
|
-
h("span", { className: "k" }, lookup("settings.community.count")),
|
|
4175
|
-
h("span", null, communityLive ? lookup("settings.community.count.v", { n: communitySummary.acceptedCount ?? 0, up: communitySummary.upstreamCount ?? "\u2014" }) : "\u2014"),
|
|
4176
|
-
h("span", { className: "k" }, lookup("settings.community.displaced")),
|
|
4177
|
-
h("span", null, communityLive ? lookup("settings.community.displaced.v", { n: communitySummary.displaced ?? 0 }) : "\u2014")
|
|
4178
|
-
),
|
|
4281
|
+
h("div", { className: "dshm-section-title" }, lookup("settings.community")),
|
|
4282
|
+
communityBody,
|
|
4179
4283
|
communitySummary && Array.isArray(communitySummary.errors) && communitySummary.errors.length && communityOn !== false ? h("div", { className: "dshm-err" }, communitySummary.errors.join("\uFF1B")) : null
|
|
4180
4284
|
),
|
|
4181
4285
|
// ② 精选清单(registry.json):自定义源整体替换主清单,仅影响市场「精选」区
|
|
@@ -4226,7 +4330,7 @@ function SettingsTab({ notify, onRegistryChanged, onForceMarket }) {
|
|
|
4226
4330
|
"div",
|
|
4227
4331
|
{ className: "dshm-kv", style: { marginTop: "4px" } },
|
|
4228
4332
|
h("span", { className: "k" }, lookup("settings.configured")),
|
|
4229
|
-
h("span", null, snap.registryUrl ? h("span", { className: "dshm-code" }, snap.registryUrl) : h("span", { className: "dshm-hint" }, lookup("settings.address.default"))),
|
|
4333
|
+
h("span", null, snap.registryUrl ? h("span", { className: "dshm-code dshm-code-1line", title: snap.registryUrl }, snap.registryUrl) : h("span", { className: "dshm-hint" }, lookup("settings.address.default"))),
|
|
4230
4334
|
h("span", { className: "k" }, lookup("settings.effective")),
|
|
4231
4335
|
h("span", null, regSourceLabel(state), state && !state.isDefault ? h("span", { className: "dshm-badge info", style: { marginLeft: "6px" } }, lookup("badge.custom")) : null),
|
|
4232
4336
|
h("span", { className: "k" }, lookup("settings.updated")),
|
|
@@ -4251,7 +4355,9 @@ function SettingsTab({ notify, onRegistryChanged, onForceMarket }) {
|
|
|
4251
4355
|
h("span", { className: "dshm-links-sep" }, "\xB7"),
|
|
4252
4356
|
h(ExtLink, { href: "https://www.npmjs.com/package/dsh-m" }, lookup("settings.about.npm"))
|
|
4253
4357
|
)
|
|
4254
|
-
)
|
|
4358
|
+
),
|
|
4359
|
+
// ④ 操作记录:恒通宽卡(第二批搬迁),进行中常驻 + 已结束滚动区,空态 hint 导览
|
|
4360
|
+
h(OperationsCard, { records: opsRecords, onClearFinished: onOpsClearFinished, onRemove: onOpsRemove })
|
|
4255
4361
|
);
|
|
4256
4362
|
}
|
|
4257
4363
|
function Section(title, sub, ...children) {
|
|
@@ -4421,10 +4527,9 @@ var OP_STATUS_CLS = {
|
|
|
4421
4527
|
failed: "err",
|
|
4422
4528
|
superseded: "sup"
|
|
4423
4529
|
};
|
|
4424
|
-
function
|
|
4530
|
+
function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
4425
4531
|
const active = records.filter((r) => r.status === "queued" || r.status === "running" || r.status === "input");
|
|
4426
|
-
const finished = records.filter((r) => active.indexOf(r) < 0).slice(-
|
|
4427
|
-
if (!active.length && !finished.length) return null;
|
|
4532
|
+
const finished = records.filter((r) => active.indexOf(r) < 0).slice(-50);
|
|
4428
4533
|
const clearable = records.some((r) => TERMINAL_CLEARABLE2.has(r.status));
|
|
4429
4534
|
const row = (r) => h(
|
|
4430
4535
|
"div",
|
|
@@ -4440,14 +4545,30 @@ function OperationsPanel({ records, onClearFinished, onRemove }) {
|
|
|
4440
4545
|
);
|
|
4441
4546
|
return h(
|
|
4442
4547
|
"div",
|
|
4443
|
-
{ className: "
|
|
4548
|
+
{ className: "dshm-section dshm-ops-card" },
|
|
4549
|
+
h("div", { className: "dshm-section-title" }, lookup("settings.ops")),
|
|
4550
|
+
active.length && finished.length ? h("div", { className: "dsvm-ops-caption" }, lookup("settings.ops.group.active")) : null,
|
|
4444
4551
|
active.length ? h("div", { className: "dsvm-opgroup" }, ...active.map(row)) : null,
|
|
4445
4552
|
finished.length ? h(
|
|
4446
4553
|
"div",
|
|
4447
|
-
{ className: "dsvm-
|
|
4448
|
-
|
|
4554
|
+
{ className: "dsvm-ops-caption", style: { marginTop: active.length ? "7px" : "0" } },
|
|
4555
|
+
lookup("settings.ops.group.done")
|
|
4556
|
+
) : null,
|
|
4557
|
+
finished.length ? h(
|
|
4558
|
+
"div",
|
|
4559
|
+
{ className: "dshm-ops-scroll" },
|
|
4560
|
+
h(
|
|
4561
|
+
"div",
|
|
4562
|
+
{ className: "dsvm-opgroup done" },
|
|
4563
|
+
...finished.map(row)
|
|
4564
|
+
)
|
|
4565
|
+
) : null,
|
|
4566
|
+
finished.length ? h(
|
|
4567
|
+
"div",
|
|
4568
|
+
{ className: "dshm-actions" },
|
|
4449
4569
|
h("button", { className: "dshm-btn sm", disabled: !clearable, title: clearable ? void 0 : lookup("op.clear.none"), onClick: onClearFinished }, lookup("op.clear"))
|
|
4450
|
-
) : null
|
|
4570
|
+
) : null,
|
|
4571
|
+
!active.length && !finished.length ? h("div", { className: "dshm-hint" }, lookup("settings.ops.empty")) : null
|
|
4451
4572
|
);
|
|
4452
4573
|
}
|
|
4453
4574
|
var TABS = [
|
|
@@ -4567,6 +4688,16 @@ function MarketPanel({ onClose }) {
|
|
|
4567
4688
|
const updates = useAsync(() => api("installedUpdates"), []);
|
|
4568
4689
|
const [opRecords, setOpRecords] = useState(() => opsStore.list().map((r) => ({ ...r })));
|
|
4569
4690
|
const syncOps = useCallback(() => setOpRecords(opsStore.list().map((r) => ({ ...r }))), []);
|
|
4691
|
+
const openOps = useCallback(() => {
|
|
4692
|
+
setTab("settings");
|
|
4693
|
+
if (typeof document !== "undefined") {
|
|
4694
|
+
setTimeout(() => {
|
|
4695
|
+
const el = document.querySelector(".dshm-ops-card");
|
|
4696
|
+
if (el && el.scrollIntoView) el.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
4697
|
+
}, 60);
|
|
4698
|
+
}
|
|
4699
|
+
}, [setTab]);
|
|
4700
|
+
const opsAttention = opRecords.some((r) => r.status === "failed" || r.status === "warned");
|
|
4570
4701
|
const runOp = useCallback(
|
|
4571
4702
|
(kind, target, exec, meta = {}, reuseId) => (
|
|
4572
4703
|
// session:true = 活会话标记(终审·新伤1):重挂载的 restore 跳过(泵仍拥有);persist 时剥离。
|
|
@@ -4727,7 +4858,9 @@ function MarketPanel({ onClose }) {
|
|
|
4727
4858
|
},
|
|
4728
4859
|
lookup(labelKey),
|
|
4729
4860
|
countKey && counts[countKey] != null ? h("span", { className: "dshm-count" }, String(counts[countKey])) : null,
|
|
4730
|
-
key === "installed" && outdatedCount > 0 ? h("span", { className: "dsvm-reddot", title: lookup("installed.upgradeAll", { n: outdatedCount }) }) : null
|
|
4861
|
+
key === "installed" && outdatedCount > 0 ? h("span", { className: "dsvm-reddot", title: lookup("installed.upgradeAll", { n: outdatedCount }) }) : null,
|
|
4862
|
+
// 底部操作区搬迁补偿(第二批):failed/warned 终态无人主动逛设置页,红点兜底可见性
|
|
4863
|
+
key === "settings" && opsAttention ? h("span", { className: "dsvm-reddot", title: lookup("settings.ops.reddot") }) : null
|
|
4731
4864
|
)
|
|
4732
4865
|
)
|
|
4733
4866
|
),
|
|
@@ -4756,20 +4889,23 @@ function MarketPanel({ onClose }) {
|
|
|
4756
4889
|
h(
|
|
4757
4890
|
"div",
|
|
4758
4891
|
{ className: "dshm-body" },
|
|
4759
|
-
tab === "market" ? h(MarketTab, { notify, markets, onMutation: refreshViews, ops, favorites, profileKind: profile?.kind ?? null }) : null,
|
|
4892
|
+
tab === "market" ? h(MarketTab, { notify, markets, onMutation: refreshViews, ops, favorites, profileKind: profile?.kind ?? null, onOpenOps: openOps }) : null,
|
|
4760
4893
|
tab === "installed" ? h(InstalledTab, { notify, installed, updates, onMutation: refreshViews, ops }) : null,
|
|
4761
|
-
tab === "settings" ? h(SettingsTab, {
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4894
|
+
tab === "settings" ? h(SettingsTab, {
|
|
4895
|
+
notify,
|
|
4896
|
+
onRegistryChanged,
|
|
4897
|
+
onForceMarket: () => marketReloadAll(true),
|
|
4898
|
+
opsRecords: opRecords,
|
|
4899
|
+
onOpsClearFinished: () => {
|
|
4765
4900
|
opsStore.clearFinished();
|
|
4766
4901
|
syncOps();
|
|
4767
4902
|
},
|
|
4768
|
-
|
|
4903
|
+
onOpsRemove: (id) => {
|
|
4769
4904
|
opsStore.remove(id);
|
|
4770
4905
|
syncOps();
|
|
4771
4906
|
}
|
|
4772
|
-
})
|
|
4907
|
+
}) : null
|
|
4908
|
+
// 操作记录已整体搬迁至设置 tab 末位通宽卡(0.9.x 布局重构·第二批):底部不再常驻
|
|
4773
4909
|
),
|
|
4774
4910
|
toast ? h(
|
|
4775
4911
|
"div",
|