dshmarket 1.3.0 → 1.4.0
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/LICENSE +21 -0
- package/README.md +4 -0
- package/README.zh.md +4 -0
- package/client/client.js +245 -74
- package/client/client.js.map +1 -1
- package/lib/dsh-cli.js +37 -6
- package/lib/install.js +32 -13
- package/lib/pnpm-compat.js +14 -0
- package/lib/restart.js +30 -4
- package/lib/routes.js +12 -3
- package/lib/types/dsh-cli.d.ts +4 -1
- package/lib/types/install.d.ts +16 -6
- package/lib/types/pnpm-compat.d.ts +1 -1
- package/lib/types/restart.d.ts +18 -0
- package/package.json +11 -3
- package/src/client/Market.module.css +18 -2
- package/src/client/MarketSection.tsx +119 -24
- package/src/client/locales.ts +12 -0
- package/src/client/market-data.ts +27 -3
- package/src/dsh-cli.ts +36 -7
- package/src/install.ts +33 -12
- package/src/pnpm-compat.ts +15 -1
- package/src/restart.ts +34 -4
- package/src/routes.ts +11 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fkysly and dsh-market contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -51,6 +51,10 @@ Installs prefer npm tarballs over full-repo GitHub downloads whenever a plugin p
|
|
|
51
51
|
- For terminal-attached launches, the detached replacement keeps running after the original terminal closes
|
|
52
52
|
- Listing ≠ endorsement: plugins are third-party code, install sources you trust
|
|
53
53
|
|
|
54
|
+
## Submit your plugin
|
|
55
|
+
|
|
56
|
+
**This repo is the market app, not the catalog.** The plugin list comes from the curated [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) registry — to get your plugin listed in the market, open a PR **there** (one entry in the list; the site and this market pick it up automatically, usually within a day). Please don't PR plugin entries against this repo.
|
|
57
|
+
|
|
54
58
|
## Data source
|
|
55
59
|
|
|
56
60
|
Live from [awesome-dsh-plugin.com/plugins.json](https://awesome-dsh-plugin.com/plugins.json) — curated entries, npm mapping, and star counts refreshed daily by CI — with a bundled snapshot as offline fallback.
|
package/README.zh.md
CHANGED
|
@@ -51,6 +51,10 @@ dsh plugin --profile web add dshmarket
|
|
|
51
51
|
- 从终端启动时,替代进程脱离原终端,关闭原终端后仍会继续运行
|
|
52
52
|
- 收录 ≠ 背书:插件是第三方代码,请只安装你信任的来源
|
|
53
53
|
|
|
54
|
+
## 提交你的插件
|
|
55
|
+
|
|
56
|
+
**这个仓库是市场应用本身,不是插件目录。** 市场里的插件列表来自精选列表 [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)——想让你的插件上架,请去**那边**提 PR(在列表里加一条即可,站点和本市场会自动收录,通常一天内生效)。请不要往本仓库提插件条目。
|
|
57
|
+
|
|
54
58
|
## 数据源
|
|
55
59
|
|
|
56
60
|
实时来自 [awesome-dsh-plugin.com/plugins.json](https://awesome-dsh-plugin.com/plugins.json)——精选条目、npm 映射、star 数由 CI 每日刷新——内置快照做离线兜底。
|
package/client/client.js
CHANGED
|
@@ -66,6 +66,12 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
66
66
|
catsLess: "收起",
|
|
67
67
|
sortHot: "最热",
|
|
68
68
|
sortNew: "最新",
|
|
69
|
+
prevPage: "上一页",
|
|
70
|
+
nextPage: "下一页",
|
|
71
|
+
firstPage: "首页",
|
|
72
|
+
lastPage: "末页",
|
|
73
|
+
pageInfo: "第 {0} / {1} 页",
|
|
74
|
+
perPage: "每页",
|
|
69
75
|
marketUpdate: "市场有新版本,升级",
|
|
70
76
|
updateAll: "全部更新",
|
|
71
77
|
tabThemes: "主题",
|
|
@@ -134,6 +140,12 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
134
140
|
catsLess: "Less",
|
|
135
141
|
sortHot: "Top",
|
|
136
142
|
sortNew: "New",
|
|
143
|
+
prevPage: "Previous",
|
|
144
|
+
nextPage: "Next",
|
|
145
|
+
firstPage: "First",
|
|
146
|
+
lastPage: "Last",
|
|
147
|
+
pageInfo: "Page {0} of {1}",
|
|
148
|
+
perPage: "Per page",
|
|
137
149
|
marketUpdate: "Market update available — upgrade",
|
|
138
150
|
updateAll: "Update all",
|
|
139
151
|
tabThemes: "Themes",
|
|
@@ -193,6 +205,29 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
193
205
|
return open || active === "all" ? categories : [active, ...categories.filter((id) => id !== active)];
|
|
194
206
|
}
|
|
195
207
|
/**
|
|
208
|
+
* Page-number list for the discover pager. With few pages it is simply
|
|
209
|
+
* 1..total; with many it windows around the current page and inserts '…'
|
|
210
|
+
* so a 400-plugin catalog stays a compact `1 … 4 5 6 … 17` instead of a
|
|
211
|
+
* long row of numbered buttons. Always begins with 1 and ends with total.
|
|
212
|
+
*/
|
|
213
|
+
function pageItems(current, total) {
|
|
214
|
+
if (total <= 7) {
|
|
215
|
+
const all = [];
|
|
216
|
+
for (let i = 1; i <= total; i++) all.push(i);
|
|
217
|
+
return all;
|
|
218
|
+
}
|
|
219
|
+
const items = [1];
|
|
220
|
+
let start = Math.max(2, current - 1);
|
|
221
|
+
let end = Math.min(total - 1, current + 1);
|
|
222
|
+
if (current <= 4) end = 5;
|
|
223
|
+
if (current >= total - 3) start = total - 4;
|
|
224
|
+
if (start > 2) items.push("…");
|
|
225
|
+
for (let i = start; i <= end; i++) items.push(i);
|
|
226
|
+
if (end < total - 1) items.push("…");
|
|
227
|
+
items.push(total);
|
|
228
|
+
return items;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
196
231
|
* Unified installed-state matching (#15): both sides collapse to lowercase
|
|
197
232
|
* identity sets — the registry entry contributes its bare name, npm name and
|
|
198
233
|
* owner/repo; the dependency contributes its key and the repo inside its
|
|
@@ -235,10 +270,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
235
270
|
return matchInstalledName(plugin, installed) !== null;
|
|
236
271
|
}
|
|
237
272
|
/**
|
|
238
|
-
* The brand mark
|
|
239
|
-
*
|
|
273
|
+
* The header brand mark now lives in MarketSection.tsx as an inline SVG
|
|
274
|
+
* (official-style monochrome glyph, fill="currentColor") so it follows the
|
|
275
|
+
* active theme; the colored assets/logo.svg tile is no longer inlined here.
|
|
240
276
|
*/
|
|
241
|
-
const LOGO_URI = "data:image/svg+xml," + encodeURIComponent("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\"><rect width=\"128\" height=\"128\" rx=\"28\" fill=\"#f6f2ea\"/><g transform=\"translate(15.7 16.7) scale(0.3) translate(-112 -78)\"><g fill=\"#2b2620\"><rect x=\"112\" y=\"112\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"112\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"112\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"112\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"312\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"312\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/></g><rect x=\"346\" y=\"78\" width=\"88\" height=\"88\" rx=\"14\" fill=\"#c0392b\" transform=\"rotate(9 390 122)\"/></g></svg>");
|
|
242
277
|
/** Four representative colors for a theme card's preview strip. */
|
|
243
278
|
function themeSwatch(def) {
|
|
244
279
|
const tk = def.tokens || {};
|
|
@@ -282,7 +317,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
282
317
|
}
|
|
283
318
|
//#endregion
|
|
284
319
|
//#region \0dsh-css:/home/runner/work/dsh-market/dsh-market/src/client/Market.module.css.mjs
|
|
285
|
-
const css = ".eGUBIq_root{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);flex-direction:column;display:flex;position:relative}.eGUBIq_head{flex-direction:column;gap:12px;padding:4px 4px 12px;display:flex}.eGUBIq_title{margin:0;font-size:16px;font-weight:500;line-height:24px}.eGUBIq_sub{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:14px;line-height:22px}.eGUBIq_searchInline{flex-shrink:0;width:200px;margin-bottom:6px}.eGUBIq_tabs{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-end;gap:2px;display:flex}.eGUBIq_tab{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;padding:7px 12px;font-size:13px}.eGUBIq_tab.eGUBIq_on{color:var(--dsw-alias-brand-primary,#4f6ef7);border-bottom-color:var(--dsw-alias-brand-primary,#4f6ef7);font-weight:600}.eGUBIq_restart{background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;align-items:center;gap:8px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_body{flex:1;padding:12px 4px 24px;overflow-x:hidden;overflow-y:auto}.eGUBIq_cats{z-index:5;background:var(--dsw-alias-bg-layer-2,#f7f8fa);margin:-12px -4px 2px;padding:12px 4px 4px;position:sticky;top:-13px}.eGUBIq_catsRow{align-items:flex-start;gap:8px;display:flex;position:relative}.eGUBIq_sort{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l1,#e5e7eb);border-radius:8px;flex-shrink:0;gap:2px;padding:2px;display:flex}.eGUBIq_sort button{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:3px 10px;font-size:12px}.eGUBIq_sort button.eGUBIq_on{background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600;box-shadow:0 1px 3px #00000014}.eGUBIq_star{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_top{z-index:20;border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);width:38px;height:38px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;border-radius:99px;font-size:16px;position:absolute;bottom:18px;right:18px;box-shadow:0 4px 14px #0000001f}.eGUBIq_top:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_tag{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:11px;line-height:16px}.eGUBIq_okState{color:var(--dsw-alias-state-success-primary,#16a34a);white-space:nowrap;font-size:12px;font-weight:600}.eGUBIq_dangerBtn.eGUBIq_dangerBtn{border-color:var(--dsw-alias-state-error-primary,#dc2626);color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_dangerArmed.eGUBIq_dangerArmed{background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.eGUBIq_warnBtn.eGUBIq_warnBtn{background:var(--dsw-alias-state-warn-primary,#ea580c);color:#fff}.eGUBIq_catsWrap{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.eGUBIq_catsCollapsed{max-height:62px;overflow:hidden}.eGUBIq_catsToggle.eGUBIq_catsToggle{height:26px;min-height:26px;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.eGUBIq_cmdDetails{margin:0}.eGUBIq_cmdSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.eGUBIq_cmdSummary::-webkit-details-marker{display:none}.eGUBIq_cmdSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.eGUBIq_cmdDetails[open]>.eGUBIq_cmdSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.eGUBIq_cmdSummary:hover{color:var(--dsw-alias-label-primary,#1f2328)}.eGUBIq_cmd{background:var(--dsw-alias-bg-layer-2,#f3f4f6);word-break:break-all;border-radius:6px;margin:8px 0 0;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:18px}.eGUBIq_warnLine{color:var(--dsw-alias-state-warn-primary,#b45309);margin:0;font-size:12px;font-weight:600;line-height:18px}.eGUBIq_modalNote{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:12px 0 0;font-size:12px;line-height:18px}.eGUBIq_grid{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;display:grid}.eGUBIq_sect{color:var(--dsw-alias-label-secondary,#6b7280);margin:14px 2px 8px;font-size:12px;font-weight:600}.eGUBIq_sect:first-child{margin-top:2px}.eGUBIq_swatches{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;gap:0;height:34px;display:flex;overflow:hidden}.eGUBIq_themesGrid{margin-bottom:12px}.eGUBIq_swatches i{flex:1}.eGUBIq_card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.eGUBIq_row1{align-items:center;gap:10px;min-width:0;display:flex}.eGUBIq_av{color:#fff;object-fit:cover;background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:8px;flex-shrink:0;place-items:center;width:32px;height:32px;font-size:14px;font-weight:700;display:grid}.eGUBIq_nm{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.eGUBIq_owner{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_desc{color:var(--dsw-alias-label-tertiary,#8b93a1);min-height:36px;margin:0;font-size:12px;line-height:18px}.eGUBIq_foot{align-items:center;gap:8px;margin-top:auto;display:flex}.eGUBIq_grow{flex:1}.eGUBIq_titleRow{align-items:center;gap:10px;display:flex}.eGUBIq_descTight{min-height:0}.eGUBIq_src{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px;text-decoration:none}.eGUBIq_src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_dot{vertical-align:2px;margin-left:5px}.eGUBIq_loading{color:var(--dsw-alias-label-secondary,#9ca3af);flex-direction:column;align-items:center;gap:12px;padding:48px;font-size:13px;display:flex}.eGUBIq_spin{border:3px solid var(--dsw-alias-border-l1,#e5e7eb);border-top-color:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;width:22px;height:22px;animation:.8s linear infinite eGUBIq_sp}@keyframes eGUBIq_sp{to{transform:rotate(360deg)}}.eGUBIq_progress{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:8px;align-items:center;gap:9px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_irow .eGUBIq_progress{margin-top:8px}.eGUBIq_progress .eGUBIq_spin{border-width:2px;flex-shrink:0;width:14px;height:14px}.eGUBIq_progress code{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.eGUBIq_empty{color:var(--dsw-alias-label-secondary,#9ca3af);text-align:center;padding:32px;font-size:13px}.eGUBIq_err{color:var(--dsw-alias-state-error-primary,#dc2626);white-space:pre-wrap;word-break:break-all;margin:8px 0;font-size:12px}.eGUBIq_irow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;align-items:center;gap:10px;margin-bottom:8px;padding:12px 14px;display:flex}.eGUBIq_irow>.eGUBIq_src,.eGUBIq_irow>.eGUBIq_owner,.eGUBIq_dangerBtn.eGUBIq_dangerBtn,.eGUBIq_warnBtn.eGUBIq_warnBtn,.eGUBIq_dangerArmed.eGUBIq_dangerArmed{white-space:nowrap;flex-shrink:0}.eGUBIq_spec{color:var(--dsw-alias-label-secondary,#9ca3af);font-family:ui-monospace,Menlo,monospace;font-size:11px}.eGUBIq_staleAction{margin-top:8px}.eGUBIq_pct{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:11px;font-weight:600}.eGUBIq_cancelBtn{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#6b7280);font:inherit;cursor:pointer;white-space:nowrap;border-radius:6px;flex-shrink:0;padding:2px 10px;font-size:11px;line-height:16px}.eGUBIq_cancelBtn:hover{color:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_sentinel{height:1px}";
|
|
320
|
+
const css = ".eGUBIq_root{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);flex-direction:column;display:flex;position:relative}.eGUBIq_head{flex-direction:column;gap:12px;padding:4px 4px 12px;display:flex}.eGUBIq_title{margin:0;font-size:16px;font-weight:500;line-height:24px}.eGUBIq_sub{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:14px;line-height:22px}.eGUBIq_searchInline{flex-shrink:0;width:200px;margin-bottom:6px}.eGUBIq_tabs{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-end;gap:2px;display:flex}.eGUBIq_tab{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;padding:7px 12px;font-size:13px}.eGUBIq_tab.eGUBIq_on{color:var(--dsw-alias-brand-primary,#4f6ef7);border-bottom-color:var(--dsw-alias-brand-primary,#4f6ef7);font-weight:600}.eGUBIq_restart{background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;align-items:center;gap:8px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_body{flex:1;padding:12px 4px 24px;overflow-x:hidden;overflow-y:auto}.eGUBIq_cats{z-index:5;background:var(--dsw-alias-bg-layer-2,#f7f8fa);margin:-12px -4px 2px;padding:12px 4px 4px;position:sticky;top:-13px}.eGUBIq_catsRow{align-items:flex-start;gap:8px;display:flex;position:relative}.eGUBIq_sort{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l1,#e5e7eb);border-radius:8px;flex-shrink:0;gap:2px;padding:2px;display:flex}.eGUBIq_sort button{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:3px 10px;font-size:12px}.eGUBIq_sort button.eGUBIq_on{background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600;box-shadow:0 1px 3px #00000014}.eGUBIq_star{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_top{z-index:20;border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);width:38px;height:38px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;border-radius:99px;font-size:16px;position:absolute;bottom:18px;right:18px;box-shadow:0 4px 14px #0000001f}.eGUBIq_top:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_tag{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:11px;line-height:16px}.eGUBIq_okState{color:var(--dsw-alias-state-success-primary,#16a34a);white-space:nowrap;font-size:12px;font-weight:600}.eGUBIq_dangerBtn.eGUBIq_dangerBtn{border-color:var(--dsw-alias-state-error-primary,#dc2626);color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_dangerArmed.eGUBIq_dangerArmed{background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.eGUBIq_warnBtn.eGUBIq_warnBtn{background:var(--dsw-alias-state-warn-primary,#ea580c);color:#fff}.eGUBIq_catsWrap{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.eGUBIq_catsCollapsed{max-height:62px;overflow:hidden}.eGUBIq_catsToggle.eGUBIq_catsToggle{height:26px;min-height:26px;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.eGUBIq_cmdDetails{margin:0}.eGUBIq_cmdSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.eGUBIq_cmdSummary::-webkit-details-marker{display:none}.eGUBIq_cmdSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.eGUBIq_cmdDetails[open]>.eGUBIq_cmdSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.eGUBIq_cmdSummary:hover{color:var(--dsw-alias-label-primary,#1f2328)}.eGUBIq_cmd{background:var(--dsw-alias-bg-layer-2,#f3f4f6);word-break:break-all;border-radius:6px;margin:8px 0 0;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:18px}.eGUBIq_warnLine{color:var(--dsw-alias-state-warn-primary,#b45309);margin:0;font-size:12px;font-weight:600;line-height:18px}.eGUBIq_modalNote{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:12px 0 0;font-size:12px;line-height:18px}.eGUBIq_grid{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;display:grid}.eGUBIq_sect{color:var(--dsw-alias-label-secondary,#6b7280);margin:14px 2px 8px;font-size:12px;font-weight:600}.eGUBIq_sect:first-child{margin-top:2px}.eGUBIq_swatches{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;gap:0;height:34px;display:flex;overflow:hidden}.eGUBIq_themesGrid{margin-bottom:12px}.eGUBIq_swatches i{flex:1}.eGUBIq_card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.eGUBIq_row1{align-items:center;gap:10px;min-width:0;display:flex}.eGUBIq_av{color:#fff;object-fit:cover;background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:8px;flex-shrink:0;place-items:center;width:32px;height:32px;font-size:14px;font-weight:700;display:grid}.eGUBIq_nm{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.eGUBIq_owner{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.eGUBIq_desc{color:var(--dsw-alias-label-tertiary,#8b93a1);min-height:36px;margin:0;font-size:12px;line-height:18px}.eGUBIq_foot{align-items:center;gap:8px;margin-top:auto;display:flex}.eGUBIq_grow{flex:1}.eGUBIq_titleRow{align-items:center;gap:10px;display:flex}.eGUBIq_descTight{min-height:0}.eGUBIq_src{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px;text-decoration:none}.eGUBIq_src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_dot{vertical-align:2px;margin-left:5px}.eGUBIq_loading{color:var(--dsw-alias-label-secondary,#9ca3af);flex-direction:column;align-items:center;gap:12px;padding:48px;font-size:13px;display:flex}.eGUBIq_spin{border:3px solid var(--dsw-alias-border-l1,#e5e7eb);border-top-color:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;width:22px;height:22px;animation:.8s linear infinite eGUBIq_sp}@keyframes eGUBIq_sp{to{transform:rotate(360deg)}}.eGUBIq_progress{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:8px;flex-wrap:wrap;align-items:center;gap:9px;margin:0;padding:8px 12px;font-size:12px;display:flex}.eGUBIq_bar{background:var(--dsw-alias-border-l1,#e5e7eb);border-radius:99px;width:100%;height:4px;overflow:hidden}.eGUBIq_barFill{background:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;height:100%;transition:width .6s}.eGUBIq_barWave{width:30%;animation:1.2s ease-in-out infinite eGUBIq_dshmSlide}@keyframes eGUBIq_dshmSlide{0%{margin-left:-30%}to{margin-left:100%}}.eGUBIq_irow .eGUBIq_progress{margin-top:8px}.eGUBIq_progress .eGUBIq_spin{border-width:2px;flex-shrink:0;width:14px;height:14px}.eGUBIq_progress code{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.eGUBIq_empty{color:var(--dsw-alias-label-secondary,#9ca3af);text-align:center;padding:32px;font-size:13px}.eGUBIq_err{color:var(--dsw-alias-state-error-primary,#dc2626);white-space:pre-wrap;word-break:break-all;margin:8px 0;font-size:12px}.eGUBIq_irow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;align-items:center;gap:10px;margin-bottom:8px;padding:12px 14px;display:flex}.eGUBIq_irow>.eGUBIq_src,.eGUBIq_irow>.eGUBIq_owner,.eGUBIq_dangerBtn.eGUBIq_dangerBtn,.eGUBIq_warnBtn.eGUBIq_warnBtn,.eGUBIq_dangerArmed.eGUBIq_dangerArmed{white-space:nowrap;flex-shrink:0}.eGUBIq_spec{color:var(--dsw-alias-label-secondary,#9ca3af);font-family:ui-monospace,Menlo,monospace;font-size:11px}.eGUBIq_staleAction{margin-top:8px}.eGUBIq_pct{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:11px;font-weight:600}.eGUBIq_cancelBtn{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#6b7280);font:inherit;cursor:pointer;white-space:nowrap;border-radius:6px;flex-shrink:0;padding:2px 10px;font-size:11px;line-height:16px}.eGUBIq_cancelBtn:hover{color:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626)}.eGUBIq_pager{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;margin:16px 0 4px;display:flex}.eGUBIq_pagerPages{flex-wrap:wrap;flex:1;justify-content:center;align-items:center;gap:6px;min-width:0;display:flex}.eGUBIq_pagerSize{flex-shrink:0;align-items:center;gap:4px;display:flex}.eGUBIq_sizeLabel{color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px}.eGUBIq_sizeBtn{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#6b7280);font:inherit;cursor:pointer;border-radius:6px;padding:3px 8px;font-size:12px;line-height:18px}.eGUBIq_sizeBtn:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);border-color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_sizeOn{background:var(--dsw-alias-brand-primary,#4f6ef7);border-color:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff;font-weight:600}.eGUBIq_pageBtn{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#6b7280);font:inherit;cursor:pointer;border-radius:6px;min-width:28px;padding:4px 10px;font-size:12px;line-height:18px}.eGUBIq_pageBtn:hover:not(:disabled){color:var(--dsw-alias-brand-primary,#4f6ef7);border-color:var(--dsw-alias-brand-primary,#4f6ef7)}.eGUBIq_pageBtn:disabled{opacity:.45;cursor:default}.eGUBIq_pageOn{background:var(--dsw-alias-brand-primary,#4f6ef7);border-color:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff;font-weight:600}.eGUBIq_pageEllipsis{color:var(--dsw-alias-label-secondary,#9ca3af);padding:0 2px;font-size:12px}.eGUBIq_pageInfo{color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;font-size:12px}";
|
|
286
321
|
const tagId = "dshmarket/Market.module.css";
|
|
287
322
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
288
323
|
const tag = document.createElement("style");
|
|
@@ -292,62 +327,75 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
292
327
|
document.head.appendChild(tag);
|
|
293
328
|
}
|
|
294
329
|
var Market_module_css_default = {
|
|
295
|
-
"dangerBtn": "eGUBIq_dangerBtn",
|
|
296
|
-
"top": "eGUBIq_top",
|
|
297
330
|
"catsWrap": "eGUBIq_catsWrap",
|
|
298
|
-
"
|
|
299
|
-
"grid": "eGUBIq_grid",
|
|
300
|
-
"grow": "eGUBIq_grow",
|
|
301
|
-
"titleRow": "eGUBIq_titleRow",
|
|
302
|
-
"staleAction": "eGUBIq_staleAction",
|
|
303
|
-
"modalNote": "eGUBIq_modalNote",
|
|
304
|
-
"star": "eGUBIq_star",
|
|
305
|
-
"sect": "eGUBIq_sect",
|
|
306
|
-
"row1": "eGUBIq_row1",
|
|
307
|
-
"av": "eGUBIq_av",
|
|
308
|
-
"warnBtn": "eGUBIq_warnBtn",
|
|
309
|
-
"pct": "eGUBIq_pct",
|
|
310
|
-
"loading": "eGUBIq_loading",
|
|
311
|
-
"cancelBtn": "eGUBIq_cancelBtn",
|
|
312
|
-
"spec": "eGUBIq_spec",
|
|
313
|
-
"catsRow": "eGUBIq_catsRow",
|
|
331
|
+
"pageInfo": "eGUBIq_pageInfo",
|
|
314
332
|
"cats": "eGUBIq_cats",
|
|
333
|
+
"catsRow": "eGUBIq_catsRow",
|
|
315
334
|
"themesGrid": "eGUBIq_themesGrid",
|
|
335
|
+
"star": "eGUBIq_star",
|
|
336
|
+
"grow": "eGUBIq_grow",
|
|
337
|
+
"card": "eGUBIq_card",
|
|
338
|
+
"pagerPages": "eGUBIq_pagerPages",
|
|
339
|
+
"pageEllipsis": "eGUBIq_pageEllipsis",
|
|
340
|
+
"pager": "eGUBIq_pager",
|
|
341
|
+
"sort": "eGUBIq_sort",
|
|
342
|
+
"warnBtn": "eGUBIq_warnBtn",
|
|
316
343
|
"progress": "eGUBIq_progress",
|
|
344
|
+
"okState": "eGUBIq_okState",
|
|
345
|
+
"root": "eGUBIq_root",
|
|
346
|
+
"sub": "eGUBIq_sub",
|
|
347
|
+
"pageOn": "eGUBIq_pageOn",
|
|
348
|
+
"tabs": "eGUBIq_tabs",
|
|
349
|
+
"swatches": "eGUBIq_swatches",
|
|
317
350
|
"descTight": "eGUBIq_descTight",
|
|
318
351
|
"irow": "eGUBIq_irow",
|
|
319
|
-
"
|
|
352
|
+
"sect": "eGUBIq_sect",
|
|
353
|
+
"foot": "eGUBIq_foot",
|
|
354
|
+
"sizeBtn": "eGUBIq_sizeBtn",
|
|
355
|
+
"staleAction": "eGUBIq_staleAction",
|
|
356
|
+
"pct": "eGUBIq_pct",
|
|
357
|
+
"barWave": "eGUBIq_barWave",
|
|
358
|
+
"catsToggle": "eGUBIq_catsToggle",
|
|
320
359
|
"owner": "eGUBIq_owner",
|
|
321
|
-
"warnLine": "eGUBIq_warnLine",
|
|
322
|
-
"nm": "eGUBIq_nm",
|
|
323
|
-
"dangerArmed": "eGUBIq_dangerArmed",
|
|
324
|
-
"desc": "eGUBIq_desc",
|
|
325
|
-
"empty": "eGUBIq_empty",
|
|
326
|
-
"src": "eGUBIq_src",
|
|
327
360
|
"body": "eGUBIq_body",
|
|
328
|
-
"
|
|
329
|
-
"catsCollapsed": "eGUBIq_catsCollapsed",
|
|
330
|
-
"tab": "eGUBIq_tab",
|
|
331
|
-
"on": "eGUBIq_on",
|
|
332
|
-
"sort": "eGUBIq_sort",
|
|
361
|
+
"av": "eGUBIq_av",
|
|
333
362
|
"cmd": "eGUBIq_cmd",
|
|
334
|
-
"
|
|
363
|
+
"err": "eGUBIq_err",
|
|
335
364
|
"head": "eGUBIq_head",
|
|
336
|
-
"
|
|
337
|
-
"
|
|
338
|
-
"
|
|
365
|
+
"spec": "eGUBIq_spec",
|
|
366
|
+
"grid": "eGUBIq_grid",
|
|
367
|
+
"cancelBtn": "eGUBIq_cancelBtn",
|
|
368
|
+
"pagerSize": "eGUBIq_pagerSize",
|
|
369
|
+
"sizeLabel": "eGUBIq_sizeLabel",
|
|
370
|
+
"cmdSummary": "eGUBIq_cmdSummary",
|
|
371
|
+
"loading": "eGUBIq_loading",
|
|
372
|
+
"top": "eGUBIq_top",
|
|
373
|
+
"cmdDetails": "eGUBIq_cmdDetails",
|
|
374
|
+
"src": "eGUBIq_src",
|
|
375
|
+
"on": "eGUBIq_on",
|
|
376
|
+
"catsCollapsed": "eGUBIq_catsCollapsed",
|
|
377
|
+
"restart": "eGUBIq_restart",
|
|
378
|
+
"dangerArmed": "eGUBIq_dangerArmed",
|
|
379
|
+
"dangerBtn": "eGUBIq_dangerBtn",
|
|
339
380
|
"dot": "eGUBIq_dot",
|
|
340
|
-
"title": "eGUBIq_title",
|
|
341
381
|
"sp": "eGUBIq_sp",
|
|
342
|
-
"
|
|
343
|
-
"
|
|
344
|
-
"
|
|
345
|
-
"
|
|
346
|
-
"
|
|
382
|
+
"desc": "eGUBIq_desc",
|
|
383
|
+
"bar": "eGUBIq_bar",
|
|
384
|
+
"empty": "eGUBIq_empty",
|
|
385
|
+
"warnLine": "eGUBIq_warnLine",
|
|
386
|
+
"pageBtn": "eGUBIq_pageBtn",
|
|
387
|
+
"dshmSlide": "eGUBIq_dshmSlide",
|
|
388
|
+
"tag": "eGUBIq_tag",
|
|
389
|
+
"nm": "eGUBIq_nm",
|
|
347
390
|
"spin": "eGUBIq_spin",
|
|
348
|
-
"
|
|
349
|
-
"
|
|
350
|
-
"
|
|
391
|
+
"searchInline": "eGUBIq_searchInline",
|
|
392
|
+
"sizeOn": "eGUBIq_sizeOn",
|
|
393
|
+
"barFill": "eGUBIq_barFill",
|
|
394
|
+
"title": "eGUBIq_title",
|
|
395
|
+
"titleRow": "eGUBIq_titleRow",
|
|
396
|
+
"tab": "eGUBIq_tab",
|
|
397
|
+
"row1": "eGUBIq_row1",
|
|
398
|
+
"modalNote": "eGUBIq_modalNote"
|
|
351
399
|
};
|
|
352
400
|
//#endregion
|
|
353
401
|
//#region src/client/MarketSection.tsx
|
|
@@ -376,12 +424,44 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
376
424
|
});
|
|
377
425
|
}
|
|
378
426
|
/**
|
|
427
|
+
* Official-style market glyph: the shared block-grid brand mark converted to
|
|
428
|
+
* the official monochrome icon form (16×16, fill="currentColor") so it
|
|
429
|
+
* follows the active theme. Mirrors the settings-nav glyph used for the
|
|
430
|
+
* "market" section id.
|
|
431
|
+
*/
|
|
432
|
+
function MarketLogo({ size = 16, style }) {
|
|
433
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
434
|
+
width: size,
|
|
435
|
+
height: size,
|
|
436
|
+
viewBox: "0 0 16 16",
|
|
437
|
+
fill: "none",
|
|
438
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
439
|
+
"aria-hidden": "true",
|
|
440
|
+
style,
|
|
441
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
442
|
+
fill: "currentColor",
|
|
443
|
+
d: "M2.35 1.75H4.95A0.6 0.6 0 0 1 5.55 2.35V4.95A0.6 0.6 0 0 1 4.95 5.55H2.35A0.6 0.6 0 0 1 1.75 4.95V2.35A0.6 0.6 0 0 1 2.35 1.75ZM6.7 1.75H9.3A0.6 0.6 0 0 1 9.9 2.35V4.95A0.6 0.6 0 0 1 9.3 5.55H6.7A0.6 0.6 0 0 1 6.1 4.95V2.35A0.6 0.6 0 0 1 6.7 1.75ZM2.35 6.1H4.95A0.6 0.6 0 0 1 5.55 6.7V9.3A0.6 0.6 0 0 1 4.95 9.9H2.35A0.6 0.6 0 0 1 1.75 9.3V6.7A0.6 0.6 0 0 1 2.35 6.1ZM6.7 6.1H9.3A0.6 0.6 0 0 1 9.9 6.7V9.3A0.6 0.6 0 0 1 9.3 9.9H6.7A0.6 0.6 0 0 1 6.1 9.3V6.7A0.6 0.6 0 0 1 6.7 6.1ZM11.05 6.1H13.65A0.6 0.6 0 0 1 14.25 6.7V9.3A0.6 0.6 0 0 1 13.65 9.9H11.05A0.6 0.6 0 0 1 10.45 9.3V6.7A0.6 0.6 0 0 1 11.05 6.1ZM2.35 10.45H4.95A0.6 0.6 0 0 1 5.55 11.05V13.65A0.6 0.6 0 0 1 4.95 14.25H2.35A0.6 0.6 0 0 1 1.75 13.65V11.05A0.6 0.6 0 0 1 2.35 10.45ZM6.7 10.45H9.3A0.6 0.6 0 0 1 9.9 11.05V13.65A0.6 0.6 0 0 1 9.3 14.25H6.7A0.6 0.6 0 0 1 6.1 13.65V11.05A0.6 0.6 0 0 1 6.7 10.45ZM11.05 10.45H13.65A0.6 0.6 0 0 1 14.25 11.05V13.65A0.6 0.6 0 0 1 13.65 14.25H11.05A0.6 0.6 0 0 1 10.45 13.65V11.05A0.6 0.6 0 0 1 11.05 10.45Z"
|
|
444
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
445
|
+
fill: "currentColor",
|
|
446
|
+
d: "M11.05 1.75H13.65A0.6 0.6 0 0 1 14.25 2.35V4.95A0.6 0.6 0 0 1 13.65 5.55H11.05A0.6 0.6 0 0 1 10.45 4.95V2.35A0.6 0.6 0 0 1 11.05 1.75Z",
|
|
447
|
+
transform: "rotate(9 12.35 3.65)"
|
|
448
|
+
})]
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
379
452
|
* Module-scope caches so re-entering the section renders instantly instead
|
|
380
453
|
* of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
|
|
381
454
|
* state survives section switches; a background refetch keeps it current.
|
|
382
455
|
*/
|
|
383
456
|
let cachedRegistry = null;
|
|
384
457
|
let cachedInstalled = null;
|
|
458
|
+
/** Discover grid page-size choices — the catalog grows daily, so cap each page. */
|
|
459
|
+
const PAGE_SIZES = [
|
|
460
|
+
24,
|
|
461
|
+
48,
|
|
462
|
+
96
|
|
463
|
+
];
|
|
464
|
+
const DEFAULT_PAGE_SIZE = 24;
|
|
385
465
|
function MarketSection(props) {
|
|
386
466
|
const t = props.t;
|
|
387
467
|
const localeSnap = (0, react.useSyncExternalStore)((cb) => props.locale.subscribe(cb), () => props.locale.getSnapshot());
|
|
@@ -404,23 +484,17 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
404
484
|
const [cat, setCat] = (0, react.useState)("all");
|
|
405
485
|
const [confirming, setConfirming] = (0, react.useState)(null);
|
|
406
486
|
const [busyUrl, setBusyUrl] = (0, react.useState)(null);
|
|
487
|
+
/** Consecutive idle polls with a pending install that never landed (#32). */
|
|
488
|
+
const idleStrikes = (0, react.useRef)(0);
|
|
407
489
|
const [doneUrls, setDoneUrls] = (0, react.useState)([]);
|
|
408
490
|
const [installError, setInstallError] = (0, react.useState)(null);
|
|
409
491
|
const [updates, setUpdates] = (0, react.useState)({});
|
|
410
492
|
const [updatingName, setUpdatingName] = (0, react.useState)(null);
|
|
411
493
|
const [staleName, setStaleName] = (0, react.useState)(null);
|
|
412
|
-
/**
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
*/
|
|
417
|
-
const [visibleCount, setVisibleCount] = (0, react.useState)(60);
|
|
418
|
-
const sentinelRef = (0, react.useCallback)((node) => {
|
|
419
|
-
if (node === null) return;
|
|
420
|
-
new IntersectionObserver((entries) => {
|
|
421
|
-
if (entries.some((entry) => entry.isIntersecting)) setVisibleCount((count) => count + 120);
|
|
422
|
-
}, { rootMargin: "600px" }).observe(node);
|
|
423
|
-
}, []);
|
|
494
|
+
/** 1-based discover page; reset to 1 whenever the list shape changes. */
|
|
495
|
+
const [page, setPage] = (0, react.useState)(1);
|
|
496
|
+
/** Cards per discover page; changing it jumps back to page 1. */
|
|
497
|
+
const [pageSize, setPageSize] = (0, react.useState)(DEFAULT_PAGE_SIZE);
|
|
424
498
|
/** Determinate percent parsed from pnpm's Progress line, when available. */
|
|
425
499
|
const [progressPct, setProgressPct] = (0, react.useState)(null);
|
|
426
500
|
/** Blocked build scripts from the last install: enables approve-and-retry (#6). */
|
|
@@ -504,7 +578,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
504
578
|
body: "{}"
|
|
505
579
|
}).then((res) => res.json()).then((body) => {
|
|
506
580
|
if (body.ok) setEnvReady(true);
|
|
507
|
-
else
|
|
581
|
+
else {
|
|
582
|
+
setEnvFailed(true);
|
|
583
|
+
if (typeof body.error === "string") setInstallError(body.error);
|
|
584
|
+
}
|
|
508
585
|
}).catch(() => setEnvFailed(true)).finally(() => setEnvFixing(false));
|
|
509
586
|
}, []);
|
|
510
587
|
(0, react.useEffect)(() => {
|
|
@@ -531,9 +608,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
531
608
|
setInstalled(status.installed || {});
|
|
532
609
|
if (readSession("dshm-pending") !== null && busyUrl !== null) {
|
|
533
610
|
if (data !== null && data.plugins.some((p) => p.url === busyUrl && isInstalled(p, status.installed || {}))) {
|
|
611
|
+
idleStrikes.current = 0;
|
|
534
612
|
sessionStorage.removeItem("dshm-pending");
|
|
535
613
|
setDoneUrls((urls) => urls.includes(busyUrl) ? urls : urls.concat(busyUrl));
|
|
536
614
|
setBusyUrl(null);
|
|
615
|
+
} else if (++idleStrikes.current >= 2) {
|
|
616
|
+
idleStrikes.current = 0;
|
|
617
|
+
sessionStorage.removeItem("dshm-pending");
|
|
618
|
+
setBusyUrl(null);
|
|
619
|
+
setInstallError(t("installFail") + " — " + t("exportLog"));
|
|
537
620
|
}
|
|
538
621
|
}
|
|
539
622
|
}
|
|
@@ -558,12 +641,34 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
558
641
|
sort
|
|
559
642
|
]);
|
|
560
643
|
(0, react.useEffect)(() => {
|
|
561
|
-
|
|
644
|
+
setPage(1);
|
|
562
645
|
}, [
|
|
563
646
|
q,
|
|
564
647
|
cat,
|
|
565
648
|
sort
|
|
566
649
|
]);
|
|
650
|
+
const totalPages = Math.max(1, Math.ceil(plugins.length / pageSize));
|
|
651
|
+
const currentPage = Math.min(page, totalPages);
|
|
652
|
+
const pagePlugins = plugins.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
|
653
|
+
const scrollToTop = () => {
|
|
654
|
+
const el = bodyRef.current;
|
|
655
|
+
if (el) {
|
|
656
|
+
if (typeof el.scrollTo === "function") el.scrollTo({
|
|
657
|
+
top: 0,
|
|
658
|
+
behavior: "smooth"
|
|
659
|
+
});
|
|
660
|
+
else el.scrollTop = 0;
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
const goToPage = (next) => {
|
|
664
|
+
setPage(Math.max(1, Math.min(next, totalPages)));
|
|
665
|
+
scrollToTop();
|
|
666
|
+
};
|
|
667
|
+
const changePageSize = (size) => {
|
|
668
|
+
setPageSize(size);
|
|
669
|
+
setPage(1);
|
|
670
|
+
scrollToTop();
|
|
671
|
+
};
|
|
567
672
|
const doInstall = (0, react.useCallback)((plugin) => {
|
|
568
673
|
setBuildsSkipped(null);
|
|
569
674
|
setConfirming(null);
|
|
@@ -855,6 +960,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
855
960
|
className: Market_module_css_default.cancelBtn,
|
|
856
961
|
onClick: doCancel,
|
|
857
962
|
children: t("cancelOp")
|
|
963
|
+
}),
|
|
964
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
965
|
+
className: Market_module_css_default.bar,
|
|
966
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
967
|
+
className: progressPct !== null ? Market_module_css_default.barFill : `${Market_module_css_default.barFill} ${Market_module_css_default.barWave}`,
|
|
968
|
+
style: progressPct !== null ? { width: `${progressPct}%` } : void 0
|
|
969
|
+
})
|
|
858
970
|
})
|
|
859
971
|
]
|
|
860
972
|
})
|
|
@@ -1014,15 +1126,9 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1014
1126
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1015
1127
|
className: Market_module_css_default.titleRow,
|
|
1016
1128
|
children: [
|
|
1017
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
height: 22,
|
|
1021
|
-
alt: "",
|
|
1022
|
-
style: {
|
|
1023
|
-
borderRadius: "5px",
|
|
1024
|
-
flexShrink: 0
|
|
1025
|
-
}
|
|
1129
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketLogo, {
|
|
1130
|
+
size: 22,
|
|
1131
|
+
style: { flexShrink: 0 }
|
|
1026
1132
|
}),
|
|
1027
1133
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1028
1134
|
className: Market_module_css_default.title,
|
|
@@ -1262,10 +1368,68 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1262
1368
|
children: t("empty")
|
|
1263
1369
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1264
1370
|
className: Market_module_css_default.grid,
|
|
1265
|
-
children:
|
|
1266
|
-
}),
|
|
1267
|
-
|
|
1268
|
-
|
|
1371
|
+
children: pagePlugins.map(pluginCard)
|
|
1372
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1373
|
+
className: Market_module_css_default.pager,
|
|
1374
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1375
|
+
className: Market_module_css_default.pagerPages,
|
|
1376
|
+
children: totalPages > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1377
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1378
|
+
type: "button",
|
|
1379
|
+
className: Market_module_css_default.pageBtn,
|
|
1380
|
+
disabled: currentPage === 1,
|
|
1381
|
+
onClick: () => goToPage(1),
|
|
1382
|
+
"aria-label": t("firstPage"),
|
|
1383
|
+
children: "«"
|
|
1384
|
+
}),
|
|
1385
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1386
|
+
type: "button",
|
|
1387
|
+
className: Market_module_css_default.pageBtn,
|
|
1388
|
+
disabled: currentPage === 1,
|
|
1389
|
+
onClick: () => goToPage(currentPage - 1),
|
|
1390
|
+
children: t("prevPage")
|
|
1391
|
+
}),
|
|
1392
|
+
pageItems(currentPage, totalPages).map((item, i) => item === "…" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1393
|
+
className: Market_module_css_default.pageEllipsis,
|
|
1394
|
+
children: "…"
|
|
1395
|
+
}, "e" + i) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1396
|
+
type: "button",
|
|
1397
|
+
className: item === currentPage ? `${Market_module_css_default.pageBtn} ${Market_module_css_default.pageOn}` : Market_module_css_default.pageBtn,
|
|
1398
|
+
onClick: () => goToPage(item),
|
|
1399
|
+
children: item
|
|
1400
|
+
}, item)),
|
|
1401
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1402
|
+
type: "button",
|
|
1403
|
+
className: Market_module_css_default.pageBtn,
|
|
1404
|
+
disabled: currentPage === totalPages,
|
|
1405
|
+
onClick: () => goToPage(currentPage + 1),
|
|
1406
|
+
children: t("nextPage")
|
|
1407
|
+
}),
|
|
1408
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1409
|
+
type: "button",
|
|
1410
|
+
className: Market_module_css_default.pageBtn,
|
|
1411
|
+
disabled: currentPage === totalPages,
|
|
1412
|
+
onClick: () => goToPage(totalPages),
|
|
1413
|
+
"aria-label": t("lastPage"),
|
|
1414
|
+
children: "»"
|
|
1415
|
+
}),
|
|
1416
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1417
|
+
className: Market_module_css_default.pageInfo,
|
|
1418
|
+
children: t("pageInfo").replace("{0}", String(currentPage)).replace("{1}", String(totalPages))
|
|
1419
|
+
})
|
|
1420
|
+
] })
|
|
1421
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1422
|
+
className: Market_module_css_default.pagerSize,
|
|
1423
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1424
|
+
className: Market_module_css_default.sizeLabel,
|
|
1425
|
+
children: t("perPage")
|
|
1426
|
+
}), PAGE_SIZES.map((size) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1427
|
+
type: "button",
|
|
1428
|
+
className: size === pageSize ? `${Market_module_css_default.sizeBtn} ${Market_module_css_default.sizeOn}` : Market_module_css_default.sizeBtn,
|
|
1429
|
+
onClick: () => changePageSize(size),
|
|
1430
|
+
children: size
|
|
1431
|
+
}, size))]
|
|
1432
|
+
})]
|
|
1269
1433
|
})] })] }) : tab === "themes" && themeSnap !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(() => {
|
|
1270
1434
|
const extra = themeSnap.themes.filter((def) => def.id !== "light" && def.id !== "dark");
|
|
1271
1435
|
return extra.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1336,6 +1500,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1336
1500
|
className: Market_module_css_default.cancelBtn,
|
|
1337
1501
|
onClick: doCancel,
|
|
1338
1502
|
children: t("cancelOp")
|
|
1503
|
+
}),
|
|
1504
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1505
|
+
className: Market_module_css_default.bar,
|
|
1506
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1507
|
+
className: progressPct !== null ? Market_module_css_default.barFill : `${Market_module_css_default.barFill} ${Market_module_css_default.barWave}`,
|
|
1508
|
+
style: progressPct !== null ? { width: `${progressPct}%` } : void 0
|
|
1509
|
+
})
|
|
1339
1510
|
})
|
|
1340
1511
|
]
|
|
1341
1512
|
})
|