dsh-plugin-shop 0.8.4-beta.0 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/client.js +464 -337
- package/lib/index.js +918 -94
- package/lib/typert.host.js +10 -10
- package/lib/typert.remote-client.js +10 -10
- package/lib/types/client/locales.d.ts +2 -0
- package/lib/types/client/present.d.ts +1 -0
- package/lib/types/client/restart-monitor.d.ts +62 -6
- package/lib/types/host/executor.d.ts +50 -3
- package/lib/types/host/index.d.ts +82 -21
- package/lib/types/host/manager-runner.d.ts +51 -0
- package/lib/types/host/plugin-manager.d.ts +100 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -4515,7 +4515,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4515
4515
|
},
|
|
4516
4516
|
sourceLocation: {
|
|
4517
4517
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4518
|
-
"line":
|
|
4518
|
+
"line": 1253,
|
|
4519
4519
|
"column": 9
|
|
4520
4520
|
}
|
|
4521
4521
|
},
|
|
@@ -4534,7 +4534,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4534
4534
|
},
|
|
4535
4535
|
sourceLocation: {
|
|
4536
4536
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4537
|
-
"line":
|
|
4537
|
+
"line": 1720,
|
|
4538
4538
|
"column": 9
|
|
4539
4539
|
}
|
|
4540
4540
|
},
|
|
@@ -4553,7 +4553,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4553
4553
|
},
|
|
4554
4554
|
sourceLocation: {
|
|
4555
4555
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4556
|
-
"line":
|
|
4556
|
+
"line": 1711,
|
|
4557
4557
|
"column": 9
|
|
4558
4558
|
}
|
|
4559
4559
|
},
|
|
@@ -4583,7 +4583,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4583
4583
|
},
|
|
4584
4584
|
sourceLocation: {
|
|
4585
4585
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4586
|
-
"line":
|
|
4586
|
+
"line": 1379,
|
|
4587
4587
|
"column": 9
|
|
4588
4588
|
}
|
|
4589
4589
|
},
|
|
@@ -4612,7 +4612,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4612
4612
|
},
|
|
4613
4613
|
sourceLocation: {
|
|
4614
4614
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4615
|
-
"line":
|
|
4615
|
+
"line": 1687,
|
|
4616
4616
|
"column": 3
|
|
4617
4617
|
}
|
|
4618
4618
|
},
|
|
@@ -4631,7 +4631,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4631
4631
|
},
|
|
4632
4632
|
sourceLocation: {
|
|
4633
4633
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4634
|
-
"line":
|
|
4634
|
+
"line": 1916,
|
|
4635
4635
|
"column": 9
|
|
4636
4636
|
}
|
|
4637
4637
|
},
|
|
@@ -4660,7 +4660,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4660
4660
|
},
|
|
4661
4661
|
sourceLocation: {
|
|
4662
4662
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4663
|
-
"line":
|
|
4663
|
+
"line": 924,
|
|
4664
4664
|
"column": 9
|
|
4665
4665
|
}
|
|
4666
4666
|
},
|
|
@@ -4690,7 +4690,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4690
4690
|
},
|
|
4691
4691
|
sourceLocation: {
|
|
4692
4692
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4693
|
-
"line":
|
|
4693
|
+
"line": 1827,
|
|
4694
4694
|
"column": 9
|
|
4695
4695
|
}
|
|
4696
4696
|
},
|
|
@@ -4719,7 +4719,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4719
4719
|
},
|
|
4720
4720
|
sourceLocation: {
|
|
4721
4721
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4722
|
-
"line":
|
|
4722
|
+
"line": 2020,
|
|
4723
4723
|
"column": 9
|
|
4724
4724
|
}
|
|
4725
4725
|
},
|
|
@@ -4738,7 +4738,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4738
4738
|
},
|
|
4739
4739
|
sourceLocation: {
|
|
4740
4740
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4741
|
-
"line":
|
|
4741
|
+
"line": 1978,
|
|
4742
4742
|
"column": 9
|
|
4743
4743
|
}
|
|
4744
4744
|
}
|
|
@@ -6630,7 +6630,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6630
6630
|
kind: "done",
|
|
6631
6631
|
activation: status.activation ?? "restart",
|
|
6632
6632
|
log: status.log,
|
|
6633
|
-
...status.restartReason !== void 0 ? { restartReason: status.restartReason } : {}
|
|
6633
|
+
...status.restartReason !== void 0 ? { restartReason: status.restartReason } : {},
|
|
6634
|
+
...status.detail !== void 0 ? { detail: status.detail } : {}
|
|
6634
6635
|
};
|
|
6635
6636
|
return {
|
|
6636
6637
|
kind: "failed",
|
|
@@ -6984,7 +6985,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6984
6985
|
github: "GitHub",
|
|
6985
6986
|
enabledSwitch: "启用",
|
|
6986
6987
|
toggleFailed: "设置失败,请重试。",
|
|
6987
|
-
hotApplyNote: "已生效,无需重启"
|
|
6988
|
+
hotApplyNote: "已生效,无需重启",
|
|
6989
|
+
toggleRestartNote: "已保存,重启 dsh 后生效"
|
|
6988
6990
|
};
|
|
6989
6991
|
/** English dictionary checked against the Chinese key set. */
|
|
6990
6992
|
const en = {
|
|
@@ -7100,7 +7102,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7100
7102
|
github: "GitHub",
|
|
7101
7103
|
enabledSwitch: "Enable",
|
|
7102
7104
|
toggleFailed: "Failed to update. Please retry.",
|
|
7103
|
-
hotApplyNote: "applied without a restart"
|
|
7105
|
+
hotApplyNote: "applied without a restart",
|
|
7106
|
+
toggleRestartNote: "saved; it takes effect after dsh restarts"
|
|
7104
7107
|
};
|
|
7105
7108
|
//#endregion
|
|
7106
7109
|
//#region src/client/module-table.ts
|
|
@@ -7291,40 +7294,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7291
7294
|
}
|
|
7292
7295
|
//#endregion
|
|
7293
7296
|
//#region src/client/restart-monitor.ts
|
|
7294
|
-
/**
|
|
7295
|
-
* The restart handoff's browser half (design §8), held by the page rather
|
|
7296
|
-
* than by the tab that confirmed the restart.
|
|
7297
|
-
*
|
|
7298
|
-
* It lived in a RestartPanel effect until 2026-09-27, and a self-update
|
|
7299
|
-
* killed it. dsh's client HMR (`@deepseek-ai/dsh-client-hmr`, mounted by the
|
|
7300
|
-
* web bundle unconditionally) stat-polls every client bundle and hot-swaps
|
|
7301
|
-
* one whose file changed; a self-update rewrites this package's own
|
|
7302
|
-
* `lib/client.js`, so the swap disposes the tab's fiber and mounts a fresh
|
|
7303
|
-
* instance of a freshly imported module. The effect's cleanup then stopped
|
|
7304
|
-
* the probe, and once the restart finished nothing reloaded the page: it sat
|
|
7305
|
-
* on the old process's answers while dsh's socket quietly reconnected to the
|
|
7306
|
-
* new one. Measured on dsh 0.1.5-rc.3 updating 0.8.2 to 0.8.3; with the
|
|
7307
|
-
* `/plugins/events` channel blocked the same flow reloaded.
|
|
7308
|
-
*
|
|
7309
|
-
* So the state sits on `globalThis` under a registry symbol — the one thing a
|
|
7310
|
-
* swapped-in module instance shares with the one it replaced — and the probe
|
|
7311
|
-
* loop is plain timers owned by no fiber. Any tab reads the state, so the
|
|
7312
|
-
* replacement renders the restart under way instead of offering another.
|
|
7313
|
-
*/
|
|
7314
7297
|
/** Registry symbol, so every module instance on the page finds the same store. */
|
|
7315
7298
|
const STORE_KEY = Symbol.for("dsh-plugin-shop.restart-monitor");
|
|
7316
7299
|
function monitorStore() {
|
|
7317
7300
|
const page = globalThis;
|
|
7318
|
-
let
|
|
7319
|
-
if (
|
|
7320
|
-
|
|
7301
|
+
let stored = page[STORE_KEY];
|
|
7302
|
+
if (stored === void 0) {
|
|
7303
|
+
stored = {
|
|
7321
7304
|
state: null,
|
|
7322
7305
|
listeners: /* @__PURE__ */ new Set(),
|
|
7323
7306
|
stop: null
|
|
7324
7307
|
};
|
|
7325
|
-
page[STORE_KEY] =
|
|
7308
|
+
page[STORE_KEY] = stored;
|
|
7326
7309
|
}
|
|
7327
|
-
return
|
|
7310
|
+
return Object.assign(stored, {
|
|
7311
|
+
carriers: stored.carriers ?? [],
|
|
7312
|
+
attempt: stored.attempt ?? null
|
|
7313
|
+
});
|
|
7328
7314
|
}
|
|
7329
7315
|
function settle(store, state) {
|
|
7330
7316
|
store.state = state;
|
|
@@ -7410,6 +7396,114 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7410
7396
|
logFile
|
|
7411
7397
|
});
|
|
7412
7398
|
}
|
|
7399
|
+
/**
|
|
7400
|
+
* Register one module instance's path to the host; the client half's apply
|
|
7401
|
+
* does, with the `restart` it hands the tab. The returned function withdraws
|
|
7402
|
+
* it, and has to run BEFORE the mount it rides is disposed: a request still in
|
|
7403
|
+
* flight on it is then asked again through the newest live path — at once if
|
|
7404
|
+
* one is registered, or as soon as one is — rather than waiting on a call the
|
|
7405
|
+
* dispose is about to abort.
|
|
7406
|
+
*/
|
|
7407
|
+
function registerRestartCarrier(restart) {
|
|
7408
|
+
const store = monitorStore();
|
|
7409
|
+
const carrier = {
|
|
7410
|
+
restart,
|
|
7411
|
+
live: true
|
|
7412
|
+
};
|
|
7413
|
+
store.carriers.push(carrier);
|
|
7414
|
+
const attempt = store.attempt;
|
|
7415
|
+
if (attempt !== null && !attempt.carrier.live) ask(store, attempt, carrier);
|
|
7416
|
+
return () => {
|
|
7417
|
+
if (!carrier.live) return;
|
|
7418
|
+
carrier.live = false;
|
|
7419
|
+
const current = monitorStore();
|
|
7420
|
+
current.carriers = current.carriers.filter((each) => each !== carrier);
|
|
7421
|
+
const orphaned = current.attempt;
|
|
7422
|
+
const next = current.carriers.at(-1);
|
|
7423
|
+
if (orphaned !== null && orphaned.carrier === carrier && next !== void 0) ask(current, orphaned, next);
|
|
7424
|
+
};
|
|
7425
|
+
}
|
|
7426
|
+
/**
|
|
7427
|
+
* Ask the host to restart, for the page (design §8). The request is the
|
|
7428
|
+
* page's from the confirm on, not from the answer: every offer renders it as
|
|
7429
|
+
* under way, and a second press joins it rather than asking twice. It rides
|
|
7430
|
+
* the newest path a module instance registered, or — where no client half
|
|
7431
|
+
* registered one — the pressing tab's own `restart`.
|
|
7432
|
+
*
|
|
7433
|
+
* Resolves, never rejects, with what the press should show. A commit starts
|
|
7434
|
+
* the monitor and is `started`. A refusal and an unreachable host leave
|
|
7435
|
+
* nothing under way. A path withdrawn mid-call decides nothing but a commit;
|
|
7436
|
+
* the ask on the path that replaced it decides the rest, and that ask
|
|
7437
|
+
* finding no host is followed as a restart, since the first ask may have
|
|
7438
|
+
* committed and taken its host down with it.
|
|
7439
|
+
*/
|
|
7440
|
+
function requestRestart(options) {
|
|
7441
|
+
const store = monitorStore();
|
|
7442
|
+
if (store.state?.kind === "restarting") return Promise.resolve({ kind: "started" });
|
|
7443
|
+
return new Promise((resolve) => {
|
|
7444
|
+
const pending = store.attempt;
|
|
7445
|
+
if (pending !== null) {
|
|
7446
|
+
pending.waiters.push(resolve);
|
|
7447
|
+
return;
|
|
7448
|
+
}
|
|
7449
|
+
const carrier = store.carriers.at(-1) ?? {
|
|
7450
|
+
restart: options.restart,
|
|
7451
|
+
live: true
|
|
7452
|
+
};
|
|
7453
|
+
const attempt = {
|
|
7454
|
+
carrier,
|
|
7455
|
+
reload: options.reload,
|
|
7456
|
+
reissued: false,
|
|
7457
|
+
waiters: [resolve]
|
|
7458
|
+
};
|
|
7459
|
+
store.attempt = attempt;
|
|
7460
|
+
settle(store, { kind: "requesting" });
|
|
7461
|
+
ask(store, attempt, carrier);
|
|
7462
|
+
});
|
|
7463
|
+
}
|
|
7464
|
+
/** Carry the request on one path. Its answer decides only while the request
|
|
7465
|
+
* is still the page's and that path still carries it — a commit excepted. */
|
|
7466
|
+
function ask(store, attempt, carrier) {
|
|
7467
|
+
if (attempt.carrier !== carrier) {
|
|
7468
|
+
attempt.carrier = carrier;
|
|
7469
|
+
attempt.reissued = true;
|
|
7470
|
+
}
|
|
7471
|
+
(async () => carrier.restart())().then((result) => {
|
|
7472
|
+
if (store.attempt !== attempt) return;
|
|
7473
|
+
if (result.ok) {
|
|
7474
|
+
finish(store, attempt, { kind: "started" });
|
|
7475
|
+
startRestartMonitor({
|
|
7476
|
+
reload: attempt.reload,
|
|
7477
|
+
...typeof result.logFile === "string" ? { logFile: result.logFile } : {}
|
|
7478
|
+
});
|
|
7479
|
+
return;
|
|
7480
|
+
}
|
|
7481
|
+
if (superseded(attempt, carrier)) return;
|
|
7482
|
+
finish(store, attempt, {
|
|
7483
|
+
kind: "refused",
|
|
7484
|
+
detail: result.detail
|
|
7485
|
+
});
|
|
7486
|
+
settle(store, null);
|
|
7487
|
+
}, () => {
|
|
7488
|
+
if (store.attempt !== attempt || superseded(attempt, carrier)) return;
|
|
7489
|
+
if (attempt.reissued) {
|
|
7490
|
+
finish(store, attempt, { kind: "started" });
|
|
7491
|
+
startRestartMonitor({ reload: attempt.reload });
|
|
7492
|
+
return;
|
|
7493
|
+
}
|
|
7494
|
+
finish(store, attempt, { kind: "unreachable" });
|
|
7495
|
+
settle(store, null);
|
|
7496
|
+
});
|
|
7497
|
+
}
|
|
7498
|
+
/** Whether a path's answer is one the request has moved past: the path was
|
|
7499
|
+
* withdrawn, so the dispose aborted it or the ask that replaced it decides. */
|
|
7500
|
+
function superseded(attempt, carrier) {
|
|
7501
|
+
return !carrier.live || attempt.carrier !== carrier;
|
|
7502
|
+
}
|
|
7503
|
+
function finish(store, attempt, outcome) {
|
|
7504
|
+
store.attempt = null;
|
|
7505
|
+
for (const waiter of attempt.waiters) waiter(outcome);
|
|
7506
|
+
}
|
|
7413
7507
|
//#endregion
|
|
7414
7508
|
//#region src/client/useFlows.ts
|
|
7415
7509
|
/**
|
|
@@ -7690,121 +7784,121 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7690
7784
|
};
|
|
7691
7785
|
}
|
|
7692
7786
|
//#endregion
|
|
7693
|
-
//#region \0dsh-plugin-shop-css:
|
|
7694
|
-
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 HUE per\n * category (seven fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so seven brand opacities read as seven\n * shades of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.sc389ac_client.sc41672_config.s8eefa1_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.sc389ac_client.sfe36ad_spec.s8eefa1_ts` pins this. */\n\n.s688753_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n /* The shelf never scrolls sideways: a card too wide for its track wraps\n * its badges rather than widening the panel.\n *\n * Clipped on BOTH axes, with a margin, because `.s9f28cb_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.sbc2e10_toolbar`, itself\n * the first child here, and this rule carries no padding — so its focus\n * ring paints ENTIRELY outside the panel.\n *\n * Both axes is the load-bearing part: `overflow-clip-margin` is inert\n * unless the element clips on both. Clipping x alone left the margin doing\n * nothing — measured against the live app on 0.7.1, the ring reached 0 of\n * its 3px on the left at every device pixel ratio (1, 1.25, 1.5, 2), while\n * keeping the full 3px on the right, where the 280px input stops short of\n * the panel and never meets the clip edge. Raising the margin to 6px\n * changed nothing; clipping both axes with the SAME 3px restored the whole\n * ring. A test that reads declarations cannot see that difference, which is\n * why the first attempt at this shipped broken.\n *\n * `clip` is not a scroll container, so this does not bring back the\n * accidental scrolling `hidden` caused by coercing the other axis to\n * `auto`. Nothing is lost vertically: the panel's scrollHeight equals its\n * height and no descendant paints outside the clip rect (measured).\n * `overflow-x: hidden` stays as the fallback for engines without `clip`,\n * where the ring is clipped as it was before, never worse. */\n overflow-x: hidden;\n overflow: clip;\n overflow-clip-margin: 3px;\n}\n\n.s7237a9_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.s601d42_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.sa26d1f_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.sceffd1_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.sceffd1_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.s6f1efd_skeletonName {\n width: 55%;\n height: 14px;\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.s4db475_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.se9c3a9_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 10px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n/* The ghost of the action line, right where the real buttons land. */\n.s3cbb84_skeletonActions {\n display: block;\n width: 84px;\n height: 24px;\n margin: 0 12px 10px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sceffd1_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 .sceffd1_skeletonCard span { animation: none; opacity: 0.75; }\n .sceffd1_skeletonCard::after { content: none; }\n}\n\n.se4623a_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.se4623a_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.se4623a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sbc2e10_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.sb9d854_toolbarRight {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* The shop's own version, right of the search box: `v0.4.4`, plus the\n * update button when the version check found a newer release. */\n.s17e39d_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.sff4480_versionText {\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.sf22160_updateSelfButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.sf22160_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.sf22160_updateSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The on-demand re-check next to the version number: a quiet pill; the\n * border and text carry it in the light theme where bg layers are white. */\n.s1abadc_checkUpdateButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.s1abadc_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.s1abadc_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.s1abadc_checkUpdateButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The project's GitHub mark, right of the version row: a quiet icon link.\n * The octocat carries itself — color shift on hover, no text, no border. */\n.se9af4e_githubLink {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 3px;\n border-radius: 6px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.se9af4e_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.se9af4e_githubLink:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The self-update's expanded states (running log / done + restart /\n * failure detail) sit under the toolbar, above the category bar. */\n.s11efce_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s9f28cb_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.s9f28cb_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.scfe278_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.sfd2800_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.saa7982_categoryButton {\n /* The hue this button carries when selected. `All` and `Installed` select by\n * something other than a category and keep the brand token; the six category\n * buttons override it from the shared hue table below, so a pressed Tool tab\n * turns the same blue as a tool card's spine. */\n --category-hue: var(--dsw-alias-brand-primary);\n padding: 3px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Blend text with the theme foreground: darker on light backgrounds, lighter\n * on dark ones. The unblended category hue belongs on the border and fill. */\n.saa7982_categoryButton:hover {\n border-color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-border-l2));\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Selected. Written `.saa7982_categoryButton.s47a604_categoryButtonOn` — TWO classes — so it\n * matches `.saa7982_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s47a604_categoryButtonOn` it lost both `border-color` and `color` to the\n * hover rule for as long as the pointer stayed on the tab that had just been\n * clicked, which is precisely when a reader looks for confirmation.\n *\n * EVERY declaration here is a colour or a shadow: a pressed tab must occupy\n * exactly the same box as an unpressed one, so the bar does not reflow — and\n * with ~9 pills on a wrapping row, one that grows can push the rest onto\n * another line and move the tab out from under the pointer that just clicked\n * it. That is what `font-weight: 600` did (bold metrics are wider than\n * regular), and it is why nothing may be added here that resolves to a length:\n * no padding, no border-width, no font-size, no letter-spacing.\n * `css-tokens.sc389ac_client.sfe36ad_spec.s8eefa1_ts` fails the build on one.\n *\n * `box-shadow` is the exception that earns its place: it paints outside the\n * layout box, so an inset ring doubles the border's weight at zero cost to the\n * metrics. It is what `font-weight: 600` used to be — a second, thickness-\n * based signal that hover does not also produce — and the `other` tab needs it\n * most: its hue IS the neutral gray this file uses for \"no category\", so on\n * the light theme hue alone barely separates pressed from unpressed. */\n.saa7982_categoryButton.s47a604_categoryButtonOn {\n border-color: var(--category-hue);\n background: color-mix(in srgb, var(--category-hue) 14%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n box-shadow: inset 0 0 0 1px var(--category-hue);\n}\n\n/* Forced colours replace every colour above with the system palette, which\n * would leave the three colour declarations saying nothing and the pressed tab\n * indistinguishable from its neighbours. `box-shadow` is dropped in this mode\n * too, so the ring has to come back as an outline. */\n@media (forced-colors: active) {\n .saa7982_categoryButton.s47a604_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.saa7982_categoryButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The incompatible filter, at the right edge of the category bar: `margin-left:\n * auto` pushes it past the pills, and the bar wraps, so on a narrow panel it\n * drops to its own line rather than squeezing them. It is a MODIFIER, not a\n * ninth category — the categories select what to show and this one subtracts\n * from whatever they selected — so it takes the error hue it filters on rather\n * than joining the hue table.\n *\n * And it is a SWITCH, which is the difference the shape now carries. It used\n * to wear `.saa7982_categoryButton`: same pill, same row, same size as the eight tabs,\n * differing only in being red. That reads as a ninth tab, and it is not one —\n * the tabs are choose-one and this is on-or-off. So it drops the pill chrome\n * entirely (no border, no fill, nothing to compete with the row it sits\n * beside) and puts the state in a track, the same one every installed card\n * carries. Nothing here restates the switch geometry; `--switch-hue` is the\n * whole of what this control says about it, and it reaches the label too, so\n * one declaration keeps the word and the track the same colour. */\n.s6000bb_incompatibleFilter {\n --switch-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Matches the pills' vertical padding so the bar keeps one line box whether\n * this control wraps onto a row of its own or shares theirs. */\n padding: 3px 0;\n border: 0;\n background: none;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Hover lifts the word to full contrast and warms the track's border. Scoped\n * to the OFF track: `.s6000bb_incompatibleFilter:hover .s21d1d6_switch` outranks `.sfaf305_switchOn`\n * by two classes, so unscoped it would strip the hue from the border at\n * exactly the moment a reader has the pointer on it to check the state. */\n.s6000bb_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.s6000bb_incompatibleFilter:hover .s21d1d6_switch:not(.sfaf305_switchOn) {\n border-color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-border-l2));\n}\n\n/* On. Written with both classes for the reason `.saa7982_categoryButton.s47a604_categoryButtonOn`\n * is: it has to match `:hover`'s specificity and come after it, or the colour\n * reverts under a pointer that has not moved since the click. */\n.s6000bb_incompatibleFilter.s9fb743_incompatibleFilterOn {\n color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Off here means \"nothing is being taken away\" — the resting state — so the\n * knob steps back to the secondary label. The enable switch keeps the full\n * strength dot, where off means \"this plugin is disabled\" and is worth\n * noticing. In this bar it would be the heaviest mark in a row of hairline\n * pills, and on the light theme it is the WHOLE control: bg-layer-2 is the\n * same white as the panel there, so an off track is a hairline outline with a\n * near-black dot sitting in it. */\n.s6000bb_incompatibleFilter .s21d1d6_switch:not(.sfaf305_switchOn) .s3e9566_switchKnob {\n background: var(--dsw-alias-label-secondary);\n}\n\n/* The ring has no border to trace, so it takes an offset and the pill radius\n * of the tabs it sits beside rather than hugging the text. */\n.s6000bb_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s3627e7_updatableHeading {\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.s879949_catalogStatsRow {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n.s7f1200_catalogStats {\n margin: 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/* Sits beside the 12px stats caption, so it is quieter than `.se4623a_actionButton`:\n * this is an affordance, not a call to action — the catalog reloads on its\n * own at mount and the shelf is already usable without it. Named\n * `catalogRefresh*` (not `reload*`) so it cannot collide with the §4 page\n * reload offer below, which reloads the whole tab rather than refetching\n * the catalog data. */\n.s7f50e0_catalogRefreshButton {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.s7f50e0_catalogRefreshButton:hover:not(:disabled) {\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.s7f50e0_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s7f50e0_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s284f4c_catalogRefreshFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s894d35_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/* Single-line rows: one full-width column, one plugin per line. */\n.s73be4c_cards {\n display: grid;\n grid-template-columns: 1fr;\n max-width: 100%;\n gap: 8px;\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 .s73be4c_cards { animation: none; }\n}\n\n.s7ce0b5_card {\n position: relative;\n display: flex;\n flex-direction: column;\n /* A grid item's min-width is auto by default: its content would widen the\n * 1fr track past the panel and overflow horizontally. */\n min-width: 0;\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 140px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.se9f199_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s571a2d_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s7ce0b5_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 .s7ce0b5_card { transition: none; }\n .s7ce0b5_card:hover { transform: none; }\n}\n\n/* The signature: a spine and cover in the category's own hue. The hues are\n * fixed mid-bright colors that read on both themes; `other` deliberately\n * stays a neutral gray so the fallback category does not compete. */\n.s3afd93_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--category-hue, #8B8E96);\n}\n\n/* The hue table, keyed by `data-category` and read by BOTH surfaces that\n * speak in category colour: a card's spine and badge, and the category bar's\n * own tab. One table, so a tab can never disagree with the cards it filters to\n * — which is the whole point of colouring the tab. `.saa7982_categoryButton` sets the\n * brand fallback for `All`/`Installed`; these attribute selectors are one\n * specificity step above it and win wherever the attribute is present. */\n.s7ce0b5_card[data-category='tool'], .saa7982_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.s7ce0b5_card[data-category='provider'], .saa7982_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.s7ce0b5_card[data-category='ui'], .saa7982_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.s7ce0b5_card[data-category='workflow'], .saa7982_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.s7ce0b5_card[data-category='integration'], .saa7982_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.s7ce0b5_card[data-category='theme'], .saa7982_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.s7ce0b5_card[data-category='other'], .saa7982_categoryButton[data-category='other'] { --category-hue: #8B8E96; }\n\n/* The category sits in the badge row as a quiet chip in the category's own\n * hue — the border carries it where the light theme's white layers cannot\n * (the same lesson as the check button). */\n.sda4302_categoryBadge {\n padding: 1px 7px;\n border: 1px solid color-mix(in srgb, var(--category-hue, #8B8E96) 45%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--category-hue, #8B8E96);\n white-space: nowrap;\n}\n\n.sf9a029_entryHeader {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px 2px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.sf9a029_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name fills the row and truncates rather than wraps; the badges stay\n * intact beside it. */\n.scde6f0_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n flex: 1 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--dsw-alias-label-primary);\n}\n\n.s5b12f5_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* The action line: buttons side by side; an active install/uninstall flow\n * (gate, log, notices) takes the full width below them. */\n.sbfb66e_cardActions {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 10px;\n}\n\n.sbfb66e_cardActions > .sbf0f49_gate,\n.sbfb66e_cardActions > .se45c46_installPanel,\n.sbfb66e_cardActions > .s6a7b50_installedActions {\n flex-basis: 100%;\n}\n\n/* The entry's version, always visible on the card (the expanded detail\n * repeats it in the version row) — the same quiet mono as the toolbar. */\n.sa3f608_cardVersion {\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/* The octocat marking a github-sourced entry, beside its short commit. */\n.s908192_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sda8b40_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.sda8b40_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.sda8b40_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.sda8b40_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.s6eb4e5_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n}\n\n.s3e85ad_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sef80ea_chevron, .sc0d8c8_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.sc0d8c8_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sef80ea_chevron, .sc0d8c8_chevronOpen { transition: none; }\n}\n\n.safe8c4_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sbd2517_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.s15225a_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/* Expanded cards show the full summary: the clamp is lifted, never raised —\n * a higher number would still truncate the author's text, just later. */\n.s273e04_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.s20dbc5_summaryZhExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n/* `white-space: pre-line` so the newline in the copy is the copy's own: the\n dictionary decides where the line breaks, and a translator changes it\n without touching the component. Collapses runs of spaces like `normal`, so\n only the explicit \\n survives. */\n.s927eb9_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n.sa35ed7_remedy {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s2fcacb_remedyLead {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The exemption command, bound for a terminal unchanged: one click selects\n * all of it, and it wraps anywhere rather than widening the card. A border,\n * not a fill, marks the box: the bg layers are one white in the light theme. */\n.se87ea1_allowCommand {\n display: block;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-all;\n user-select: all;\n color: var(--dsw-alias-label-primary);\n}\n\n/* A refused install on a surface that does not state its blockers — the\n * outdated row — writes them out on their own full-width line under the\n * disabled button, the command that clears dsh's refusal included. */\n.sbccf5d_refusal {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-basis: 100%;\n}\n\n.sca4074_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3ed23b_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sbd7053_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sbd7053_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.se69ccd_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.s71ed47_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.s488064_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.s488064_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.s488064_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.s488064_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.s488064_detailRow a:hover {\n text-decoration: underline;\n}\n\n.s488064_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* What the entry IS rather than what you can do with it — how big it is and\n * who published it — at the right edge of the action row. `margin-left: auto`\n * is what pushes it there, and it lives on this wrapper rather than on either\n * label so the group stays flush right when only one of the two has a value —\n * a packument that named no account has no author, and an entry the registry\n * could not measure honestly has no size. Rarer than it was (every live entry\n * now carries a size, github included), but the wrapper is not what makes it\n * rare: without one, an EMPTY meta group still costs 8px, because\n * `.sbfb66e_cardActions` is a flex row with `gap: 8px` and a zero-width item is still\n * an item. The row is a wrapping flex, so an active install flow (which claims\n * the full width) drops the whole group to the next line rather than squeezing\n * it. */\n.sd941dc_cardMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n min-width: 0;\n}\n\n/* The on-disk size, left of the author. Mono and tabular so the digits of one\n * figure line up with the digits of another WHEREVER the two land: `.sd941dc_cardMeta`\n * is flush right and the author sits outside the size, so a size's x position\n * moves with the author's width and is different again on the many entries\n * that carry no author at all. There is no column to align to, which is why\n * the reason given here is per-figure legibility rather than the column the\n * first version of this comment claimed. Secondary colour, because it\n * qualifies the entry rather than announcing it.\n *\n * `font-variant-numeric` is safe HERE and would not be on a pill: this element\n * has no state rules, so nothing it does can reflow a wrapping row. */\n.sff4055_size {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n letter-spacing: 0.02em;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The publishing account, at the outer end of `.sd941dc_cardMeta` on the action row —\n * NOT beside the npm link in the expanded detail, which is where it used to\n * live and what this comment described until the accurate half was deleted\n * with the `margin-left: auto` that moved to `.sd941dc_cardMeta`. There is no middot:\n * `.sd941dc_cardMeta`'s 8px gap separates it from the size.\n *\n * Secondary label colour carries the distinction — never a background fill,\n * which is invisible in the light theme where every bg-layer token is the\n * same white. */\n.s74b808_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.s5a1b52_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.se45c46_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.s7bcc5e_installButton, .sb977c6_confirmButton, .s3cfd9a_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.s7bcc5e_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.s7bcc5e_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sb977c6_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.sb977c6_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s3cfd9a_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.s3cfd9a_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s7bcc5e_installButton:focus-visible, .sb977c6_confirmButton:focus-visible, .s3cfd9a_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The shelf card of a plugin that is installed and current carries this\n * non-interactive label instead of an install button. Border + text do the\n * work in the light theme, where every bg-layer token resolves to white. */\n.sfaf388_installedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* An installed card's controls: the installed label or the update button,\n * plus the uninstall button. The install panel's running/failed states are\n * column layouts and sit as one item of this row. */\n.s6a7b50_installedActions {\n display: flex;\n align-items: flex-start;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* Uninstall revokes privilege; the quiet outline keeps it from competing\n * with the primary action, and the error tint says \"removes\". */\n.sb0c03c_uninstallButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 55%, transparent);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.sb0c03c_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.sb0c03c_uninstallButton:focus-visible {\n outline: 2px solid var(--dsw-alias-state-error-primary);\n outline-offset: 1px;\n}\n\n/* The restart dsh button on a done install: quiet outline, same rank as\n * the other secondary actions. */\n.se1e373_restartSelfButton {\n /* The version row's third state. Geometry matches .s1abadc_checkUpdateButton and\n * .sf22160_updateSelfButton exactly — the row is one evolving control and a\n * different pill would read as a different kind of thing. It takes the\n * emphasised fill rather than the neutral one because at that moment the\n * restart is the only thing left to do, the same reason Update has it. */\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.se1e373_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The two activation offers share one recipe: a border in an alias token,\n * never a `bg-layer` fill alone — all four bg-layer tokens collapse to the\n * same white under `body` in the light theme, and a fill-only button would\n * vanish there. Grouped rather than copied, because a copy is a rule that\n * can be corrected on one button and left wrong on the other, silently. */\n.s785196_restartButton,\n.s578d0b_reloadButton {\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.s785196_restartButton:hover,\n.s578d0b_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s785196_restartButton:focus-visible,\n.s578d0b_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The §4 reload offer: a notice plus its button, one item of\n * `.s6a7b50_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.s168719_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sbf0f49_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.s62b4ea_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s8a8304_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s9a546e_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.secbb11_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s2fe11f_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s597ed4_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.s2fbc07_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.se1ef74_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.s878e49_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.scaf26f_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sb46af7_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.se50b2b_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.s103f71_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s2ba5be_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s2283c2_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.se41dca_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.se41dca_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.s970b51_outdatedVersions {\n /* Two inline labels with nothing between them in the markup ran together as\n * `installed v1.0.0latest v2.0.0`: JSX drops the whitespace-only line, and\n * the per-label class the markup asked for was never defined (singular\n * against this rule's plural). The container owns the gap, the same idiom\n * as .s5b12f5_badges — the labels need no class of their own. */\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfe5725_outdatedActions {\n display: flex;\n align-items: center;\n /* The reload offer (§4) mounts inside the switch beside the Update button\n * and is a two-line block, not a control: without wrapping, a row reading\n * [switch][notice + Reload][Update] overflows the settings dialog. */\n flex-wrap: wrap;\n gap: 10px;\n}\n\n/* The shop's one switch. It is worn by two controls that mean different\n * things — the enable/disable toggle on an installed card, and the shelf's\n * incompatible filter — so the geometry lives here once and each caller states\n * only its hue.\n *\n * `--switch-hue` is that knob, and it is read from the ANCESTOR rather than\n * declared per state: `.s6000bb_incompatibleFilter` sets it once and it reaches the\n * track and the label together, which is what keeps a red switch from sitting\n * under a neutral word. A declaration on `.s21d1d6_switch` itself would shadow the\n * inherited value (an element's own rule beats what it inherits), so the\n * default rides in the `var()` fallback and is resolved once into\n * `--track-hue` instead of being spelled out at each use.\n *\n * `box-sizing` and `padding` are stated because the two callers are different\n * elements — a `<button>`, which the UA gives padding, and a `<span>`, which\n * it does not. Without them the same class renders two sizes, and the knob\n * sits 2px above centre in the taller one. */\n.s21d1d6_switch {\n --track-hue: var(--switch-hue, var(--dsw-alias-state-success-primary));\n box-sizing: border-box;\n display: inline-block;\n position: relative;\n width: 32px;\n height: 18px;\n padding: 0;\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/* The knob's POSITION is the state, which is the reason this control needs no\n * `forced-colors` fallback the way the category pills do: a system palette\n * replaces every colour below and moves nothing. */\n.sfaf305_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.s3e9566_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.sfaf305_switchOn .s3e9566_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s21d1d6_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 .s21d1d6_switch, .s3e9566_switchKnob { transition: none; }\n}\n\n/* The hot enable/disable switch on installed rows: the knob button plus the\n * §8 hot-apply / failure notices rendered beside it. */\n.s98de45_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.sfe5725_outdatedActions`: `.s168719_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.s6a7b50_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
7695
|
-
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"
|
|
7787
|
+
//#region \0dsh-plugin-shop-css:58798e8a
|
|
7788
|
+
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 HUE per\n * category (seven fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so seven brand opacities read as seven\n * shades of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.sf53492_client.s9448d6_config.se8518e_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.sf53492_client.s5506db_spec.se8518e_ts` pins this. */\n\n.s606016_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n /* The shelf never scrolls sideways: a card too wide for its track wraps\n * its badges rather than widening the panel.\n *\n * Clipped on BOTH axes, with a margin, because `.sdebeb0_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.s308509_toolbar`, itself\n * the first child here, and this rule carries no padding — so its focus\n * ring paints ENTIRELY outside the panel.\n *\n * Both axes is the load-bearing part: `overflow-clip-margin` is inert\n * unless the element clips on both. Clipping x alone left the margin doing\n * nothing — measured against the live app on 0.7.1, the ring reached 0 of\n * its 3px on the left at every device pixel ratio (1, 1.25, 1.5, 2), while\n * keeping the full 3px on the right, where the 280px input stops short of\n * the panel and never meets the clip edge. Raising the margin to 6px\n * changed nothing; clipping both axes with the SAME 3px restored the whole\n * ring. A test that reads declarations cannot see that difference, which is\n * why the first attempt at this shipped broken.\n *\n * `clip` is not a scroll container, so this does not bring back the\n * accidental scrolling `hidden` caused by coercing the other axis to\n * `auto`. Nothing is lost vertically: the panel's scrollHeight equals its\n * height and no descendant paints outside the clip rect (measured).\n * `overflow-x: hidden` stays as the fallback for engines without `clip`,\n * where the ring is clipped as it was before, never worse. */\n overflow-x: hidden;\n overflow: clip;\n overflow-clip-margin: 3px;\n}\n\n.sf8aa3f_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.s445a84_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.saff1f5_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.sf506c5_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.sf506c5_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.sd2356c_skeletonName {\n width: 55%;\n height: 14px;\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.s79ae29_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.s5fbc74_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 10px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n/* The ghost of the action line, right where the real buttons land. */\n.sbac887_skeletonActions {\n display: block;\n width: 84px;\n height: 24px;\n margin: 0 12px 10px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sf506c5_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 .sf506c5_skeletonCard span { animation: none; opacity: 0.75; }\n .sf506c5_skeletonCard::after { content: none; }\n}\n\n.s6248e9_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.s6248e9_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.s6248e9_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s308509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s706abc_toolbarRight {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* The shop's own version, right of the search box: `v0.4.4`, plus the\n * update button when the version check found a newer release. */\n.sf7f7be_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.saaaff3_versionText {\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.sd80651_updateSelfButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.sd80651_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.sd80651_updateSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The on-demand re-check next to the version number: a quiet pill; the\n * border and text carry it in the light theme where bg layers are white. */\n.sa20b3d_checkUpdateButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.sa20b3d_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.sa20b3d_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.sa20b3d_checkUpdateButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The project's GitHub mark, right of the version row: a quiet icon link.\n * The octocat carries itself — color shift on hover, no text, no border. */\n.sd10b8d_githubLink {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 3px;\n border-radius: 6px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sd10b8d_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sd10b8d_githubLink:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The self-update's expanded states (running log / done + restart /\n * failure detail) sit under the toolbar, above the category bar. */\n.s789529_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.sdebeb0_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.sdebeb0_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s1965b1_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.s170980_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.s498a11_categoryButton {\n /* The hue this button carries when selected. `All` and `Installed` select by\n * something other than a category and keep the brand token; the six category\n * buttons override it from the shared hue table below, so a pressed Tool tab\n * turns the same blue as a tool card's spine. */\n --category-hue: var(--dsw-alias-brand-primary);\n padding: 3px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Blend text with the theme foreground: darker on light backgrounds, lighter\n * on dark ones. The unblended category hue belongs on the border and fill. */\n.s498a11_categoryButton:hover {\n border-color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-border-l2));\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Selected. Written `.s498a11_categoryButton.s89c60c_categoryButtonOn` — TWO classes — so it\n * matches `.s498a11_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s89c60c_categoryButtonOn` it lost both `border-color` and `color` to the\n * hover rule for as long as the pointer stayed on the tab that had just been\n * clicked, which is precisely when a reader looks for confirmation.\n *\n * EVERY declaration here is a colour or a shadow: a pressed tab must occupy\n * exactly the same box as an unpressed one, so the bar does not reflow — and\n * with ~9 pills on a wrapping row, one that grows can push the rest onto\n * another line and move the tab out from under the pointer that just clicked\n * it. That is what `font-weight: 600` did (bold metrics are wider than\n * regular), and it is why nothing may be added here that resolves to a length:\n * no padding, no border-width, no font-size, no letter-spacing.\n * `css-tokens.sf53492_client.s5506db_spec.se8518e_ts` fails the build on one.\n *\n * `box-shadow` is the exception that earns its place: it paints outside the\n * layout box, so an inset ring doubles the border's weight at zero cost to the\n * metrics. It is what `font-weight: 600` used to be — a second, thickness-\n * based signal that hover does not also produce — and the `other` tab needs it\n * most: its hue IS the neutral gray this file uses for \"no category\", so on\n * the light theme hue alone barely separates pressed from unpressed. */\n.s498a11_categoryButton.s89c60c_categoryButtonOn {\n border-color: var(--category-hue);\n background: color-mix(in srgb, var(--category-hue) 14%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n box-shadow: inset 0 0 0 1px var(--category-hue);\n}\n\n/* Forced colours replace every colour above with the system palette, which\n * would leave the three colour declarations saying nothing and the pressed tab\n * indistinguishable from its neighbours. `box-shadow` is dropped in this mode\n * too, so the ring has to come back as an outline. */\n@media (forced-colors: active) {\n .s498a11_categoryButton.s89c60c_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.s498a11_categoryButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The incompatible filter, at the right edge of the category bar: `margin-left:\n * auto` pushes it past the pills, and the bar wraps, so on a narrow panel it\n * drops to its own line rather than squeezing them. It is a MODIFIER, not a\n * ninth category — the categories select what to show and this one subtracts\n * from whatever they selected — so it takes the error hue it filters on rather\n * than joining the hue table.\n *\n * And it is a SWITCH, which is the difference the shape now carries. It used\n * to wear `.s498a11_categoryButton`: same pill, same row, same size as the eight tabs,\n * differing only in being red. That reads as a ninth tab, and it is not one —\n * the tabs are choose-one and this is on-or-off. So it drops the pill chrome\n * entirely (no border, no fill, nothing to compete with the row it sits\n * beside) and puts the state in a track, the same one every installed card\n * carries. Nothing here restates the switch geometry; `--switch-hue` is the\n * whole of what this control says about it, and it reaches the label too, so\n * one declaration keeps the word and the track the same colour. */\n.s461978_incompatibleFilter {\n --switch-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Matches the pills' vertical padding so the bar keeps one line box whether\n * this control wraps onto a row of its own or shares theirs. */\n padding: 3px 0;\n border: 0;\n background: none;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Hover lifts the word to full contrast and warms the track's border. Scoped\n * to the OFF track: `.s461978_incompatibleFilter:hover .s8f2d24_switch` outranks `.sf5c955_switchOn`\n * by two classes, so unscoped it would strip the hue from the border at\n * exactly the moment a reader has the pointer on it to check the state. */\n.s461978_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.s461978_incompatibleFilter:hover .s8f2d24_switch:not(.sf5c955_switchOn) {\n border-color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-border-l2));\n}\n\n/* On. Written with both classes for the reason `.s498a11_categoryButton.s89c60c_categoryButtonOn`\n * is: it has to match `:hover`'s specificity and come after it, or the colour\n * reverts under a pointer that has not moved since the click. */\n.s461978_incompatibleFilter.s43ebb1_incompatibleFilterOn {\n color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Off here means \"nothing is being taken away\" — the resting state — so the\n * knob steps back to the secondary label. The enable switch keeps the full\n * strength dot, where off means \"this plugin is disabled\" and is worth\n * noticing. In this bar it would be the heaviest mark in a row of hairline\n * pills, and on the light theme it is the WHOLE control: bg-layer-2 is the\n * same white as the panel there, so an off track is a hairline outline with a\n * near-black dot sitting in it. */\n.s461978_incompatibleFilter .s8f2d24_switch:not(.sf5c955_switchOn) .sba3163_switchKnob {\n background: var(--dsw-alias-label-secondary);\n}\n\n/* The ring has no border to trace, so it takes an offset and the pill radius\n * of the tabs it sits beside rather than hugging the text. */\n.s461978_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s27d400_updatableHeading {\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.sf7ebed_catalogStatsRow {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n.s43730a_catalogStats {\n margin: 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/* Sits beside the 12px stats caption, so it is quieter than `.s6248e9_actionButton`:\n * this is an affordance, not a call to action — the catalog reloads on its\n * own at mount and the shelf is already usable without it. Named\n * `catalogRefresh*` (not `reload*`) so it cannot collide with the §4 page\n * reload offer below, which reloads the whole tab rather than refetching\n * the catalog data. */\n.s1d4e19_catalogRefreshButton {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.s1d4e19_catalogRefreshButton:hover:not(:disabled) {\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.s1d4e19_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s1d4e19_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sb2cffb_catalogRefreshFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s88613c_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/* Single-line rows: one full-width column, one plugin per line. */\n.s4cb40b_cards {\n display: grid;\n grid-template-columns: 1fr;\n max-width: 100%;\n gap: 8px;\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 .s4cb40b_cards { animation: none; }\n}\n\n.sf0df6a_card {\n position: relative;\n display: flex;\n flex-direction: column;\n /* A grid item's min-width is auto by default: its content would widen the\n * 1fr track past the panel and overflow horizontally. */\n min-width: 0;\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 140px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.s509fc6_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s21d1c6_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf0df6a_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 .sf0df6a_card { transition: none; }\n .sf0df6a_card:hover { transform: none; }\n}\n\n/* The signature: a spine and cover in the category's own hue. The hues are\n * fixed mid-bright colors that read on both themes; `other` deliberately\n * stays a neutral gray so the fallback category does not compete. */\n.s9b6447_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--category-hue, #8B8E96);\n}\n\n/* The hue table, keyed by `data-category` and read by BOTH surfaces that\n * speak in category colour: a card's spine and badge, and the category bar's\n * own tab. One table, so a tab can never disagree with the cards it filters to\n * — which is the whole point of colouring the tab. `.s498a11_categoryButton` sets the\n * brand fallback for `All`/`Installed`; these attribute selectors are one\n * specificity step above it and win wherever the attribute is present. */\n.sf0df6a_card[data-category='tool'], .s498a11_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.sf0df6a_card[data-category='provider'], .s498a11_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.sf0df6a_card[data-category='ui'], .s498a11_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.sf0df6a_card[data-category='workflow'], .s498a11_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.sf0df6a_card[data-category='integration'], .s498a11_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.sf0df6a_card[data-category='theme'], .s498a11_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.sf0df6a_card[data-category='other'], .s498a11_categoryButton[data-category='other'] { --category-hue: #8B8E96; }\n\n/* The category sits in the badge row as a quiet chip in the category's own\n * hue — the border carries it where the light theme's white layers cannot\n * (the same lesson as the check button). */\n.s3d32c7_categoryBadge {\n padding: 1px 7px;\n border: 1px solid color-mix(in srgb, var(--category-hue, #8B8E96) 45%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--category-hue, #8B8E96);\n white-space: nowrap;\n}\n\n.sed0c53_entryHeader {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px 2px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.sed0c53_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name fills the row and truncates rather than wraps; the badges stay\n * intact beside it. */\n.s233aa2_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n flex: 1 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--dsw-alias-label-primary);\n}\n\n.s407380_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* The action line: buttons side by side; an active install/uninstall flow\n * (gate, log, notices) takes the full width below them. */\n.s75d683_cardActions {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 10px;\n}\n\n.s75d683_cardActions > .s628956_gate,\n.s75d683_cardActions > .s158ebe_installPanel,\n.s75d683_cardActions > .sff7a43_installedActions {\n flex-basis: 100%;\n}\n\n/* The entry's version, always visible on the card (the expanded detail\n * repeats it in the version row) — the same quiet mono as the toolbar. */\n.s5e4251_cardVersion {\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/* The octocat marking a github-sourced entry, beside its short commit. */\n.se5a0a2_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s19f5d6_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s19f5d6_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.s19f5d6_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.s19f5d6_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.s8d11d0_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n}\n\n.s583e15_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc8024b_chevron, .s13c0de_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s13c0de_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sc8024b_chevron, .s13c0de_chevronOpen { transition: none; }\n}\n\n.s25d65c_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.s2679e5_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.s3f29fa_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/* Expanded cards show the full summary: the clamp is lifted, never raised —\n * a higher number would still truncate the author's text, just later. */\n.se19379_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.s7c8ac8_summaryZhExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n/* `white-space: pre-line` so the newline in the copy is the copy's own: the\n dictionary decides where the line breaks, and a translator changes it\n without touching the component. Collapses runs of spaces like `normal`, so\n only the explicit \\n survives. */\n.s759c19_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n.s51362c_remedy {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3755f7_remedyLead {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The exemption command, bound for a terminal unchanged: one click selects\n * all of it, and it wraps anywhere rather than widening the card. A border,\n * not a fill, marks the box: the bg layers are one white in the light theme. */\n.s1a33b7_allowCommand {\n display: block;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-all;\n user-select: all;\n color: var(--dsw-alias-label-primary);\n}\n\n/* A refused install on a surface that does not state its blockers — the\n * outdated row — writes them out on their own full-width line under the\n * disabled button, the command that clears dsh's refusal included. */\n.s23346a_refusal {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-basis: 100%;\n}\n\n.s15b82b_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s20c5f7_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s587cdd_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s587cdd_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.sa970d5_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.s2b23c3_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.s24534d_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.s24534d_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.s24534d_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.s24534d_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.s24534d_detailRow a:hover {\n text-decoration: underline;\n}\n\n.s24534d_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* What the entry IS rather than what you can do with it — how big it is and\n * who published it — at the right edge of the action row. `margin-left: auto`\n * is what pushes it there, and it lives on this wrapper rather than on either\n * label so the group stays flush right when only one of the two has a value —\n * a packument that named no account has no author, and an entry the registry\n * could not measure honestly has no size. Rarer than it was (every live entry\n * now carries a size, github included), but the wrapper is not what makes it\n * rare: without one, an EMPTY meta group still costs 8px, because\n * `.s75d683_cardActions` is a flex row with `gap: 8px` and a zero-width item is still\n * an item. The row is a wrapping flex, so an active install flow (which claims\n * the full width) drops the whole group to the next line rather than squeezing\n * it. */\n.s244d8b_cardMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n min-width: 0;\n}\n\n/* The on-disk size, left of the author. Mono and tabular so the digits of one\n * figure line up with the digits of another WHEREVER the two land: `.s244d8b_cardMeta`\n * is flush right and the author sits outside the size, so a size's x position\n * moves with the author's width and is different again on the many entries\n * that carry no author at all. There is no column to align to, which is why\n * the reason given here is per-figure legibility rather than the column the\n * first version of this comment claimed. Secondary colour, because it\n * qualifies the entry rather than announcing it.\n *\n * `font-variant-numeric` is safe HERE and would not be on a pill: this element\n * has no state rules, so nothing it does can reflow a wrapping row. */\n.s753f0d_size {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n letter-spacing: 0.02em;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The publishing account, at the outer end of `.s244d8b_cardMeta` on the action row —\n * NOT beside the npm link in the expanded detail, which is where it used to\n * live and what this comment described until the accurate half was deleted\n * with the `margin-left: auto` that moved to `.s244d8b_cardMeta`. There is no middot:\n * `.s244d8b_cardMeta`'s 8px gap separates it from the size.\n *\n * Secondary label colour carries the distinction — never a background fill,\n * which is invisible in the light theme where every bg-layer token is the\n * same white. */\n.sd50776_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.s5ae7ae_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.s158ebe_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.se4286a_installButton, .s5bf7c7_confirmButton, .s13641e_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.se4286a_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.se4286a_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s5bf7c7_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.s5bf7c7_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s13641e_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.s13641e_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se4286a_installButton:focus-visible, .s5bf7c7_confirmButton:focus-visible, .s13641e_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The shelf card of a plugin that is installed and current carries this\n * non-interactive label instead of an install button. Border + text do the\n * work in the light theme, where every bg-layer token resolves to white. */\n.s82b33f_installedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* An installed card's controls: the installed label or the update button,\n * plus the uninstall button. The install panel's running/failed states are\n * column layouts and sit as one item of this row. */\n.sff7a43_installedActions {\n display: flex;\n align-items: flex-start;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* Uninstall revokes privilege; the quiet outline keeps it from competing\n * with the primary action, and the error tint says \"removes\". */\n.se0c7da_uninstallButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 55%, transparent);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.se0c7da_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.se0c7da_uninstallButton:focus-visible {\n outline: 2px solid var(--dsw-alias-state-error-primary);\n outline-offset: 1px;\n}\n\n/* The restart dsh button on a done install: quiet outline, same rank as\n * the other secondary actions. */\n.s1fc455_restartSelfButton {\n /* The version row's third state. Geometry matches .sa20b3d_checkUpdateButton and\n * .sd80651_updateSelfButton exactly — the row is one evolving control and a\n * different pill would read as a different kind of thing. It takes the\n * emphasised fill rather than the neutral one because at that moment the\n * restart is the only thing left to do, the same reason Update has it. */\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.s1fc455_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The two activation offers share one recipe: a border in an alias token,\n * never a `bg-layer` fill alone — all four bg-layer tokens collapse to the\n * same white under `body` in the light theme, and a fill-only button would\n * vanish there. Grouped rather than copied, because a copy is a rule that\n * can be corrected on one button and left wrong on the other, silently. */\n.sb62dca_restartButton,\n.sdd9811_reloadButton {\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.sb62dca_restartButton:hover,\n.sdd9811_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.sb62dca_restartButton:focus-visible,\n.sdd9811_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The §4 reload offer: a notice plus its button, one item of\n * `.sff7a43_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.s10c127_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.s628956_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.sf3567b_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.sf22ea7_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s75023b_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s6ae9f6_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.sb3806b_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s8923e8_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.sc09af4_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sdb4d54_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.s67b8c9_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sf1da6c_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s5b19fe_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s759942_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.sca7cd0_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s6079f6_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sd2e99f_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.s5ee082_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5ee082_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.sb71e84_outdatedVersions {\n /* Two inline labels with nothing between them in the markup ran together as\n * `installed v1.0.0latest v2.0.0`: JSX drops the whitespace-only line, and\n * the per-label class the markup asked for was never defined (singular\n * against this rule's plural). The container owns the gap, the same idiom\n * as .s407380_badges — the labels need no class of their own. */\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sd5ce04_outdatedActions {\n display: flex;\n align-items: center;\n /* The reload offer (§4) mounts inside the switch beside the Update button\n * and is a two-line block, not a control: without wrapping, a row reading\n * [switch][notice + Reload][Update] overflows the settings dialog. */\n flex-wrap: wrap;\n gap: 10px;\n}\n\n/* The shop's one switch. It is worn by two controls that mean different\n * things — the enable/disable toggle on an installed card, and the shelf's\n * incompatible filter — so the geometry lives here once and each caller states\n * only its hue.\n *\n * `--switch-hue` is that knob, and it is read from the ANCESTOR rather than\n * declared per state: `.s461978_incompatibleFilter` sets it once and it reaches the\n * track and the label together, which is what keeps a red switch from sitting\n * under a neutral word. A declaration on `.s8f2d24_switch` itself would shadow the\n * inherited value (an element's own rule beats what it inherits), so the\n * default rides in the `var()` fallback and is resolved once into\n * `--track-hue` instead of being spelled out at each use.\n *\n * `box-sizing` and `padding` are stated because the two callers are different\n * elements — a `<button>`, which the UA gives padding, and a `<span>`, which\n * it does not. Without them the same class renders two sizes, and the knob\n * sits 2px above centre in the taller one. */\n.s8f2d24_switch {\n --track-hue: var(--switch-hue, var(--dsw-alias-state-success-primary));\n box-sizing: border-box;\n display: inline-block;\n position: relative;\n width: 32px;\n height: 18px;\n padding: 0;\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/* The knob's POSITION is the state, which is the reason this control needs no\n * `forced-colors` fallback the way the category pills do: a system palette\n * replaces every colour below and moves nothing. */\n.sf5c955_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.sba3163_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.sf5c955_switchOn .sba3163_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s8f2d24_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 .s8f2d24_switch, .sba3163_switchKnob { transition: none; }\n}\n\n/* The hot enable/disable switch on installed rows: the knob button plus the\n * §8 hot-apply / failure notices rendered beside it. */\n.s538638_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.sd5ce04_outdatedActions`: `.s10c127_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.sff7a43_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
7789
|
+
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"58798e8a\"]")) {
|
|
7696
7790
|
const tag = document.createElement("style");
|
|
7697
|
-
tag.dataset.pluginCss = "
|
|
7791
|
+
tag.dataset.pluginCss = "58798e8a";
|
|
7698
7792
|
tag.textContent = css;
|
|
7699
7793
|
document.head.appendChild(tag);
|
|
7700
7794
|
}
|
|
7701
|
-
var
|
|
7702
|
-
"client": "
|
|
7703
|
-
"config": "
|
|
7704
|
-
"ts": "
|
|
7705
|
-
"spec": "
|
|
7706
|
-
"panel": "
|
|
7707
|
-
"searchInput": "
|
|
7708
|
-
"toolbar": "
|
|
7709
|
-
"stateLine": "
|
|
7710
|
-
"srOnly": "
|
|
7711
|
-
"skeletonGrid": "
|
|
7712
|
-
"skeletonCard": "
|
|
7713
|
-
"skeletonName": "
|
|
7714
|
-
"skeletonSummary": "
|
|
7715
|
-
"skeletonSummaryShort": "
|
|
7716
|
-
"skeletonActions": "
|
|
7717
|
-
"actionButton": "
|
|
7718
|
-
"toolbarRight": "
|
|
7719
|
-
"versionBlock": "
|
|
7720
|
-
"versionText": "
|
|
7721
|
-
"updateSelfButton": "
|
|
7722
|
-
"checkUpdateButton": "
|
|
7723
|
-
"githubLink": "
|
|
7724
|
-
"selfUpdatePanel": "
|
|
7725
|
-
"staleBadge": "
|
|
7726
|
-
"categoryBar": "
|
|
7727
|
-
"categoryButton": "
|
|
7728
|
-
"categoryButtonOn": "
|
|
7729
|
-
"incompatibleFilter": "
|
|
7730
|
-
"switch": "
|
|
7731
|
-
"switchOn": "
|
|
7732
|
-
"incompatibleFilterOn": "
|
|
7733
|
-
"switchKnob": "
|
|
7734
|
-
"updatableHeading": "
|
|
7735
|
-
"catalogStatsRow": "
|
|
7736
|
-
"catalogStats": "
|
|
7737
|
-
"catalogRefreshButton": "
|
|
7738
|
-
"catalogRefreshFailed": "
|
|
7739
|
-
"emptyLine": "
|
|
7740
|
-
"cards": "
|
|
7741
|
-
"card": "
|
|
7742
|
-
"cardsSentry": "
|
|
7743
|
-
"showingLine": "
|
|
7744
|
-
"cardSpine": "
|
|
7745
|
-
"categoryBadge": "
|
|
7746
|
-
"entryHeader": "
|
|
7747
|
-
"name": "
|
|
7748
|
-
"badges": "
|
|
7749
|
-
"cardActions": "
|
|
7750
|
-
"gate": "
|
|
7751
|
-
"installPanel": "
|
|
7752
|
-
"installedActions": "
|
|
7753
|
-
"cardVersion": "
|
|
7754
|
-
"sourceBadge": "
|
|
7755
|
-
"tierBadge": "
|
|
7756
|
-
"incompatibleBadge": "
|
|
7757
|
-
"starsBadge": "
|
|
7758
|
-
"chevron": "
|
|
7759
|
-
"chevronOpen": "
|
|
7760
|
-
"body": "
|
|
7761
|
-
"summary": "
|
|
7762
|
-
"summaryZh": "
|
|
7763
|
-
"summaryExpanded": "
|
|
7764
|
-
"summaryZhExpanded": "
|
|
7765
|
-
"incompatibleDetail": "
|
|
7766
|
-
"remedy": "
|
|
7767
|
-
"remedyLead": "
|
|
7768
|
-
"allowCommand": "
|
|
7769
|
-
"refusal": "
|
|
7770
|
-
"capabilitiesBlock": "
|
|
7771
|
-
"capabilitiesNote": "
|
|
7772
|
-
"capabilities": "
|
|
7773
|
-
"detail": "
|
|
7774
|
-
"detailRows": "
|
|
7775
|
-
"detailRow": "
|
|
7776
|
-
"cardMeta": "
|
|
7777
|
-
"size": "
|
|
7778
|
-
"author": "
|
|
7779
|
-
"reviewedLine": "
|
|
7780
|
-
"installButton": "
|
|
7781
|
-
"confirmButton": "
|
|
7782
|
-
"cancelButton": "
|
|
7783
|
-
"installedLabel": "
|
|
7784
|
-
"uninstallButton": "
|
|
7785
|
-
"restartSelfButton": "
|
|
7786
|
-
"restartButton": "
|
|
7787
|
-
"reloadButton": "
|
|
7788
|
-
"reloadPanel": "
|
|
7789
|
-
"gateTitle": "
|
|
7790
|
-
"gateBody": "
|
|
7791
|
-
"gateWarning": "
|
|
7792
|
-
"gateActions": "
|
|
7793
|
-
"installing": "
|
|
7794
|
-
"log": "
|
|
7795
|
-
"logLine": "
|
|
7796
|
-
"notice": "
|
|
7797
|
-
"failedHeading": "
|
|
7798
|
-
"failedDetail": "
|
|
7799
|
-
"rejectedCode": "
|
|
7800
|
-
"rejectedDetail": "
|
|
7801
|
-
"outdatedSection": "
|
|
7802
|
-
"outdatedList": "
|
|
7803
|
-
"outdatedRow": "
|
|
7804
|
-
"outdatedInfo": "
|
|
7805
|
-
"outdatedVersions": "
|
|
7806
|
-
"outdatedActions": "
|
|
7807
|
-
"switchWrap": "
|
|
7795
|
+
var _dsh_plugin_shop_css_58798e8a_default = {
|
|
7796
|
+
"client": "sf53492_client",
|
|
7797
|
+
"config": "s9448d6_config",
|
|
7798
|
+
"ts": "se8518e_ts",
|
|
7799
|
+
"spec": "s5506db_spec",
|
|
7800
|
+
"panel": "s606016_panel",
|
|
7801
|
+
"searchInput": "sdebeb0_searchInput",
|
|
7802
|
+
"toolbar": "s308509_toolbar",
|
|
7803
|
+
"stateLine": "sf8aa3f_stateLine",
|
|
7804
|
+
"srOnly": "s445a84_srOnly",
|
|
7805
|
+
"skeletonGrid": "saff1f5_skeletonGrid",
|
|
7806
|
+
"skeletonCard": "sf506c5_skeletonCard",
|
|
7807
|
+
"skeletonName": "sd2356c_skeletonName",
|
|
7808
|
+
"skeletonSummary": "s79ae29_skeletonSummary",
|
|
7809
|
+
"skeletonSummaryShort": "s5fbc74_skeletonSummaryShort",
|
|
7810
|
+
"skeletonActions": "sbac887_skeletonActions",
|
|
7811
|
+
"actionButton": "s6248e9_actionButton",
|
|
7812
|
+
"toolbarRight": "s706abc_toolbarRight",
|
|
7813
|
+
"versionBlock": "sf7f7be_versionBlock",
|
|
7814
|
+
"versionText": "saaaff3_versionText",
|
|
7815
|
+
"updateSelfButton": "sd80651_updateSelfButton",
|
|
7816
|
+
"checkUpdateButton": "sa20b3d_checkUpdateButton",
|
|
7817
|
+
"githubLink": "sd10b8d_githubLink",
|
|
7818
|
+
"selfUpdatePanel": "s789529_selfUpdatePanel",
|
|
7819
|
+
"staleBadge": "s1965b1_staleBadge",
|
|
7820
|
+
"categoryBar": "s170980_categoryBar",
|
|
7821
|
+
"categoryButton": "s498a11_categoryButton",
|
|
7822
|
+
"categoryButtonOn": "s89c60c_categoryButtonOn",
|
|
7823
|
+
"incompatibleFilter": "s461978_incompatibleFilter",
|
|
7824
|
+
"switch": "s8f2d24_switch",
|
|
7825
|
+
"switchOn": "sf5c955_switchOn",
|
|
7826
|
+
"incompatibleFilterOn": "s43ebb1_incompatibleFilterOn",
|
|
7827
|
+
"switchKnob": "sba3163_switchKnob",
|
|
7828
|
+
"updatableHeading": "s27d400_updatableHeading",
|
|
7829
|
+
"catalogStatsRow": "sf7ebed_catalogStatsRow",
|
|
7830
|
+
"catalogStats": "s43730a_catalogStats",
|
|
7831
|
+
"catalogRefreshButton": "s1d4e19_catalogRefreshButton",
|
|
7832
|
+
"catalogRefreshFailed": "sb2cffb_catalogRefreshFailed",
|
|
7833
|
+
"emptyLine": "s88613c_emptyLine",
|
|
7834
|
+
"cards": "s4cb40b_cards",
|
|
7835
|
+
"card": "sf0df6a_card",
|
|
7836
|
+
"cardsSentry": "s509fc6_cardsSentry",
|
|
7837
|
+
"showingLine": "s21d1c6_showingLine",
|
|
7838
|
+
"cardSpine": "s9b6447_cardSpine",
|
|
7839
|
+
"categoryBadge": "s3d32c7_categoryBadge",
|
|
7840
|
+
"entryHeader": "sed0c53_entryHeader",
|
|
7841
|
+
"name": "s233aa2_name",
|
|
7842
|
+
"badges": "s407380_badges",
|
|
7843
|
+
"cardActions": "s75d683_cardActions",
|
|
7844
|
+
"gate": "s628956_gate",
|
|
7845
|
+
"installPanel": "s158ebe_installPanel",
|
|
7846
|
+
"installedActions": "sff7a43_installedActions",
|
|
7847
|
+
"cardVersion": "s5e4251_cardVersion",
|
|
7848
|
+
"sourceBadge": "se5a0a2_sourceBadge",
|
|
7849
|
+
"tierBadge": "s19f5d6_tierBadge",
|
|
7850
|
+
"incompatibleBadge": "s8d11d0_incompatibleBadge",
|
|
7851
|
+
"starsBadge": "s583e15_starsBadge",
|
|
7852
|
+
"chevron": "sc8024b_chevron",
|
|
7853
|
+
"chevronOpen": "s13c0de_chevronOpen",
|
|
7854
|
+
"body": "s25d65c_body",
|
|
7855
|
+
"summary": "s2679e5_summary",
|
|
7856
|
+
"summaryZh": "s3f29fa_summaryZh",
|
|
7857
|
+
"summaryExpanded": "se19379_summaryExpanded",
|
|
7858
|
+
"summaryZhExpanded": "s7c8ac8_summaryZhExpanded",
|
|
7859
|
+
"incompatibleDetail": "s759c19_incompatibleDetail",
|
|
7860
|
+
"remedy": "s51362c_remedy",
|
|
7861
|
+
"remedyLead": "s3755f7_remedyLead",
|
|
7862
|
+
"allowCommand": "s1a33b7_allowCommand",
|
|
7863
|
+
"refusal": "s23346a_refusal",
|
|
7864
|
+
"capabilitiesBlock": "s15b82b_capabilitiesBlock",
|
|
7865
|
+
"capabilitiesNote": "s20c5f7_capabilitiesNote",
|
|
7866
|
+
"capabilities": "s587cdd_capabilities",
|
|
7867
|
+
"detail": "sa970d5_detail",
|
|
7868
|
+
"detailRows": "s2b23c3_detailRows",
|
|
7869
|
+
"detailRow": "s24534d_detailRow",
|
|
7870
|
+
"cardMeta": "s244d8b_cardMeta",
|
|
7871
|
+
"size": "s753f0d_size",
|
|
7872
|
+
"author": "sd50776_author",
|
|
7873
|
+
"reviewedLine": "s5ae7ae_reviewedLine",
|
|
7874
|
+
"installButton": "se4286a_installButton",
|
|
7875
|
+
"confirmButton": "s5bf7c7_confirmButton",
|
|
7876
|
+
"cancelButton": "s13641e_cancelButton",
|
|
7877
|
+
"installedLabel": "s82b33f_installedLabel",
|
|
7878
|
+
"uninstallButton": "se0c7da_uninstallButton",
|
|
7879
|
+
"restartSelfButton": "s1fc455_restartSelfButton",
|
|
7880
|
+
"restartButton": "sb62dca_restartButton",
|
|
7881
|
+
"reloadButton": "sdd9811_reloadButton",
|
|
7882
|
+
"reloadPanel": "s10c127_reloadPanel",
|
|
7883
|
+
"gateTitle": "sf3567b_gateTitle",
|
|
7884
|
+
"gateBody": "sf22ea7_gateBody",
|
|
7885
|
+
"gateWarning": "s75023b_gateWarning",
|
|
7886
|
+
"gateActions": "s6ae9f6_gateActions",
|
|
7887
|
+
"installing": "sb3806b_installing",
|
|
7888
|
+
"log": "s8923e8_log",
|
|
7889
|
+
"logLine": "sc09af4_logLine",
|
|
7890
|
+
"notice": "sdb4d54_notice",
|
|
7891
|
+
"failedHeading": "s67b8c9_failedHeading",
|
|
7892
|
+
"failedDetail": "sf1da6c_failedDetail",
|
|
7893
|
+
"rejectedCode": "s5b19fe_rejectedCode",
|
|
7894
|
+
"rejectedDetail": "s759942_rejectedDetail",
|
|
7895
|
+
"outdatedSection": "sca7cd0_outdatedSection",
|
|
7896
|
+
"outdatedList": "s6079f6_outdatedList",
|
|
7897
|
+
"outdatedRow": "sd2e99f_outdatedRow",
|
|
7898
|
+
"outdatedInfo": "s5ee082_outdatedInfo",
|
|
7899
|
+
"outdatedVersions": "sb71e84_outdatedVersions",
|
|
7900
|
+
"outdatedActions": "sd5ce04_outdatedActions",
|
|
7901
|
+
"switchWrap": "s538638_switchWrap"
|
|
7808
7902
|
};
|
|
7809
7903
|
//#endregion
|
|
7810
7904
|
//#region src/client/ShopTab.tsx
|
|
@@ -7821,14 +7915,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7821
7915
|
* those nodes, and React's next commit throws on the ones it no longer finds
|
|
7822
7916
|
* (design 2026-09-26-market-borrowings §4). The tab renders no portals, so its
|
|
7823
7917
|
* root is its whole surface. */
|
|
7824
|
-
const PANEL_ROOT = `${
|
|
7918
|
+
const PANEL_ROOT = `${_dsh_plugin_shop_css_58798e8a_default.panel} notranslate`;
|
|
7825
7919
|
function ChevronIcon({ open }) {
|
|
7826
7920
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
7827
7921
|
viewBox: "0 0 16 16",
|
|
7828
7922
|
width: "14",
|
|
7829
7923
|
height: "14",
|
|
7830
7924
|
"aria-hidden": "true",
|
|
7831
|
-
className: open ?
|
|
7925
|
+
className: open ? _dsh_plugin_shop_css_58798e8a_default.chevronOpen : _dsh_plugin_shop_css_58798e8a_default.chevron,
|
|
7832
7926
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
7833
7927
|
fill: "currentColor",
|
|
7834
7928
|
d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
|
|
@@ -7858,32 +7952,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7858
7952
|
subdir: entry.subdir
|
|
7859
7953
|
};
|
|
7860
7954
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7861
|
-
className:
|
|
7955
|
+
className: _dsh_plugin_shop_css_58798e8a_default.card,
|
|
7862
7956
|
"data-shop-entry": entry.name,
|
|
7863
7957
|
"data-category": category,
|
|
7864
7958
|
children: [
|
|
7865
7959
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7866
|
-
className:
|
|
7960
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cardSpine,
|
|
7867
7961
|
"aria-hidden": "true"
|
|
7868
7962
|
}),
|
|
7869
7963
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7870
7964
|
type: "button",
|
|
7871
|
-
className:
|
|
7965
|
+
className: _dsh_plugin_shop_css_58798e8a_default.entryHeader,
|
|
7872
7966
|
"aria-expanded": open,
|
|
7873
7967
|
"aria-controls": detailId,
|
|
7874
7968
|
onClick: () => setOpen((current) => !current),
|
|
7875
7969
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7876
|
-
className:
|
|
7970
|
+
className: _dsh_plugin_shop_css_58798e8a_default.name,
|
|
7877
7971
|
children: entry.name
|
|
7878
7972
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7879
|
-
className:
|
|
7973
|
+
className: _dsh_plugin_shop_css_58798e8a_default.badges,
|
|
7880
7974
|
children: [
|
|
7881
7975
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7882
|
-
className:
|
|
7976
|
+
className: _dsh_plugin_shop_css_58798e8a_default.categoryBadge,
|
|
7883
7977
|
children: t(categoryKey(entry))
|
|
7884
7978
|
}),
|
|
7885
7979
|
entry.source === "npm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7886
|
-
className:
|
|
7980
|
+
className: _dsh_plugin_shop_css_58798e8a_default.sourceBadge,
|
|
7887
7981
|
"data-shop-source-npm": true,
|
|
7888
7982
|
role: "img",
|
|
7889
7983
|
"aria-label": t("npmSource"),
|
|
@@ -7900,7 +7994,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7900
7994
|
})
|
|
7901
7995
|
}),
|
|
7902
7996
|
hasGithubHome(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7903
|
-
className:
|
|
7997
|
+
className: _dsh_plugin_shop_css_58798e8a_default.sourceBadge,
|
|
7904
7998
|
"data-shop-source-github": true,
|
|
7905
7999
|
role: "img",
|
|
7906
8000
|
"aria-label": t("githubSource"),
|
|
@@ -7914,17 +8008,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7914
8008
|
})
|
|
7915
8009
|
}),
|
|
7916
8010
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7917
|
-
className:
|
|
8011
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cardVersion,
|
|
7918
8012
|
"data-card-version": true,
|
|
7919
8013
|
children: ["v", displayVersion(entry)]
|
|
7920
8014
|
}),
|
|
7921
8015
|
entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7922
|
-
className:
|
|
8016
|
+
className: _dsh_plugin_shop_css_58798e8a_default.tierBadge,
|
|
7923
8017
|
"data-tier": entry.tier,
|
|
7924
8018
|
children: t(tierKey(entry.tier))
|
|
7925
8019
|
}),
|
|
7926
8020
|
stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7927
|
-
className:
|
|
8021
|
+
className: _dsh_plugin_shop_css_58798e8a_default.starsBadge,
|
|
7928
8022
|
role: "img",
|
|
7929
8023
|
"aria-label": t("stars", { count: stars }),
|
|
7930
8024
|
children: ["★ ", formatStars(stars)]
|
|
@@ -7934,39 +8028,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7934
8028
|
})]
|
|
7935
8029
|
}),
|
|
7936
8030
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7937
|
-
className:
|
|
8031
|
+
className: _dsh_plugin_shop_css_58798e8a_default.body,
|
|
7938
8032
|
children: [
|
|
7939
8033
|
summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7940
|
-
className: open ? `${
|
|
8034
|
+
className: open ? `${_dsh_plugin_shop_css_58798e8a_default.summary} ${_dsh_plugin_shop_css_58798e8a_default.summaryExpanded}` : _dsh_plugin_shop_css_58798e8a_default.summary,
|
|
7941
8035
|
children: summary.en
|
|
7942
8036
|
}),
|
|
7943
8037
|
summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7944
|
-
className: open ? `${
|
|
8038
|
+
className: open ? `${_dsh_plugin_shop_css_58798e8a_default.summaryZh} ${_dsh_plugin_shop_css_58798e8a_default.summaryZhExpanded}` : _dsh_plugin_shop_css_58798e8a_default.summaryZh,
|
|
7945
8039
|
children: summary.zh
|
|
7946
8040
|
}),
|
|
7947
8041
|
blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
7948
8042
|
blocker,
|
|
7949
|
-
className:
|
|
8043
|
+
className: _dsh_plugin_shop_css_58798e8a_default.incompatibleDetail,
|
|
7950
8044
|
surface: "detail"
|
|
7951
8045
|
}, blocker.kind)),
|
|
7952
8046
|
open && entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7953
|
-
className:
|
|
8047
|
+
className: _dsh_plugin_shop_css_58798e8a_default.capabilitiesBlock,
|
|
7954
8048
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7955
|
-
className:
|
|
8049
|
+
className: _dsh_plugin_shop_css_58798e8a_default.capabilitiesNote,
|
|
7956
8050
|
children: t("capabilitiesNote")
|
|
7957
8051
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
7958
|
-
className:
|
|
8052
|
+
className: _dsh_plugin_shop_css_58798e8a_default.capabilities,
|
|
7959
8053
|
children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
|
|
7960
8054
|
})]
|
|
7961
8055
|
}),
|
|
7962
8056
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
7963
8057
|
id: detailId,
|
|
7964
|
-
className:
|
|
8058
|
+
className: _dsh_plugin_shop_css_58798e8a_default.detail,
|
|
7965
8059
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
7966
|
-
className:
|
|
8060
|
+
className: _dsh_plugin_shop_css_58798e8a_default.detailRows,
|
|
7967
8061
|
children: [
|
|
7968
8062
|
npmUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7969
|
-
className:
|
|
8063
|
+
className: _dsh_plugin_shop_css_58798e8a_default.detailRow,
|
|
7970
8064
|
"data-shop-npm": true,
|
|
7971
8065
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("npmPage") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
7972
8066
|
href: npmUrl,
|
|
@@ -7976,7 +8070,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7976
8070
|
}) })]
|
|
7977
8071
|
}),
|
|
7978
8072
|
entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7979
|
-
className:
|
|
8073
|
+
className: _dsh_plugin_shop_css_58798e8a_default.detailRow,
|
|
7980
8074
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("repository") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /^https?:\/\//.test(entry.repository) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
7981
8075
|
href: entry.repository,
|
|
7982
8076
|
target: "_blank",
|
|
@@ -7985,12 +8079,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7985
8079
|
}) : entry.repository })]
|
|
7986
8080
|
}),
|
|
7987
8081
|
entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7988
|
-
className:
|
|
8082
|
+
className: _dsh_plugin_shop_css_58798e8a_default.detailRow,
|
|
7989
8083
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("license") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: isCustomLicense(entry.license) ? t("customLicense") : entry.license })]
|
|
7990
8084
|
})
|
|
7991
8085
|
]
|
|
7992
8086
|
}), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7993
|
-
className:
|
|
8087
|
+
className: _dsh_plugin_shop_css_58798e8a_default.reviewedLine,
|
|
7994
8088
|
children: entry.review.reviewedVersion !== void 0 ? t("reviewedVersionLine", {
|
|
7995
8089
|
reviewed: entry.review.reviewedVersion,
|
|
7996
8090
|
current: entry.version
|
|
@@ -8003,7 +8097,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8003
8097
|
]
|
|
8004
8098
|
}),
|
|
8005
8099
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8006
|
-
className:
|
|
8100
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cardActions,
|
|
8007
8101
|
"data-shop-actions": true,
|
|
8008
8102
|
children: [installed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!inInstalledView && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
|
|
8009
8103
|
target: installTarget,
|
|
@@ -8035,7 +8129,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8035
8129
|
restartBlocked,
|
|
8036
8130
|
reload
|
|
8037
8131
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8038
|
-
className:
|
|
8132
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installedLabel,
|
|
8039
8133
|
"data-shop-installed": true,
|
|
8040
8134
|
children: t("installed")
|
|
8041
8135
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerBadge, {
|
|
@@ -8046,6 +8140,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8046
8140
|
row: installed,
|
|
8047
8141
|
t,
|
|
8048
8142
|
setEnabled,
|
|
8143
|
+
restart,
|
|
8144
|
+
restartBlocked,
|
|
8049
8145
|
reload
|
|
8050
8146
|
}),
|
|
8051
8147
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UninstallPanel, {
|
|
@@ -8057,16 +8153,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8057
8153
|
flow: uninstallFlow
|
|
8058
8154
|
})
|
|
8059
8155
|
] }), (size !== void 0 || author !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8060
|
-
className:
|
|
8156
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cardMeta,
|
|
8061
8157
|
children: [size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8062
|
-
className:
|
|
8158
|
+
className: _dsh_plugin_shop_css_58798e8a_default.size,
|
|
8063
8159
|
"data-shop-size": true,
|
|
8064
8160
|
role: "img",
|
|
8065
8161
|
"aria-label": t("sizeLabel", { size }),
|
|
8066
8162
|
title: t("sizeLabel", { size }),
|
|
8067
8163
|
children: size
|
|
8068
8164
|
}), author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8069
|
-
className:
|
|
8165
|
+
className: _dsh_plugin_shop_css_58798e8a_default.author,
|
|
8070
8166
|
"data-shop-author": true,
|
|
8071
8167
|
children: t("authorLine", { author })
|
|
8072
8168
|
})]
|
|
@@ -8115,13 +8211,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8115
8211
|
...attribute,
|
|
8116
8212
|
children: blocker.text
|
|
8117
8213
|
}), blocker.remedy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8118
|
-
className:
|
|
8214
|
+
className: _dsh_plugin_shop_css_58798e8a_default.remedy,
|
|
8119
8215
|
"data-shop-remedy": blocker.kind,
|
|
8120
8216
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8121
|
-
className:
|
|
8217
|
+
className: _dsh_plugin_shop_css_58798e8a_default.remedyLead,
|
|
8122
8218
|
children: blocker.remedy.lead
|
|
8123
8219
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
8124
|
-
className:
|
|
8220
|
+
className: _dsh_plugin_shop_css_58798e8a_default.allowCommand,
|
|
8125
8221
|
"data-shop-allow-command": true,
|
|
8126
8222
|
children: blocker.remedy.command
|
|
8127
8223
|
})]
|
|
@@ -8159,7 +8255,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8159
8255
|
if (lead === void 0 || word === null) return null;
|
|
8160
8256
|
const detail = blockers.map((blocker) => blocker.text).join("\n");
|
|
8161
8257
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8162
|
-
className:
|
|
8258
|
+
className: _dsh_plugin_shop_css_58798e8a_default.incompatibleBadge,
|
|
8163
8259
|
"data-shop-blocker": lead.kind,
|
|
8164
8260
|
role: "img",
|
|
8165
8261
|
"aria-label": detail,
|
|
@@ -8176,33 +8272,40 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8176
8272
|
const [gateOpen, setGateOpen] = (0, react.useState)(false);
|
|
8177
8273
|
const { view, start } = flow;
|
|
8178
8274
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8179
|
-
className:
|
|
8275
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installPanel,
|
|
8180
8276
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8181
|
-
className:
|
|
8277
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installing,
|
|
8182
8278
|
children: t(installPhaseKey(view.phase))
|
|
8183
8279
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8184
|
-
className:
|
|
8280
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
8185
8281
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8186
|
-
className:
|
|
8282
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
8283
|
+
"data-shop-log-line": true,
|
|
8187
8284
|
children: line
|
|
8188
8285
|
}, index))
|
|
8189
8286
|
})]
|
|
8190
8287
|
});
|
|
8191
8288
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8192
|
-
className:
|
|
8289
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installedActions,
|
|
8193
8290
|
children: [
|
|
8194
8291
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8195
|
-
className:
|
|
8292
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
8196
8293
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8197
|
-
className:
|
|
8294
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
8295
|
+
"data-shop-log-line": true,
|
|
8198
8296
|
children: line
|
|
8199
8297
|
}, index))
|
|
8200
8298
|
}),
|
|
8201
8299
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8202
|
-
className:
|
|
8300
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8203
8301
|
"data-shop-restart-notice": true,
|
|
8204
8302
|
children: t(activationNoticeKey(view.activation, view.restartReason))
|
|
8205
8303
|
}),
|
|
8304
|
+
view.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8305
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8306
|
+
"data-shop-done-note": true,
|
|
8307
|
+
children: view.detail
|
|
8308
|
+
}),
|
|
8206
8309
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivationOffer, {
|
|
8207
8310
|
activation: view.activation,
|
|
8208
8311
|
t,
|
|
@@ -8214,56 +8317,57 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8214
8317
|
]
|
|
8215
8318
|
});
|
|
8216
8319
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8217
|
-
className:
|
|
8320
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installPanel,
|
|
8218
8321
|
children: [
|
|
8219
8322
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8220
|
-
className:
|
|
8323
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedHeading,
|
|
8221
8324
|
children: t("installFailed")
|
|
8222
8325
|
}),
|
|
8223
8326
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8224
|
-
className:
|
|
8327
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
8225
8328
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8226
|
-
className:
|
|
8329
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
8330
|
+
"data-shop-log-line": true,
|
|
8227
8331
|
children: line
|
|
8228
8332
|
}, index))
|
|
8229
8333
|
}),
|
|
8230
8334
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8231
|
-
className:
|
|
8335
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
8232
8336
|
children: view.detail === "" ? t("installTransportFailed") : view.detail
|
|
8233
8337
|
})
|
|
8234
8338
|
]
|
|
8235
8339
|
});
|
|
8236
8340
|
if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8237
|
-
className:
|
|
8341
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installPanel,
|
|
8238
8342
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8239
|
-
className:
|
|
8343
|
+
className: _dsh_plugin_shop_css_58798e8a_default.rejectedCode,
|
|
8240
8344
|
children: t(rejectionCodeKey(view.code))
|
|
8241
8345
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8242
|
-
className:
|
|
8346
|
+
className: _dsh_plugin_shop_css_58798e8a_default.rejectedDetail,
|
|
8243
8347
|
children: view.detail
|
|
8244
8348
|
})]
|
|
8245
8349
|
});
|
|
8246
8350
|
if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8247
|
-
className:
|
|
8351
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gate,
|
|
8248
8352
|
children: [
|
|
8249
8353
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8250
|
-
className:
|
|
8354
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateTitle,
|
|
8251
8355
|
children: t("acknowledgementTitle")
|
|
8252
8356
|
}),
|
|
8253
8357
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8254
|
-
className:
|
|
8358
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateBody,
|
|
8255
8359
|
children: t("acknowledgementBody")
|
|
8256
8360
|
}),
|
|
8257
8361
|
!blockersStated && blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
8258
8362
|
blocker,
|
|
8259
|
-
className:
|
|
8363
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateWarning,
|
|
8260
8364
|
surface: "warning"
|
|
8261
8365
|
}, blocker.kind)),
|
|
8262
8366
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8263
|
-
className:
|
|
8367
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateActions,
|
|
8264
8368
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8265
8369
|
type: "button",
|
|
8266
|
-
className:
|
|
8370
|
+
className: _dsh_plugin_shop_css_58798e8a_default.confirmButton,
|
|
8267
8371
|
"data-shop-confirm": true,
|
|
8268
8372
|
onClick: () => {
|
|
8269
8373
|
setGateOpen(false);
|
|
@@ -8275,7 +8379,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8275
8379
|
children: t("confirm")
|
|
8276
8380
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8277
8381
|
type: "button",
|
|
8278
|
-
className:
|
|
8382
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cancelButton,
|
|
8279
8383
|
onClick: () => setGateOpen(false),
|
|
8280
8384
|
children: t("cancel")
|
|
8281
8385
|
})]
|
|
@@ -8287,7 +8391,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8287
8391
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
8288
8392
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8289
8393
|
type: "button",
|
|
8290
|
-
className:
|
|
8394
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installButton,
|
|
8291
8395
|
disabled: refused,
|
|
8292
8396
|
...refused ? { "data-shop-refused": true } : {},
|
|
8293
8397
|
...update ? { "data-shop-update": true } : { "data-shop-install": true },
|
|
@@ -8305,11 +8409,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8305
8409
|
t
|
|
8306
8410
|
}),
|
|
8307
8411
|
refused && !blockersStated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8308
|
-
className:
|
|
8412
|
+
className: _dsh_plugin_shop_css_58798e8a_default.refusal,
|
|
8309
8413
|
"data-shop-refusal": true,
|
|
8310
8414
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
8311
8415
|
blocker,
|
|
8312
|
-
className:
|
|
8416
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateWarning,
|
|
8313
8417
|
surface: "warning"
|
|
8314
8418
|
}, blocker.kind))
|
|
8315
8419
|
})
|
|
@@ -8324,23 +8428,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8324
8428
|
function UninstallPanel({ name, t, restart, restartBlocked, reload, flow }) {
|
|
8325
8429
|
const { view, start, reset } = flow;
|
|
8326
8430
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8327
|
-
className:
|
|
8431
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installPanel,
|
|
8328
8432
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8329
|
-
className:
|
|
8433
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installing,
|
|
8330
8434
|
children: t("uninstalling")
|
|
8331
8435
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8332
|
-
className:
|
|
8436
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
8333
8437
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8334
|
-
className:
|
|
8438
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
8439
|
+
"data-shop-log-line": true,
|
|
8335
8440
|
children: line
|
|
8336
8441
|
}, index))
|
|
8337
8442
|
})]
|
|
8338
8443
|
});
|
|
8339
8444
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8340
|
-
className:
|
|
8445
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installedActions,
|
|
8341
8446
|
children: [
|
|
8447
|
+
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8448
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
8449
|
+
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8450
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
8451
|
+
"data-shop-log-line": true,
|
|
8452
|
+
children: line
|
|
8453
|
+
}, index))
|
|
8454
|
+
}),
|
|
8342
8455
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8343
|
-
className:
|
|
8456
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8344
8457
|
"data-shop-uninstall-done": true,
|
|
8345
8458
|
children: t(uninstallActivationNoticeKey(view.activation))
|
|
8346
8459
|
}),
|
|
@@ -8354,7 +8467,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8354
8467
|
}),
|
|
8355
8468
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8356
8469
|
type: "button",
|
|
8357
|
-
className:
|
|
8470
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cancelButton,
|
|
8358
8471
|
"data-shop-uninstall-dismiss": true,
|
|
8359
8472
|
onClick: reset,
|
|
8360
8473
|
children: t("dismiss")
|
|
@@ -8362,26 +8475,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8362
8475
|
]
|
|
8363
8476
|
});
|
|
8364
8477
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8365
|
-
className:
|
|
8478
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installPanel,
|
|
8366
8479
|
children: [
|
|
8367
8480
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8368
|
-
className:
|
|
8481
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedHeading,
|
|
8369
8482
|
children: t("uninstallFailed")
|
|
8370
8483
|
}),
|
|
8371
8484
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8372
|
-
className:
|
|
8485
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
8373
8486
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8374
|
-
className:
|
|
8487
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
8488
|
+
"data-shop-log-line": true,
|
|
8375
8489
|
children: line
|
|
8376
8490
|
}, index))
|
|
8377
8491
|
}),
|
|
8378
8492
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8379
|
-
className:
|
|
8493
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
8380
8494
|
children: view.detail === "" ? t("uninstallTransportFailed") : view.detail
|
|
8381
8495
|
}),
|
|
8382
8496
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8383
8497
|
type: "button",
|
|
8384
|
-
className:
|
|
8498
|
+
className: _dsh_plugin_shop_css_58798e8a_default.uninstallButton,
|
|
8385
8499
|
"data-shop-uninstall-retry": true,
|
|
8386
8500
|
onClick: () => void start({ name }),
|
|
8387
8501
|
children: t("retry")
|
|
@@ -8391,7 +8505,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8391
8505
|
if (view.kind !== "idle") return null;
|
|
8392
8506
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8393
8507
|
type: "button",
|
|
8394
|
-
className:
|
|
8508
|
+
className: _dsh_plugin_shop_css_58798e8a_default.uninstallButton,
|
|
8395
8509
|
"data-shop-uninstall": true,
|
|
8396
8510
|
onClick: () => void start({ name }),
|
|
8397
8511
|
children: t("uninstall")
|
|
@@ -8406,12 +8520,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8406
8520
|
/** The §8 restart flow (amendment 2026-08-27): after an install, update, or
|
|
8407
8521
|
* uninstall reports done, this panel offers a restart of dsh. The
|
|
8408
8522
|
* confirmation gate states the cost — the page disconnects and in-flight
|
|
8409
|
-
* conversations/tasks are interrupted — and on confirm the
|
|
8410
|
-
* commits the two-phase handoff: the host exits,
|
|
8411
|
-
* the page's
|
|
8412
|
-
*
|
|
8413
|
-
*
|
|
8414
|
-
* never comes back names the manual command. */
|
|
8523
|
+
* conversations/tasks are interrupted — and on confirm the page asks the host
|
|
8524
|
+
* (restart-monitor.ts), which commits the two-phase handoff: the host exits,
|
|
8525
|
+
* a helper re-runs dsh, and the page's monitor polls the origin after a grace
|
|
8526
|
+
* period, refreshing the page once the NEW server keeps answering. A refused
|
|
8527
|
+
* restart renders the host's published detail above the offer, which stays;
|
|
8528
|
+
* a server that never comes back names the manual command. */
|
|
8415
8529
|
function RestartPanel({ t, restart, reload, gate }) {
|
|
8416
8530
|
const [ownGateOpen, setOwnGateOpen] = (0, react.useState)(false);
|
|
8417
8531
|
const gateOpen = gate === void 0 ? ownGateOpen : gate.open;
|
|
@@ -8423,71 +8537,65 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8423
8537
|
const monitor = useRestartMonitor();
|
|
8424
8538
|
const onConfirm = async () => {
|
|
8425
8539
|
setGateOpen(false);
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
reload,
|
|
8434
|
-
...typeof result.logFile === "string" ? { logFile: result.logFile } : {}
|
|
8435
|
-
});
|
|
8436
|
-
} catch {
|
|
8437
|
-
setRefusal(t("restartTransportFailed"));
|
|
8438
|
-
}
|
|
8540
|
+
setRefusal(null);
|
|
8541
|
+
const outcome = await requestRestart({
|
|
8542
|
+
reload,
|
|
8543
|
+
restart
|
|
8544
|
+
});
|
|
8545
|
+
if (outcome.kind === "refused") setRefusal(outcome.detail);
|
|
8546
|
+
else if (outcome.kind === "unreachable") setRefusal(t("restartTransportFailed"));
|
|
8439
8547
|
};
|
|
8440
|
-
if (monitor?.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8441
|
-
className:
|
|
8548
|
+
if (monitor?.kind === "requesting" || monitor?.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8549
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8442
8550
|
"data-shop-restarting": true,
|
|
8443
8551
|
children: t("restarting")
|
|
8444
8552
|
});
|
|
8445
8553
|
if (monitor?.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8446
|
-
className:
|
|
8554
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
8447
8555
|
"data-shop-restart-error": true,
|
|
8448
8556
|
children: monitor.logFile === void 0 ? t("restartFailedNotice") : t("restartFailedLogNotice", { log: monitor.logFile })
|
|
8449
8557
|
});
|
|
8450
|
-
if (refusal !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8451
|
-
className: _dsh_plugin_shop_css_c4028823_default.failedDetail,
|
|
8452
|
-
"data-shop-restart-error": true,
|
|
8453
|
-
children: refusal
|
|
8454
|
-
});
|
|
8455
8558
|
if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8456
|
-
className:
|
|
8559
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gate,
|
|
8457
8560
|
children: [
|
|
8458
8561
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8459
|
-
className:
|
|
8562
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateTitle,
|
|
8460
8563
|
children: t("restartTitle")
|
|
8461
8564
|
}),
|
|
8462
8565
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8463
|
-
className:
|
|
8566
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateBody,
|
|
8464
8567
|
children: t("restartBody")
|
|
8465
8568
|
}),
|
|
8466
8569
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8467
|
-
className:
|
|
8570
|
+
className: _dsh_plugin_shop_css_58798e8a_default.gateActions,
|
|
8468
8571
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8469
8572
|
type: "button",
|
|
8470
|
-
className:
|
|
8573
|
+
className: _dsh_plugin_shop_css_58798e8a_default.confirmButton,
|
|
8471
8574
|
"data-shop-restart-confirm": true,
|
|
8472
8575
|
onClick: () => void onConfirm(),
|
|
8473
8576
|
children: t("restartConfirm")
|
|
8474
8577
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8475
8578
|
type: "button",
|
|
8476
|
-
className:
|
|
8579
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cancelButton,
|
|
8477
8580
|
onClick: () => setGateOpen(false),
|
|
8478
8581
|
children: t("cancel")
|
|
8479
8582
|
})]
|
|
8480
8583
|
})
|
|
8481
8584
|
]
|
|
8482
8585
|
});
|
|
8483
|
-
|
|
8484
|
-
|
|
8586
|
+
const refused = refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8587
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
8588
|
+
"data-shop-restart-error": true,
|
|
8589
|
+
children: refusal
|
|
8590
|
+
});
|
|
8591
|
+
if (gate !== void 0) return refused;
|
|
8592
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [refused, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8485
8593
|
type: "button",
|
|
8486
|
-
className:
|
|
8594
|
+
className: _dsh_plugin_shop_css_58798e8a_default.restartButton,
|
|
8487
8595
|
"data-shop-restart": true,
|
|
8488
8596
|
onClick: () => setGateOpen(true),
|
|
8489
8597
|
children: t("restart")
|
|
8490
|
-
});
|
|
8598
|
+
})] });
|
|
8491
8599
|
}
|
|
8492
8600
|
/**
|
|
8493
8601
|
* The §4/§8 offer under a settled install, update or uninstall: a reload
|
|
@@ -8514,7 +8622,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8514
8622
|
restart,
|
|
8515
8623
|
reload
|
|
8516
8624
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8517
|
-
className:
|
|
8625
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8518
8626
|
"data-shop-restart-disabled": true,
|
|
8519
8627
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
8520
8628
|
});
|
|
@@ -8525,14 +8633,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8525
8633
|
* would help without knowing that now is a good time. */
|
|
8526
8634
|
function ReloadPanel({ t, reload, where }) {
|
|
8527
8635
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8528
|
-
className:
|
|
8636
|
+
className: _dsh_plugin_shop_css_58798e8a_default.reloadPanel,
|
|
8529
8637
|
"data-shop-reload": where,
|
|
8530
8638
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8531
|
-
className:
|
|
8639
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8532
8640
|
children: t("reloadNote")
|
|
8533
8641
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8534
8642
|
type: "button",
|
|
8535
|
-
className:
|
|
8643
|
+
className: _dsh_plugin_shop_css_58798e8a_default.reloadButton,
|
|
8536
8644
|
onClick: reload,
|
|
8537
8645
|
children: t("reload")
|
|
8538
8646
|
})]
|
|
@@ -8545,10 +8653,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8545
8653
|
* transport throw renders the localized failure line — its private detail
|
|
8546
8654
|
* (which can name hosts and ports) never reaches the UI.
|
|
8547
8655
|
*/
|
|
8548
|
-
function EnabledSwitch({ row, t, setEnabled, reload }) {
|
|
8656
|
+
function EnabledSwitch({ row, t, setEnabled, restart, restartBlocked, reload }) {
|
|
8549
8657
|
const [enabled, setEnabledState] = (0, react.useState)(row.enabled);
|
|
8550
8658
|
const [toggle, setToggle] = (0, react.useState)({ kind: "idle" });
|
|
8551
|
-
const [
|
|
8659
|
+
const [owed, setOwed] = (0, react.useState)("nothing");
|
|
8552
8660
|
const onToggle = async () => {
|
|
8553
8661
|
if (toggle.kind === "saving") return;
|
|
8554
8662
|
const next = !enabled;
|
|
@@ -8561,7 +8669,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8561
8669
|
if (result.ok) {
|
|
8562
8670
|
setEnabledState(next);
|
|
8563
8671
|
setToggle({ kind: "saved" });
|
|
8564
|
-
if (result.activation
|
|
8672
|
+
if (result.activation === "restart") setOwed("restart");
|
|
8673
|
+
else if (result.activation !== "live") setOwed((previous) => previous === "restart" ? previous : "reload");
|
|
8565
8674
|
} else setToggle({
|
|
8566
8675
|
kind: "error",
|
|
8567
8676
|
detail: result.detail || t("toggleFailed")
|
|
@@ -8574,7 +8683,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8574
8683
|
}
|
|
8575
8684
|
};
|
|
8576
8685
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8577
|
-
className:
|
|
8686
|
+
className: _dsh_plugin_shop_css_58798e8a_default.switchWrap,
|
|
8578
8687
|
"data-shop-enabled-switch": row.name,
|
|
8579
8688
|
children: [
|
|
8580
8689
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -8583,23 +8692,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8583
8692
|
"aria-checked": enabled,
|
|
8584
8693
|
"aria-label": t("enabledSwitch"),
|
|
8585
8694
|
"data-shop-toggle": true,
|
|
8586
|
-
className: `${
|
|
8695
|
+
className: `${_dsh_plugin_shop_css_58798e8a_default.switch} ${enabled ? _dsh_plugin_shop_css_58798e8a_default.switchOn : ""}`,
|
|
8587
8696
|
onClick: () => void onToggle(),
|
|
8588
8697
|
disabled: toggle.kind === "saving",
|
|
8589
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
8698
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_58798e8a_default.switchKnob })
|
|
8590
8699
|
}),
|
|
8591
|
-
toggle.kind === "saved" &&
|
|
8592
|
-
className:
|
|
8700
|
+
toggle.kind === "saved" && owed === "nothing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8701
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8593
8702
|
"data-shop-hot-apply": true,
|
|
8594
8703
|
children: t("hotApplyNote")
|
|
8595
8704
|
}),
|
|
8596
|
-
|
|
8705
|
+
owed === "restart" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8706
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
8707
|
+
"data-shop-toggle-restart": true,
|
|
8708
|
+
children: t("toggleRestartNote")
|
|
8709
|
+
}),
|
|
8710
|
+
owed !== "nothing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivationOffer, {
|
|
8711
|
+
activation: owed,
|
|
8597
8712
|
t,
|
|
8713
|
+
restart,
|
|
8714
|
+
restartBlocked,
|
|
8598
8715
|
reload,
|
|
8599
8716
|
where: "toggle"
|
|
8600
8717
|
}),
|
|
8601
8718
|
toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8602
|
-
className:
|
|
8719
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
8603
8720
|
"data-shop-toggle-error": true,
|
|
8604
8721
|
children: toggle.detail
|
|
8605
8722
|
})
|
|
@@ -8611,23 +8728,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8611
8728
|
* install flow for `name@latest`, reusing `InstallPanel`). */
|
|
8612
8729
|
function OutdatedRow({ row, tier, missing, harness, t, setEnabled, flowFor, restart, restartBlocked, reload }) {
|
|
8613
8730
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8614
|
-
className:
|
|
8731
|
+
className: _dsh_plugin_shop_css_58798e8a_default.outdatedRow,
|
|
8615
8732
|
"data-shop-outdated-entry": row.name,
|
|
8616
8733
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8617
|
-
className:
|
|
8734
|
+
className: _dsh_plugin_shop_css_58798e8a_default.outdatedInfo,
|
|
8618
8735
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8619
|
-
className:
|
|
8736
|
+
className: _dsh_plugin_shop_css_58798e8a_default.name,
|
|
8620
8737
|
children: row.name
|
|
8621
8738
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8622
|
-
className:
|
|
8739
|
+
className: _dsh_plugin_shop_css_58798e8a_default.outdatedVersions,
|
|
8623
8740
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installedVersion", { version: row.source === "github" ? row.installed.slice(0, 7) : row.installed }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("latestVersion", { version: row.latest }) })]
|
|
8624
8741
|
})]
|
|
8625
8742
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8626
|
-
className:
|
|
8743
|
+
className: _dsh_plugin_shop_css_58798e8a_default.outdatedActions,
|
|
8627
8744
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnabledSwitch, {
|
|
8628
8745
|
row,
|
|
8629
8746
|
t,
|
|
8630
8747
|
setEnabled,
|
|
8748
|
+
restart,
|
|
8749
|
+
restartBlocked,
|
|
8631
8750
|
reload
|
|
8632
8751
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
|
|
8633
8752
|
target: {
|
|
@@ -8669,22 +8788,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8669
8788
|
function OutdatedSection({ state, entriesByKey, missingByKey, harnessVerdicts, t, setEnabled, flowFor, restart, restartBlocked, reload }) {
|
|
8670
8789
|
if (state.kind === "loading") return null;
|
|
8671
8790
|
if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8672
|
-
className:
|
|
8791
|
+
className: _dsh_plugin_shop_css_58798e8a_default.stateLine,
|
|
8673
8792
|
"data-shop-outdated-error": true,
|
|
8674
8793
|
children: t("installedError")
|
|
8675
8794
|
});
|
|
8676
8795
|
const outdated = state.entries.filter((entry) => entry.outdated);
|
|
8677
8796
|
if (outdated.length === 0) return null;
|
|
8678
8797
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
8679
|
-
className:
|
|
8798
|
+
className: _dsh_plugin_shop_css_58798e8a_default.outdatedSection,
|
|
8680
8799
|
"data-shop-outdated": true,
|
|
8681
8800
|
"aria-labelledby": UPDATABLE_HEADING_ID,
|
|
8682
8801
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
8683
|
-
className:
|
|
8802
|
+
className: _dsh_plugin_shop_css_58798e8a_default.updatableHeading,
|
|
8684
8803
|
id: UPDATABLE_HEADING_ID,
|
|
8685
8804
|
children: t("updatableSection")
|
|
8686
8805
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
8687
|
-
className:
|
|
8806
|
+
className: _dsh_plugin_shop_css_58798e8a_default.outdatedList,
|
|
8688
8807
|
children: outdated.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
|
|
8689
8808
|
row,
|
|
8690
8809
|
tier: entriesByKey.get(identityKey(row))?.tier ?? "community",
|
|
@@ -8735,16 +8854,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8735
8854
|
role: "alert",
|
|
8736
8855
|
children: [
|
|
8737
8856
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8738
|
-
className:
|
|
8857
|
+
className: _dsh_plugin_shop_css_58798e8a_default.stateLine,
|
|
8739
8858
|
children: say("tabCrashed", en.tabCrashed)
|
|
8740
8859
|
}),
|
|
8741
8860
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
8742
|
-
className:
|
|
8861
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
8743
8862
|
children: error.message
|
|
8744
8863
|
}),
|
|
8745
8864
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8746
8865
|
type: "button",
|
|
8747
|
-
className:
|
|
8866
|
+
className: _dsh_plugin_shop_css_58798e8a_default.actionButton,
|
|
8748
8867
|
onClick: () => this.setState({ error: null }),
|
|
8749
8868
|
children: say("retry", en.retry)
|
|
8750
8869
|
})
|
|
@@ -9001,19 +9120,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9001
9120
|
"data-shop-tab": true,
|
|
9002
9121
|
"aria-busy": "true",
|
|
9003
9122
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9004
|
-
className:
|
|
9123
|
+
className: _dsh_plugin_shop_css_58798e8a_default.srOnly,
|
|
9005
9124
|
children: t("loading")
|
|
9006
9125
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9007
|
-
className:
|
|
9126
|
+
className: _dsh_plugin_shop_css_58798e8a_default.skeletonGrid,
|
|
9008
9127
|
"data-shop-skeleton": true,
|
|
9009
9128
|
"aria-hidden": "true",
|
|
9010
9129
|
children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9011
|
-
className:
|
|
9130
|
+
className: _dsh_plugin_shop_css_58798e8a_default.skeletonCard,
|
|
9012
9131
|
children: [
|
|
9013
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
9014
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
9015
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
9016
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
9132
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_58798e8a_default.skeletonName }),
|
|
9133
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_58798e8a_default.skeletonSummary }),
|
|
9134
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_58798e8a_default.skeletonSummaryShort }),
|
|
9135
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_58798e8a_default.skeletonActions })
|
|
9017
9136
|
]
|
|
9018
9137
|
}, i))
|
|
9019
9138
|
})]
|
|
@@ -9023,11 +9142,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9023
9142
|
translate: "no",
|
|
9024
9143
|
"data-shop-tab": true,
|
|
9025
9144
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9026
|
-
className:
|
|
9145
|
+
className: _dsh_plugin_shop_css_58798e8a_default.stateLine,
|
|
9027
9146
|
children: t("error")
|
|
9028
9147
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9029
9148
|
type: "button",
|
|
9030
|
-
className:
|
|
9149
|
+
className: _dsh_plugin_shop_css_58798e8a_default.actionButton,
|
|
9031
9150
|
onClick: () => {
|
|
9032
9151
|
setRequest({ kind: "retry" });
|
|
9033
9152
|
setVersionReload((current) => current + 1);
|
|
@@ -9042,10 +9161,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9042
9161
|
"data-shop-tab": true,
|
|
9043
9162
|
children: [
|
|
9044
9163
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9045
|
-
className:
|
|
9164
|
+
className: _dsh_plugin_shop_css_58798e8a_default.toolbar,
|
|
9046
9165
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9047
9166
|
type: "search",
|
|
9048
|
-
className:
|
|
9167
|
+
className: _dsh_plugin_shop_css_58798e8a_default.searchInput,
|
|
9049
9168
|
"aria-label": t("search"),
|
|
9050
9169
|
placeholder: t("search"),
|
|
9051
9170
|
value: query,
|
|
@@ -9054,27 +9173,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9054
9173
|
setVisibleCount(48);
|
|
9055
9174
|
}
|
|
9056
9175
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9057
|
-
className:
|
|
9176
|
+
className: _dsh_plugin_shop_css_58798e8a_default.toolbarRight,
|
|
9058
9177
|
children: [
|
|
9059
9178
|
result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9060
|
-
className:
|
|
9179
|
+
className: _dsh_plugin_shop_css_58798e8a_default.staleBadge,
|
|
9061
9180
|
children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
|
|
9062
9181
|
}),
|
|
9063
9182
|
selfVersion !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9064
|
-
className:
|
|
9183
|
+
className: _dsh_plugin_shop_css_58798e8a_default.versionBlock,
|
|
9065
9184
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9066
|
-
className:
|
|
9185
|
+
className: _dsh_plugin_shop_css_58798e8a_default.versionText,
|
|
9067
9186
|
"data-shop-version": true,
|
|
9068
9187
|
children: ["v", selfVersion.installed]
|
|
9069
9188
|
}), restartMonitor !== null ? null : selfPending && restartBlocked === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9070
9189
|
type: "button",
|
|
9071
|
-
className:
|
|
9190
|
+
className: _dsh_plugin_shop_css_58798e8a_default.restartSelfButton,
|
|
9072
9191
|
"data-shop-restart": true,
|
|
9073
9192
|
onClick: () => setSelfRestartGate(true),
|
|
9074
9193
|
children: t("restart")
|
|
9075
9194
|
}) : !selfPending && selfVersion.outdated && selfVersion.latest !== null && selfUpdate.view.kind === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9076
9195
|
type: "button",
|
|
9077
|
-
className:
|
|
9196
|
+
className: _dsh_plugin_shop_css_58798e8a_default.updateSelfButton,
|
|
9078
9197
|
"data-shop-update-self": true,
|
|
9079
9198
|
onClick: () => {
|
|
9080
9199
|
if (selfVersion.latest !== null) selfUpdate.start({ version: selfVersion.latest });
|
|
@@ -9082,7 +9201,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9082
9201
|
children: t("update")
|
|
9083
9202
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9084
9203
|
type: "button",
|
|
9085
|
-
className:
|
|
9204
|
+
className: _dsh_plugin_shop_css_58798e8a_default.checkUpdateButton,
|
|
9086
9205
|
"data-shop-check-update": true,
|
|
9087
9206
|
title: t("checkUpdateTitle"),
|
|
9088
9207
|
disabled: checkState !== "idle",
|
|
@@ -9091,7 +9210,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9091
9210
|
})]
|
|
9092
9211
|
}),
|
|
9093
9212
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
9094
|
-
className:
|
|
9213
|
+
className: _dsh_plugin_shop_css_58798e8a_default.githubLink,
|
|
9095
9214
|
href: SHOP_REPO_URL,
|
|
9096
9215
|
target: "_blank",
|
|
9097
9216
|
rel: "noopener noreferrer",
|
|
@@ -9110,27 +9229,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9110
9229
|
})]
|
|
9111
9230
|
}),
|
|
9112
9231
|
selfUpdate.view.kind === "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9113
|
-
className:
|
|
9232
|
+
className: _dsh_plugin_shop_css_58798e8a_default.selfUpdatePanel,
|
|
9114
9233
|
"data-shop-self-updating": true,
|
|
9115
9234
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9116
|
-
className:
|
|
9235
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installing,
|
|
9117
9236
|
children: t(installPhaseKey(selfUpdate.view.phase))
|
|
9118
9237
|
}), selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9119
|
-
className:
|
|
9238
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
9120
9239
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9121
|
-
className:
|
|
9240
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
9241
|
+
"data-shop-log-line": true,
|
|
9122
9242
|
children: line
|
|
9123
9243
|
}, index))
|
|
9124
9244
|
})]
|
|
9125
9245
|
}),
|
|
9126
9246
|
selfPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9127
|
-
className:
|
|
9247
|
+
className: _dsh_plugin_shop_css_58798e8a_default.selfUpdatePanel,
|
|
9128
9248
|
"data-shop-self-update-done": true,
|
|
9129
9249
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9130
|
-
className:
|
|
9250
|
+
className: _dsh_plugin_shop_css_58798e8a_default.installedActions,
|
|
9131
9251
|
children: [
|
|
9132
9252
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9133
|
-
className:
|
|
9253
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
9134
9254
|
children: t("installedRestartNotice")
|
|
9135
9255
|
}),
|
|
9136
9256
|
restartBlocked === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RestartPanel, {
|
|
@@ -9143,7 +9263,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9143
9263
|
}
|
|
9144
9264
|
}),
|
|
9145
9265
|
restartBlocked !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9146
|
-
className:
|
|
9266
|
+
className: _dsh_plugin_shop_css_58798e8a_default.notice,
|
|
9147
9267
|
"data-shop-restart-disabled": true,
|
|
9148
9268
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
9149
9269
|
})
|
|
@@ -9151,34 +9271,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9151
9271
|
})
|
|
9152
9272
|
}),
|
|
9153
9273
|
selfUpdate.view.kind === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9154
|
-
className:
|
|
9274
|
+
className: _dsh_plugin_shop_css_58798e8a_default.selfUpdatePanel,
|
|
9155
9275
|
"data-shop-self-update-failed": true,
|
|
9156
9276
|
children: [
|
|
9157
9277
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9158
|
-
className:
|
|
9278
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedHeading,
|
|
9159
9279
|
children: t("updateFailed")
|
|
9160
9280
|
}),
|
|
9161
9281
|
selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9162
|
-
className:
|
|
9282
|
+
className: _dsh_plugin_shop_css_58798e8a_default.log,
|
|
9163
9283
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9164
|
-
className:
|
|
9284
|
+
className: _dsh_plugin_shop_css_58798e8a_default.logLine,
|
|
9285
|
+
"data-shop-log-line": true,
|
|
9165
9286
|
children: line
|
|
9166
9287
|
}, index))
|
|
9167
9288
|
}),
|
|
9168
9289
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9169
|
-
className:
|
|
9290
|
+
className: _dsh_plugin_shop_css_58798e8a_default.failedDetail,
|
|
9170
9291
|
children: selfUpdate.view.detail === "" ? t("updateTransportFailed") : selfUpdate.view.detail
|
|
9171
9292
|
})
|
|
9172
9293
|
]
|
|
9173
9294
|
}),
|
|
9174
9295
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9175
|
-
className:
|
|
9296
|
+
className: _dsh_plugin_shop_css_58798e8a_default.categoryBar,
|
|
9176
9297
|
role: "group",
|
|
9177
9298
|
"aria-label": t("catalog"),
|
|
9178
9299
|
children: [
|
|
9179
9300
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
9180
9301
|
type: "button",
|
|
9181
|
-
className: category === null ? `${
|
|
9302
|
+
className: category === null ? `${_dsh_plugin_shop_css_58798e8a_default.categoryButton} ${_dsh_plugin_shop_css_58798e8a_default.categoryButtonOn}` : _dsh_plugin_shop_css_58798e8a_default.categoryButton,
|
|
9182
9303
|
"aria-pressed": category === null,
|
|
9183
9304
|
onClick: () => {
|
|
9184
9305
|
setCategory(null);
|
|
@@ -9193,7 +9314,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9193
9314
|
}),
|
|
9194
9315
|
CATEGORY_ORDER.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
9195
9316
|
type: "button",
|
|
9196
|
-
className: category === key ? `${
|
|
9317
|
+
className: category === key ? `${_dsh_plugin_shop_css_58798e8a_default.categoryButton} ${_dsh_plugin_shop_css_58798e8a_default.categoryButtonOn}` : _dsh_plugin_shop_css_58798e8a_default.categoryButton,
|
|
9197
9318
|
"aria-pressed": category === key,
|
|
9198
9319
|
"data-category": key,
|
|
9199
9320
|
"data-shop-category-tab": key,
|
|
@@ -9209,7 +9330,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9209
9330
|
}, key)),
|
|
9210
9331
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
9211
9332
|
type: "button",
|
|
9212
|
-
className: category === "installed" ? `${
|
|
9333
|
+
className: category === "installed" ? `${_dsh_plugin_shop_css_58798e8a_default.categoryButton} ${_dsh_plugin_shop_css_58798e8a_default.categoryButtonOn}` : _dsh_plugin_shop_css_58798e8a_default.categoryButton,
|
|
9213
9334
|
"aria-pressed": category === "installed",
|
|
9214
9335
|
"data-shop-category-installed": true,
|
|
9215
9336
|
onClick: () => {
|
|
@@ -9226,7 +9347,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9226
9347
|
type: "button",
|
|
9227
9348
|
role: "switch",
|
|
9228
9349
|
"aria-checked": hideIncompatible,
|
|
9229
|
-
className: hideIncompatible ? `${
|
|
9350
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_58798e8a_default.incompatibleFilter} ${_dsh_plugin_shop_css_58798e8a_default.incompatibleFilterOn}` : _dsh_plugin_shop_css_58798e8a_default.incompatibleFilter,
|
|
9230
9351
|
title: t(hideIncompatible ? "showIncompatibleTitle" : "incompatibleFilterTitle"),
|
|
9231
9352
|
"data-shop-hide-incompatible": true,
|
|
9232
9353
|
onClick: () => {
|
|
@@ -9234,18 +9355,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9234
9355
|
setVisibleCount(48);
|
|
9235
9356
|
},
|
|
9236
9357
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9237
|
-
className: hideIncompatible ? `${
|
|
9358
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_58798e8a_default.switch} ${_dsh_plugin_shop_css_58798e8a_default.switchOn}` : _dsh_plugin_shop_css_58798e8a_default.switch,
|
|
9238
9359
|
"aria-hidden": "true",
|
|
9239
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
9360
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_58798e8a_default.switchKnob })
|
|
9240
9361
|
}), t("hideIncompatible", { count: incompatibleCount })]
|
|
9241
9362
|
})
|
|
9242
9363
|
]
|
|
9243
9364
|
}),
|
|
9244
9365
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9245
|
-
className:
|
|
9366
|
+
className: _dsh_plugin_shop_css_58798e8a_default.catalogStatsRow,
|
|
9246
9367
|
children: [
|
|
9247
9368
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9248
|
-
className:
|
|
9369
|
+
className: _dsh_plugin_shop_css_58798e8a_default.catalogStats,
|
|
9249
9370
|
"data-shop-catalog-stats": true,
|
|
9250
9371
|
children: t("catalogStats", {
|
|
9251
9372
|
count: String(browsable.length),
|
|
@@ -9254,7 +9375,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9254
9375
|
}),
|
|
9255
9376
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9256
9377
|
type: "button",
|
|
9257
|
-
className:
|
|
9378
|
+
className: _dsh_plugin_shop_css_58798e8a_default.catalogRefreshButton,
|
|
9258
9379
|
"data-shop-catalog-refresh": true,
|
|
9259
9380
|
disabled: reloading,
|
|
9260
9381
|
onClick: () => {
|
|
@@ -9266,21 +9387,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9266
9387
|
children: reloading ? t("refreshing") : t("refresh")
|
|
9267
9388
|
}),
|
|
9268
9389
|
reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9269
|
-
className:
|
|
9390
|
+
className: _dsh_plugin_shop_css_58798e8a_default.catalogRefreshFailed,
|
|
9270
9391
|
"data-shop-catalog-refresh-failed": true,
|
|
9271
9392
|
children: t("refreshFailed")
|
|
9272
9393
|
})
|
|
9273
9394
|
]
|
|
9274
9395
|
}),
|
|
9275
9396
|
result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9276
|
-
className:
|
|
9397
|
+
className: _dsh_plugin_shop_css_58798e8a_default.emptyLine,
|
|
9277
9398
|
children: t("empty")
|
|
9278
9399
|
}) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9279
|
-
className:
|
|
9400
|
+
className: _dsh_plugin_shop_css_58798e8a_default.emptyLine,
|
|
9280
9401
|
"data-shop-empty": true,
|
|
9281
9402
|
children: matched.length > 0 ? t("emptyIncompatibleFiltered") : t("emptySearch")
|
|
9282
9403
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
9283
|
-
className:
|
|
9404
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cards,
|
|
9284
9405
|
children: [visible.map((entry) => {
|
|
9285
9406
|
const key = entryKey(entry);
|
|
9286
9407
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
|
|
@@ -9301,12 +9422,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9301
9422
|
}) }, key);
|
|
9302
9423
|
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
9303
9424
|
ref: sentinelRef,
|
|
9304
|
-
className:
|
|
9425
|
+
className: _dsh_plugin_shop_css_58798e8a_default.cardsSentry,
|
|
9305
9426
|
"data-shop-sentry": true,
|
|
9306
9427
|
"aria-hidden": "true"
|
|
9307
9428
|
})]
|
|
9308
9429
|
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9309
|
-
className:
|
|
9430
|
+
className: _dsh_plugin_shop_css_58798e8a_default.showingLine,
|
|
9310
9431
|
"aria-live": "polite",
|
|
9311
9432
|
children: t("showing", {
|
|
9312
9433
|
shown: String(visibleCount),
|
|
@@ -9377,7 +9498,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9377
9498
|
en
|
|
9378
9499
|
}), "dsh-plugin-shop: dictionaries");
|
|
9379
9500
|
const dispose = await ctx.remote.$mount(TYPERT_REMOTE);
|
|
9380
|
-
|
|
9501
|
+
let withdrawRestart = () => {};
|
|
9502
|
+
ctx.effect(() => () => {
|
|
9503
|
+
withdrawRestart();
|
|
9504
|
+
return dispose();
|
|
9505
|
+
}, "dsh-plugin-shop: shop remote mount");
|
|
9381
9506
|
const ns = ctx.get("remote.shop");
|
|
9382
9507
|
if (ns === void 0) throw new Error("dsh-plugin-shop: the shop remote did not register (service \"remote.shop\" missing after $mount)");
|
|
9383
9508
|
const unwrap = (result) => {
|
|
@@ -9427,6 +9552,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9427
9552
|
...result,
|
|
9428
9553
|
incompatible: await refineAgainstModuleTable(result.incompatible ?? {}, ctx.get("modules"), pageRemoved)
|
|
9429
9554
|
});
|
|
9555
|
+
const restart = async () => unwrap(await ns.restart());
|
|
9556
|
+
withdrawRestart = registerRestartCarrier(restart);
|
|
9430
9557
|
const injected = () => ({
|
|
9431
9558
|
catalog: async (args) => handOver(await hostCatalog(args)),
|
|
9432
9559
|
install: async (args) => {
|
|
@@ -9444,7 +9571,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9444
9571
|
noteUninstalled: (name) => {
|
|
9445
9572
|
pageRemoved.add(name);
|
|
9446
9573
|
},
|
|
9447
|
-
restart
|
|
9574
|
+
restart,
|
|
9448
9575
|
version: async () => unwrap(await ns.version()),
|
|
9449
9576
|
updateStart: async (args) => {
|
|
9450
9577
|
warmCatalog = null;
|