dshmarket 1.2.3 → 1.2.4

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/client/client.js CHANGED
@@ -38,6 +38,11 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
38
38
  update: "更新",
39
39
  updating: "更新中…",
40
40
  updated: "✓ 已更新,重启后生效",
41
+ cancelOp: "取消",
42
+ cancelled: "已取消",
43
+ busyWait: "已有操作正在进行,请等它结束(同一时间只执行一个安装/更新/卸载)",
44
+ approveBuilds: "放行构建脚本并重试",
45
+ buildsSkipped: "该插件需要运行构建脚本才能工作,出于安全默认被拦下。点击下方按钮为它放行并重装:",
41
46
  updateNow: "立即更新",
42
47
  updateFail: "更新失败",
43
48
  upToDate: "已是最新",
@@ -97,6 +102,11 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
97
102
  update: "Update",
98
103
  updating: "Updating…",
99
104
  updated: "✓ Updated — restart to apply",
105
+ cancelOp: "Cancel",
106
+ cancelled: "Cancelled",
107
+ busyWait: "Another operation is already running — please wait for it to finish (one install/update/uninstall at a time)",
108
+ approveBuilds: "Allow build scripts and retry",
109
+ buildsSkipped: "This plugin needs its build scripts to run; they are blocked by default for safety. Click below to allow them and reinstall:",
100
110
  updateNow: "Update now",
101
111
  updateFail: "Update failed",
102
112
  upToDate: "Up to date",
@@ -264,7 +274,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
264
274
  }
265
275
  //#endregion
266
276
  //#region \0dsh-css:/home/runner/work/dsh-market/dsh-market/src/client/Market.module.css.mjs
267
- 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}";
277
+ 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}";
268
278
  const tagId = "dshmarket/Market.module.css";
269
279
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
270
280
  const tag = document.createElement("style");
@@ -274,59 +284,62 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
274
284
  document.head.appendChild(tag);
275
285
  }
276
286
  var Market_module_css_default = {
277
- "grid": "eGUBIq_grid",
278
- "cmdDetails": "eGUBIq_cmdDetails",
279
- "title": "eGUBIq_title",
287
+ "warnBtn": "eGUBIq_warnBtn",
288
+ "grow": "eGUBIq_grow",
289
+ "sentinel": "eGUBIq_sentinel",
280
290
  "body": "eGUBIq_body",
281
- "empty": "eGUBIq_empty",
282
- "nm": "eGUBIq_nm",
283
- "on": "eGUBIq_on",
284
- "loading": "eGUBIq_loading",
285
- "card": "eGUBIq_card",
286
- "modalNote": "eGUBIq_modalNote",
287
- "catsRow": "eGUBIq_catsRow",
288
- "cats": "eGUBIq_cats",
289
- "foot": "eGUBIq_foot",
290
- "tabs": "eGUBIq_tabs",
291
- "catsWrap": "eGUBIq_catsWrap",
292
291
  "titleRow": "eGUBIq_titleRow",
293
- "warnLine": "eGUBIq_warnLine",
294
- "src": "eGUBIq_src",
295
- "cmdSummary": "eGUBIq_cmdSummary",
296
- "restart": "eGUBIq_restart",
297
- "root": "eGUBIq_root",
292
+ "tag": "eGUBIq_tag",
293
+ "sect": "eGUBIq_sect",
294
+ "catsRow": "eGUBIq_catsRow",
298
295
  "dangerArmed": "eGUBIq_dangerArmed",
299
- "desc": "eGUBIq_desc",
300
- "err": "eGUBIq_err",
301
- "top": "eGUBIq_top",
302
- "catsToggle": "eGUBIq_catsToggle",
296
+ "catsCollapsed": "eGUBIq_catsCollapsed",
297
+ "head": "eGUBIq_head",
298
+ "star": "eGUBIq_star",
299
+ "swatches": "eGUBIq_swatches",
300
+ "card": "eGUBIq_card",
301
+ "grid": "eGUBIq_grid",
302
+ "root": "eGUBIq_root",
303
303
  "tab": "eGUBIq_tab",
304
304
  "av": "eGUBIq_av",
305
- "dangerBtn": "eGUBIq_dangerBtn",
305
+ "searchInline": "eGUBIq_searchInline",
306
+ "desc": "eGUBIq_desc",
307
+ "foot": "eGUBIq_foot",
308
+ "themesGrid": "eGUBIq_themesGrid",
309
+ "src": "eGUBIq_src",
306
310
  "dot": "eGUBIq_dot",
307
- "irow": "eGUBIq_irow",
308
- "cmd": "eGUBIq_cmd",
309
- "swatches": "eGUBIq_swatches",
310
311
  "spin": "eGUBIq_spin",
311
- "sort": "eGUBIq_sort",
312
+ "descTight": "eGUBIq_descTight",
313
+ "row1": "eGUBIq_row1",
314
+ "progress": "eGUBIq_progress",
315
+ "err": "eGUBIq_err",
316
+ "title": "eGUBIq_title",
317
+ "restart": "eGUBIq_restart",
318
+ "cmdSummary": "eGUBIq_cmdSummary",
319
+ "loading": "eGUBIq_loading",
320
+ "sp": "eGUBIq_sp",
312
321
  "spec": "eGUBIq_spec",
313
- "grow": "eGUBIq_grow",
314
- "star": "eGUBIq_star",
315
- "themesGrid": "eGUBIq_themesGrid",
316
- "okState": "eGUBIq_okState",
317
- "sect": "eGUBIq_sect",
318
322
  "staleAction": "eGUBIq_staleAction",
323
+ "cancelBtn": "eGUBIq_cancelBtn",
324
+ "tabs": "eGUBIq_tabs",
325
+ "on": "eGUBIq_on",
326
+ "top": "eGUBIq_top",
319
327
  "sub": "eGUBIq_sub",
320
- "row1": "eGUBIq_row1",
328
+ "modalNote": "eGUBIq_modalNote",
329
+ "cmdDetails": "eGUBIq_cmdDetails",
321
330
  "owner": "eGUBIq_owner",
322
- "sp": "eGUBIq_sp",
323
- "head": "eGUBIq_head",
324
- "warnBtn": "eGUBIq_warnBtn",
325
- "catsCollapsed": "eGUBIq_catsCollapsed",
326
- "progress": "eGUBIq_progress",
327
- "searchInline": "eGUBIq_searchInline",
328
- "tag": "eGUBIq_tag",
329
- "descTight": "eGUBIq_descTight"
331
+ "okState": "eGUBIq_okState",
332
+ "empty": "eGUBIq_empty",
333
+ "cmd": "eGUBIq_cmd",
334
+ "pct": "eGUBIq_pct",
335
+ "nm": "eGUBIq_nm",
336
+ "sort": "eGUBIq_sort",
337
+ "warnLine": "eGUBIq_warnLine",
338
+ "irow": "eGUBIq_irow",
339
+ "cats": "eGUBIq_cats",
340
+ "catsToggle": "eGUBIq_catsToggle",
341
+ "dangerBtn": "eGUBIq_dangerBtn",
342
+ "catsWrap": "eGUBIq_catsWrap"
330
343
  };
331
344
  //#endregion
332
345
  //#region src/client/MarketSection.tsx
@@ -354,14 +367,25 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
354
367
  onError: () => setFailed(true)
355
368
  });
356
369
  }
370
+ /**
371
+ * Module-scope caches so re-entering the section renders instantly instead
372
+ * of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
373
+ * state survives section switches; a background refetch keeps it current.
374
+ */
375
+ let cachedRegistry = null;
376
+ let cachedInstalled = null;
357
377
  function MarketSection(props) {
358
378
  const t = props.t;
359
379
  const localeSnap = (0, react.useSyncExternalStore)((cb) => props.locale.subscribe(cb), () => props.locale.getSnapshot());
360
380
  const lang = String(localeSnap.active).toLowerCase().startsWith("zh") ? "zh" : "en";
361
381
  const themeSnap = (0, react.useSyncExternalStore)(props.themeStore.subscribe, props.themeStore.getSnapshot);
362
- const [data, setData] = (0, react.useState)(null);
382
+ const [data, setData] = (0, react.useState)(cachedRegistry);
363
383
  const [loadError, setLoadError] = (0, react.useState)(false);
364
- const [installed, setInstalled] = (0, react.useState)({});
384
+ const [installed, setInstalledState] = (0, react.useState)(cachedInstalled ?? {});
385
+ const setInstalled = (0, react.useCallback)((value) => {
386
+ cachedInstalled = value;
387
+ setInstalledState(value);
388
+ }, []);
365
389
  const [skins, setSkins] = (0, react.useState)([]);
366
390
  const [tab, setTab] = (0, react.useState)(() => {
367
391
  const saved = sessionStorage.getItem("dshm-tab");
@@ -377,6 +401,22 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
377
401
  const [updates, setUpdates] = (0, react.useState)({});
378
402
  const [updatingName, setUpdatingName] = (0, react.useState)(null);
379
403
  const [staleName, setStaleName] = (0, react.useState)(null);
404
+ /**
405
+ * Cards rendered so far — the discover grid renders incrementally (60,
406
+ * then +120 as the sentinel scrolls into view) instead of all 400+ at
407
+ * once, which built a ~70k px DOM and made section switches lag (#30).
408
+ */
409
+ const [visibleCount, setVisibleCount] = (0, react.useState)(60);
410
+ const sentinelRef = (0, react.useCallback)((node) => {
411
+ if (node === null) return;
412
+ new IntersectionObserver((entries) => {
413
+ if (entries.some((entry) => entry.isIntersecting)) setVisibleCount((count) => count + 120);
414
+ }, { rootMargin: "600px" }).observe(node);
415
+ }, []);
416
+ /** Determinate percent parsed from pnpm's Progress line, when available. */
417
+ const [progressPct, setProgressPct] = (0, react.useState)(null);
418
+ /** Blocked build scripts from the last install: enables approve-and-retry (#6). */
419
+ const [buildsSkipped, setBuildsSkipped] = (0, react.useState)(null);
380
420
  const [updatingAll, setUpdatingAll] = (0, react.useState)(false);
381
421
  const [updatedNames, setUpdatedNames] = (0, react.useState)([]);
382
422
  const [hotUrls, setHotUrls] = (0, react.useState)([]);
@@ -406,7 +446,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
406
446
  fetch("/dsh-market/registry", { cache: "no-store" }).then((res) => {
407
447
  if (!res.ok) throw new Error("HTTP " + res.status);
408
448
  return res.json();
409
- }).then((body) => setData(body.registry)).catch(() => setLoadError(true));
449
+ }).then((body) => {
450
+ cachedRegistry = body.registry;
451
+ setData(body.registry);
452
+ }).catch(() => setLoadError(true));
410
453
  fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((status) => {
411
454
  setEnvReady(status.pnpm !== false);
412
455
  if (typeof status.boot === "string") setBootId(status.boot);
@@ -463,9 +506,16 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
463
506
  }
464
507
  const timer = setInterval(() => {
465
508
  fetch("/dsh-market/status", { cache: "no-store" }).then((res) => res.json()).then((status) => {
466
- if (status.active) setProgressLine((status.lastLine || "…") + " (" + status.seconds + "s)");
467
- else {
509
+ if (status.active) {
510
+ setProgressLine((status.lastLine || "…") + " (" + status.seconds + "s)");
511
+ const m = /resolved (\d+), reused (\d+), downloaded (\d+), added (\d+)/.exec(status.lastLine || "");
512
+ if (m !== null && Number(m[1]) > 0) {
513
+ const done = Number(m[2]) + Number(m[3]) + Number(m[4]);
514
+ setProgressPct(Math.max(4, Math.min(96, Math.round(done / Number(m[1]) * 100))));
515
+ }
516
+ } else {
468
517
  setProgressLine(null);
518
+ setProgressPct(null);
469
519
  setInstalled(status.installed || {});
470
520
  if (readSession("dshm-pending") !== null && busyUrl !== null) {
471
521
  if (data !== null && data.plugins.some((p) => p.url === busyUrl && isInstalled(p, status.installed || {}))) {
@@ -495,7 +545,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
495
545
  lang,
496
546
  sort
497
547
  ]);
548
+ (0, react.useEffect)(() => {
549
+ setVisibleCount(60);
550
+ }, [
551
+ q,
552
+ cat,
553
+ sort
554
+ ]);
498
555
  const doInstall = (0, react.useCallback)((plugin) => {
556
+ setBuildsSkipped(null);
499
557
  setConfirming(null);
500
558
  setInstallError(null);
501
559
  setBusyUrl(plugin.url);
@@ -515,6 +573,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
515
573
  location.reload();
516
574
  return;
517
575
  }
576
+ if (body.cancelled === true) {
577
+ refreshInstalled();
578
+ return;
579
+ }
518
580
  if (status === 200 && body.ok) {
519
581
  sessionStorage.setItem("dshm-tab", "installed");
520
582
  if (body.hot) {
@@ -523,6 +585,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
523
585
  } else setDoneUrls((urls) => urls.includes(plugin.url) ? urls : urls.concat(plugin.url));
524
586
  refreshInstalled();
525
587
  } else {
588
+ if (status === 409) {
589
+ setInstallError(t("busyWait"));
590
+ return;
591
+ }
592
+ if (Array.isArray(body.ignoredBuilds) && body.ignoredBuilds.length > 0) setBuildsSkipped({
593
+ plugin,
594
+ names: body.ignoredBuilds.map(String)
595
+ });
526
596
  const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
527
597
  const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join("\n").trim() || "exit " + body.exitCode;
528
598
  setInstallError(t("installFail") + ": " + plugin.name + " — " + detail.trim().slice(-600));
@@ -532,6 +602,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
532
602
  setInstallError(t("installFail") + ": " + String(error));
533
603
  }).finally(() => setBusyUrl(null));
534
604
  }, [refreshInstalled, t]);
605
+ /** Cancel the running plugin command (#6 by @qichuang321). */
606
+ const doCancel = (0, react.useCallback)(() => {
607
+ fetch("/dsh-market/cancel", {
608
+ method: "POST",
609
+ headers: { "content-type": "application/json" },
610
+ body: "{}"
611
+ }).catch(() => {});
612
+ }, []);
535
613
  const doUpdate = (0, react.useCallback)((name, force = false) => {
536
614
  setInstallError(null);
537
615
  setStaleName(null);
@@ -547,10 +625,18 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
547
625
  status: res.status,
548
626
  body
549
627
  }))).then(({ status, body }) => {
628
+ if (body.cancelled === true) {
629
+ refreshInstalled();
630
+ return;
631
+ }
550
632
  if (status === 200 && body.ok) {
551
633
  setUpdatedNames((names) => names.concat(name));
552
634
  refreshInstalled();
553
635
  } else {
636
+ if (status === 409) {
637
+ setInstallError(t("busyWait"));
638
+ return;
639
+ }
554
640
  if (body.stale === true) setStaleName(name);
555
641
  const text = (v) => typeof v === "string" ? v : v && typeof v.text === "string" ? v.text : v == null ? "" : JSON.stringify(v);
556
642
  const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join("\n").trim() || "exit " + body.exitCode;
@@ -691,10 +777,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
691
777
  }),
692
778
  busy && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
693
779
  className: Market_module_css_default.progress,
694
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
695
- className: Market_module_css_default.grow,
696
- children: progressLine || t("progressHint")
697
- })]
780
+ children: [
781
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }),
782
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
783
+ className: Market_module_css_default.grow,
784
+ children: progressLine || t("progressHint")
785
+ }),
786
+ progressPct !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
787
+ className: Market_module_css_default.pct,
788
+ children: [progressPct, "%"]
789
+ }),
790
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
791
+ type: "button",
792
+ className: Market_module_css_default.cancelBtn,
793
+ onClick: doCancel,
794
+ children: t("cancelOp")
795
+ })
796
+ ]
698
797
  })
699
798
  ]
700
799
  }, p.url);
@@ -998,6 +1097,33 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
998
1097
  })
999
1098
  ]
1000
1099
  }),
1100
+ buildsSkipped !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1101
+ className: Market_module_css_default.restart,
1102
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1103
+ className: Market_module_css_default.grow,
1104
+ children: [
1105
+ t("buildsSkipped"),
1106
+ " ",
1107
+ buildsSkipped.names.join(", ")
1108
+ ]
1109
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1110
+ size: "sm",
1111
+ disabled: busyUrl !== null,
1112
+ onClick: () => {
1113
+ const { plugin, names } = buildsSkipped;
1114
+ setBuildsSkipped(null);
1115
+ fetch("/dsh-market/approve-builds", {
1116
+ method: "POST",
1117
+ headers: { "content-type": "application/json" },
1118
+ body: JSON.stringify({ packages: names })
1119
+ }).then((res) => res.json()).then((body) => {
1120
+ if (body.ok) doInstall(plugin);
1121
+ else setInstallError(String(body.error || "approve failed"));
1122
+ }).catch((error) => setInstallError(String(error)));
1123
+ },
1124
+ children: t("approveBuilds")
1125
+ })]
1126
+ }),
1001
1127
  installError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1002
1128
  className: Market_module_css_default.err,
1003
1129
  children: [installError, staleName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1064,10 +1190,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1064
1190
  }), plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1065
1191
  className: Market_module_css_default.empty,
1066
1192
  children: t("empty")
1067
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1193
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1068
1194
  className: Market_module_css_default.grid,
1069
- children: plugins.map(pluginCard)
1070
- })] }) : tab === "themes" && themeSnap !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(() => {
1195
+ children: plugins.slice(0, visibleCount).map(pluginCard)
1196
+ }), plugins.length > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1197
+ ref: sentinelRef,
1198
+ className: Market_module_css_default.sentinel
1199
+ })] })] }) : tab === "themes" && themeSnap !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(() => {
1071
1200
  const extra = themeSnap.themes.filter((def) => def.id !== "light" && def.id !== "dark");
1072
1201
  return extra.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1073
1202
  className: `${Market_module_css_default.grid} ${Market_module_css_default.themesGrid}`,
@@ -1122,10 +1251,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1122
1251
  }),
1123
1252
  updatingName === name && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1124
1253
  className: Market_module_css_default.progress,
1125
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1126
- className: Market_module_css_default.grow,
1127
- children: progressLine || t("progressHint")
1128
- })]
1254
+ children: [
1255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.spin }),
1256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1257
+ className: Market_module_css_default.grow,
1258
+ children: progressLine || t("progressHint")
1259
+ }),
1260
+ progressPct !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1261
+ className: Market_module_css_default.pct,
1262
+ children: [progressPct, "%"]
1263
+ }),
1264
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1265
+ type: "button",
1266
+ className: Market_module_css_default.cancelBtn,
1267
+ onClick: doCancel,
1268
+ children: t("cancelOp")
1269
+ })
1270
+ ]
1129
1271
  })
1130
1272
  ]
1131
1273
  }),