dsh-plugin-shop 0.1.4 → 0.3.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/lib/client.js CHANGED
@@ -4093,12 +4093,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4093
4093
  }
4094
4094
  //#endregion
4095
4095
  //#region lib/typert.remote-client.js
4096
- const dsh_plugin_shop_store_catalog_parameter_0$schema = union([_undefined(), object({ "refresh": union([
4096
+ const dsh_plugin_shop_shop_catalog_parameter_0$schema = union([_undefined(), object({ "refresh": union([
4097
4097
  _undefined(),
4098
4098
  literal(false),
4099
4099
  literal(true)
4100
4100
  ]).optional() })]);
4101
- const dsh_plugin_shop_store_catalog_result$schema = object({
4101
+ const dsh_plugin_shop_shop_catalog_result$schema = object({
4102
4102
  "schemaVersion": number(),
4103
4103
  "builtAt": string(),
4104
4104
  "stale": boolean(),
@@ -4142,7 +4142,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4142
4142
  "detail": string()
4143
4143
  }))
4144
4144
  });
4145
- const dsh_plugin_shop_store_installStart_parameter_0$schema = object({
4145
+ const dsh_plugin_shop_shop_installStart_parameter_0$schema = object({
4146
4146
  "name": string(),
4147
4147
  "version": string(),
4148
4148
  "acknowledged": union([
@@ -4151,7 +4151,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4151
4151
  literal(true)
4152
4152
  ]).optional()
4153
4153
  });
4154
- const dsh_plugin_shop_store_installStart_result$schema = union([object({
4154
+ const dsh_plugin_shop_shop_installStart_result$schema = union([object({
4155
4155
  "ok": literal(true),
4156
4156
  "installId": string()
4157
4157
  }), object({
@@ -4164,8 +4164,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4164
4164
  ]),
4165
4165
  "detail": string()
4166
4166
  })]);
4167
- const dsh_plugin_shop_store_installStatus_parameter_0$schema = object({ "installId": string() });
4168
- const dsh_plugin_shop_store_installStatus_result$schema = object({
4167
+ const dsh_plugin_shop_shop_installStatus_parameter_0$schema = object({ "installId": string() });
4168
+ const dsh_plugin_shop_shop_installStatus_result$schema = object({
4169
4169
  "found": boolean(),
4170
4170
  "state": union([
4171
4171
  literal("running"),
@@ -4180,16 +4180,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4180
4180
  ]).optional(),
4181
4181
  "detail": union([_undefined(), string()]).optional()
4182
4182
  });
4183
- const dsh_plugin_shop_store_outdated_result$schema = array(object({
4183
+ const dsh_plugin_shop_shop_outdated_result$schema = array(object({
4184
4184
  "name": string(),
4185
4185
  "installed": string(),
4186
4186
  "latest": string()
4187
4187
  }));
4188
- const dsh_plugin_shop_store_setEnabled_parameter_0$schema = object({
4188
+ const dsh_plugin_shop_shop_setEnabled_parameter_0$schema = object({
4189
4189
  "name": string(),
4190
4190
  "enabled": boolean()
4191
4191
  });
4192
- const dsh_plugin_shop_store_setEnabled_result$schema = object({
4192
+ const dsh_plugin_shop_shop_setEnabled_result$schema = object({
4193
4193
  "ok": boolean(),
4194
4194
  "detail": union([_undefined(), string()]).optional()
4195
4195
  });
@@ -4197,9 +4197,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4197
4197
  package: "dsh-plugin-shop",
4198
4198
  descriptors: [
4199
4199
  {
4200
- id: "dsh-plugin-shop#store/catalog",
4201
- service: "store",
4202
- namespace: "store",
4200
+ id: "dsh-plugin-shop#shop/catalog",
4201
+ service: "shop",
4202
+ namespace: "shop",
4203
4203
  method: "catalog",
4204
4204
  invocation: { kind: "direct" },
4205
4205
  parameters: [{
@@ -4209,14 +4209,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4209
4209
  acceptsUndefined: true,
4210
4210
  codec: {
4211
4211
  mode: "strict",
4212
- typeSymbol: "dsh-plugin-shop#store/catalog:args",
4213
- schema: dsh_plugin_shop_store_catalog_parameter_0$schema
4212
+ typeSymbol: "dsh-plugin-shop#shop/catalog:args",
4213
+ schema: dsh_plugin_shop_shop_catalog_parameter_0$schema
4214
4214
  }
4215
4215
  }],
4216
4216
  result: {
4217
4217
  mode: "strict",
4218
- typeSymbol: "dsh-plugin-shop/types#StoreCatalogResult",
4219
- schema: dsh_plugin_shop_store_catalog_result$schema
4218
+ typeSymbol: "dsh-plugin-shop/types#ShopCatalogResult",
4219
+ schema: dsh_plugin_shop_shop_catalog_result$schema
4220
4220
  },
4221
4221
  sourceLocation: {
4222
4222
  "file": "packages/dsh-plugin-shop/src/host/index.ts",
@@ -4225,9 +4225,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4225
4225
  }
4226
4226
  },
4227
4227
  {
4228
- id: "dsh-plugin-shop#store/installStart",
4229
- service: "store",
4230
- namespace: "store",
4228
+ id: "dsh-plugin-shop#shop/installStart",
4229
+ service: "shop",
4230
+ namespace: "shop",
4231
4231
  method: "installStart",
4232
4232
  implementation: "install",
4233
4233
  invocation: { kind: "direct" },
@@ -4238,13 +4238,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4238
4238
  codec: {
4239
4239
  mode: "strict",
4240
4240
  typeSymbol: "dsh-plugin-shop/types#InstallArgs",
4241
- schema: dsh_plugin_shop_store_installStart_parameter_0$schema
4241
+ schema: dsh_plugin_shop_shop_installStart_parameter_0$schema
4242
4242
  }
4243
4243
  }],
4244
4244
  result: {
4245
4245
  mode: "strict",
4246
- typeSymbol: "dsh-plugin-shop/types#StoreInstallResult",
4247
- schema: dsh_plugin_shop_store_installStart_result$schema
4246
+ typeSymbol: "dsh-plugin-shop/types#ShopInstallResult",
4247
+ schema: dsh_plugin_shop_shop_installStart_result$schema
4248
4248
  },
4249
4249
  sourceLocation: {
4250
4250
  "file": "packages/dsh-plugin-shop/src/host/index.ts",
@@ -4253,9 +4253,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4253
4253
  }
4254
4254
  },
4255
4255
  {
4256
- id: "dsh-plugin-shop#store/installStatus",
4257
- service: "store",
4258
- namespace: "store",
4256
+ id: "dsh-plugin-shop#shop/installStatus",
4257
+ service: "shop",
4258
+ namespace: "shop",
4259
4259
  method: "installStatus",
4260
4260
  invocation: { kind: "direct" },
4261
4261
  parameters: [{
@@ -4264,14 +4264,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4264
4264
  source: "json",
4265
4265
  codec: {
4266
4266
  mode: "strict",
4267
- typeSymbol: "dsh-plugin-shop#store/installStatus:args",
4268
- schema: dsh_plugin_shop_store_installStatus_parameter_0$schema
4267
+ typeSymbol: "dsh-plugin-shop#shop/installStatus:args",
4268
+ schema: dsh_plugin_shop_shop_installStatus_parameter_0$schema
4269
4269
  }
4270
4270
  }],
4271
4271
  result: {
4272
4272
  mode: "strict",
4273
- typeSymbol: "dsh-plugin-shop/types#StoreInstallStatusResult",
4274
- schema: dsh_plugin_shop_store_installStatus_result$schema
4273
+ typeSymbol: "dsh-plugin-shop/types#ShopInstallStatusResult",
4274
+ schema: dsh_plugin_shop_shop_installStatus_result$schema
4275
4275
  },
4276
4276
  sourceLocation: {
4277
4277
  "file": "packages/dsh-plugin-shop/src/host/index.ts",
@@ -4280,16 +4280,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4280
4280
  }
4281
4281
  },
4282
4282
  {
4283
- id: "dsh-plugin-shop#store/outdated",
4284
- service: "store",
4285
- namespace: "store",
4283
+ id: "dsh-plugin-shop#shop/outdated",
4284
+ service: "shop",
4285
+ namespace: "shop",
4286
4286
  method: "outdated",
4287
4287
  invocation: { kind: "direct" },
4288
4288
  parameters: [],
4289
4289
  result: {
4290
4290
  mode: "strict",
4291
- typeSymbol: "dsh-plugin-shop#store/outdated:result",
4292
- schema: dsh_plugin_shop_store_outdated_result$schema
4291
+ typeSymbol: "dsh-plugin-shop#shop/outdated:result",
4292
+ schema: dsh_plugin_shop_shop_outdated_result$schema
4293
4293
  },
4294
4294
  sourceLocation: {
4295
4295
  "file": "packages/dsh-plugin-shop/src/host/index.ts",
@@ -4298,9 +4298,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4298
4298
  }
4299
4299
  },
4300
4300
  {
4301
- id: "dsh-plugin-shop#store/setEnabled",
4302
- service: "store",
4303
- namespace: "store",
4301
+ id: "dsh-plugin-shop#shop/setEnabled",
4302
+ service: "shop",
4303
+ namespace: "shop",
4304
4304
  method: "setEnabled",
4305
4305
  invocation: { kind: "direct" },
4306
4306
  parameters: [{
@@ -4309,14 +4309,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4309
4309
  source: "json",
4310
4310
  codec: {
4311
4311
  mode: "strict",
4312
- typeSymbol: "dsh-plugin-shop#store/setEnabled:args",
4313
- schema: dsh_plugin_shop_store_setEnabled_parameter_0$schema
4312
+ typeSymbol: "dsh-plugin-shop#shop/setEnabled:args",
4313
+ schema: dsh_plugin_shop_shop_setEnabled_parameter_0$schema
4314
4314
  }
4315
4315
  }],
4316
4316
  result: {
4317
4317
  mode: "strict",
4318
- typeSymbol: "dsh-plugin-shop/types#StoreSetEnabledResult",
4319
- schema: dsh_plugin_shop_store_setEnabled_result$schema
4318
+ typeSymbol: "dsh-plugin-shop/types#ShopSetEnabledResult",
4319
+ schema: dsh_plugin_shop_shop_setEnabled_result$schema
4320
4320
  },
4321
4321
  sourceLocation: {
4322
4322
  "file": "packages/dsh-plugin-shop/src/host/index.ts",
@@ -4336,7 +4336,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4336
4336
  case "community": return "tierCommunity";
4337
4337
  }
4338
4338
  }
4339
- /** A derived listing has no author-declared catalog section; the store
4339
+ /** A derived listing has no author-declared catalog section; the shop
4340
4340
  * presents it as unclaimed, which is the signal that prompts an author to add
4341
4341
  * one (§6.1). Never present a derived entry as though the author wrote it. */
4342
4342
  function isUnclaimed(entry) {
@@ -4359,6 +4359,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4359
4359
  }
4360
4360
  /** §7.2 once-per-second poll cadence, as a named constant. */
4361
4361
  const INSTALL_POLL_MS = 1e3;
4362
+ /** The next number of cards to show: the current window plus one batch,
4363
+ * clamped so the window never claims more cards than the list holds. */
4364
+ function nextVisibleCount(visible, total, batch) {
4365
+ return Math.min(visible + batch, total);
4366
+ }
4362
4367
  /** Pure install view reducer. A `status` event only applies to the install the
4363
4368
  * view is tracking — a status for an install it never started (idle) is an
4364
4369
  * unrelated event and a no-op, like any other event it does not recognize. */
@@ -4399,7 +4404,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4399
4404
  }
4400
4405
  }
4401
4406
  }
4402
- const STORE_KEYWORDS = [
4407
+ const SHOP_KEYWORDS = [
4403
4408
  "store",
4404
4409
  "market",
4405
4410
  "mall",
@@ -4407,21 +4412,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4407
4412
  "marketplace"
4408
4413
  ];
4409
4414
  /**
4410
- * Whether a package name reads as a plugin store (a marketplace for dsh
4411
- * plugins, e.g. `dsh-plugin-shop`, `dsh-store`, `pluginstore`). The store
4415
+ * Whether a package name reads as a plugin shop (a marketplace for dsh
4416
+ * plugins, e.g. `dsh-plugin-shop`, `dsh-store`, `pluginstore`). The shop
4412
4417
  * tab hides these so the market does not list competing markets.
4413
4418
  *
4414
4419
  * Precision over recall: a name merely CONTAINING a keyword segment without
4415
4420
  * a plugin qualifier or a keyword ending (`market-data-provider`,
4416
- * `marketplace-hub`) is NOT a store plugin, and `dsh-restore` must never
4417
- * match on the substring "store".
4421
+ * `marketplace-hub`) is NOT a shop plugin, and `dsh-restore` must never
4422
+ * match on the substring "store". The keyword list keeps "store" on purpose:
4423
+ * it matches other people's package names, not ours.
4418
4424
  */
4419
- function isStoreLike(name) {
4425
+ function isShopLike(name) {
4420
4426
  const segments = name.toLowerCase().split(/[-_.]+/);
4421
4427
  const hasPlugin = segments.includes("plugin");
4422
4428
  if (segments.some((segment) => /plugin(store|market|mall|shop|marketplace)/.test(segment) || /(store|market|mall|shop|marketplace)plugin/.test(segment))) return true;
4423
- if (segments.filter((segment) => STORE_KEYWORDS.includes(segment)).length === 0) return false;
4424
- return hasPlugin || STORE_KEYWORDS.includes(segments.at(-1));
4429
+ if (segments.filter((segment) => SHOP_KEYWORDS.includes(segment)).length === 0) return false;
4430
+ return hasPlugin || SHOP_KEYWORDS.includes(segments.at(-1));
4425
4431
  }
4426
4432
  const CATEGORY_KEYS = {
4427
4433
  tool: "categoryTool",
@@ -4438,10 +4444,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4438
4444
  }
4439
4445
  //#endregion
4440
4446
  //#region src/client/locales.ts
4441
- /** Copy dictionaries for the store Settings tab. */
4447
+ /** Copy dictionaries for the shop Settings tab. */
4442
4448
  /** Simplified Chinese dictionary and key source of truth. */
4443
4449
  const zh = {
4444
- tab: "插件市场",
4450
+ tab: "插件商店",
4445
4451
  loading: "正在读取目录…",
4446
4452
  error: "暂时无法读取目录。",
4447
4453
  retry: "重试",
@@ -4473,6 +4479,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4473
4479
  installTransportFailed: "安装请求未能送达。请稍后重试。",
4474
4480
  refresh: "刷新",
4475
4481
  staleLabel: "显示 {date} 的快照",
4482
+ showing: "显示前 {shown} 个(共 {total})· 继续滚动加载",
4476
4483
  version: "版本",
4477
4484
  repository: "仓库",
4478
4485
  license: "许可",
@@ -4491,7 +4498,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4491
4498
  };
4492
4499
  /** English dictionary checked against the Chinese key set. */
4493
4500
  const en = {
4494
- tab: "Plugin store",
4501
+ tab: "Plugin shop",
4495
4502
  loading: "Reading the catalog…",
4496
4503
  error: "The catalog is temporarily unavailable.",
4497
4504
  retry: "Retry",
@@ -4523,6 +4530,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4523
4530
  installTransportFailed: "The install request could not be delivered. Please retry.",
4524
4531
  refresh: "Refresh",
4525
4532
  staleLabel: "showing {date}",
4533
+ showing: "showing first {shown} of {total} — scroll to load more",
4526
4534
  version: "Version",
4527
4535
  repository: "Repository",
4528
4536
  license: "License",
@@ -4591,87 +4599,89 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4591
4599
  };
4592
4600
  }
4593
4601
  //#endregion
4594
- //#region \0dsh-plugin-shop-css:9ac4dc0a
4595
- const css = "/* Store tab styles — a market shelf inside the settings surface. The visual\n * language is the dsh theme's alias tokens ONLY (the four tokens the previous\n * styles referenced that do not exist — bg-layer-3, interactive-bg-hover,\n * state-error, state-success — are corrected to bg-layer-2 and the\n * state-*-primary set). The signature is the category spine: one brand hue\n * at six opacities, one per category, with the category name as the cover\n * label. Class names are mapped to content-derived names at bundle time\n * (tsdown.sc0638f_client.s5f77d3_config.s9c91c3_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.sc0638f_client.s456164_spec.s9c91c3_ts` pins this. */\n\n.s3ee4f7_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.s34fbb8_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.sf8980c_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.s7cc50d_skeletonGrid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n}\n\n.sc1d9dd_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.sc1d9dd_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshStoreSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshStoreSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.sb9166d_skeletonCover {\n display: block;\n height: 26px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);\n}\n\n.s9f0885_skeletonName {\n width: 55%;\n height: 14px;\n margin: 12px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s18a7d7_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.se58a1d_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 14px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sc1d9dd_skeletonCard span {\n animation: dshStoreSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshStoreSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sc1d9dd_skeletonCard span { animation: none; opacity: 0.75; }\n .sc1d9dd_skeletonCard::after { content: none; }\n}\n\n.sd2f7a7_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.sd2f7a7_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.sd2f7a7_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s8b7c86_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s631085_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s631085_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sb9cba1_staleBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s8da7f6_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.s7cf245_catalogHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.s104623_catalogStats {\n margin: -8px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc4b2b5_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n.s2b38ed_cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n list-style: none;\n margin: 0;\n padding: 0;\n animation: dshStoreCardsIn 220ms ease;\n}\n\n@keyframes dshStoreCardsIn {\n from { opacity: 0; transform: translateY(3px); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s2b38ed_cards { animation: none; }\n}\n\n.se139f2_card {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n}\n\n.se139f2_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .se139f2_card { transition: none; }\n .se139f2_card:hover { transform: none; }\n}\n\n/* The signature: a brand spine in the category's own opacity. */\n.sd7b5c1_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) var(--spine-opacity, 40%), transparent);\n}\n\n.se139f2_card[data-category='tool'] { --spine-opacity: 100%; }\n.se139f2_card[data-category='provider'] { --spine-opacity: 82%; }\n.se139f2_card[data-category='ui'] { --spine-opacity: 64%; }\n.se139f2_card[data-category='workflow'] { --spine-opacity: 48%; }\n.se139f2_card[data-category='integration'] { --spine-opacity: 34%; }\n.se139f2_card[data-category='other'] { --spine-opacity: 22%; }\n\n.s3cb96a_cardCover {\n display: block;\n padding: 5px 12px 5px 12px;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) var(--spine-opacity, 40%), transparent);\n}\n\n.s756c69_coverLabel {\n display: block;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--dsw-alias-brand-primary);\n}\n\n.s715e28_entryHeader {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n padding: 10px 12px 6px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.s715e28_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name owns the full header width; badges sit on their own line below. */\n.s13952b_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n\n.scf3634_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.s564750_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s564750_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s564750_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s564750_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s8d8459_unclaimedBadge {\n padding: 1px 7px;\n border-radius: 999px;\n border: 1px dashed var(--dsw-alias-border-l2);\n font-size: 11px;\n line-height: 1.6;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s22f9c9_chevron, .s9812b3_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s9812b3_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s22f9c9_chevron, .s9812b3_chevronOpen { transition: none; }\n}\n\n.s1630e4_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px 12px;\n}\n\n.s817163_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.s7b7b74_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.sa1cf55_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.sc5187f_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s254ff5_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s254ff5_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sd5c609_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.s9f6608_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.s60a4c7_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.s60a4c7_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.s60a4c7_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.s27bac7_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.se261d7_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.sd477fc_installButton, .sf60f0d_confirmButton, .se03737_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.sd477fc_installButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sd477fc_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sf60f0d_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sf60f0d_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.se03737_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.se03737_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.sd477fc_installButton:focus-visible, .sf60f0d_confirmButton:focus-visible, .se03737_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s52e3df_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s2fa7f4_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.sa5c938_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sef3bcb_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s27c2b0_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sca368e_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.s1b9272_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa67c51_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.s58085b_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sbead84_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s27ed17_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s42db4e_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Installed section. */\n.s69767e_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s2d4d0e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s573b74_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s2bb39b_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s2bb39b_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s7a2aa4_outdatedVersions {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s74c7b2_outdatedActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* The enable/disable switch. */\n.s5a5c20_switch {\n position: relative;\n width: 32px;\n height: 18px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n.sa963e5_switchOn {\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 55%, transparent);\n}\n\n.s2e73a7_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.sa963e5_switchOn .s2e73a7_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s5a5c20_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s5a5c20_switch, .s2e73a7_switchKnob { transition: none; }\n}\n";
4596
- if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"9ac4dc0a\"]")) {
4602
+ //#region \0dsh-plugin-shop-css:e3675a89
4603
+ const css = "/* Shop tab styles — a market shelf inside the settings surface. The visual\n * language is the dsh theme's alias tokens ONLY (the four tokens the previous\n * styles referenced that do not exist — bg-layer-3, interactive-bg-hover,\n * state-error, state-success — are corrected to bg-layer-2 and the\n * state-*-primary set). The signature is the category spine: one brand hue\n * at six opacities, one per category, with the category name as the cover\n * label. Class names are mapped to content-derived names at bundle time\n * (tsdown.s8583e3_client.s942a79_config.s5f67aa_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.s8583e3_client.sfd9d8a_spec.s5f67aa_ts` pins this. */\n\n.s255e5a_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.s44a3ec_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s3a0ece_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.se0c3b4_skeletonGrid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n}\n\n.s520416_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s520416_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.s30e662_skeletonCover {\n display: block;\n height: 26px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);\n}\n\n.s8c7d6f_skeletonName {\n width: 55%;\n height: 14px;\n margin: 12px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sf5179e_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sbb0d25_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 14px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s520416_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s520416_skeletonCard span { animation: none; opacity: 0.75; }\n .s520416_skeletonCard::after { content: none; }\n}\n\n.s73242a_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s73242a_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s73242a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s646509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s232ec4_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s232ec4_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s1555aa_staleBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s3946f1_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.s668774_catalogHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.sccc4d1_catalogStats {\n margin: -8px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s6de1ab_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n.sf657f5_cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n list-style: none;\n margin: 0;\n padding: 0;\n animation: dshShopCardsIn 220ms ease;\n}\n\n@keyframes dshShopCardsIn {\n from { opacity: 0; transform: translateY(3px); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sf657f5_cards { animation: none; }\n}\n\n.s65f383_card {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n /* Off-screen cards skip layout and paint; the placeholder keeps scrollbar\n * estimation sane before the browser has measured the real height. */\n content-visibility: auto;\n contain-intrinsic-size: auto 240px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.sd7ee01_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s705cc6_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s65f383_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s65f383_card { transition: none; }\n .s65f383_card:hover { transform: none; }\n}\n\n/* The signature: a brand spine in the category's own opacity. */\n.s4ce25d_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) var(--spine-opacity, 40%), transparent);\n}\n\n.s65f383_card[data-category='tool'] { --spine-opacity: 100%; }\n.s65f383_card[data-category='provider'] { --spine-opacity: 82%; }\n.s65f383_card[data-category='ui'] { --spine-opacity: 64%; }\n.s65f383_card[data-category='workflow'] { --spine-opacity: 48%; }\n.s65f383_card[data-category='integration'] { --spine-opacity: 34%; }\n.s65f383_card[data-category='other'] { --spine-opacity: 22%; }\n\n.s9e2bec_cardCover {\n display: block;\n padding: 5px 12px 5px 12px;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) var(--spine-opacity, 40%), transparent);\n}\n\n.s1a7c5b_coverLabel {\n display: block;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--dsw-alias-brand-primary);\n}\n\n.sa97234_entryHeader {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n padding: 10px 12px 6px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.sa97234_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name owns the full header width; badges sit on their own line below. */\n.sc3f149_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n\n.s513026_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.s5e82cb_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s5e82cb_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s23e3e1_unclaimedBadge {\n padding: 1px 7px;\n border-radius: 999px;\n border: 1px dashed var(--dsw-alias-border-l2);\n font-size: 11px;\n line-height: 1.6;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s73f7fb_chevron, .s61393c_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s61393c_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s73f7fb_chevron, .s61393c_chevronOpen { transition: none; }\n}\n\n.s820ebf_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px 12px;\n}\n\n.sb8fbc8_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.se507db_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.s9d2029_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3bdbd5_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s441702_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s441702_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sde3f0c_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.se98179_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sfb4d2f_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sfb4d2f_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfb4d2f_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sd58c6d_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.s4d374c_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.se7aaed_installButton, .sb43a49_confirmButton, .s6e45d1_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.se7aaed_installButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.se7aaed_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sb43a49_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sb43a49_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s6e45d1_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.s6e45d1_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se7aaed_installButton:focus-visible, .sb43a49_confirmButton:focus-visible, .s6e45d1_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sc4f2ac_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s559c38_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s3c0ace_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s4b2373_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s52b5a5_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s64ab71_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.s1531a8_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf20dda_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.seb9b08_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sfd3021_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s50ba35_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.se75489_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Installed section. */\n.sa276cf_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sceae6e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s8d2072_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s5c2545_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5c2545_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s877c68_outdatedVersions {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa1f556_outdatedActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* The enable/disable switch. */\n.s11c019_switch {\n position: relative;\n width: 32px;\n height: 18px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n.s7580e8_switchOn {\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 55%, transparent);\n}\n\n.saab2b3_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.s7580e8_switchOn .saab2b3_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s11c019_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s11c019_switch, .saab2b3_switchKnob { transition: none; }\n}\n";
4604
+ if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"e3675a89\"]")) {
4597
4605
  const tag = document.createElement("style");
4598
- tag.dataset.pluginCss = "9ac4dc0a";
4606
+ tag.dataset.pluginCss = "e3675a89";
4599
4607
  tag.textContent = css;
4600
4608
  document.head.appendChild(tag);
4601
4609
  }
4602
- var _dsh_plugin_shop_css_9ac4dc0a_default = {
4603
- "client": "sc0638f_client",
4604
- "config": "s5f77d3_config",
4605
- "ts": "s9c91c3_ts",
4606
- "spec": "s456164_spec",
4607
- "panel": "s3ee4f7_panel",
4608
- "stateLine": "s34fbb8_stateLine",
4609
- "srOnly": "sf8980c_srOnly",
4610
- "skeletonGrid": "s7cc50d_skeletonGrid",
4611
- "skeletonCard": "sc1d9dd_skeletonCard",
4612
- "skeletonCover": "sb9166d_skeletonCover",
4613
- "skeletonName": "s9f0885_skeletonName",
4614
- "skeletonSummary": "s18a7d7_skeletonSummary",
4615
- "skeletonSummaryShort": "se58a1d_skeletonSummaryShort",
4616
- "actionButton": "sd2f7a7_actionButton",
4617
- "toolbar": "s8b7c86_toolbar",
4618
- "searchInput": "s631085_searchInput",
4619
- "staleBlock": "sb9cba1_staleBlock",
4620
- "staleBadge": "s8da7f6_staleBadge",
4621
- "catalogHeading": "s7cf245_catalogHeading",
4622
- "catalogStats": "s104623_catalogStats",
4623
- "emptyLine": "sc4b2b5_emptyLine",
4624
- "cards": "s2b38ed_cards",
4625
- "card": "se139f2_card",
4626
- "cardSpine": "sd7b5c1_cardSpine",
4627
- "cardCover": "s3cb96a_cardCover",
4628
- "coverLabel": "s756c69_coverLabel",
4629
- "entryHeader": "s715e28_entryHeader",
4630
- "name": "s13952b_name",
4631
- "badges": "scf3634_badges",
4632
- "tierBadge": "s564750_tierBadge",
4633
- "unclaimedBadge": "s8d8459_unclaimedBadge",
4634
- "chevron": "s22f9c9_chevron",
4635
- "chevronOpen": "s9812b3_chevronOpen",
4636
- "body": "s1630e4_body",
4637
- "summary": "s817163_summary",
4638
- "summaryZh": "s7b7b74_summaryZh",
4639
- "capabilitiesBlock": "sa1cf55_capabilitiesBlock",
4640
- "capabilitiesNote": "sc5187f_capabilitiesNote",
4641
- "capabilities": "s254ff5_capabilities",
4642
- "detail": "sd5c609_detail",
4643
- "detailRows": "s9f6608_detailRows",
4644
- "detailRow": "s60a4c7_detailRow",
4645
- "reviewedLine": "s27bac7_reviewedLine",
4646
- "installPanel": "se261d7_installPanel",
4647
- "installButton": "sd477fc_installButton",
4648
- "confirmButton": "sf60f0d_confirmButton",
4649
- "cancelButton": "se03737_cancelButton",
4650
- "gate": "s52e3df_gate",
4651
- "gateTitle": "s2fa7f4_gateTitle",
4652
- "gateBody": "sa5c938_gateBody",
4653
- "gateActions": "sef3bcb_gateActions",
4654
- "installing": "s27c2b0_installing",
4655
- "log": "sca368e_log",
4656
- "logLine": "s1b9272_logLine",
4657
- "notice": "sa67c51_notice",
4658
- "failedHeading": "s58085b_failedHeading",
4659
- "failedDetail": "sbead84_failedDetail",
4660
- "rejectedCode": "s27ed17_rejectedCode",
4661
- "rejectedDetail": "s42db4e_rejectedDetail",
4662
- "outdatedSection": "s69767e_outdatedSection",
4663
- "outdatedList": "s2d4d0e_outdatedList",
4664
- "outdatedRow": "s573b74_outdatedRow",
4665
- "outdatedInfo": "s2bb39b_outdatedInfo",
4666
- "outdatedVersions": "s7a2aa4_outdatedVersions",
4667
- "outdatedActions": "s74c7b2_outdatedActions",
4668
- "switch": "s5a5c20_switch",
4669
- "switchOn": "sa963e5_switchOn",
4670
- "switchKnob": "s2e73a7_switchKnob"
4610
+ var _dsh_plugin_shop_css_e3675a89_default = {
4611
+ "client": "s8583e3_client",
4612
+ "config": "s942a79_config",
4613
+ "ts": "s5f67aa_ts",
4614
+ "spec": "sfd9d8a_spec",
4615
+ "panel": "s255e5a_panel",
4616
+ "stateLine": "s44a3ec_stateLine",
4617
+ "srOnly": "s3a0ece_srOnly",
4618
+ "skeletonGrid": "se0c3b4_skeletonGrid",
4619
+ "skeletonCard": "s520416_skeletonCard",
4620
+ "skeletonCover": "s30e662_skeletonCover",
4621
+ "skeletonName": "s8c7d6f_skeletonName",
4622
+ "skeletonSummary": "sf5179e_skeletonSummary",
4623
+ "skeletonSummaryShort": "sbb0d25_skeletonSummaryShort",
4624
+ "actionButton": "s73242a_actionButton",
4625
+ "toolbar": "s646509_toolbar",
4626
+ "searchInput": "s232ec4_searchInput",
4627
+ "staleBlock": "s1555aa_staleBlock",
4628
+ "staleBadge": "s3946f1_staleBadge",
4629
+ "catalogHeading": "s668774_catalogHeading",
4630
+ "catalogStats": "sccc4d1_catalogStats",
4631
+ "emptyLine": "s6de1ab_emptyLine",
4632
+ "cards": "sf657f5_cards",
4633
+ "card": "s65f383_card",
4634
+ "cardsSentry": "sd7ee01_cardsSentry",
4635
+ "showingLine": "s705cc6_showingLine",
4636
+ "cardSpine": "s4ce25d_cardSpine",
4637
+ "cardCover": "s9e2bec_cardCover",
4638
+ "coverLabel": "s1a7c5b_coverLabel",
4639
+ "entryHeader": "sa97234_entryHeader",
4640
+ "name": "sc3f149_name",
4641
+ "badges": "s513026_badges",
4642
+ "tierBadge": "s5e82cb_tierBadge",
4643
+ "unclaimedBadge": "s23e3e1_unclaimedBadge",
4644
+ "chevron": "s73f7fb_chevron",
4645
+ "chevronOpen": "s61393c_chevronOpen",
4646
+ "body": "s820ebf_body",
4647
+ "summary": "sb8fbc8_summary",
4648
+ "summaryZh": "se507db_summaryZh",
4649
+ "capabilitiesBlock": "s9d2029_capabilitiesBlock",
4650
+ "capabilitiesNote": "s3bdbd5_capabilitiesNote",
4651
+ "capabilities": "s441702_capabilities",
4652
+ "detail": "sde3f0c_detail",
4653
+ "detailRows": "se98179_detailRows",
4654
+ "detailRow": "sfb4d2f_detailRow",
4655
+ "reviewedLine": "sd58c6d_reviewedLine",
4656
+ "installPanel": "s4d374c_installPanel",
4657
+ "installButton": "se7aaed_installButton",
4658
+ "confirmButton": "sb43a49_confirmButton",
4659
+ "cancelButton": "s6e45d1_cancelButton",
4660
+ "gate": "sc4f2ac_gate",
4661
+ "gateTitle": "s559c38_gateTitle",
4662
+ "gateBody": "s3c0ace_gateBody",
4663
+ "gateActions": "s4b2373_gateActions",
4664
+ "installing": "s52b5a5_installing",
4665
+ "log": "s64ab71_log",
4666
+ "logLine": "s1531a8_logLine",
4667
+ "notice": "sf20dda_notice",
4668
+ "failedHeading": "seb9b08_failedHeading",
4669
+ "failedDetail": "sfd3021_failedDetail",
4670
+ "rejectedCode": "s50ba35_rejectedCode",
4671
+ "rejectedDetail": "se75489_rejectedDetail",
4672
+ "outdatedSection": "sa276cf_outdatedSection",
4673
+ "outdatedList": "sceae6e_outdatedList",
4674
+ "outdatedRow": "s8d2072_outdatedRow",
4675
+ "outdatedInfo": "s5c2545_outdatedInfo",
4676
+ "outdatedVersions": "s877c68_outdatedVersions",
4677
+ "outdatedActions": "sa1f556_outdatedActions",
4678
+ "switch": "s11c019_switch",
4679
+ "switchOn": "s7580e8_switchOn",
4680
+ "switchKnob": "saab2b3_switchKnob"
4671
4681
  };
4672
4682
  //#endregion
4673
- //#region src/client/StoreTab.tsx
4674
- /** The store tab: browse the catalog, detail an entry, install with the
4683
+ //#region src/client/ShopTab.tsx
4684
+ /** The shop tab: browse the catalog, detail an entry, install with the
4675
4685
  * acknowledgement gate, poll the install to its terminal state (§7.2).
4676
4686
  * Everything the tab renders is text — summaries, capabilities, log lines,
4677
4687
  * details — never markup, so hostile npm descriptions cannot inject (spec
@@ -4682,7 +4692,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4682
4692
  width: "14",
4683
4693
  height: "14",
4684
4694
  "aria-hidden": "true",
4685
- className: open ? _dsh_plugin_shop_css_9ac4dc0a_default.chevronOpen : _dsh_plugin_shop_css_9ac4dc0a_default.chevron,
4695
+ className: open ? _dsh_plugin_shop_css_e3675a89_default.chevronOpen : _dsh_plugin_shop_css_e3675a89_default.chevron,
4686
4696
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4687
4697
  fill: "currentColor",
4688
4698
  d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
@@ -4693,47 +4703,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4693
4703
  * (name, tier, category, unclaimed marker), the plain-text summary in both
4694
4704
  * languages, the self-declared capabilities, the detail section, and the
4695
4705
  * install controls. */
4696
- function EntryCard({ entry, t, install, installStatus }) {
4706
+ const EntryCard = (0, react.memo)(function EntryCard({ entry, t, install, installStatus }) {
4697
4707
  const [open, setOpen] = (0, react.useState)(false);
4698
4708
  const detailId = (0, react.useId)();
4699
4709
  const summary = entry.catalog?.summary;
4700
4710
  const category = entry.catalog?.category ?? "other";
4701
4711
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4702
- className: _dsh_plugin_shop_css_9ac4dc0a_default.card,
4703
- "data-store-entry": entry.name,
4712
+ className: _dsh_plugin_shop_css_e3675a89_default.card,
4713
+ "data-shop-entry": entry.name,
4704
4714
  "data-category": category,
4705
4715
  children: [
4706
4716
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4707
- className: _dsh_plugin_shop_css_9ac4dc0a_default.cardSpine,
4717
+ className: _dsh_plugin_shop_css_e3675a89_default.cardSpine,
4708
4718
  "aria-hidden": "true"
4709
4719
  }),
4710
4720
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4711
- className: _dsh_plugin_shop_css_9ac4dc0a_default.cardCover,
4721
+ className: _dsh_plugin_shop_css_e3675a89_default.cardCover,
4712
4722
  "aria-hidden": "true",
4713
4723
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4714
- className: _dsh_plugin_shop_css_9ac4dc0a_default.coverLabel,
4724
+ className: _dsh_plugin_shop_css_e3675a89_default.coverLabel,
4715
4725
  children: t(categoryKey(entry))
4716
4726
  })
4717
4727
  }),
4718
4728
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4719
4729
  type: "button",
4720
- className: _dsh_plugin_shop_css_9ac4dc0a_default.entryHeader,
4730
+ className: _dsh_plugin_shop_css_e3675a89_default.entryHeader,
4721
4731
  "aria-expanded": open,
4722
4732
  "aria-controls": detailId,
4723
4733
  onClick: () => setOpen((current) => !current),
4724
4734
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4725
- className: _dsh_plugin_shop_css_9ac4dc0a_default.name,
4735
+ className: _dsh_plugin_shop_css_e3675a89_default.name,
4726
4736
  children: entry.name
4727
4737
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4728
- className: _dsh_plugin_shop_css_9ac4dc0a_default.badges,
4738
+ className: _dsh_plugin_shop_css_e3675a89_default.badges,
4729
4739
  children: [
4730
4740
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4731
- className: _dsh_plugin_shop_css_9ac4dc0a_default.tierBadge,
4741
+ className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
4732
4742
  "data-tier": entry.tier,
4733
4743
  children: t(tierKey(entry.tier))
4734
4744
  }),
4735
4745
  isUnclaimed(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4736
- className: _dsh_plugin_shop_css_9ac4dc0a_default.unclaimedBadge,
4746
+ className: _dsh_plugin_shop_css_e3675a89_default.unclaimedBadge,
4737
4747
  children: t("unclaimed")
4738
4748
  }),
4739
4749
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { open })
@@ -4741,47 +4751,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4741
4751
  })]
4742
4752
  }),
4743
4753
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4744
- className: _dsh_plugin_shop_css_9ac4dc0a_default.body,
4754
+ className: _dsh_plugin_shop_css_e3675a89_default.body,
4745
4755
  children: [
4746
4756
  summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4747
- className: _dsh_plugin_shop_css_9ac4dc0a_default.summary,
4757
+ className: _dsh_plugin_shop_css_e3675a89_default.summary,
4748
4758
  children: summary.en
4749
4759
  }),
4750
4760
  summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4751
- className: _dsh_plugin_shop_css_9ac4dc0a_default.summaryZh,
4761
+ className: _dsh_plugin_shop_css_e3675a89_default.summaryZh,
4752
4762
  children: summary.zh
4753
4763
  }),
4754
4764
  entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4755
- className: _dsh_plugin_shop_css_9ac4dc0a_default.capabilitiesBlock,
4765
+ className: _dsh_plugin_shop_css_e3675a89_default.capabilitiesBlock,
4756
4766
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4757
- className: _dsh_plugin_shop_css_9ac4dc0a_default.capabilitiesNote,
4767
+ className: _dsh_plugin_shop_css_e3675a89_default.capabilitiesNote,
4758
4768
  children: t("capabilitiesNote")
4759
4769
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
4760
- className: _dsh_plugin_shop_css_9ac4dc0a_default.capabilities,
4770
+ className: _dsh_plugin_shop_css_e3675a89_default.capabilities,
4761
4771
  children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
4762
4772
  })]
4763
4773
  }),
4764
4774
  open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4765
4775
  id: detailId,
4766
- className: _dsh_plugin_shop_css_9ac4dc0a_default.detail,
4776
+ className: _dsh_plugin_shop_css_e3675a89_default.detail,
4767
4777
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
4768
- className: _dsh_plugin_shop_css_9ac4dc0a_default.detailRows,
4778
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRows,
4769
4779
  children: [
4770
4780
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4771
- className: _dsh_plugin_shop_css_9ac4dc0a_default.detailRow,
4781
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
4772
4782
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("version") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: entry.version })]
4773
4783
  }),
4774
4784
  entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4775
- className: _dsh_plugin_shop_css_9ac4dc0a_default.detailRow,
4785
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
4776
4786
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("repository") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: entry.repository })]
4777
4787
  }),
4778
4788
  entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4779
- className: _dsh_plugin_shop_css_9ac4dc0a_default.detailRow,
4789
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
4780
4790
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("license") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: entry.license })]
4781
4791
  })
4782
4792
  ]
4783
4793
  }), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4784
- className: _dsh_plugin_shop_css_9ac4dc0a_default.reviewedLine,
4794
+ className: _dsh_plugin_shop_css_e3675a89_default.reviewedLine,
4785
4795
  children: t("reviewedVersionLine", {
4786
4796
  reviewed: entry.review.reviewedVersion,
4787
4797
  current: entry.version
@@ -4800,7 +4810,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4800
4810
  })
4801
4811
  ]
4802
4812
  });
4803
- }
4813
+ });
4804
4814
  /** One entry's install flow: the button, the §9.3 acknowledgement gate for
4805
4815
  * community-tier entries, and the live view — running log, restart notice,
4806
4816
  * failure detail, rejection detail — driven by `useInstall`. Shared by the
@@ -4810,70 +4820,70 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4810
4820
  const [gateOpen, setGateOpen] = (0, react.useState)(false);
4811
4821
  const { view, start } = useInstall(install, installStatus);
4812
4822
  if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4813
- className: _dsh_plugin_shop_css_9ac4dc0a_default.installPanel,
4823
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
4814
4824
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4815
- className: _dsh_plugin_shop_css_9ac4dc0a_default.installing,
4825
+ className: _dsh_plugin_shop_css_e3675a89_default.installing,
4816
4826
  children: t("installing")
4817
4827
  }), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4818
- className: _dsh_plugin_shop_css_9ac4dc0a_default.log,
4828
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
4819
4829
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4820
- className: _dsh_plugin_shop_css_9ac4dc0a_default.logLine,
4830
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
4821
4831
  children: line
4822
4832
  }, index))
4823
4833
  })]
4824
4834
  });
4825
4835
  if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4826
- className: _dsh_plugin_shop_css_9ac4dc0a_default.notice,
4827
- "data-store-restart-notice": true,
4836
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
4837
+ "data-shop-restart-notice": true,
4828
4838
  children: view.needsRestart ? t("installedRestartNotice") : t("installedNoRestartNotice")
4829
4839
  });
4830
4840
  if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4831
- className: _dsh_plugin_shop_css_9ac4dc0a_default.installPanel,
4841
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
4832
4842
  children: [
4833
4843
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4834
- className: _dsh_plugin_shop_css_9ac4dc0a_default.failedHeading,
4844
+ className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
4835
4845
  children: t("installFailed")
4836
4846
  }),
4837
4847
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4838
- className: _dsh_plugin_shop_css_9ac4dc0a_default.log,
4848
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
4839
4849
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4840
- className: _dsh_plugin_shop_css_9ac4dc0a_default.logLine,
4850
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
4841
4851
  children: line
4842
4852
  }, index))
4843
4853
  }),
4844
4854
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4845
- className: _dsh_plugin_shop_css_9ac4dc0a_default.failedDetail,
4855
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
4846
4856
  children: view.detail === "" ? t("installTransportFailed") : view.detail
4847
4857
  })
4848
4858
  ]
4849
4859
  });
4850
4860
  if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4851
- className: _dsh_plugin_shop_css_9ac4dc0a_default.installPanel,
4861
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
4852
4862
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4853
- className: _dsh_plugin_shop_css_9ac4dc0a_default.rejectedCode,
4863
+ className: _dsh_plugin_shop_css_e3675a89_default.rejectedCode,
4854
4864
  children: t(rejectionCodeKey(view.code))
4855
4865
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4856
- className: _dsh_plugin_shop_css_9ac4dc0a_default.rejectedDetail,
4866
+ className: _dsh_plugin_shop_css_e3675a89_default.rejectedDetail,
4857
4867
  children: view.detail
4858
4868
  })]
4859
4869
  });
4860
4870
  if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4861
- className: _dsh_plugin_shop_css_9ac4dc0a_default.gate,
4871
+ className: _dsh_plugin_shop_css_e3675a89_default.gate,
4862
4872
  children: [
4863
4873
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4864
- className: _dsh_plugin_shop_css_9ac4dc0a_default.gateTitle,
4874
+ className: _dsh_plugin_shop_css_e3675a89_default.gateTitle,
4865
4875
  children: t("acknowledgementTitle")
4866
4876
  }),
4867
4877
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4868
- className: _dsh_plugin_shop_css_9ac4dc0a_default.gateBody,
4878
+ className: _dsh_plugin_shop_css_e3675a89_default.gateBody,
4869
4879
  children: t("acknowledgementBody")
4870
4880
  }),
4871
4881
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4872
- className: _dsh_plugin_shop_css_9ac4dc0a_default.gateActions,
4882
+ className: _dsh_plugin_shop_css_e3675a89_default.gateActions,
4873
4883
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4874
4884
  type: "button",
4875
- className: _dsh_plugin_shop_css_9ac4dc0a_default.confirmButton,
4876
- "data-store-confirm": true,
4885
+ className: _dsh_plugin_shop_css_e3675a89_default.confirmButton,
4886
+ "data-shop-confirm": true,
4877
4887
  onClick: () => {
4878
4888
  setGateOpen(false);
4879
4889
  start({
@@ -4885,7 +4895,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4885
4895
  children: t("confirm")
4886
4896
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4887
4897
  type: "button",
4888
- className: _dsh_plugin_shop_css_9ac4dc0a_default.cancelButton,
4898
+ className: _dsh_plugin_shop_css_e3675a89_default.cancelButton,
4889
4899
  onClick: () => setGateOpen(false),
4890
4900
  children: t("cancel")
4891
4901
  })]
@@ -4895,8 +4905,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4895
4905
  const update = variant === "update";
4896
4906
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4897
4907
  type: "button",
4898
- className: _dsh_plugin_shop_css_9ac4dc0a_default.installButton,
4899
- ...update ? { "data-store-update": true } : { "data-store-install": true },
4908
+ className: _dsh_plugin_shop_css_e3675a89_default.installButton,
4909
+ ...update ? { "data-shop-update": true } : { "data-shop-install": true },
4900
4910
  onClick: () => {
4901
4911
  if (tier === "verified") start({
4902
4912
  name,
@@ -4941,37 +4951,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4941
4951
  }
4942
4952
  };
4943
4953
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4944
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedRow,
4945
- "data-store-outdated-entry": row.name,
4954
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedRow,
4955
+ "data-shop-outdated-entry": row.name,
4946
4956
  children: [
4947
4957
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4948
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedInfo,
4958
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedInfo,
4949
4959
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4950
- className: _dsh_plugin_shop_css_9ac4dc0a_default.name,
4960
+ className: _dsh_plugin_shop_css_e3675a89_default.name,
4951
4961
  children: row.name
4952
4962
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4953
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedVersions,
4963
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedVersions,
4954
4964
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4955
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedVersion,
4965
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedVersion,
4956
4966
  children: t("installedVersion", { version: row.installed })
4957
4967
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4958
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedVersion,
4968
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedVersion,
4959
4969
  children: t("latestVersion", { version: row.latest })
4960
4970
  })]
4961
4971
  })]
4962
4972
  }),
4963
4973
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4964
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedActions,
4974
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedActions,
4965
4975
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4966
4976
  type: "button",
4967
4977
  role: "switch",
4968
4978
  "aria-checked": enabled,
4969
4979
  "aria-label": t("enabledSwitch"),
4970
- "data-store-toggle": true,
4971
- className: `${_dsh_plugin_shop_css_9ac4dc0a_default.switch} ${enabled ? _dsh_plugin_shop_css_9ac4dc0a_default.switchOn : ""}`,
4980
+ "data-shop-toggle": true,
4981
+ className: `${_dsh_plugin_shop_css_e3675a89_default.switch} ${enabled ? _dsh_plugin_shop_css_e3675a89_default.switchOn : ""}`,
4972
4982
  onClick: () => void onToggle(),
4973
4983
  disabled: toggle.kind === "saving",
4974
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_9ac4dc0a_default.switchKnob })
4984
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.switchKnob })
4975
4985
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
4976
4986
  name: row.name,
4977
4987
  version: row.latest,
@@ -4983,13 +4993,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4983
4993
  })]
4984
4994
  }),
4985
4995
  toggle.kind === "saved" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4986
- className: _dsh_plugin_shop_css_9ac4dc0a_default.notice,
4987
- "data-store-hot-apply": true,
4996
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
4997
+ "data-shop-hot-apply": true,
4988
4998
  children: t("hotApplyNote")
4989
4999
  }),
4990
5000
  toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4991
- className: _dsh_plugin_shop_css_9ac4dc0a_default.failedDetail,
4992
- "data-store-toggle-error": true,
5001
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
5002
+ "data-shop-toggle-error": true,
4993
5003
  children: toggle.detail
4994
5004
  })
4995
5005
  ]
@@ -5002,19 +5012,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5002
5012
  function OutdatedSection({ state, tiers, t, setEnabled, install, installStatus }) {
5003
5013
  if (state.kind === "loading") return null;
5004
5014
  if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5005
- className: _dsh_plugin_shop_css_9ac4dc0a_default.stateLine,
5006
- "data-store-outdated-error": true,
5015
+ className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
5016
+ "data-shop-outdated-error": true,
5007
5017
  children: t("error")
5008
5018
  });
5009
5019
  if (state.entries.length === 0) return null;
5010
5020
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5011
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedSection,
5012
- "data-store-outdated": true,
5021
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedSection,
5022
+ "data-shop-outdated": true,
5013
5023
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5014
- className: _dsh_plugin_shop_css_9ac4dc0a_default.catalogHeading,
5024
+ className: _dsh_plugin_shop_css_e3675a89_default.catalogHeading,
5015
5025
  children: t("installedSection")
5016
5026
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5017
- className: _dsh_plugin_shop_css_9ac4dc0a_default.outdatedList,
5027
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedList,
5018
5028
  children: state.entries.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
5019
5029
  row,
5020
5030
  tier: tiers.get(row.name) ?? "community",
@@ -5026,14 +5036,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5026
5036
  })]
5027
5037
  });
5028
5038
  }
5029
- /** The store tab root: browse, search, refresh, and render one card per
5039
+ /** The shop tab root: browse, search, refresh, and render one card per
5030
5040
  * entry. Data attributes on the e2e-relevant nodes follow the Task 3 list. */
5031
- function StoreTab(props) {
5041
+ function ShopTab(props) {
5032
5042
  const { t, catalog, install, installStatus, setEnabled, outdated } = props;
5033
5043
  const [catalogState, setCatalogState] = (0, react.useState)({ kind: "loading" });
5034
5044
  const [outdatedState, setOutdatedState] = (0, react.useState)({ kind: "loading" });
5035
5045
  const [request, setRequest] = (0, react.useState)({ kind: "initial" });
5036
5046
  const [query, setQuery] = (0, react.useState)("");
5047
+ const incremental = typeof IntersectionObserver !== "undefined";
5048
+ const [visibleCount, setVisibleCount] = (0, react.useState)(48);
5049
+ const sentinelRef = (0, react.useRef)(null);
5050
+ const filteredLenRef = (0, react.useRef)(0);
5037
5051
  (0, react.useEffect)(() => {
5038
5052
  let cancelled = false;
5039
5053
  if (request.kind !== "refresh") setCatalogState((current) => current.kind === "ready" ? current : { kind: "loading" });
@@ -5075,106 +5089,137 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5075
5089
  if (catalogState.kind !== "ready") return [];
5076
5090
  const q = query.trim().toLowerCase();
5077
5091
  return catalogState.result.plugins.filter((entry) => {
5078
- if (isStoreLike(entry.name)) return false;
5092
+ if (isShopLike(entry.name)) return false;
5079
5093
  if (q === "") return true;
5080
5094
  const summaryEn = entry.catalog?.summary.en ?? "";
5081
5095
  const summaryZh = entry.catalog?.summary.zh ?? "";
5082
5096
  return entry.name.toLowerCase().includes(q) || summaryEn.toLowerCase().includes(q) || summaryZh.toLowerCase().includes(q);
5083
5097
  });
5084
5098
  }, [catalogState, query]);
5099
+ filteredLenRef.current = filtered.length;
5100
+ (0, react.useEffect)(() => {
5101
+ if (!incremental) return;
5102
+ const node = sentinelRef.current;
5103
+ if (node === null) return;
5104
+ const observer = new IntersectionObserver((entries) => {
5105
+ if (entries.some((entry) => entry.isIntersecting)) setVisibleCount((current) => nextVisibleCount(current, filteredLenRef.current, 48));
5106
+ }, { rootMargin: "0px 0px 1200px 0px" });
5107
+ observer.observe(node);
5108
+ return () => observer.disconnect();
5109
+ }, [
5110
+ incremental,
5111
+ visibleCount,
5112
+ filtered.length
5113
+ ]);
5114
+ const visible = incremental ? filtered.slice(0, visibleCount) : filtered;
5085
5115
  const tiers = (0, react.useMemo)(() => {
5086
5116
  const map = /* @__PURE__ */ new Map();
5087
5117
  if (catalogState.kind === "ready") for (const entry of catalogState.result.plugins) map.set(entry.name, entry.tier);
5088
5118
  return map;
5089
5119
  }, [catalogState]);
5090
5120
  if (catalogState.kind === "loading") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5091
- className: _dsh_plugin_shop_css_9ac4dc0a_default.panel,
5092
- "data-store-tab": true,
5121
+ className: _dsh_plugin_shop_css_e3675a89_default.panel,
5122
+ "data-shop-tab": true,
5093
5123
  "aria-busy": "true",
5094
5124
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5095
- className: _dsh_plugin_shop_css_9ac4dc0a_default.srOnly,
5125
+ className: _dsh_plugin_shop_css_e3675a89_default.srOnly,
5096
5126
  children: t("loading")
5097
5127
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5098
- className: _dsh_plugin_shop_css_9ac4dc0a_default.skeletonGrid,
5099
- "data-store-skeleton": true,
5128
+ className: _dsh_plugin_shop_css_e3675a89_default.skeletonGrid,
5129
+ "data-shop-skeleton": true,
5100
5130
  "aria-hidden": "true",
5101
5131
  children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5102
- className: _dsh_plugin_shop_css_9ac4dc0a_default.skeletonCard,
5132
+ className: _dsh_plugin_shop_css_e3675a89_default.skeletonCard,
5103
5133
  children: [
5104
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_9ac4dc0a_default.skeletonCover }),
5105
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_9ac4dc0a_default.skeletonName }),
5106
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_9ac4dc0a_default.skeletonSummary }),
5107
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_9ac4dc0a_default.skeletonSummaryShort })
5134
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonCover }),
5135
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonName }),
5136
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonSummary }),
5137
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonSummaryShort })
5108
5138
  ]
5109
5139
  }, i))
5110
5140
  })]
5111
5141
  });
5112
5142
  if (catalogState.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5113
- className: _dsh_plugin_shop_css_9ac4dc0a_default.panel,
5114
- "data-store-tab": true,
5143
+ className: _dsh_plugin_shop_css_e3675a89_default.panel,
5144
+ "data-shop-tab": true,
5115
5145
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5116
- className: _dsh_plugin_shop_css_9ac4dc0a_default.stateLine,
5146
+ className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
5117
5147
  children: t("error")
5118
5148
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5119
5149
  type: "button",
5120
- className: _dsh_plugin_shop_css_9ac4dc0a_default.actionButton,
5150
+ className: _dsh_plugin_shop_css_e3675a89_default.actionButton,
5121
5151
  onClick: () => setRequest({ kind: "retry" }),
5122
5152
  children: t("retry")
5123
5153
  })]
5124
5154
  });
5125
5155
  const { result } = catalogState;
5126
5156
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5127
- className: _dsh_plugin_shop_css_9ac4dc0a_default.panel,
5128
- "data-store-tab": true,
5157
+ className: _dsh_plugin_shop_css_e3675a89_default.panel,
5158
+ "data-shop-tab": true,
5129
5159
  children: [
5130
5160
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5131
- className: _dsh_plugin_shop_css_9ac4dc0a_default.toolbar,
5161
+ className: _dsh_plugin_shop_css_e3675a89_default.toolbar,
5132
5162
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5133
5163
  type: "search",
5134
- className: _dsh_plugin_shop_css_9ac4dc0a_default.searchInput,
5164
+ className: _dsh_plugin_shop_css_e3675a89_default.searchInput,
5135
5165
  "aria-label": t("search"),
5136
5166
  placeholder: t("search"),
5137
5167
  value: query,
5138
- onChange: (event) => setQuery(event.target.value)
5168
+ onChange: (event) => {
5169
+ setQuery(event.target.value);
5170
+ setVisibleCount(48);
5171
+ }
5139
5172
  }), result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5140
- className: _dsh_plugin_shop_css_9ac4dc0a_default.staleBlock,
5173
+ className: _dsh_plugin_shop_css_e3675a89_default.staleBlock,
5141
5174
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5142
- className: _dsh_plugin_shop_css_9ac4dc0a_default.staleBadge,
5175
+ className: _dsh_plugin_shop_css_e3675a89_default.staleBadge,
5143
5176
  children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
5144
5177
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5145
5178
  type: "button",
5146
- className: _dsh_plugin_shop_css_9ac4dc0a_default.actionButton,
5179
+ className: _dsh_plugin_shop_css_e3675a89_default.actionButton,
5147
5180
  onClick: () => setRequest({ kind: "refresh" }),
5148
5181
  children: t("refresh")
5149
5182
  })]
5150
5183
  })]
5151
5184
  }),
5152
5185
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5153
- className: _dsh_plugin_shop_css_9ac4dc0a_default.catalogHeading,
5186
+ className: _dsh_plugin_shop_css_e3675a89_default.catalogHeading,
5154
5187
  children: t("catalog")
5155
5188
  }),
5156
5189
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5157
- className: _dsh_plugin_shop_css_9ac4dc0a_default.catalogStats,
5190
+ className: _dsh_plugin_shop_css_e3675a89_default.catalogStats,
5158
5191
  children: t("catalogStats", {
5159
5192
  count: String(result.plugins.length),
5160
5193
  date: result.builtAt.slice(0, 10)
5161
5194
  })
5162
5195
  }),
5163
5196
  result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5164
- className: _dsh_plugin_shop_css_9ac4dc0a_default.emptyLine,
5197
+ className: _dsh_plugin_shop_css_e3675a89_default.emptyLine,
5165
5198
  children: t("empty")
5166
5199
  }) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5167
- className: _dsh_plugin_shop_css_9ac4dc0a_default.emptyLine,
5200
+ className: _dsh_plugin_shop_css_e3675a89_default.emptyLine,
5168
5201
  children: t("emptySearch")
5169
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5170
- className: _dsh_plugin_shop_css_9ac4dc0a_default.cards,
5171
- children: filtered.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
5202
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
5203
+ className: _dsh_plugin_shop_css_e3675a89_default.cards,
5204
+ children: [visible.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
5172
5205
  entry,
5173
5206
  t,
5174
5207
  install,
5175
5208
  installStatus
5176
- }) }, entry.name))
5177
- }),
5209
+ }) }, entry.name)), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
5210
+ ref: sentinelRef,
5211
+ className: _dsh_plugin_shop_css_e3675a89_default.cardsSentry,
5212
+ "data-shop-sentry": true,
5213
+ "aria-hidden": "true"
5214
+ })]
5215
+ }), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5216
+ className: _dsh_plugin_shop_css_e3675a89_default.showingLine,
5217
+ "aria-live": "polite",
5218
+ children: t("showing", {
5219
+ shown: String(visibleCount),
5220
+ total: String(filtered.length)
5221
+ })
5222
+ })] }),
5178
5223
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedSection, {
5179
5224
  state: outdatedState,
5180
5225
  tiers,
@@ -5189,34 +5234,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5189
5234
  //#endregion
5190
5235
  //#region src/client/index.ts
5191
5236
  /** Dictionary namespace owned by this plugin. */
5192
- const NS = "settings.store";
5237
+ const NS = "settings.shop";
5193
5238
  /** Services required by the tab registration and the Remote mount.
5194
5239
  *
5195
- * `remote.store` is deliberately ABSENT: this package both mounts its own
5240
+ * `remote.shop` is deliberately ABSENT: this package both mounts its own
5196
5241
  * Remote (the assembly does not know it, §7.3) and consumes it, and cordis
5197
5242
  * will not let one package do both through the inject face. Declaring the
5198
- * face makes the boot's activation gate wait for the `remote.store` service —
5243
+ * face makes the boot's activation gate wait for the `remote.shop` service —
5199
5244
  * which only this package's own apply can register — and the real web boot
5200
- * deadlocked on exactly that ("waiting for service: remote.store"). The
5201
- * namespace is therefore read through the reflect store instead (`ctx.get`,
5245
+ * deadlocked on exactly that ("waiting for service: remote.shop"). The
5246
+ * namespace is therefore read through the reflect shop instead (`ctx.get`,
5202
5247
  * see apply), which has no inject requirement. */
5203
5248
  const inject = [
5204
5249
  "remote",
5205
5250
  "slots",
5206
5251
  "locale"
5207
5252
  ];
5208
- /** Mount the store Remote and contribute the store tab. */
5253
+ /** Mount the shop Remote and contribute the shop tab. */
5209
5254
  async function apply(ctx) {
5210
5255
  ctx.effect(() => ctx.locale.register(NS, {
5211
5256
  zh,
5212
5257
  en
5213
5258
  }), "dsh-plugin-shop: dictionaries");
5214
5259
  const dispose = await ctx.remote.$mount(TYPERT_REMOTE);
5215
- ctx.effect(() => dispose, "dsh-plugin-shop: store remote mount");
5216
- const ns = ctx.get("remote.store");
5217
- if (ns === void 0) throw new Error("dsh-plugin-shop: the store remote did not register (service \"remote.store\" missing after $mount)");
5260
+ ctx.effect(() => dispose, "dsh-plugin-shop: shop remote mount");
5261
+ const ns = ctx.get("remote.shop");
5262
+ if (ns === void 0) throw new Error("dsh-plugin-shop: the shop remote did not register (service \"remote.shop\" missing after $mount)");
5218
5263
  const unwrap = (result) => {
5219
- if (!result.ok) throw new Error(`store remote: ${result.error.code}: ${result.error.message}`);
5264
+ if (!result.ok) throw new Error(`shop remote: ${result.error.code}: ${result.error.message}`);
5220
5265
  return result.value;
5221
5266
  };
5222
5267
  const injected = () => ({
@@ -5228,12 +5273,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5228
5273
  });
5229
5274
  ctx.slots.inject("settings.plugins.tab", () => ctx.slots.register({
5230
5275
  name: "settings.plugins.tab",
5231
- id: "store",
5276
+ id: "shop",
5232
5277
  order: 20,
5233
5278
  label: () => ctx.locale.bind(NS)("tab"),
5234
5279
  locale: NS,
5235
5280
  inject: injected
5236
- }, StoreTab));
5281
+ }, ShopTab));
5237
5282
  }
5238
5283
  //#endregion
5239
5284
  exports.NS = NS;