dshmarket 1.3.1 → 1.4.1

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
@@ -66,6 +66,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
66
66
  catsLess: "收起",
67
67
  sortHot: "最热",
68
68
  sortNew: "最新",
69
+ sortOld: "最早",
70
+ prevPage: "上一页",
71
+ nextPage: "下一页",
72
+ firstPage: "首页",
73
+ lastPage: "末页",
74
+ pageInfo: "第 {0} / {1} 页",
75
+ perPage: "每页",
69
76
  marketUpdate: "市场有新版本,升级",
70
77
  updateAll: "全部更新",
71
78
  tabThemes: "主题",
@@ -134,6 +141,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
134
141
  catsLess: "Less",
135
142
  sortHot: "Top",
136
143
  sortNew: "New",
144
+ sortOld: "Oldest",
145
+ prevPage: "Previous",
146
+ nextPage: "Next",
147
+ firstPage: "First",
148
+ lastPage: "Last",
149
+ pageInfo: "Page {0} of {1}",
150
+ perPage: "Per page",
137
151
  marketUpdate: "Market update available — upgrade",
138
152
  updateAll: "Update all",
139
153
  tabThemes: "Themes",
@@ -179,6 +193,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
179
193
  });
180
194
  if (options.sort === "hot") return [...list].sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1));
181
195
  if (options.sort === "new") return [...list].sort((a, b) => String(b.added).localeCompare(String(a.added)));
196
+ if (options.sort === "old") return [...list].sort((a, b) => String(a.added).localeCompare(String(b.added)));
182
197
  return list;
183
198
  }
184
199
  /** The themes tab listing: theme category only, most-starred first. */
@@ -193,6 +208,29 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
193
208
  return open || active === "all" ? categories : [active, ...categories.filter((id) => id !== active)];
194
209
  }
195
210
  /**
211
+ * Page-number list for the discover pager. With few pages it is simply
212
+ * 1..total; with many it windows around the current page and inserts '…'
213
+ * so a 400-plugin catalog stays a compact `1 … 4 5 6 … 17` instead of a
214
+ * long row of numbered buttons. Always begins with 1 and ends with total.
215
+ */
216
+ function pageItems(current, total) {
217
+ if (total <= 7) {
218
+ const all = [];
219
+ for (let i = 1; i <= total; i++) all.push(i);
220
+ return all;
221
+ }
222
+ const items = [1];
223
+ let start = Math.max(2, current - 1);
224
+ let end = Math.min(total - 1, current + 1);
225
+ if (current <= 4) end = 5;
226
+ if (current >= total - 3) start = total - 4;
227
+ if (start > 2) items.push("…");
228
+ for (let i = start; i <= end; i++) items.push(i);
229
+ if (end < total - 1) items.push("…");
230
+ items.push(total);
231
+ return items;
232
+ }
233
+ /**
196
234
  * Unified installed-state matching (#15): both sides collapse to lowercase
197
235
  * identity sets — the registry entry contributes its bare name, npm name and
198
236
  * owner/repo; the dependency contributes its key and the repo inside its
@@ -282,7 +320,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
282
320
  }
283
321
  //#endregion
284
322
  //#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}";
323
+ 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
324
  const tagId = "dshmarket/Market.module.css";
287
325
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
288
326
  const tag = document.createElement("style");
@@ -292,62 +330,75 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
292
330
  document.head.appendChild(tag);
293
331
  }
294
332
  var Market_module_css_default = {
295
- "warnBtn": "eGUBIq_warnBtn",
296
- "star": "eGUBIq_star",
297
- "catsWrap": "eGUBIq_catsWrap",
298
- "row1": "eGUBIq_row1",
299
- "owner": "eGUBIq_owner",
300
- "spin": "eGUBIq_spin",
301
- "empty": "eGUBIq_empty",
302
- "sub": "eGUBIq_sub",
303
- "dangerArmed": "eGUBIq_dangerArmed",
304
- "warnLine": "eGUBIq_warnLine",
305
- "tabs": "eGUBIq_tabs",
306
- "title": "eGUBIq_title",
307
- "sort": "eGUBIq_sort",
308
- "tab": "eGUBIq_tab",
309
- "themesGrid": "eGUBIq_themesGrid",
310
- "root": "eGUBIq_root",
311
- "grow": "eGUBIq_grow",
312
333
  "staleAction": "eGUBIq_staleAction",
334
+ "sizeOn": "eGUBIq_sizeOn",
335
+ "av": "eGUBIq_av",
336
+ "dangerBtn": "eGUBIq_dangerBtn",
337
+ "head": "eGUBIq_head",
338
+ "bar": "eGUBIq_bar",
313
339
  "cmdDetails": "eGUBIq_cmdDetails",
314
- "cancelBtn": "eGUBIq_cancelBtn",
315
- "nm": "eGUBIq_nm",
316
- "desc": "eGUBIq_desc",
317
- "catsToggle": "eGUBIq_catsToggle",
318
- "irow": "eGUBIq_irow",
319
- "loading": "eGUBIq_loading",
320
- "cmd": "eGUBIq_cmd",
321
- "restart": "eGUBIq_restart",
322
340
  "sect": "eGUBIq_sect",
323
- "titleRow": "eGUBIq_titleRow",
341
+ "cmd": "eGUBIq_cmd",
342
+ "barWave": "eGUBIq_barWave",
343
+ "foot": "eGUBIq_foot",
344
+ "spec": "eGUBIq_spec",
345
+ "empty": "eGUBIq_empty",
346
+ "pageEllipsis": "eGUBIq_pageEllipsis",
347
+ "title": "eGUBIq_title",
348
+ "star": "eGUBIq_star",
349
+ "searchInline": "eGUBIq_searchInline",
350
+ "warnLine": "eGUBIq_warnLine",
351
+ "warnBtn": "eGUBIq_warnBtn",
324
352
  "catsRow": "eGUBIq_catsRow",
325
- "dangerBtn": "eGUBIq_dangerBtn",
326
- "dot": "eGUBIq_dot",
353
+ "dangerArmed": "eGUBIq_dangerArmed",
327
354
  "cats": "eGUBIq_cats",
355
+ "grow": "eGUBIq_grow",
356
+ "dot": "eGUBIq_dot",
357
+ "nm": "eGUBIq_nm",
358
+ "top": "eGUBIq_top",
359
+ "cmdSummary": "eGUBIq_cmdSummary",
328
360
  "progress": "eGUBIq_progress",
329
- "sp": "eGUBIq_sp",
361
+ "spin": "eGUBIq_spin",
362
+ "pagerSize": "eGUBIq_pagerSize",
363
+ "src": "eGUBIq_src",
330
364
  "err": "eGUBIq_err",
331
- "spec": "eGUBIq_spec",
365
+ "row1": "eGUBIq_row1",
366
+ "desc": "eGUBIq_desc",
367
+ "pageBtn": "eGUBIq_pageBtn",
332
368
  "pct": "eGUBIq_pct",
333
- "tag": "eGUBIq_tag",
369
+ "grid": "eGUBIq_grid",
370
+ "catsToggle": "eGUBIq_catsToggle",
371
+ "sizeLabel": "eGUBIq_sizeLabel",
334
372
  "catsCollapsed": "eGUBIq_catsCollapsed",
335
- "src": "eGUBIq_src",
336
- "cmdSummary": "eGUBIq_cmdSummary",
337
- "on": "eGUBIq_on",
338
- "sentinel": "eGUBIq_sentinel",
339
- "searchInline": "eGUBIq_searchInline",
340
- "foot": "eGUBIq_foot",
341
- "swatches": "eGUBIq_swatches",
342
- "modalNote": "eGUBIq_modalNote",
373
+ "cancelBtn": "eGUBIq_cancelBtn",
374
+ "pagerPages": "eGUBIq_pagerPages",
375
+ "barFill": "eGUBIq_barFill",
376
+ "sp": "eGUBIq_sp",
377
+ "tag": "eGUBIq_tag",
378
+ "tabs": "eGUBIq_tabs",
379
+ "tab": "eGUBIq_tab",
380
+ "dshmSlide": "eGUBIq_dshmSlide",
381
+ "themesGrid": "eGUBIq_themesGrid",
382
+ "pageInfo": "eGUBIq_pageInfo",
343
383
  "body": "eGUBIq_body",
344
- "descTight": "eGUBIq_descTight",
345
- "av": "eGUBIq_av",
346
- "top": "eGUBIq_top",
384
+ "pageOn": "eGUBIq_pageOn",
385
+ "pager": "eGUBIq_pager",
386
+ "root": "eGUBIq_root",
387
+ "on": "eGUBIq_on",
347
388
  "okState": "eGUBIq_okState",
389
+ "catsWrap": "eGUBIq_catsWrap",
390
+ "modalNote": "eGUBIq_modalNote",
391
+ "sort": "eGUBIq_sort",
392
+ "swatches": "eGUBIq_swatches",
348
393
  "card": "eGUBIq_card",
349
- "head": "eGUBIq_head",
350
- "grid": "eGUBIq_grid"
394
+ "descTight": "eGUBIq_descTight",
395
+ "loading": "eGUBIq_loading",
396
+ "irow": "eGUBIq_irow",
397
+ "restart": "eGUBIq_restart",
398
+ "sub": "eGUBIq_sub",
399
+ "owner": "eGUBIq_owner",
400
+ "sizeBtn": "eGUBIq_sizeBtn",
401
+ "titleRow": "eGUBIq_titleRow"
351
402
  };
352
403
  //#endregion
353
404
  //#region src/client/MarketSection.tsx
@@ -407,6 +458,24 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
407
458
  */
408
459
  let cachedRegistry = null;
409
460
  let cachedInstalled = null;
461
+ /** Discover grid page-size choices — the catalog grows daily, so cap each page. */
462
+ const PAGE_SIZES = [
463
+ 24,
464
+ 48,
465
+ 96
466
+ ];
467
+ const DEFAULT_PAGE_SIZE = 24;
468
+ /** Sort orders offered by the Discover toolbar, in display order. */
469
+ const SORT_KEYS = [
470
+ "hot",
471
+ "new",
472
+ "old"
473
+ ];
474
+ const SORT_LABELS = {
475
+ hot: "sortHot",
476
+ new: "sortNew",
477
+ old: "sortOld"
478
+ };
410
479
  function MarketSection(props) {
411
480
  const t = props.t;
412
481
  const localeSnap = (0, react.useSyncExternalStore)((cb) => props.locale.subscribe(cb), () => props.locale.getSnapshot());
@@ -436,18 +505,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
436
505
  const [updates, setUpdates] = (0, react.useState)({});
437
506
  const [updatingName, setUpdatingName] = (0, react.useState)(null);
438
507
  const [staleName, setStaleName] = (0, react.useState)(null);
439
- /**
440
- * Cards rendered so far — the discover grid renders incrementally (60,
441
- * then +120 as the sentinel scrolls into view) instead of all 400+ at
442
- * once, which built a ~70k px DOM and made section switches lag (#30).
443
- */
444
- const [visibleCount, setVisibleCount] = (0, react.useState)(60);
445
- const sentinelRef = (0, react.useCallback)((node) => {
446
- if (node === null) return;
447
- new IntersectionObserver((entries) => {
448
- if (entries.some((entry) => entry.isIntersecting)) setVisibleCount((count) => count + 120);
449
- }, { rootMargin: "600px" }).observe(node);
450
- }, []);
508
+ /** 1-based discover page; reset to 1 whenever the list shape changes. */
509
+ const [page, setPage] = (0, react.useState)(1);
510
+ /** Cards per discover page; changing it jumps back to page 1. */
511
+ const [pageSize, setPageSize] = (0, react.useState)(DEFAULT_PAGE_SIZE);
451
512
  /** Determinate percent parsed from pnpm's Progress line, when available. */
452
513
  const [progressPct, setProgressPct] = (0, react.useState)(null);
453
514
  /** Blocked build scripts from the last install: enables approve-and-retry (#6). */
@@ -594,12 +655,34 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
594
655
  sort
595
656
  ]);
596
657
  (0, react.useEffect)(() => {
597
- setVisibleCount(60);
658
+ setPage(1);
598
659
  }, [
599
660
  q,
600
661
  cat,
601
662
  sort
602
663
  ]);
664
+ const totalPages = Math.max(1, Math.ceil(plugins.length / pageSize));
665
+ const currentPage = Math.min(page, totalPages);
666
+ const pagePlugins = plugins.slice((currentPage - 1) * pageSize, currentPage * pageSize);
667
+ const scrollToTop = () => {
668
+ const el = bodyRef.current;
669
+ if (el) {
670
+ if (typeof el.scrollTo === "function") el.scrollTo({
671
+ top: 0,
672
+ behavior: "smooth"
673
+ });
674
+ else el.scrollTop = 0;
675
+ }
676
+ };
677
+ const goToPage = (next) => {
678
+ setPage(Math.max(1, Math.min(next, totalPages)));
679
+ scrollToTop();
680
+ };
681
+ const changePageSize = (size) => {
682
+ setPageSize(size);
683
+ setPage(1);
684
+ scrollToTop();
685
+ };
603
686
  const doInstall = (0, react.useCallback)((plugin) => {
604
687
  setBuildsSkipped(null);
605
688
  setConfirming(null);
@@ -891,6 +974,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
891
974
  className: Market_module_css_default.cancelBtn,
892
975
  onClick: doCancel,
893
976
  children: t("cancelOp")
977
+ }),
978
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
979
+ className: Market_module_css_default.bar,
980
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
981
+ className: progressPct !== null ? Market_module_css_default.barFill : `${Market_module_css_default.barFill} ${Market_module_css_default.barWave}`,
982
+ style: progressPct !== null ? { width: `${progressPct}%` } : void 0
983
+ })
894
984
  })
895
985
  ]
896
986
  })
@@ -1280,10 +1370,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1280
1370
  })()
1281
1371
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1282
1372
  className: Market_module_css_default.sort,
1283
- children: ["hot", "new"].map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1373
+ children: SORT_KEYS.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1284
1374
  className: sort === key ? Market_module_css_default.on : "",
1285
1375
  onClick: () => setSort(key),
1286
- children: t(key === "hot" ? "sortHot" : "sortNew")
1376
+ children: t(SORT_LABELS[key])
1287
1377
  }, key))
1288
1378
  })]
1289
1379
  })
@@ -1292,10 +1382,68 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1292
1382
  children: t("empty")
1293
1383
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1294
1384
  className: Market_module_css_default.grid,
1295
- children: plugins.slice(0, visibleCount).map(pluginCard)
1296
- }), plugins.length > visibleCount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1297
- ref: sentinelRef,
1298
- className: Market_module_css_default.sentinel
1385
+ children: pagePlugins.map(pluginCard)
1386
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1387
+ className: Market_module_css_default.pager,
1388
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1389
+ className: Market_module_css_default.pagerPages,
1390
+ children: totalPages > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1391
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1392
+ type: "button",
1393
+ className: Market_module_css_default.pageBtn,
1394
+ disabled: currentPage === 1,
1395
+ onClick: () => goToPage(1),
1396
+ "aria-label": t("firstPage"),
1397
+ children: "«"
1398
+ }),
1399
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1400
+ type: "button",
1401
+ className: Market_module_css_default.pageBtn,
1402
+ disabled: currentPage === 1,
1403
+ onClick: () => goToPage(currentPage - 1),
1404
+ children: t("prevPage")
1405
+ }),
1406
+ pageItems(currentPage, totalPages).map((item, i) => item === "…" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1407
+ className: Market_module_css_default.pageEllipsis,
1408
+ children: "…"
1409
+ }, "e" + i) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1410
+ type: "button",
1411
+ className: item === currentPage ? `${Market_module_css_default.pageBtn} ${Market_module_css_default.pageOn}` : Market_module_css_default.pageBtn,
1412
+ onClick: () => goToPage(item),
1413
+ children: item
1414
+ }, item)),
1415
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1416
+ type: "button",
1417
+ className: Market_module_css_default.pageBtn,
1418
+ disabled: currentPage === totalPages,
1419
+ onClick: () => goToPage(currentPage + 1),
1420
+ children: t("nextPage")
1421
+ }),
1422
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1423
+ type: "button",
1424
+ className: Market_module_css_default.pageBtn,
1425
+ disabled: currentPage === totalPages,
1426
+ onClick: () => goToPage(totalPages),
1427
+ "aria-label": t("lastPage"),
1428
+ children: "»"
1429
+ }),
1430
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1431
+ className: Market_module_css_default.pageInfo,
1432
+ children: t("pageInfo").replace("{0}", String(currentPage)).replace("{1}", String(totalPages))
1433
+ })
1434
+ ] })
1435
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1436
+ className: Market_module_css_default.pagerSize,
1437
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1438
+ className: Market_module_css_default.sizeLabel,
1439
+ children: t("perPage")
1440
+ }), PAGE_SIZES.map((size) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1441
+ type: "button",
1442
+ className: size === pageSize ? `${Market_module_css_default.sizeBtn} ${Market_module_css_default.sizeOn}` : Market_module_css_default.sizeBtn,
1443
+ onClick: () => changePageSize(size),
1444
+ children: size
1445
+ }, size))]
1446
+ })]
1299
1447
  })] })] }) : tab === "themes" && themeSnap !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(() => {
1300
1448
  const extra = themeSnap.themes.filter((def) => def.id !== "light" && def.id !== "dark");
1301
1449
  return extra.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1366,6 +1514,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1366
1514
  className: Market_module_css_default.cancelBtn,
1367
1515
  onClick: doCancel,
1368
1516
  children: t("cancelOp")
1517
+ }),
1518
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1519
+ className: Market_module_css_default.bar,
1520
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1521
+ className: progressPct !== null ? Market_module_css_default.barFill : `${Market_module_css_default.barFill} ${Market_module_css_default.barWave}`,
1522
+ style: progressPct !== null ? { width: `${progressPct}%` } : void 0
1523
+ })
1369
1524
  })
1370
1525
  ]
1371
1526
  })