dsh-plugin-shop 0.8.6 → 0.8.7-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/client.js +548 -321
- package/lib/index.js +68 -28
- package/lib/typert.host.js +3 -1
- package/lib/typert.remote-client.js +2 -0
- package/lib/types/client/locales.d.ts +28 -0
- package/lib/types/client/present.d.ts +90 -12
- package/lib/types/host/compatibility.d.ts +29 -13
- package/lib/types/host/types.d.ts +24 -5
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -4321,12 +4321,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4321
4321
|
"profiles": union([_undefined(), array(string())]).optional()
|
|
4322
4322
|
})]).optional(),
|
|
4323
4323
|
"dshPeers": union([_undefined(), record(string(), string())]).optional(),
|
|
4324
|
+
"manifestVersion": union([_undefined(), string()]).optional(),
|
|
4324
4325
|
"unpackedSize": union([_undefined(), number()]).optional(),
|
|
4325
4326
|
"installSize": union([_undefined(), number()]).optional(),
|
|
4326
4327
|
"archived": union([
|
|
4327
4328
|
_undefined(),
|
|
4328
4329
|
literal(false),
|
|
4329
4330
|
literal(true)
|
|
4331
|
+
]).optional(),
|
|
4332
|
+
"forked": union([
|
|
4333
|
+
_undefined(),
|
|
4334
|
+
literal(false),
|
|
4335
|
+
literal(true)
|
|
4330
4336
|
]).optional()
|
|
4331
4337
|
})),
|
|
4332
4338
|
"denied": array(object({
|
|
@@ -6484,10 +6490,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6484
6490
|
*
|
|
6485
6491
|
* The second is the one harness reason that blocks (design
|
|
6486
6492
|
* 2026-09-26-dsh-017-readiness, B1, amending "warn, never block"): dsh 0.1.7
|
|
6487
|
-
* refuses the install itself, before pnpm runs
|
|
6488
|
-
*
|
|
6489
|
-
*
|
|
6490
|
-
*
|
|
6493
|
+
* refuses the install itself, an npm entry before pnpm runs and a github
|
|
6494
|
+
* entry after it, rolling the profile back, and the shop cannot install past
|
|
6495
|
+
* it. The verdict is dsh's own rule on the profile's own exemptions, whichever
|
|
6496
|
+
* channel the entry comes from (design
|
|
6497
|
+
* 2026-09-28-bundle-components-and-github-peers, section 7.3), so a disabled
|
|
6498
|
+
* button is dsh's answer given early, never the shop's opinion — and
|
|
6499
|
+
* recording the exemption the card shows is what enables it again.
|
|
6491
6500
|
*/
|
|
6492
6501
|
function refusesInstall(blockers) {
|
|
6493
6502
|
return blockers.some((blocker) => blocker.kind === "name-taken" || blocker.kind === "harness-peers");
|
|
@@ -6542,15 +6551,61 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6542
6551
|
case "desktop-profile": return "desktopProfileCode";
|
|
6543
6552
|
}
|
|
6544
6553
|
}
|
|
6545
|
-
/**
|
|
6546
|
-
|
|
6547
|
-
|
|
6554
|
+
/** A commit pin as the registry writes one: forty lowercase hex. */
|
|
6555
|
+
const COMMIT_PIN = /^[0-9a-f]{40}$/;
|
|
6556
|
+
/**
|
|
6557
|
+
* How a version string reads on the shelf, decided by its source and its
|
|
6558
|
+
* shape alone (market borrowings §11).
|
|
6559
|
+
*
|
|
6560
|
+
* Shape, never the entry's `tarball`, because an installed row carries only
|
|
6561
|
+
* the pin the shop recorded at install — the catalog `version` of that moment
|
|
6562
|
+
* — and no `tarball`. The registry pins a commit as forty lowercase hex and a
|
|
6563
|
+
* release by its tag, so the two shapes do not cross; `present.test.ts`
|
|
6564
|
+
* checks that against the committed live catalog.
|
|
6565
|
+
*
|
|
6566
|
+
* - An npm version takes the `v` the shelf has always shown, and only before
|
|
6567
|
+
* a digit: an installed row reports the manifest's spec, and a range there
|
|
6568
|
+
* (`^1.2.3`) is not a version to prefix.
|
|
6569
|
+
* - A commit is cut to the seven characters git abbreviates to, with no `v`:
|
|
6570
|
+
* it is not a version number.
|
|
6571
|
+
* - A release tag prints exactly as tagged, never cut and never prefixed:
|
|
6572
|
+
* cutting `v0.29.10` to seven characters printed `v0.29.1`, another
|
|
6573
|
+
* version, and the `v` this function no longer adds doubled the tag's own.
|
|
6574
|
+
*/
|
|
6575
|
+
function versionLabel(source, version) {
|
|
6576
|
+
if (source === "npm") return {
|
|
6577
|
+
kind: "npm",
|
|
6578
|
+
text: /^\d/.test(version) ? `v${version}` : version,
|
|
6579
|
+
value: version
|
|
6580
|
+
};
|
|
6581
|
+
if (COMMIT_PIN.test(version)) {
|
|
6582
|
+
const short = version.slice(0, 7);
|
|
6583
|
+
return {
|
|
6584
|
+
kind: "commit",
|
|
6585
|
+
text: short,
|
|
6586
|
+
value: short
|
|
6587
|
+
};
|
|
6588
|
+
}
|
|
6589
|
+
return {
|
|
6590
|
+
kind: "release",
|
|
6591
|
+
text: version,
|
|
6592
|
+
value: version
|
|
6593
|
+
};
|
|
6594
|
+
}
|
|
6595
|
+
/** The copy that names a version's kind, for the accessible name and the
|
|
6596
|
+
* tooltip; its `{version}` takes {@link VersionLabel.value}. */
|
|
6597
|
+
function versionLabelKey(kind) {
|
|
6598
|
+
switch (kind) {
|
|
6599
|
+
case "npm": return "npmVersionLabel";
|
|
6600
|
+
case "commit": return "commitVersionLabel";
|
|
6601
|
+
case "release": return "releaseVersionLabel";
|
|
6602
|
+
}
|
|
6548
6603
|
}
|
|
6549
6604
|
/** The hash pin a stale line names for a repo or release-rescued entry — the
|
|
6550
6605
|
* reviewed commit, or the reviewed release tarball sha256 (market borrowings
|
|
6551
|
-
* §3.1). Shortened to 7 chars like the card
|
|
6552
|
-
* hand-built fixture carrying no pin. The npm form is a version
|
|
6553
|
-
*
|
|
6606
|
+
* §3.1). Shortened to 7 chars like a commit on the card; '' only for a
|
|
6607
|
+
* hand-built fixture carrying no pin. The npm form is a version, which
|
|
6608
|
+
* {@link versionLabel} prints instead. */
|
|
6554
6609
|
function reviewHashPin(review) {
|
|
6555
6610
|
return (review.reviewedCommit ?? review.reviewedSha256 ?? "").slice(0, 7);
|
|
6556
6611
|
}
|
|
@@ -6675,6 +6730,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6675
6730
|
}
|
|
6676
6731
|
}
|
|
6677
6732
|
}
|
|
6733
|
+
/**
|
|
6734
|
+
* Which order the shelf is in (design 2026-10-12-shelf-orders). `stars` is
|
|
6735
|
+
* the default AND the tie-break of both date orders, so the two date orders
|
|
6736
|
+
* are stable re-sorts of it rather than orders with comparators of their own.
|
|
6737
|
+
*/
|
|
6738
|
+
const SHELF_ORDER_KEYS = {
|
|
6739
|
+
stars: "sortStars",
|
|
6740
|
+
added: "sortAdded",
|
|
6741
|
+
updated: "sortUpdated"
|
|
6742
|
+
};
|
|
6743
|
+
/** The three orders in display order (map insertion order). `readonly`: this
|
|
6744
|
+
* is a shared vocabulary, and an order list a caller can push to is a bug
|
|
6745
|
+
* waiting for its second caller. */
|
|
6746
|
+
const SHELF_ORDERS = Object.keys(SHELF_ORDER_KEYS);
|
|
6747
|
+
/** The locale key naming one order (the toggle's buttons). */
|
|
6748
|
+
function shelfOrderLocaleKey(order) {
|
|
6749
|
+
return SHELF_ORDER_KEYS[order];
|
|
6750
|
+
}
|
|
6678
6751
|
const CATEGORY_KEYS = {
|
|
6679
6752
|
tool: "categoryTool",
|
|
6680
6753
|
provider: "categoryProvider",
|
|
@@ -6821,6 +6894,77 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6821
6894
|
return NAME_COLLATOR.compare(a.name, b.name);
|
|
6822
6895
|
});
|
|
6823
6896
|
}
|
|
6897
|
+
/** The day form the registry writes into `added` (`emit.ts` E9 enforces it
|
|
6898
|
+
* on every build on its side; a catalog is untrusted input on this side). */
|
|
6899
|
+
const DAY_FORM = /^\d{4}-\d{2}-\d{2}$/;
|
|
6900
|
+
/**
|
|
6901
|
+
* The ES date-time form WITH an explicit zone. The zone is required, and not
|
|
6902
|
+
* for tidiness: a date-time string with no zone is parsed as LOCAL time, so
|
|
6903
|
+
* accepting one would make the shelf's order depend on the machine.
|
|
6904
|
+
*/
|
|
6905
|
+
const INSTANT_FORM = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
6906
|
+
/**
|
|
6907
|
+
* One date string as milliseconds, or undefined when it cannot be trusted.
|
|
6908
|
+
*
|
|
6909
|
+
* The form is checked BEFORE `Date.parse`, and that order is load-bearing:
|
|
6910
|
+
* V8 answers a real instant for `2026-02-31T00:00:00Z` (3 March) and for
|
|
6911
|
+
* `October 12` (a 2001 date), so `Date.parse` alone is not a validity test.
|
|
6912
|
+
*/
|
|
6913
|
+
function parseForm(value, form) {
|
|
6914
|
+
if (typeof value !== "string" || !form.test(value)) return void 0;
|
|
6915
|
+
const ms = Date.parse(value);
|
|
6916
|
+
return Number.isNaN(ms) ? void 0 : ms;
|
|
6917
|
+
}
|
|
6918
|
+
/** `shelfTime` with the catalog's build time already parsed, for the n calls
|
|
6919
|
+
* `orderShelf` makes in one pass. */
|
|
6920
|
+
function timeOf(entry, order, built) {
|
|
6921
|
+
if (order === "stars") return void 0;
|
|
6922
|
+
const ms = order === "added" ? parseForm(entry.added, DAY_FORM) : parseForm(entry.publishedAt, INSTANT_FORM);
|
|
6923
|
+
if (ms === void 0 || built === void 0 || ms > built) return void 0;
|
|
6924
|
+
return ms;
|
|
6925
|
+
}
|
|
6926
|
+
/**
|
|
6927
|
+
* The entry's sort key under a date order, or undefined when it has no usable
|
|
6928
|
+
* date (design §3): absent, off-form, unparseable, or later than the catalog's
|
|
6929
|
+
* own `builtAt`. Milliseconds since the epoch. `'stars'` carries no date, so
|
|
6930
|
+
* this answers undefined for it.
|
|
6931
|
+
*/
|
|
6932
|
+
function shelfTime(entry, order, builtAt) {
|
|
6933
|
+
return timeOf(entry, order, parseForm(builtAt, INSTANT_FORM));
|
|
6934
|
+
}
|
|
6935
|
+
/**
|
|
6936
|
+
* A UTC calendar day for display: "2026-10-12". Derived from the instant the
|
|
6937
|
+
* sort ranked by, so a card's label and its position cannot disagree. UTC and
|
|
6938
|
+
* never a local getter: a reader in UTC+8 must see the same days the catalog
|
|
6939
|
+
* was built in, the calendar the stats row already prints.
|
|
6940
|
+
*/
|
|
6941
|
+
function utcDay(ms) {
|
|
6942
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
6943
|
+
}
|
|
6944
|
+
/**
|
|
6945
|
+
* The shelf in `order` (design 2026-10-12-shelf-orders §2, §5). `'stars'`
|
|
6946
|
+
* returns the array it was handed, so the default path allocates nothing and
|
|
6947
|
+
* does not invalidate the memos downstream of it.
|
|
6948
|
+
*
|
|
6949
|
+
* Each key is computed ONCE per entry rather than inside the comparator, and
|
|
6950
|
+
* the sort is stable (ES2019), so entries sharing a date keep the star order
|
|
6951
|
+
* they arrived in — which is how the tie-break is defined without a second
|
|
6952
|
+
* comparator that could drift from `sortByStars`.
|
|
6953
|
+
*/
|
|
6954
|
+
function orderShelf(starOrdered, order, builtAt) {
|
|
6955
|
+
if (order === "stars") return starOrdered;
|
|
6956
|
+
const built = parseForm(builtAt, INSTANT_FORM);
|
|
6957
|
+
const keyed = starOrdered.map((entry) => ({
|
|
6958
|
+
entry,
|
|
6959
|
+
time: timeOf(entry, order, built)
|
|
6960
|
+
}));
|
|
6961
|
+
keyed.sort((a, b) => {
|
|
6962
|
+
if (a.time === void 0) return b.time === void 0 ? 0 : 1;
|
|
6963
|
+
if (b.time === void 0) return -1;
|
|
6964
|
+
return b.time - a.time;
|
|
6965
|
+
});
|
|
6966
|
+
return keyed.map((item) => item.entry);
|
|
6967
|
+
}
|
|
6824
6968
|
/** 999 → "999"; 1000 → "1k"; 1234 → "1.2k"; 1500 → "1.5k"; 99999 → "100k". */
|
|
6825
6969
|
function formatStars(n) {
|
|
6826
6970
|
if (n < 1e3) return String(n);
|
|
@@ -6893,6 +7037,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6893
7037
|
all: "全部",
|
|
6894
7038
|
catalog: "插件目录",
|
|
6895
7039
|
catalogStats: "{count} 个插件 · 构建于 {date}",
|
|
7040
|
+
/** The shelf's order control, and the date each card carries under the two
|
|
7041
|
+
* date orders (design 2026-10-12-shelf-orders §4). */
|
|
7042
|
+
sortLabel: "排序",
|
|
7043
|
+
sortStars: "星标",
|
|
7044
|
+
sortAdded: "最新上架",
|
|
7045
|
+
sortUpdated: "最近更新",
|
|
7046
|
+
listedOn: "上架 {date}",
|
|
7047
|
+
updatedOn: "更新 {date}",
|
|
6896
7048
|
stars: "{count} 星",
|
|
6897
7049
|
categoryTool: "工具",
|
|
6898
7050
|
categoryProvider: "模型服务",
|
|
@@ -6977,7 +7129,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6977
7129
|
emptyIncompatibleFiltered: "匹配的插件都标为不兼容,已被「隐藏不兼容」筛掉。",
|
|
6978
7130
|
license: "许可",
|
|
6979
7131
|
customLicense: "自定义许可",
|
|
6980
|
-
reviewedVersionLine: "已审核
|
|
7132
|
+
reviewedVersionLine: "已审核 {reviewed} / 当前 {current} 未审核",
|
|
6981
7133
|
reviewedPinLine: "已审核 {pin} / 当前 {current} 未审核",
|
|
6982
7134
|
deniedCode: "已拒绝",
|
|
6983
7135
|
notInCatalogCode: "不在目录中",
|
|
@@ -6991,6 +7143,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6991
7143
|
nameTakenDetail: "已安装同名的另一个插件({holder})。\n两个同名插件声明相同的加载项 id,无法共存;安装它会替换掉已装的那个。",
|
|
6992
7144
|
npmSource: "npm 包",
|
|
6993
7145
|
githubSource: "源码在 GitHub",
|
|
7146
|
+
/** The accessible name and the tooltip of a card's version, which say which
|
|
7147
|
+
* of three things the printed string is (market borrowings §11): the string
|
|
7148
|
+
* alone cannot tell a release tag from a version number, and a short commit
|
|
7149
|
+
* printed with a `v` read as one. */
|
|
7150
|
+
npmVersionLabel: "npm 版本 {version}",
|
|
7151
|
+
commitVersionLabel: "GitHub 提交 {version}",
|
|
7152
|
+
releaseVersionLabel: "GitHub 发布 {version}",
|
|
6994
7153
|
/** The badge and the explanation for an installed github entry no catalog
|
|
6995
7154
|
* row claims (C10 MVP). The mechanism synthesizes a row for ANY github spec
|
|
6996
7155
|
* with no catalog row — shadowed by a same-named npm package, an unlisted
|
|
@@ -7000,8 +7159,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7000
7159
|
shadowedBadge: "目录未列出此包",
|
|
7001
7160
|
shadowedDetail: "此包已安装,但当前的插件目录没有它(可能是被同名 npm 包遮蔽、作者已下架、或目录尚未收录);它照常运行。",
|
|
7002
7161
|
updatableSection: "可更新",
|
|
7003
|
-
|
|
7004
|
-
|
|
7162
|
+
/** `{version}` is the shelf's own version text (`versionLabel`), which
|
|
7163
|
+
* carries the `v` an npm version takes and no other kind does. */
|
|
7164
|
+
installedVersion: "已安装 {version}",
|
|
7165
|
+
latestVersion: "最新 {version}",
|
|
7005
7166
|
update: "更新",
|
|
7006
7167
|
installed: "已安装",
|
|
7007
7168
|
uninstall: "卸载",
|
|
@@ -7057,6 +7218,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7057
7218
|
all: "All",
|
|
7058
7219
|
catalog: "Plugin catalog",
|
|
7059
7220
|
catalogStats: "{count} packages · built {date}",
|
|
7221
|
+
/** The shelf's order control, and the date each card carries under the two
|
|
7222
|
+
* date orders (design 2026-10-12-shelf-orders §4). */
|
|
7223
|
+
sortLabel: "Sort",
|
|
7224
|
+
sortStars: "Stars",
|
|
7225
|
+
sortAdded: "Newest",
|
|
7226
|
+
sortUpdated: "Recently updated",
|
|
7227
|
+
listedOn: "Listed {date}",
|
|
7228
|
+
updatedOn: "Updated {date}",
|
|
7060
7229
|
stars: "{count} stars",
|
|
7061
7230
|
categoryTool: "Tool",
|
|
7062
7231
|
categoryProvider: "Provider",
|
|
@@ -7117,7 +7286,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7117
7286
|
emptyIncompatibleFiltered: "Every matching plugin is marked incompatible, and the incompatible filter is leaving them out.",
|
|
7118
7287
|
license: "License",
|
|
7119
7288
|
customLicense: "Custom license",
|
|
7120
|
-
reviewedVersionLine: "reviewed
|
|
7289
|
+
reviewedVersionLine: "reviewed {reviewed} / current {current} unreviewed",
|
|
7121
7290
|
reviewedPinLine: "reviewed {pin} / current {current} unreviewed",
|
|
7122
7291
|
deniedCode: "Denied",
|
|
7123
7292
|
notInCatalogCode: "Not in the catalog",
|
|
@@ -7131,11 +7300,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7131
7300
|
nameTakenDetail: "A different plugin of this name is installed ({holder}).\nTwo plugins of one name declare the same loader entry id and cannot both load; installing this one would replace it.",
|
|
7132
7301
|
npmSource: "npm package",
|
|
7133
7302
|
githubSource: "source on GitHub",
|
|
7303
|
+
npmVersionLabel: "npm version {version}",
|
|
7304
|
+
commitVersionLabel: "GitHub commit {version}",
|
|
7305
|
+
releaseVersionLabel: "GitHub release {version}",
|
|
7134
7306
|
shadowedBadge: "Not in the current catalog",
|
|
7135
7307
|
shadowedDetail: "This package is installed but the current catalog does not list it (it may be shadowed by a same-named npm package, removed by the author, or never listed); it runs as before.",
|
|
7136
7308
|
updatableSection: "Updatable",
|
|
7137
|
-
installedVersion: "installed
|
|
7138
|
-
latestVersion: "latest
|
|
7309
|
+
installedVersion: "installed {version}",
|
|
7310
|
+
latestVersion: "latest {version}",
|
|
7139
7311
|
update: "Update",
|
|
7140
7312
|
installed: "Installed",
|
|
7141
7313
|
uninstall: "Uninstall",
|
|
@@ -9043,124 +9215,127 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9043
9215
|
};
|
|
9044
9216
|
}
|
|
9045
9217
|
//#endregion
|
|
9046
|
-
//#region \0dsh-plugin-shop-css:
|
|
9047
|
-
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.s8583e3_client.s942a79_config.s5f67aa_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.s8583e3_client.sfd9d8a_spec.s5f67aa_ts` pins this. */\n\n.s255e5a_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n /* 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 `.s232ec4_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.s646509_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.s44a3ec_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s3a0ece_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.se0c3b4_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s520416_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s520416_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.s8c7d6f_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.sf5179e_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sbb0d25_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 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.s96e910_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.s520416_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s520416_skeletonCard span { animation: none; opacity: 0.75; }\n .s520416_skeletonCard::after { content: none; }\n}\n\n.s73242a_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s73242a_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s73242a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s646509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s745e3c_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.s4fe61f_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.sb9b924_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.sa04455_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.sa04455_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.sa04455_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.s614a38_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.s614a38_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.s614a38_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.s614a38_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.sa987f7_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.sa987f7_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sa987f7_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.sb81ba5_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s232ec4_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s232ec4_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Subdued line under the search box when a dictionary intent fired (design\n * 2026-10-08-search-query-expansion §4). One fact, no badge. */\n.s76fb13_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s3946f1_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.sb2c859_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.s26d58e_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.s26d58e_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 `.s26d58e_categoryButton.s5f68c4_categoryButtonOn` — TWO classes — so it\n * matches `.s26d58e_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s5f68c4_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.s8583e3_client.sfd9d8a_spec.s5f67aa_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.s26d58e_categoryButton.s5f68c4_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 .s26d58e_categoryButton.s5f68c4_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.s26d58e_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 `.s26d58e_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.sfd887b_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: `.sfd887b_incompatibleFilter:hover .s11c019_switch` outranks `.s7580e8_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.sfd887b_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.sfd887b_incompatibleFilter:hover .s11c019_switch:not(.s7580e8_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 `.s26d58e_categoryButton.s5f68c4_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.sfd887b_incompatibleFilter.s6e4cba_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.sfd887b_incompatibleFilter .s11c019_switch:not(.s7580e8_switchOn) .saab2b3_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.sfd887b_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.sebf017_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.seb0a1e_catalogStatsRow {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n.sccc4d1_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 `.s73242a_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.sff243d_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.sff243d_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.sff243d_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.sff243d_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s194168_catalogRefreshFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s6de1ab_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n/* Single-line rows: one full-width column, one plugin per line. */\n.sf657f5_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 .sf657f5_cards { animation: none; }\n}\n\n.s65f383_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.sd7ee01_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s705cc6_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s65f383_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s65f383_card { transition: none; }\n .s65f383_card:hover { transform: none; }\n}\n\n/* The signature: a 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.s4ce25d_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. `.s26d58e_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.s65f383_card[data-category='tool'], .s26d58e_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.s65f383_card[data-category='provider'], .s26d58e_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.s65f383_card[data-category='ui'], .s26d58e_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.s65f383_card[data-category='workflow'], .s26d58e_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.s65f383_card[data-category='integration'], .s26d58e_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.s65f383_card[data-category='theme'], .s26d58e_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.s65f383_card[data-category='other'], .s26d58e_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.s9c8eaa_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.sa97234_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.sa97234_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.sc3f149_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.s513026_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.s9b5048_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.s9b5048_cardActions > .sc4f2ac_gate,\n.s9b5048_cardActions > .s4d374c_installPanel,\n.s9b5048_cardActions > .sf53ca0_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.sc6ec6e_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.s71f10f_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s5e82cb_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s5e82cb_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C10 shadowed badge: an installed github entry the catalog refuses\n * shadowed-by-npm. Subdued/secondary rather than a warn tint — nothing is\n * wrong with the install itself; the shelf just cannot show it. */\n.s5e82cb_tierBadge[data-tier='shadowed'] {\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/* The §C5 archived badge: a github repository the owner has frozen.\n * Subdued register, same as shadowed — nothing is wrong with the install;\n * the pinned commit still serves, so the mark is informational only. */\n.s5e82cb_tierBadge[data-tier='archived'] {\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.s4bbe02_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.sff43b4_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s73f7fb_chevron, .s61393c_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s61393c_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s73f7fb_chevron, .s61393c_chevronOpen { transition: none; }\n}\n\n.s820ebf_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sb8fbc8_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.se507db_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* 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.s10baf0_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.sb9dba9_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.s6eca19_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.s3d0044_remedy {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.sdf203f_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.sc32335_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.sc74941_refusal {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-basis: 100%;\n}\n\n.s9d2029_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3bdbd5_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s441702_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s441702_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sde3f0c_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.se98179_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sfb4d2f_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sfb4d2f_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfb4d2f_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sfb4d2f_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.sfb4d2f_detailRow a:hover {\n text-decoration: underline;\n}\n\n.sfb4d2f_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 * `.s9b5048_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.s5fbaf9_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: `.s5fbaf9_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.s2d3c05_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 `.s5fbaf9_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 `.s5fbaf9_cardMeta`. There is no middot:\n * `.s5fbaf9_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.s1ff66f_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sd58c6d_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.s4d374c_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.se7aaed_installButton, .sb43a49_confirmButton, .s6e45d1_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.se7aaed_installButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.se7aaed_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sb43a49_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sb43a49_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s6e45d1_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.s6e45d1_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se7aaed_installButton:focus-visible, .sb43a49_confirmButton:focus-visible, .s6e45d1_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* 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.sb6fc74_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.sf53ca0_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.s96967f_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.s96967f_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s96967f_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.sb00c36_restartSelfButton {\n /* The version row's third state. Geometry matches .s614a38_checkUpdateButton and\n * .sa04455_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.sb00c36_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.s6ac237_restartButton,\n.s64a5ff_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.s6ac237_restartButton:hover,\n.s64a5ff_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s6ac237_restartButton:focus-visible,\n.s64a5ff_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 * `.sf53ca0_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.sf79aef_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sc4f2ac_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s559c38_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s3c0ace_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sc323e5_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.s4b2373_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s52b5a5_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s64ab71_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.s1531a8_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf20dda_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.seb9b08_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sfd3021_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s50ba35_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.se75489_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.sa276cf_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sceae6e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s8d2072_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s5c2545_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5c2545_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s877c68_outdatedVersions {\n /* 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 .s513026_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/* The §C10 shadowed section. Reuses the outdated list's visual language; only\n * the section spacing and the per-row explanation paragraph are its own. */\n.s6c4649_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.scc2a21_shadowedDetail {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa1f556_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: `.sfd887b_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 `.s11c019_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.s11c019_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.s7580e8_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.saab2b3_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.s7580e8_switchOn .saab2b3_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s11c019_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s11c019_switch, .saab2b3_switchKnob { transition: none; }\n}\n\n/* The hot enable/disable switch on installed rows: the knob button plus the\n * §8 hot-apply / failure notices rendered beside it. */\n.sd9f9e4_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.sa1f556_outdatedActions`: `.sf79aef_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.sf53ca0_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
9048
|
-
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"
|
|
9218
|
+
//#region \0dsh-plugin-shop-css:d74581c2
|
|
9219
|
+
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.s73a3ff_client.s45aee2_config.s8a51a7_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.s73a3ff_client.s117e2f_spec.s8a51a7_ts` pins this. */\n\n.sa2d7b5_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 `.s7c10d7_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.sbee2c3_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.sa89499_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.s90f53b_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.sd5b66e_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.sfb41cd_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.sfb41cd_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.sc9bc63_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.s75708b_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.s772f28_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.s6ce39d_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.sfb41cd_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 .sfb41cd_skeletonCard span { animation: none; opacity: 0.75; }\n .sfb41cd_skeletonCard::after { content: none; }\n}\n\n.s1547e4_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.s1547e4_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.s1547e4_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sbee2c3_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.sfb98ad_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.s15df74_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s9d78e5_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.scb0503_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.scb0503_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.scb0503_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.seab5ae_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.seab5ae_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.seab5ae_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.seab5ae_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.s6932e1_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.s6932e1_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.s6932e1_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.sb1e444_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s7c10d7_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.s7c10d7_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Subdued line under the search box when a dictionary intent fired (design\n * 2026-10-08-search-query-expansion §4). One fact, no badge. */\n.s1dee54_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s5823b0_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.s52084f_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.sd07f01_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.sd07f01_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 `.sd07f01_categoryButton.s7d231e_categoryButtonOn` — TWO classes — so it\n * matches `.sd07f01_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s7d231e_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.s73a3ff_client.s117e2f_spec.s8a51a7_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.sd07f01_categoryButton.s7d231e_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 .sd07f01_categoryButton.s7d231e_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.sd07f01_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 `.sd07f01_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.s7abba7_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: `.s7abba7_incompatibleFilter:hover .sa4bed2_switch` outranks `.s97d8ec_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.s7abba7_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.s7abba7_incompatibleFilter:hover .sa4bed2_switch:not(.s97d8ec_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 `.sd07f01_categoryButton.s7d231e_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.s7abba7_incompatibleFilter.sa24b4e_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.s7abba7_incompatibleFilter .sa4bed2_switch:not(.s97d8ec_switchOn) .s24e1f5_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.s7abba7_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s3ffb2a_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.sfd3ed8_catalogStatsRow {\n display: flex;\n align-items: center;\n /* The row holds the catalog line, the refresh button and the shelf order's\n * three pills (design 2026-10-12-shelf-orders §4). Without wrapping, the\n * last of them overflows the tab at a narrow width. */\n flex-wrap: wrap;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n/* The shelf's order control, at the right end of the stats row. `margin-left:\n * auto` is what puts it there while the line and the refresh button stay\n * left — and it is safe on a wrapping row, unlike a width. */\n.sc5a073_sortGroup {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n.s275eb9_sortLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.s3c7a5d_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 `.s1547e4_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.s6d141d_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.s6d141d_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.s6d141d_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s6d141d_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s8b8ed4_catalogRefreshFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s918b21_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.sf66d65_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 .sf66d65_cards { animation: none; }\n}\n\n.sa6c0bf_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.s21cef7_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s9babb8_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa6c0bf_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 .sa6c0bf_card { transition: none; }\n .sa6c0bf_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.sce2063_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. `.sd07f01_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.sa6c0bf_card[data-category='tool'], .sd07f01_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.sa6c0bf_card[data-category='provider'], .sd07f01_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.sa6c0bf_card[data-category='ui'], .sd07f01_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.sa6c0bf_card[data-category='workflow'], .sd07f01_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.sa6c0bf_card[data-category='integration'], .sd07f01_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.sa6c0bf_card[data-category='theme'], .sd07f01_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.sa6c0bf_card[data-category='other'], .sd07f01_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.sdc7cd8_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.s6ae6ba_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.s6ae6ba_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.saf3e98_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.s93d243_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.s763b75_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.s763b75_cardActions > .sff1df6_gate,\n.s763b75_cardActions > .s6d7bee_installPanel,\n.s763b75_cardActions > .s10ddb2_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.s9d1d9e_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 /* A release tag prints as tagged, never cut to seven characters (market\n * borrowings §11), and a tag can run to any length. The cap keeps every\n * tag of up to fourteen characters whole, prerelease suffix included\n * (`v0.1.0-alpha.0`): fourteen glyphs plus the letter-spacing above come to\n * about 14.5ch, so the cap is 15ch, not 14. A longer tag ends in an ellipsis,\n * and the tooltip carries the whole of it. */\n max-width: 15ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The octocat marking a source the reader can read on GitHub, beside the\n * card's version. */\n.sad456f_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s7f352e_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s7f352e_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.s7f352e_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.s7f352e_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/* The §C10 shadowed badge: an installed github entry the catalog refuses\n * shadowed-by-npm. Subdued/secondary rather than a warn tint — nothing is\n * wrong with the install itself; the shelf just cannot show it. */\n.s7f352e_tierBadge[data-tier='shadowed'] {\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/* The §C5 archived badge: a github repository the owner has frozen.\n * Subdued register, same as shadowed — nothing is wrong with the install;\n * the pinned commit still serves, so the mark is informational only. */\n.s7f352e_tierBadge[data-tier='archived'] {\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.s649a66_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.se83753_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc7129d_chevron, .s3e170e_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s3e170e_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sc7129d_chevron, .s3e170e_chevronOpen { transition: none; }\n}\n\n.s249e15_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sdd4d7a_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.s1a6809_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.sc924dd_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.sab7503_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.s4625f5_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.s632e71_remedy {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s360025_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.s12ec11_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.sa92311_refusal {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-basis: 100%;\n}\n\n.s99a4f5_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.scf0a21_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc760c8_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sc760c8_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.s48edfc_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.sce5502_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.scc4b2b_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.scc4b2b_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.scc4b2b_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.scc4b2b_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.scc4b2b_detailRow a:hover {\n text-decoration: underline;\n}\n\n.scc4b2b_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 * `.s763b75_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.s8fb80a_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: `.s8fb80a_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 *\n * `.s72b045_shelfDate` shares this rule because it is the same kind of fact — a\n * fixed-width figure a reader compares down the shelf (design\n * 2026-10-12-shelf-orders §4) — and two copies of these declarations would\n * drift. */\n.s24611f_size,\n.s72b045_shelfDate {\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 `.s8fb80a_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 `.s8fb80a_cardMeta`. There is no middot:\n * `.s8fb80a_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.seefbaa_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sa79085_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.s6d7bee_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.sdddc5f_installButton, .safd4a8_confirmButton, .sfcf768_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.sdddc5f_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.sdddc5f_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.safd4a8_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.safd4a8_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sfcf768_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.sfcf768_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.sdddc5f_installButton:focus-visible, .safd4a8_confirmButton:focus-visible, .sfcf768_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.s563674_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.s10ddb2_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.s767a97_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.s767a97_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s767a97_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.sa6b105_restartSelfButton {\n /* The version row's third state. Geometry matches .seab5ae_checkUpdateButton and\n * .scb0503_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.sa6b105_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.s426aa0_restartButton,\n.sa283f9_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.s426aa0_restartButton:hover,\n.sa283f9_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s426aa0_restartButton:focus-visible,\n.sa283f9_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 * `.s10ddb2_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.sf20a99_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sff1df6_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.see0e3d_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.sd04ef9_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s7fd5d3_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.sf6b0aa_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.sa32b72_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf9b6a4_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.s9e4d00_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s7cd7db_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.sfb1bae_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s9591b1_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.saa0605_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sbd5c7c_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.s7c248d_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.se144d3_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s6fbe58_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.s8af496_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s8af496_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.sf82d51_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 .s93d243_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/* The §C10 shadowed section. Reuses the outdated list's visual language; only\n * the section spacing and the per-row explanation paragraph are its own. */\n.s31b89a_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.scf838f_shadowedDetail {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s109c95_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: `.s7abba7_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 `.sa4bed2_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.sa4bed2_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.s97d8ec_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.s24e1f5_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.s97d8ec_switchOn .s24e1f5_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.sa4bed2_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 .sa4bed2_switch, .s24e1f5_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.s5c21f4_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.s109c95_outdatedActions`: `.sf20a99_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.s10ddb2_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
9220
|
+
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"d74581c2\"]")) {
|
|
9049
9221
|
const tag = document.createElement("style");
|
|
9050
|
-
tag.dataset.pluginCss = "
|
|
9222
|
+
tag.dataset.pluginCss = "d74581c2";
|
|
9051
9223
|
tag.textContent = css;
|
|
9052
9224
|
document.head.appendChild(tag);
|
|
9053
9225
|
}
|
|
9054
|
-
var
|
|
9055
|
-
"client": "
|
|
9056
|
-
"config": "
|
|
9057
|
-
"ts": "
|
|
9058
|
-
"spec": "
|
|
9059
|
-
"panel": "
|
|
9060
|
-
"searchInput": "
|
|
9061
|
-
"toolbar": "
|
|
9062
|
-
"stateLine": "
|
|
9063
|
-
"srOnly": "
|
|
9064
|
-
"skeletonGrid": "
|
|
9065
|
-
"skeletonCard": "
|
|
9066
|
-
"skeletonName": "
|
|
9067
|
-
"skeletonSummary": "
|
|
9068
|
-
"skeletonSummaryShort": "
|
|
9069
|
-
"skeletonActions": "
|
|
9070
|
-
"actionButton": "
|
|
9071
|
-
"toolbarRight": "
|
|
9072
|
-
"versionBlock": "
|
|
9073
|
-
"versionText": "
|
|
9074
|
-
"updateSelfButton": "
|
|
9075
|
-
"checkUpdateButton": "
|
|
9076
|
-
"githubLink": "
|
|
9077
|
-
"selfUpdatePanel": "
|
|
9078
|
-
"expansionNote": "
|
|
9079
|
-
"staleBadge": "
|
|
9080
|
-
"categoryBar": "
|
|
9081
|
-
"categoryButton": "
|
|
9082
|
-
"categoryButtonOn": "
|
|
9083
|
-
"incompatibleFilter": "
|
|
9084
|
-
"switch": "
|
|
9085
|
-
"switchOn": "
|
|
9086
|
-
"incompatibleFilterOn": "
|
|
9087
|
-
"switchKnob": "
|
|
9088
|
-
"updatableHeading": "
|
|
9089
|
-
"catalogStatsRow": "
|
|
9090
|
-
"
|
|
9091
|
-
"
|
|
9092
|
-
"
|
|
9093
|
-
"
|
|
9094
|
-
"
|
|
9095
|
-
"
|
|
9096
|
-
"
|
|
9097
|
-
"
|
|
9098
|
-
"
|
|
9099
|
-
"
|
|
9100
|
-
"
|
|
9101
|
-
"
|
|
9102
|
-
"
|
|
9103
|
-
"
|
|
9104
|
-
"
|
|
9105
|
-
"
|
|
9106
|
-
"
|
|
9107
|
-
"
|
|
9108
|
-
"
|
|
9109
|
-
"
|
|
9110
|
-
"
|
|
9111
|
-
"
|
|
9112
|
-
"
|
|
9113
|
-
"
|
|
9114
|
-
"
|
|
9115
|
-
"
|
|
9116
|
-
"
|
|
9117
|
-
"
|
|
9118
|
-
"
|
|
9119
|
-
"
|
|
9120
|
-
"
|
|
9121
|
-
"
|
|
9122
|
-
"
|
|
9123
|
-
"
|
|
9124
|
-
"
|
|
9125
|
-
"
|
|
9126
|
-
"
|
|
9127
|
-
"
|
|
9128
|
-
"
|
|
9129
|
-
"
|
|
9130
|
-
"
|
|
9131
|
-
"
|
|
9132
|
-
"
|
|
9133
|
-
"
|
|
9134
|
-
"
|
|
9135
|
-
"
|
|
9136
|
-
"
|
|
9137
|
-
"
|
|
9138
|
-
"
|
|
9139
|
-
"
|
|
9140
|
-
"
|
|
9141
|
-
"
|
|
9142
|
-
"
|
|
9143
|
-
"
|
|
9144
|
-
"
|
|
9145
|
-
"
|
|
9146
|
-
"
|
|
9147
|
-
"
|
|
9148
|
-
"
|
|
9149
|
-
"
|
|
9150
|
-
"
|
|
9151
|
-
"
|
|
9152
|
-
"
|
|
9153
|
-
"
|
|
9154
|
-
"
|
|
9155
|
-
"
|
|
9156
|
-
"
|
|
9157
|
-
"
|
|
9158
|
-
"
|
|
9159
|
-
"
|
|
9160
|
-
"
|
|
9161
|
-
"
|
|
9162
|
-
"
|
|
9163
|
-
"
|
|
9226
|
+
var _dsh_plugin_shop_css_d74581c2_default = {
|
|
9227
|
+
"client": "s73a3ff_client",
|
|
9228
|
+
"config": "s45aee2_config",
|
|
9229
|
+
"ts": "s8a51a7_ts",
|
|
9230
|
+
"spec": "s117e2f_spec",
|
|
9231
|
+
"panel": "sa2d7b5_panel",
|
|
9232
|
+
"searchInput": "s7c10d7_searchInput",
|
|
9233
|
+
"toolbar": "sbee2c3_toolbar",
|
|
9234
|
+
"stateLine": "sa89499_stateLine",
|
|
9235
|
+
"srOnly": "s90f53b_srOnly",
|
|
9236
|
+
"skeletonGrid": "sd5b66e_skeletonGrid",
|
|
9237
|
+
"skeletonCard": "sfb41cd_skeletonCard",
|
|
9238
|
+
"skeletonName": "sc9bc63_skeletonName",
|
|
9239
|
+
"skeletonSummary": "s75708b_skeletonSummary",
|
|
9240
|
+
"skeletonSummaryShort": "s772f28_skeletonSummaryShort",
|
|
9241
|
+
"skeletonActions": "s6ce39d_skeletonActions",
|
|
9242
|
+
"actionButton": "s1547e4_actionButton",
|
|
9243
|
+
"toolbarRight": "sfb98ad_toolbarRight",
|
|
9244
|
+
"versionBlock": "s15df74_versionBlock",
|
|
9245
|
+
"versionText": "s9d78e5_versionText",
|
|
9246
|
+
"updateSelfButton": "scb0503_updateSelfButton",
|
|
9247
|
+
"checkUpdateButton": "seab5ae_checkUpdateButton",
|
|
9248
|
+
"githubLink": "s6932e1_githubLink",
|
|
9249
|
+
"selfUpdatePanel": "sb1e444_selfUpdatePanel",
|
|
9250
|
+
"expansionNote": "s1dee54_expansionNote",
|
|
9251
|
+
"staleBadge": "s5823b0_staleBadge",
|
|
9252
|
+
"categoryBar": "s52084f_categoryBar",
|
|
9253
|
+
"categoryButton": "sd07f01_categoryButton",
|
|
9254
|
+
"categoryButtonOn": "s7d231e_categoryButtonOn",
|
|
9255
|
+
"incompatibleFilter": "s7abba7_incompatibleFilter",
|
|
9256
|
+
"switch": "sa4bed2_switch",
|
|
9257
|
+
"switchOn": "s97d8ec_switchOn",
|
|
9258
|
+
"incompatibleFilterOn": "sa24b4e_incompatibleFilterOn",
|
|
9259
|
+
"switchKnob": "s24e1f5_switchKnob",
|
|
9260
|
+
"updatableHeading": "s3ffb2a_updatableHeading",
|
|
9261
|
+
"catalogStatsRow": "sfd3ed8_catalogStatsRow",
|
|
9262
|
+
"sortGroup": "sc5a073_sortGroup",
|
|
9263
|
+
"sortLabel": "s275eb9_sortLabel",
|
|
9264
|
+
"catalogStats": "s3c7a5d_catalogStats",
|
|
9265
|
+
"catalogRefreshButton": "s6d141d_catalogRefreshButton",
|
|
9266
|
+
"catalogRefreshFailed": "s8b8ed4_catalogRefreshFailed",
|
|
9267
|
+
"emptyLine": "s918b21_emptyLine",
|
|
9268
|
+
"cards": "sf66d65_cards",
|
|
9269
|
+
"card": "sa6c0bf_card",
|
|
9270
|
+
"cardsSentry": "s21cef7_cardsSentry",
|
|
9271
|
+
"showingLine": "s9babb8_showingLine",
|
|
9272
|
+
"cardSpine": "sce2063_cardSpine",
|
|
9273
|
+
"categoryBadge": "sdc7cd8_categoryBadge",
|
|
9274
|
+
"entryHeader": "s6ae6ba_entryHeader",
|
|
9275
|
+
"name": "saf3e98_name",
|
|
9276
|
+
"badges": "s93d243_badges",
|
|
9277
|
+
"cardActions": "s763b75_cardActions",
|
|
9278
|
+
"gate": "sff1df6_gate",
|
|
9279
|
+
"installPanel": "s6d7bee_installPanel",
|
|
9280
|
+
"installedActions": "s10ddb2_installedActions",
|
|
9281
|
+
"cardVersion": "s9d1d9e_cardVersion",
|
|
9282
|
+
"sourceBadge": "sad456f_sourceBadge",
|
|
9283
|
+
"tierBadge": "s7f352e_tierBadge",
|
|
9284
|
+
"incompatibleBadge": "s649a66_incompatibleBadge",
|
|
9285
|
+
"starsBadge": "se83753_starsBadge",
|
|
9286
|
+
"chevron": "sc7129d_chevron",
|
|
9287
|
+
"chevronOpen": "s3e170e_chevronOpen",
|
|
9288
|
+
"body": "s249e15_body",
|
|
9289
|
+
"summary": "sdd4d7a_summary",
|
|
9290
|
+
"summaryZh": "s1a6809_summaryZh",
|
|
9291
|
+
"summaryExpanded": "sc924dd_summaryExpanded",
|
|
9292
|
+
"summaryZhExpanded": "sab7503_summaryZhExpanded",
|
|
9293
|
+
"incompatibleDetail": "s4625f5_incompatibleDetail",
|
|
9294
|
+
"remedy": "s632e71_remedy",
|
|
9295
|
+
"remedyLead": "s360025_remedyLead",
|
|
9296
|
+
"allowCommand": "s12ec11_allowCommand",
|
|
9297
|
+
"refusal": "sa92311_refusal",
|
|
9298
|
+
"capabilitiesBlock": "s99a4f5_capabilitiesBlock",
|
|
9299
|
+
"capabilitiesNote": "scf0a21_capabilitiesNote",
|
|
9300
|
+
"capabilities": "sc760c8_capabilities",
|
|
9301
|
+
"detail": "s48edfc_detail",
|
|
9302
|
+
"detailRows": "sce5502_detailRows",
|
|
9303
|
+
"detailRow": "scc4b2b_detailRow",
|
|
9304
|
+
"cardMeta": "s8fb80a_cardMeta",
|
|
9305
|
+
"shelfDate": "s72b045_shelfDate",
|
|
9306
|
+
"size": "s24611f_size",
|
|
9307
|
+
"author": "seefbaa_author",
|
|
9308
|
+
"reviewedLine": "sa79085_reviewedLine",
|
|
9309
|
+
"installButton": "sdddc5f_installButton",
|
|
9310
|
+
"confirmButton": "safd4a8_confirmButton",
|
|
9311
|
+
"cancelButton": "sfcf768_cancelButton",
|
|
9312
|
+
"installedLabel": "s563674_installedLabel",
|
|
9313
|
+
"uninstallButton": "s767a97_uninstallButton",
|
|
9314
|
+
"restartSelfButton": "sa6b105_restartSelfButton",
|
|
9315
|
+
"restartButton": "s426aa0_restartButton",
|
|
9316
|
+
"reloadButton": "sa283f9_reloadButton",
|
|
9317
|
+
"reloadPanel": "sf20a99_reloadPanel",
|
|
9318
|
+
"gateTitle": "see0e3d_gateTitle",
|
|
9319
|
+
"gateBody": "sd04ef9_gateBody",
|
|
9320
|
+
"gateWarning": "s7fd5d3_gateWarning",
|
|
9321
|
+
"gateActions": "sf6b0aa_gateActions",
|
|
9322
|
+
"installing": "sa32b72_installing",
|
|
9323
|
+
"log": "sf9b6a4_log",
|
|
9324
|
+
"logLine": "s9e4d00_logLine",
|
|
9325
|
+
"notice": "s7cd7db_notice",
|
|
9326
|
+
"failedHeading": "sfb1bae_failedHeading",
|
|
9327
|
+
"failedDetail": "s9591b1_failedDetail",
|
|
9328
|
+
"rejectedCode": "saa0605_rejectedCode",
|
|
9329
|
+
"rejectedDetail": "sbd5c7c_rejectedDetail",
|
|
9330
|
+
"outdatedSection": "s7c248d_outdatedSection",
|
|
9331
|
+
"outdatedList": "se144d3_outdatedList",
|
|
9332
|
+
"outdatedRow": "s6fbe58_outdatedRow",
|
|
9333
|
+
"outdatedInfo": "s8af496_outdatedInfo",
|
|
9334
|
+
"outdatedVersions": "sf82d51_outdatedVersions",
|
|
9335
|
+
"shadowedSection": "s31b89a_shadowedSection",
|
|
9336
|
+
"shadowedDetail": "scf838f_shadowedDetail",
|
|
9337
|
+
"outdatedActions": "s109c95_outdatedActions",
|
|
9338
|
+
"switchWrap": "s5c21f4_switchWrap"
|
|
9164
9339
|
};
|
|
9165
9340
|
//#endregion
|
|
9166
9341
|
//#region src/client/ShopTab.tsx
|
|
@@ -9177,14 +9352,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9177
9352
|
* those nodes, and React's next commit throws on the ones it no longer finds
|
|
9178
9353
|
* (design 2026-09-26-market-borrowings §4). The tab renders no portals, so its
|
|
9179
9354
|
* root is its whole surface. */
|
|
9180
|
-
const PANEL_ROOT = `${
|
|
9355
|
+
const PANEL_ROOT = `${_dsh_plugin_shop_css_d74581c2_default.panel} notranslate`;
|
|
9181
9356
|
function ChevronIcon({ open }) {
|
|
9182
9357
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
9183
9358
|
viewBox: "0 0 16 16",
|
|
9184
9359
|
width: "14",
|
|
9185
9360
|
height: "14",
|
|
9186
9361
|
"aria-hidden": "true",
|
|
9187
|
-
className: open ?
|
|
9362
|
+
className: open ? _dsh_plugin_shop_css_d74581c2_default.chevronOpen : _dsh_plugin_shop_css_d74581c2_default.chevron,
|
|
9188
9363
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
9189
9364
|
fill: "currentColor",
|
|
9190
9365
|
d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
|
|
@@ -9197,7 +9372,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9197
9372
|
* install controls. An installed plugin's card carries its installed row:
|
|
9198
9373
|
* current → the non-interactive installed label, behind → the update button;
|
|
9199
9374
|
* uninstalled → the install button. */
|
|
9200
|
-
const EntryCard = (0, react.memo)(function EntryCard({ entry, stars, installed, missing, harness, nameTakenBy, t, flow, uninstallFlow, restart, restartBlocked, reload, setEnabled, inInstalledView, restarts }) {
|
|
9375
|
+
const EntryCard = (0, react.memo)(function EntryCard({ entry, stars, order, shelfDay, installed, missing, harness, nameTakenBy, t, flow, uninstallFlow, restart, restartBlocked, reload, setEnabled, inInstalledView, restarts }) {
|
|
9201
9376
|
const [open, setOpen] = (0, react.useState)(false);
|
|
9202
9377
|
const blockers = stateBlockers(blockersOf(missing, harness, nameTakenBy), t);
|
|
9203
9378
|
const detailId = (0, react.useId)();
|
|
@@ -9205,6 +9380,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9205
9380
|
const npmUrl = npmPageUrl(entry);
|
|
9206
9381
|
const author = authorOf(entry);
|
|
9207
9382
|
const size = formatSize(entry.installSize);
|
|
9383
|
+
const version = versionLabel(entry.source, entry.version);
|
|
9384
|
+
const versionName = t(versionLabelKey(version.kind), { version: version.value });
|
|
9208
9385
|
const category = entry.catalog?.category ?? "other";
|
|
9209
9386
|
const installTarget = {
|
|
9210
9387
|
name: entry.name,
|
|
@@ -9214,32 +9391,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9214
9391
|
subdir: entry.subdir
|
|
9215
9392
|
};
|
|
9216
9393
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9217
|
-
className:
|
|
9394
|
+
className: _dsh_plugin_shop_css_d74581c2_default.card,
|
|
9218
9395
|
"data-shop-entry": entry.name,
|
|
9219
9396
|
"data-category": category,
|
|
9220
9397
|
children: [
|
|
9221
9398
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9222
|
-
className:
|
|
9399
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cardSpine,
|
|
9223
9400
|
"aria-hidden": "true"
|
|
9224
9401
|
}),
|
|
9225
9402
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
9226
9403
|
type: "button",
|
|
9227
|
-
className:
|
|
9404
|
+
className: _dsh_plugin_shop_css_d74581c2_default.entryHeader,
|
|
9228
9405
|
"aria-expanded": open,
|
|
9229
9406
|
"aria-controls": detailId,
|
|
9230
9407
|
onClick: () => setOpen((current) => !current),
|
|
9231
9408
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9232
|
-
className:
|
|
9409
|
+
className: _dsh_plugin_shop_css_d74581c2_default.name,
|
|
9233
9410
|
children: entry.name
|
|
9234
9411
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9235
|
-
className:
|
|
9412
|
+
className: _dsh_plugin_shop_css_d74581c2_default.badges,
|
|
9236
9413
|
children: [
|
|
9237
9414
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9238
|
-
className:
|
|
9415
|
+
className: _dsh_plugin_shop_css_d74581c2_default.categoryBadge,
|
|
9239
9416
|
children: t(categoryKey(entry))
|
|
9240
9417
|
}),
|
|
9241
9418
|
entry.source === "npm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9242
|
-
className:
|
|
9419
|
+
className: _dsh_plugin_shop_css_d74581c2_default.sourceBadge,
|
|
9243
9420
|
"data-shop-source-npm": true,
|
|
9244
9421
|
role: "img",
|
|
9245
9422
|
"aria-label": t("npmSource"),
|
|
@@ -9256,7 +9433,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9256
9433
|
})
|
|
9257
9434
|
}),
|
|
9258
9435
|
hasGithubHome(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9259
|
-
className:
|
|
9436
|
+
className: _dsh_plugin_shop_css_d74581c2_default.sourceBadge,
|
|
9260
9437
|
"data-shop-source-github": true,
|
|
9261
9438
|
role: "img",
|
|
9262
9439
|
"aria-label": t("githubSource"),
|
|
@@ -9269,23 +9446,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9269
9446
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" })
|
|
9270
9447
|
})
|
|
9271
9448
|
}),
|
|
9272
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
9273
|
-
className:
|
|
9449
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9450
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cardVersion,
|
|
9274
9451
|
"data-card-version": true,
|
|
9275
|
-
|
|
9452
|
+
role: "img",
|
|
9453
|
+
"aria-label": versionName,
|
|
9454
|
+
title: versionName,
|
|
9455
|
+
children: version.text
|
|
9276
9456
|
}),
|
|
9277
9457
|
entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9278
|
-
className:
|
|
9458
|
+
className: _dsh_plugin_shop_css_d74581c2_default.tierBadge,
|
|
9279
9459
|
"data-tier": entry.tier,
|
|
9280
9460
|
children: t(tierKey(entry.tier))
|
|
9281
9461
|
}),
|
|
9282
9462
|
entry.archived === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9283
|
-
className:
|
|
9463
|
+
className: _dsh_plugin_shop_css_d74581c2_default.tierBadge,
|
|
9284
9464
|
"data-tier": "archived",
|
|
9285
9465
|
children: t("archivedBadge")
|
|
9286
9466
|
}),
|
|
9287
9467
|
stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9288
|
-
className:
|
|
9468
|
+
className: _dsh_plugin_shop_css_d74581c2_default.starsBadge,
|
|
9289
9469
|
role: "img",
|
|
9290
9470
|
"aria-label": t("stars", { count: stars }),
|
|
9291
9471
|
children: ["★ ", formatStars(stars)]
|
|
@@ -9295,39 +9475,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9295
9475
|
})]
|
|
9296
9476
|
}),
|
|
9297
9477
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9298
|
-
className:
|
|
9478
|
+
className: _dsh_plugin_shop_css_d74581c2_default.body,
|
|
9299
9479
|
children: [
|
|
9300
9480
|
summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9301
|
-
className: open ? `${
|
|
9481
|
+
className: open ? `${_dsh_plugin_shop_css_d74581c2_default.summary} ${_dsh_plugin_shop_css_d74581c2_default.summaryExpanded}` : _dsh_plugin_shop_css_d74581c2_default.summary,
|
|
9302
9482
|
children: summary.en
|
|
9303
9483
|
}),
|
|
9304
9484
|
summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9305
|
-
className: open ? `${
|
|
9485
|
+
className: open ? `${_dsh_plugin_shop_css_d74581c2_default.summaryZh} ${_dsh_plugin_shop_css_d74581c2_default.summaryZhExpanded}` : _dsh_plugin_shop_css_d74581c2_default.summaryZh,
|
|
9306
9486
|
children: summary.zh
|
|
9307
9487
|
}),
|
|
9308
9488
|
blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
9309
9489
|
blocker,
|
|
9310
|
-
className:
|
|
9490
|
+
className: _dsh_plugin_shop_css_d74581c2_default.incompatibleDetail,
|
|
9311
9491
|
surface: "detail"
|
|
9312
9492
|
}, blocker.kind)),
|
|
9313
9493
|
open && entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9314
|
-
className:
|
|
9494
|
+
className: _dsh_plugin_shop_css_d74581c2_default.capabilitiesBlock,
|
|
9315
9495
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9316
|
-
className:
|
|
9496
|
+
className: _dsh_plugin_shop_css_d74581c2_default.capabilitiesNote,
|
|
9317
9497
|
children: t("capabilitiesNote")
|
|
9318
9498
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
9319
|
-
className:
|
|
9499
|
+
className: _dsh_plugin_shop_css_d74581c2_default.capabilities,
|
|
9320
9500
|
children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
|
|
9321
9501
|
})]
|
|
9322
9502
|
}),
|
|
9323
9503
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
9324
9504
|
id: detailId,
|
|
9325
|
-
className:
|
|
9505
|
+
className: _dsh_plugin_shop_css_d74581c2_default.detail,
|
|
9326
9506
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
9327
|
-
className:
|
|
9507
|
+
className: _dsh_plugin_shop_css_d74581c2_default.detailRows,
|
|
9328
9508
|
children: [
|
|
9329
9509
|
npmUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9330
|
-
className:
|
|
9510
|
+
className: _dsh_plugin_shop_css_d74581c2_default.detailRow,
|
|
9331
9511
|
"data-shop-npm": true,
|
|
9332
9512
|
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", {
|
|
9333
9513
|
href: npmUrl,
|
|
@@ -9337,7 +9517,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9337
9517
|
}) })]
|
|
9338
9518
|
}),
|
|
9339
9519
|
entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9340
|
-
className:
|
|
9520
|
+
className: _dsh_plugin_shop_css_d74581c2_default.detailRow,
|
|
9341
9521
|
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", {
|
|
9342
9522
|
href: entry.repository,
|
|
9343
9523
|
target: "_blank",
|
|
@@ -9346,25 +9526,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9346
9526
|
}) : entry.repository })]
|
|
9347
9527
|
}),
|
|
9348
9528
|
entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9349
|
-
className:
|
|
9529
|
+
className: _dsh_plugin_shop_css_d74581c2_default.detailRow,
|
|
9350
9530
|
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 })]
|
|
9351
9531
|
})
|
|
9352
9532
|
]
|
|
9353
9533
|
}), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9354
|
-
className:
|
|
9534
|
+
className: _dsh_plugin_shop_css_d74581c2_default.reviewedLine,
|
|
9355
9535
|
children: entry.review.reviewedVersion !== void 0 ? t("reviewedVersionLine", {
|
|
9356
|
-
reviewed: entry.review.reviewedVersion,
|
|
9357
|
-
current:
|
|
9536
|
+
reviewed: versionLabel("npm", entry.review.reviewedVersion).text,
|
|
9537
|
+
current: version.text
|
|
9358
9538
|
}) : t("reviewedPinLine", {
|
|
9359
9539
|
pin: reviewHashPin(entry.review),
|
|
9360
|
-
current:
|
|
9540
|
+
current: version.text
|
|
9361
9541
|
})
|
|
9362
9542
|
})]
|
|
9363
9543
|
})
|
|
9364
9544
|
]
|
|
9365
9545
|
}),
|
|
9366
9546
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9367
|
-
className:
|
|
9547
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cardActions,
|
|
9368
9548
|
"data-shop-actions": true,
|
|
9369
9549
|
children: [installed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!inInstalledView && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
|
|
9370
9550
|
target: installTarget,
|
|
@@ -9396,7 +9576,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9396
9576
|
restartBlocked,
|
|
9397
9577
|
reload
|
|
9398
9578
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9399
|
-
className:
|
|
9579
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installedLabel,
|
|
9400
9580
|
"data-shop-installed": true,
|
|
9401
9581
|
children: t("installed")
|
|
9402
9582
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerBadge, {
|
|
@@ -9420,20 +9600,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9420
9600
|
reload,
|
|
9421
9601
|
flow: uninstallFlow
|
|
9422
9602
|
})
|
|
9423
|
-
] }), (size !== void 0 || author !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9424
|
-
className:
|
|
9425
|
-
children: [
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9603
|
+
] }), (size !== void 0 || author !== null || shelfDay !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
9604
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cardMeta,
|
|
9605
|
+
children: [
|
|
9606
|
+
shelfDay !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9607
|
+
className: _dsh_plugin_shop_css_d74581c2_default.shelfDate,
|
|
9608
|
+
"data-shop-shelf-date": true,
|
|
9609
|
+
children: t(order === "added" ? "listedOn" : "updatedOn", { date: shelfDay })
|
|
9610
|
+
}),
|
|
9611
|
+
size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9612
|
+
className: _dsh_plugin_shop_css_d74581c2_default.size,
|
|
9613
|
+
"data-shop-size": true,
|
|
9614
|
+
role: "img",
|
|
9615
|
+
"aria-label": t("sizeLabel", { size }),
|
|
9616
|
+
title: t("sizeLabel", { size }),
|
|
9617
|
+
children: size
|
|
9618
|
+
}),
|
|
9619
|
+
author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9620
|
+
className: _dsh_plugin_shop_css_d74581c2_default.author,
|
|
9621
|
+
"data-shop-author": true,
|
|
9622
|
+
children: t("authorLine", { author })
|
|
9623
|
+
})
|
|
9624
|
+
]
|
|
9437
9625
|
})]
|
|
9438
9626
|
})
|
|
9439
9627
|
]
|
|
@@ -9479,13 +9667,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9479
9667
|
...attribute,
|
|
9480
9668
|
children: blocker.text
|
|
9481
9669
|
}), blocker.remedy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9482
|
-
className:
|
|
9670
|
+
className: _dsh_plugin_shop_css_d74581c2_default.remedy,
|
|
9483
9671
|
"data-shop-remedy": blocker.kind,
|
|
9484
9672
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9485
|
-
className:
|
|
9673
|
+
className: _dsh_plugin_shop_css_d74581c2_default.remedyLead,
|
|
9486
9674
|
children: blocker.remedy.lead
|
|
9487
9675
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
9488
|
-
className:
|
|
9676
|
+
className: _dsh_plugin_shop_css_d74581c2_default.allowCommand,
|
|
9489
9677
|
"data-shop-allow-command": true,
|
|
9490
9678
|
children: blocker.remedy.command
|
|
9491
9679
|
})]
|
|
@@ -9523,7 +9711,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9523
9711
|
if (lead === void 0 || word === null) return null;
|
|
9524
9712
|
const detail = blockers.map((blocker) => blocker.text).join("\n");
|
|
9525
9713
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9526
|
-
className:
|
|
9714
|
+
className: _dsh_plugin_shop_css_d74581c2_default.incompatibleBadge,
|
|
9527
9715
|
"data-shop-blocker": lead.kind,
|
|
9528
9716
|
role: "img",
|
|
9529
9717
|
"aria-label": detail,
|
|
@@ -9540,37 +9728,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9540
9728
|
const [gateOpen, setGateOpen] = (0, react.useState)(false);
|
|
9541
9729
|
const { view, start } = flow;
|
|
9542
9730
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9543
|
-
className:
|
|
9731
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
|
|
9544
9732
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9545
|
-
className:
|
|
9733
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installing,
|
|
9546
9734
|
children: t(installPhaseKey(view.phase))
|
|
9547
9735
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9548
|
-
className:
|
|
9736
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
9549
9737
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9550
|
-
className:
|
|
9738
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
9551
9739
|
"data-shop-log-line": true,
|
|
9552
9740
|
children: line
|
|
9553
9741
|
}, index))
|
|
9554
9742
|
})]
|
|
9555
9743
|
});
|
|
9556
9744
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9557
|
-
className:
|
|
9745
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installedActions,
|
|
9558
9746
|
children: [
|
|
9559
9747
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9560
|
-
className:
|
|
9748
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
9561
9749
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9562
|
-
className:
|
|
9750
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
9563
9751
|
"data-shop-log-line": true,
|
|
9564
9752
|
children: line
|
|
9565
9753
|
}, index))
|
|
9566
9754
|
}),
|
|
9567
9755
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9568
|
-
className:
|
|
9756
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
9569
9757
|
"data-shop-restart-notice": true,
|
|
9570
9758
|
children: t(activationNoticeKey(view.activation, view.restartReason))
|
|
9571
9759
|
}),
|
|
9572
9760
|
view.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9573
|
-
className:
|
|
9761
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
9574
9762
|
"data-shop-done-note": true,
|
|
9575
9763
|
children: view.detail
|
|
9576
9764
|
}),
|
|
@@ -9585,57 +9773,57 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9585
9773
|
]
|
|
9586
9774
|
});
|
|
9587
9775
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9588
|
-
className:
|
|
9776
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
|
|
9589
9777
|
children: [
|
|
9590
9778
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9591
|
-
className:
|
|
9779
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedHeading,
|
|
9592
9780
|
children: t("installFailed")
|
|
9593
9781
|
}),
|
|
9594
9782
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9595
|
-
className:
|
|
9783
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
9596
9784
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9597
|
-
className:
|
|
9785
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
9598
9786
|
"data-shop-log-line": true,
|
|
9599
9787
|
children: line
|
|
9600
9788
|
}, index))
|
|
9601
9789
|
}),
|
|
9602
9790
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9603
|
-
className:
|
|
9791
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
9604
9792
|
children: view.detail === "" ? t("installTransportFailed") : view.detail
|
|
9605
9793
|
})
|
|
9606
9794
|
]
|
|
9607
9795
|
});
|
|
9608
9796
|
if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9609
|
-
className:
|
|
9797
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
|
|
9610
9798
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9611
|
-
className:
|
|
9799
|
+
className: _dsh_plugin_shop_css_d74581c2_default.rejectedCode,
|
|
9612
9800
|
children: t(rejectionCodeKey(view.code))
|
|
9613
9801
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9614
|
-
className:
|
|
9802
|
+
className: _dsh_plugin_shop_css_d74581c2_default.rejectedDetail,
|
|
9615
9803
|
children: view.detail
|
|
9616
9804
|
})]
|
|
9617
9805
|
});
|
|
9618
9806
|
if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9619
|
-
className:
|
|
9807
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gate,
|
|
9620
9808
|
children: [
|
|
9621
9809
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9622
|
-
className:
|
|
9810
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateTitle,
|
|
9623
9811
|
children: t("acknowledgementTitle")
|
|
9624
9812
|
}),
|
|
9625
9813
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9626
|
-
className:
|
|
9814
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateBody,
|
|
9627
9815
|
children: t("acknowledgementBody")
|
|
9628
9816
|
}),
|
|
9629
9817
|
!blockersStated && blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
9630
9818
|
blocker,
|
|
9631
|
-
className:
|
|
9819
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateWarning,
|
|
9632
9820
|
surface: "warning"
|
|
9633
9821
|
}, blocker.kind)),
|
|
9634
9822
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9635
|
-
className:
|
|
9823
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateActions,
|
|
9636
9824
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9637
9825
|
type: "button",
|
|
9638
|
-
className:
|
|
9826
|
+
className: _dsh_plugin_shop_css_d74581c2_default.confirmButton,
|
|
9639
9827
|
"data-shop-confirm": true,
|
|
9640
9828
|
onClick: () => {
|
|
9641
9829
|
setGateOpen(false);
|
|
@@ -9647,7 +9835,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9647
9835
|
children: t("confirm")
|
|
9648
9836
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9649
9837
|
type: "button",
|
|
9650
|
-
className:
|
|
9838
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cancelButton,
|
|
9651
9839
|
onClick: () => setGateOpen(false),
|
|
9652
9840
|
children: t("cancel")
|
|
9653
9841
|
})]
|
|
@@ -9659,7 +9847,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9659
9847
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9660
9848
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9661
9849
|
type: "button",
|
|
9662
|
-
className:
|
|
9850
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installButton,
|
|
9663
9851
|
disabled: refused,
|
|
9664
9852
|
...refused ? { "data-shop-refused": true } : {},
|
|
9665
9853
|
...update ? { "data-shop-update": true } : { "data-shop-install": true },
|
|
@@ -9677,11 +9865,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9677
9865
|
t
|
|
9678
9866
|
}),
|
|
9679
9867
|
refused && !blockersStated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9680
|
-
className:
|
|
9868
|
+
className: _dsh_plugin_shop_css_d74581c2_default.refusal,
|
|
9681
9869
|
"data-shop-refusal": true,
|
|
9682
9870
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
9683
9871
|
blocker,
|
|
9684
|
-
className:
|
|
9872
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateWarning,
|
|
9685
9873
|
surface: "warning"
|
|
9686
9874
|
}, blocker.kind))
|
|
9687
9875
|
})
|
|
@@ -9696,32 +9884,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9696
9884
|
function UninstallPanel({ name, t, restart, restartBlocked, reload, flow }) {
|
|
9697
9885
|
const { view, start, reset } = flow;
|
|
9698
9886
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9699
|
-
className:
|
|
9887
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
|
|
9700
9888
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9701
|
-
className:
|
|
9889
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installing,
|
|
9702
9890
|
children: t("uninstalling")
|
|
9703
9891
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9704
|
-
className:
|
|
9892
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
9705
9893
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9706
|
-
className:
|
|
9894
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
9707
9895
|
"data-shop-log-line": true,
|
|
9708
9896
|
children: line
|
|
9709
9897
|
}, index))
|
|
9710
9898
|
})]
|
|
9711
9899
|
});
|
|
9712
9900
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9713
|
-
className:
|
|
9901
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installedActions,
|
|
9714
9902
|
children: [
|
|
9715
9903
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9716
|
-
className:
|
|
9904
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
9717
9905
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9718
|
-
className:
|
|
9906
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
9719
9907
|
"data-shop-log-line": true,
|
|
9720
9908
|
children: line
|
|
9721
9909
|
}, index))
|
|
9722
9910
|
}),
|
|
9723
9911
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9724
|
-
className:
|
|
9912
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
9725
9913
|
"data-shop-uninstall-done": true,
|
|
9726
9914
|
children: t(uninstallActivationNoticeKey(view.activation))
|
|
9727
9915
|
}),
|
|
@@ -9735,7 +9923,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9735
9923
|
}),
|
|
9736
9924
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9737
9925
|
type: "button",
|
|
9738
|
-
className:
|
|
9926
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cancelButton,
|
|
9739
9927
|
"data-shop-uninstall-dismiss": true,
|
|
9740
9928
|
onClick: reset,
|
|
9741
9929
|
children: t("dismiss")
|
|
@@ -9743,27 +9931,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9743
9931
|
]
|
|
9744
9932
|
});
|
|
9745
9933
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9746
|
-
className:
|
|
9934
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
|
|
9747
9935
|
children: [
|
|
9748
9936
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9749
|
-
className:
|
|
9937
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedHeading,
|
|
9750
9938
|
children: t("uninstallFailed")
|
|
9751
9939
|
}),
|
|
9752
9940
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9753
|
-
className:
|
|
9941
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
9754
9942
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9755
|
-
className:
|
|
9943
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
9756
9944
|
"data-shop-log-line": true,
|
|
9757
9945
|
children: line
|
|
9758
9946
|
}, index))
|
|
9759
9947
|
}),
|
|
9760
9948
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9761
|
-
className:
|
|
9949
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
9762
9950
|
children: view.detail === "" ? t("uninstallTransportFailed") : view.detail
|
|
9763
9951
|
}),
|
|
9764
9952
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9765
9953
|
type: "button",
|
|
9766
|
-
className:
|
|
9954
|
+
className: _dsh_plugin_shop_css_d74581c2_default.uninstallButton,
|
|
9767
9955
|
"data-shop-uninstall-retry": true,
|
|
9768
9956
|
onClick: () => void start({ name }),
|
|
9769
9957
|
children: t("retry")
|
|
@@ -9773,7 +9961,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9773
9961
|
if (view.kind !== "idle") return null;
|
|
9774
9962
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9775
9963
|
type: "button",
|
|
9776
|
-
className:
|
|
9964
|
+
className: _dsh_plugin_shop_css_d74581c2_default.uninstallButton,
|
|
9777
9965
|
"data-shop-uninstall": true,
|
|
9778
9966
|
onClick: () => void start({ name }),
|
|
9779
9967
|
children: t("uninstall")
|
|
@@ -9814,38 +10002,38 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9814
10002
|
else if (outcome.kind === "unreachable") setRefusal(t("restartTransportFailed"));
|
|
9815
10003
|
};
|
|
9816
10004
|
if (monitor?.kind === "requesting" || monitor?.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9817
|
-
className:
|
|
10005
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
9818
10006
|
"data-shop-restarting": true,
|
|
9819
10007
|
children: t("restarting")
|
|
9820
10008
|
});
|
|
9821
10009
|
if (monitor?.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9822
|
-
className:
|
|
10010
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
9823
10011
|
"data-shop-restart-error": true,
|
|
9824
10012
|
children: monitor.logFile === void 0 ? t("restartFailedNotice") : t("restartFailedLogNotice", { log: monitor.logFile })
|
|
9825
10013
|
});
|
|
9826
10014
|
if (monitor?.kind === "not-restarted") return null;
|
|
9827
10015
|
if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9828
|
-
className:
|
|
10016
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gate,
|
|
9829
10017
|
children: [
|
|
9830
10018
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9831
|
-
className:
|
|
10019
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateTitle,
|
|
9832
10020
|
children: t("restartTitle")
|
|
9833
10021
|
}),
|
|
9834
10022
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9835
|
-
className:
|
|
10023
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateBody,
|
|
9836
10024
|
children: t("restartBody")
|
|
9837
10025
|
}),
|
|
9838
10026
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9839
|
-
className:
|
|
10027
|
+
className: _dsh_plugin_shop_css_d74581c2_default.gateActions,
|
|
9840
10028
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9841
10029
|
type: "button",
|
|
9842
|
-
className:
|
|
10030
|
+
className: _dsh_plugin_shop_css_d74581c2_default.confirmButton,
|
|
9843
10031
|
"data-shop-restart-confirm": true,
|
|
9844
10032
|
onClick: () => void onConfirm(),
|
|
9845
10033
|
children: t("restartConfirm")
|
|
9846
10034
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9847
10035
|
type: "button",
|
|
9848
|
-
className:
|
|
10036
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cancelButton,
|
|
9849
10037
|
onClick: () => setGateOpen(false),
|
|
9850
10038
|
children: t("cancel")
|
|
9851
10039
|
})]
|
|
@@ -9853,14 +10041,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9853
10041
|
]
|
|
9854
10042
|
});
|
|
9855
10043
|
const refused = refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9856
|
-
className:
|
|
10044
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
9857
10045
|
"data-shop-restart-error": true,
|
|
9858
10046
|
children: refusal
|
|
9859
10047
|
});
|
|
9860
10048
|
if (gate !== void 0) return refused;
|
|
9861
10049
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [refused, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9862
10050
|
type: "button",
|
|
9863
|
-
className:
|
|
10051
|
+
className: _dsh_plugin_shop_css_d74581c2_default.restartButton,
|
|
9864
10052
|
"data-shop-restart": true,
|
|
9865
10053
|
onClick: () => setGateOpen(true),
|
|
9866
10054
|
children: t("restart")
|
|
@@ -9878,13 +10066,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9878
10066
|
*/
|
|
9879
10067
|
function NotRestartedNotice({ t, pid, logFile }) {
|
|
9880
10068
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9881
|
-
className:
|
|
10069
|
+
className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
|
|
9882
10070
|
"data-shop-not-restarted": true,
|
|
9883
10071
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9884
|
-
className:
|
|
10072
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
9885
10073
|
children: pid === void 0 ? t("notRestartedNotice") : t("notRestartedPidNotice", { pid: String(pid) })
|
|
9886
10074
|
}), logFile !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9887
|
-
className:
|
|
10075
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
9888
10076
|
children: t("notRestartedLogNotice", { log: logFile })
|
|
9889
10077
|
})]
|
|
9890
10078
|
});
|
|
@@ -9914,7 +10102,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9914
10102
|
restart,
|
|
9915
10103
|
reload
|
|
9916
10104
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9917
|
-
className:
|
|
10105
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
9918
10106
|
"data-shop-restart-disabled": true,
|
|
9919
10107
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
9920
10108
|
});
|
|
@@ -9925,14 +10113,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9925
10113
|
* would help without knowing that now is a good time. */
|
|
9926
10114
|
function ReloadPanel({ t, reload, where }) {
|
|
9927
10115
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9928
|
-
className:
|
|
10116
|
+
className: _dsh_plugin_shop_css_d74581c2_default.reloadPanel,
|
|
9929
10117
|
"data-shop-reload": where,
|
|
9930
10118
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9931
|
-
className:
|
|
10119
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
9932
10120
|
children: t("reloadNote")
|
|
9933
10121
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9934
10122
|
type: "button",
|
|
9935
|
-
className:
|
|
10123
|
+
className: _dsh_plugin_shop_css_d74581c2_default.reloadButton,
|
|
9936
10124
|
onClick: reload,
|
|
9937
10125
|
children: t("reload")
|
|
9938
10126
|
})]
|
|
@@ -9983,7 +10171,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9983
10171
|
}
|
|
9984
10172
|
};
|
|
9985
10173
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9986
|
-
className:
|
|
10174
|
+
className: _dsh_plugin_shop_css_d74581c2_default.switchWrap,
|
|
9987
10175
|
"data-shop-enabled-switch": row.name,
|
|
9988
10176
|
children: [
|
|
9989
10177
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -9992,18 +10180,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9992
10180
|
"aria-checked": enabled,
|
|
9993
10181
|
"aria-label": t("enabledSwitch"),
|
|
9994
10182
|
"data-shop-toggle": true,
|
|
9995
|
-
className: `${
|
|
10183
|
+
className: `${_dsh_plugin_shop_css_d74581c2_default.switch} ${enabled ? _dsh_plugin_shop_css_d74581c2_default.switchOn : ""}`,
|
|
9996
10184
|
onClick: () => void onToggle(),
|
|
9997
10185
|
disabled: toggle.kind === "saving",
|
|
9998
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10186
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.switchKnob })
|
|
9999
10187
|
}),
|
|
10000
10188
|
toggle.kind === "saved" && owed === "nothing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10001
|
-
className:
|
|
10189
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
10002
10190
|
"data-shop-hot-apply": true,
|
|
10003
10191
|
children: t("hotApplyNote")
|
|
10004
10192
|
}),
|
|
10005
10193
|
owed === "restart" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10006
|
-
className:
|
|
10194
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
10007
10195
|
"data-shop-toggle-restart": true,
|
|
10008
10196
|
children: t("toggleRestartNote")
|
|
10009
10197
|
}),
|
|
@@ -10016,7 +10204,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10016
10204
|
where: "toggle"
|
|
10017
10205
|
}),
|
|
10018
10206
|
toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10019
|
-
className:
|
|
10207
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
10020
10208
|
"data-shop-toggle-error": true,
|
|
10021
10209
|
children: toggle.detail
|
|
10022
10210
|
})
|
|
@@ -10031,19 +10219,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10031
10219
|
* field is narrowed at the parameter. */
|
|
10032
10220
|
function OutdatedRow({ row, tier, missing, harness, t, setEnabled, flowFor, restart, restartBlocked, reload, restarts }) {
|
|
10033
10221
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10034
|
-
className:
|
|
10222
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedRow,
|
|
10035
10223
|
"data-shop-outdated-entry": row.name,
|
|
10036
10224
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10037
|
-
className:
|
|
10225
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedInfo,
|
|
10038
10226
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10039
|
-
className:
|
|
10227
|
+
className: _dsh_plugin_shop_css_d74581c2_default.name,
|
|
10040
10228
|
children: row.name
|
|
10041
10229
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10042
|
-
className:
|
|
10043
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installedVersion", { version: row.source
|
|
10230
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedVersions,
|
|
10231
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installedVersion", { version: versionLabel(row.source, row.installed).text }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("latestVersion", { version: versionLabel(row.source, row.latest).text }) })]
|
|
10044
10232
|
})]
|
|
10045
10233
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10046
|
-
className:
|
|
10234
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedActions,
|
|
10047
10235
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnabledSwitch, {
|
|
10048
10236
|
row,
|
|
10049
10237
|
t,
|
|
@@ -10092,22 +10280,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10092
10280
|
function OutdatedSection({ state, entriesByKey, missingByKey, harnessVerdicts, t, setEnabled, flowFor, restart, restartBlocked, reload, restarts }) {
|
|
10093
10281
|
if (state.kind === "loading") return null;
|
|
10094
10282
|
if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10095
|
-
className:
|
|
10283
|
+
className: _dsh_plugin_shop_css_d74581c2_default.stateLine,
|
|
10096
10284
|
"data-shop-outdated-error": true,
|
|
10097
10285
|
children: t("installedError")
|
|
10098
10286
|
});
|
|
10099
10287
|
const outdated = state.entries.filter((entry) => entry.outdated && entry.latest !== null);
|
|
10100
10288
|
if (outdated.length === 0) return null;
|
|
10101
10289
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10102
|
-
className:
|
|
10290
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedSection,
|
|
10103
10291
|
"data-shop-outdated": true,
|
|
10104
10292
|
"aria-labelledby": UPDATABLE_HEADING_ID,
|
|
10105
10293
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
10106
|
-
className:
|
|
10294
|
+
className: _dsh_plugin_shop_css_d74581c2_default.updatableHeading,
|
|
10107
10295
|
id: UPDATABLE_HEADING_ID,
|
|
10108
10296
|
children: t("updatableSection")
|
|
10109
10297
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10110
|
-
className:
|
|
10298
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedList,
|
|
10111
10299
|
children: outdated.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
|
|
10112
10300
|
row,
|
|
10113
10301
|
tier: entriesByKey.get(identityKey(row))?.tier ?? "community",
|
|
@@ -10135,37 +10323,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10135
10323
|
const shadowed = entries.filter((entry) => entry.shadowed === true);
|
|
10136
10324
|
if (shadowed.length === 0) return null;
|
|
10137
10325
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
10138
|
-
className:
|
|
10326
|
+
className: _dsh_plugin_shop_css_d74581c2_default.shadowedSection,
|
|
10139
10327
|
"data-shop-shadowed": true,
|
|
10140
10328
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10141
|
-
className:
|
|
10329
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedList,
|
|
10142
10330
|
children: shadowed.map((row) => {
|
|
10143
10331
|
const key = identityKey(row);
|
|
10144
10332
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10145
|
-
className:
|
|
10333
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedRow,
|
|
10146
10334
|
"data-shop-shadowed-entry": row.name,
|
|
10147
10335
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10148
|
-
className:
|
|
10336
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedInfo,
|
|
10149
10337
|
children: [
|
|
10150
10338
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10151
|
-
className:
|
|
10339
|
+
className: _dsh_plugin_shop_css_d74581c2_default.name,
|
|
10152
10340
|
children: row.name
|
|
10153
10341
|
}),
|
|
10154
10342
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10155
|
-
className:
|
|
10343
|
+
className: _dsh_plugin_shop_css_d74581c2_default.badges,
|
|
10156
10344
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10157
|
-
className:
|
|
10345
|
+
className: _dsh_plugin_shop_css_d74581c2_default.tierBadge,
|
|
10158
10346
|
"data-tier": "shadowed",
|
|
10159
10347
|
children: t("shadowedBadge")
|
|
10160
10348
|
})
|
|
10161
10349
|
}),
|
|
10162
10350
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10163
|
-
className:
|
|
10351
|
+
className: _dsh_plugin_shop_css_d74581c2_default.shadowedDetail,
|
|
10164
10352
|
children: t("shadowedDetail")
|
|
10165
10353
|
})
|
|
10166
10354
|
]
|
|
10167
10355
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10168
|
-
className:
|
|
10356
|
+
className: _dsh_plugin_shop_css_d74581c2_default.outdatedActions,
|
|
10169
10357
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UninstallPanel, {
|
|
10170
10358
|
name: row.name,
|
|
10171
10359
|
t,
|
|
@@ -10215,16 +10403,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10215
10403
|
role: "alert",
|
|
10216
10404
|
children: [
|
|
10217
10405
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10218
|
-
className:
|
|
10406
|
+
className: _dsh_plugin_shop_css_d74581c2_default.stateLine,
|
|
10219
10407
|
children: say("tabCrashed", en.tabCrashed)
|
|
10220
10408
|
}),
|
|
10221
10409
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10222
|
-
className:
|
|
10410
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
10223
10411
|
children: error.message
|
|
10224
10412
|
}),
|
|
10225
10413
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10226
10414
|
type: "button",
|
|
10227
|
-
className:
|
|
10415
|
+
className: _dsh_plugin_shop_css_d74581c2_default.actionButton,
|
|
10228
10416
|
onClick: () => this.setState({ error: null }),
|
|
10229
10417
|
children: say("retry", en.retry)
|
|
10230
10418
|
})
|
|
@@ -10311,11 +10499,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10311
10499
|
const [reloadFailed, setReloadFailed] = (0, react.useState)(false);
|
|
10312
10500
|
const [query, setQuery] = (0, react.useState)("");
|
|
10313
10501
|
const [category, setCategory] = (0, react.useState)(null);
|
|
10502
|
+
const [order, setOrder] = (0, react.useState)("stars");
|
|
10314
10503
|
const [hideIncompatible, setHideIncompatible] = (0, react.useState)(false);
|
|
10315
10504
|
const incremental = typeof IntersectionObserver !== "undefined";
|
|
10316
10505
|
const [visibleCount, setVisibleCount] = (0, react.useState)(48);
|
|
10317
10506
|
const sentinelRef = (0, react.useRef)(null);
|
|
10318
10507
|
const filteredLenRef = (0, react.useRef)(0);
|
|
10508
|
+
const sortLabelId = (0, react.useId)();
|
|
10319
10509
|
const pendingRefreshRef = (0, react.useRef)(null);
|
|
10320
10510
|
(0, react.useEffect)(() => {
|
|
10321
10511
|
let cancelled = false;
|
|
@@ -10410,7 +10600,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10410
10600
|
return map;
|
|
10411
10601
|
}, [installedState]);
|
|
10412
10602
|
const stars = (0, react.useMemo)(() => catalogState.kind === "ready" ? catalogState.result.stars : {}, [catalogState]);
|
|
10413
|
-
const
|
|
10603
|
+
const starOrder = (0, react.useMemo)(() => catalogState.kind === "ready" ? sortByStars(catalogState.result.plugins, stars) : [], [catalogState, stars]);
|
|
10604
|
+
const builtAt = catalogState.kind === "ready" ? catalogState.result.builtAt : "";
|
|
10605
|
+
const sortedCatalog = (0, react.useMemo)(() => orderShelf(starOrder, order, builtAt), [
|
|
10606
|
+
starOrder,
|
|
10607
|
+
order,
|
|
10608
|
+
builtAt
|
|
10609
|
+
]);
|
|
10414
10610
|
const browsable = (0, react.useMemo)(() => {
|
|
10415
10611
|
if (catalogState.kind !== "ready") return [];
|
|
10416
10612
|
const cleared = new Set(catalogState.result.notAShop ?? []);
|
|
@@ -10483,6 +10679,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10483
10679
|
filtered.length
|
|
10484
10680
|
]);
|
|
10485
10681
|
const visible = incremental ? filtered.slice(0, visibleCount) : filtered;
|
|
10682
|
+
/** The date a card shows under the current order, or undefined under the
|
|
10683
|
+
* star order and for an entry with no usable date. Computed from the same
|
|
10684
|
+
* `shelfTime` the order keyed on, so a label can never name a date the
|
|
10685
|
+
* order ignored. */
|
|
10686
|
+
const shelfDayOf = (entry) => {
|
|
10687
|
+
const ms = shelfTime(entry, order, builtAt);
|
|
10688
|
+
return ms === void 0 ? void 0 : utcDay(ms);
|
|
10689
|
+
};
|
|
10486
10690
|
const categoryCounts = (0, react.useMemo)(() => {
|
|
10487
10691
|
const counts = /* @__PURE__ */ new Map();
|
|
10488
10692
|
for (const entry of browsable) {
|
|
@@ -10505,19 +10709,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10505
10709
|
"data-shop-tab": true,
|
|
10506
10710
|
"aria-busy": "true",
|
|
10507
10711
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10508
|
-
className:
|
|
10712
|
+
className: _dsh_plugin_shop_css_d74581c2_default.srOnly,
|
|
10509
10713
|
children: t("loading")
|
|
10510
10714
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10511
|
-
className:
|
|
10715
|
+
className: _dsh_plugin_shop_css_d74581c2_default.skeletonGrid,
|
|
10512
10716
|
"data-shop-skeleton": true,
|
|
10513
10717
|
"aria-hidden": "true",
|
|
10514
10718
|
children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10515
|
-
className:
|
|
10719
|
+
className: _dsh_plugin_shop_css_d74581c2_default.skeletonCard,
|
|
10516
10720
|
children: [
|
|
10517
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10518
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10519
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10520
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10721
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonName }),
|
|
10722
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonSummary }),
|
|
10723
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonSummaryShort }),
|
|
10724
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonActions })
|
|
10521
10725
|
]
|
|
10522
10726
|
}, i))
|
|
10523
10727
|
})]
|
|
@@ -10527,11 +10731,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10527
10731
|
translate: "no",
|
|
10528
10732
|
"data-shop-tab": true,
|
|
10529
10733
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10530
|
-
className:
|
|
10734
|
+
className: _dsh_plugin_shop_css_d74581c2_default.stateLine,
|
|
10531
10735
|
children: t("error")
|
|
10532
10736
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10533
10737
|
type: "button",
|
|
10534
|
-
className:
|
|
10738
|
+
className: _dsh_plugin_shop_css_d74581c2_default.actionButton,
|
|
10535
10739
|
onClick: () => {
|
|
10536
10740
|
setRequest({ kind: "retry" });
|
|
10537
10741
|
setVersionReload((current) => current + 1);
|
|
@@ -10546,11 +10750,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10546
10750
|
"data-shop-tab": true,
|
|
10547
10751
|
children: [
|
|
10548
10752
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10549
|
-
className:
|
|
10753
|
+
className: _dsh_plugin_shop_css_d74581c2_default.toolbar,
|
|
10550
10754
|
children: [
|
|
10551
10755
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
10552
10756
|
type: "search",
|
|
10553
|
-
className:
|
|
10757
|
+
className: _dsh_plugin_shop_css_d74581c2_default.searchInput,
|
|
10554
10758
|
"aria-label": t("search"),
|
|
10555
10759
|
placeholder: t("search"),
|
|
10556
10760
|
value: query,
|
|
@@ -10561,31 +10765,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10561
10765
|
}),
|
|
10562
10766
|
expansionMemo.intents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10563
10767
|
"data-shop-expansion-note": true,
|
|
10564
|
-
className:
|
|
10768
|
+
className: _dsh_plugin_shop_css_d74581c2_default.expansionNote,
|
|
10565
10769
|
children: t("zhExpansionNote", { terms: expansionMemo.terms.slice(1).map((term) => term.startsWith("#") ? term.slice(1) : term).join(", ") })
|
|
10566
10770
|
}),
|
|
10567
10771
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10568
|
-
className:
|
|
10772
|
+
className: _dsh_plugin_shop_css_d74581c2_default.toolbarRight,
|
|
10569
10773
|
children: [
|
|
10570
10774
|
result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10571
|
-
className:
|
|
10775
|
+
className: _dsh_plugin_shop_css_d74581c2_default.staleBadge,
|
|
10572
10776
|
children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
|
|
10573
10777
|
}),
|
|
10574
10778
|
selfVersion !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10575
|
-
className:
|
|
10779
|
+
className: _dsh_plugin_shop_css_d74581c2_default.versionBlock,
|
|
10576
10780
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10577
|
-
className:
|
|
10781
|
+
className: _dsh_plugin_shop_css_d74581c2_default.versionText,
|
|
10578
10782
|
"data-shop-version": true,
|
|
10579
10783
|
children: ["v", selfVersion.installed]
|
|
10580
10784
|
}), restartMonitor !== null ? null : selfPending && restartBlocked === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10581
10785
|
type: "button",
|
|
10582
|
-
className:
|
|
10786
|
+
className: _dsh_plugin_shop_css_d74581c2_default.restartSelfButton,
|
|
10583
10787
|
"data-shop-restart": true,
|
|
10584
10788
|
onClick: () => setSelfRestartGate(true),
|
|
10585
10789
|
children: t("restart")
|
|
10586
10790
|
}) : !selfPending && selfVersion.outdated && selfVersion.latest !== null && selfUpdate.view.kind === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10587
10791
|
type: "button",
|
|
10588
|
-
className:
|
|
10792
|
+
className: _dsh_plugin_shop_css_d74581c2_default.updateSelfButton,
|
|
10589
10793
|
"data-shop-update-self": true,
|
|
10590
10794
|
onClick: () => {
|
|
10591
10795
|
if (selfVersion.latest !== null) selfUpdate.start({ version: selfVersion.latest });
|
|
@@ -10593,7 +10797,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10593
10797
|
children: t("update")
|
|
10594
10798
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10595
10799
|
type: "button",
|
|
10596
|
-
className:
|
|
10800
|
+
className: _dsh_plugin_shop_css_d74581c2_default.checkUpdateButton,
|
|
10597
10801
|
"data-shop-check-update": true,
|
|
10598
10802
|
title: t("checkUpdateTitle"),
|
|
10599
10803
|
disabled: checkState !== "idle",
|
|
@@ -10602,7 +10806,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10602
10806
|
})]
|
|
10603
10807
|
}),
|
|
10604
10808
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
10605
|
-
className:
|
|
10809
|
+
className: _dsh_plugin_shop_css_d74581c2_default.githubLink,
|
|
10606
10810
|
href: SHOP_REPO_URL,
|
|
10607
10811
|
target: "_blank",
|
|
10608
10812
|
rel: "noopener noreferrer",
|
|
@@ -10627,28 +10831,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10627
10831
|
logFile: restartMonitor.logFile
|
|
10628
10832
|
}),
|
|
10629
10833
|
selfUpdate.view.kind === "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10630
|
-
className:
|
|
10834
|
+
className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
|
|
10631
10835
|
"data-shop-self-updating": true,
|
|
10632
10836
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10633
|
-
className:
|
|
10837
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installing,
|
|
10634
10838
|
children: t(installPhaseKey(selfUpdate.view.phase))
|
|
10635
10839
|
}), selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10636
|
-
className:
|
|
10840
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
10637
10841
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10638
|
-
className:
|
|
10842
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
10639
10843
|
"data-shop-log-line": true,
|
|
10640
10844
|
children: line
|
|
10641
10845
|
}, index))
|
|
10642
10846
|
})]
|
|
10643
10847
|
}),
|
|
10644
10848
|
selfPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10645
|
-
className:
|
|
10849
|
+
className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
|
|
10646
10850
|
"data-shop-self-update-done": true,
|
|
10647
10851
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10648
|
-
className:
|
|
10852
|
+
className: _dsh_plugin_shop_css_d74581c2_default.installedActions,
|
|
10649
10853
|
children: [
|
|
10650
10854
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10651
|
-
className:
|
|
10855
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
10652
10856
|
children: t("installedRestartNotice")
|
|
10653
10857
|
}),
|
|
10654
10858
|
restartBlocked === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RestartPanel, {
|
|
@@ -10661,7 +10865,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10661
10865
|
}
|
|
10662
10866
|
}),
|
|
10663
10867
|
restartBlocked !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10664
|
-
className:
|
|
10868
|
+
className: _dsh_plugin_shop_css_d74581c2_default.notice,
|
|
10665
10869
|
"data-shop-restart-disabled": true,
|
|
10666
10870
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
10667
10871
|
})
|
|
@@ -10669,35 +10873,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10669
10873
|
})
|
|
10670
10874
|
}),
|
|
10671
10875
|
selfUpdate.view.kind === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10672
|
-
className:
|
|
10876
|
+
className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
|
|
10673
10877
|
"data-shop-self-update-failed": true,
|
|
10674
10878
|
children: [
|
|
10675
10879
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10676
|
-
className:
|
|
10880
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedHeading,
|
|
10677
10881
|
children: t("updateFailed")
|
|
10678
10882
|
}),
|
|
10679
10883
|
selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10680
|
-
className:
|
|
10884
|
+
className: _dsh_plugin_shop_css_d74581c2_default.log,
|
|
10681
10885
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10682
|
-
className:
|
|
10886
|
+
className: _dsh_plugin_shop_css_d74581c2_default.logLine,
|
|
10683
10887
|
"data-shop-log-line": true,
|
|
10684
10888
|
children: line
|
|
10685
10889
|
}, index))
|
|
10686
10890
|
}),
|
|
10687
10891
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10688
|
-
className:
|
|
10892
|
+
className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
|
|
10689
10893
|
children: selfUpdate.view.detail === "" ? t("updateTransportFailed") : selfUpdate.view.detail
|
|
10690
10894
|
})
|
|
10691
10895
|
]
|
|
10692
10896
|
}),
|
|
10693
10897
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10694
|
-
className:
|
|
10898
|
+
className: _dsh_plugin_shop_css_d74581c2_default.categoryBar,
|
|
10695
10899
|
role: "group",
|
|
10696
10900
|
"aria-label": t("catalog"),
|
|
10697
10901
|
children: [
|
|
10698
10902
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10699
10903
|
type: "button",
|
|
10700
|
-
className: category === null ? `${
|
|
10904
|
+
className: category === null ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
|
|
10701
10905
|
"aria-pressed": category === null,
|
|
10702
10906
|
onClick: () => {
|
|
10703
10907
|
setCategory(null);
|
|
@@ -10712,7 +10916,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10712
10916
|
}),
|
|
10713
10917
|
CATEGORY_ORDER.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10714
10918
|
type: "button",
|
|
10715
|
-
className: category === key ? `${
|
|
10919
|
+
className: category === key ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
|
|
10716
10920
|
"aria-pressed": category === key,
|
|
10717
10921
|
"data-category": key,
|
|
10718
10922
|
"data-shop-category-tab": key,
|
|
@@ -10728,7 +10932,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10728
10932
|
}, key)),
|
|
10729
10933
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10730
10934
|
type: "button",
|
|
10731
|
-
className: category === "installed" ? `${
|
|
10935
|
+
className: category === "installed" ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
|
|
10732
10936
|
"aria-pressed": category === "installed",
|
|
10733
10937
|
"data-shop-category-installed": true,
|
|
10734
10938
|
onClick: () => {
|
|
@@ -10745,7 +10949,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10745
10949
|
type: "button",
|
|
10746
10950
|
role: "switch",
|
|
10747
10951
|
"aria-checked": hideIncompatible,
|
|
10748
|
-
className: hideIncompatible ? `${
|
|
10952
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_d74581c2_default.incompatibleFilter} ${_dsh_plugin_shop_css_d74581c2_default.incompatibleFilterOn}` : _dsh_plugin_shop_css_d74581c2_default.incompatibleFilter,
|
|
10749
10953
|
title: t(hideIncompatible ? "showIncompatibleTitle" : "incompatibleFilterTitle"),
|
|
10750
10954
|
"data-shop-hide-incompatible": true,
|
|
10751
10955
|
onClick: () => {
|
|
@@ -10753,18 +10957,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10753
10957
|
setVisibleCount(48);
|
|
10754
10958
|
},
|
|
10755
10959
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10756
|
-
className: hideIncompatible ? `${
|
|
10960
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_d74581c2_default.switch} ${_dsh_plugin_shop_css_d74581c2_default.switchOn}` : _dsh_plugin_shop_css_d74581c2_default.switch,
|
|
10757
10961
|
"aria-hidden": "true",
|
|
10758
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10962
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.switchKnob })
|
|
10759
10963
|
}), t("hideIncompatible", { count: incompatibleCount })]
|
|
10760
10964
|
})
|
|
10761
10965
|
]
|
|
10762
10966
|
}),
|
|
10763
10967
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10764
|
-
className:
|
|
10968
|
+
className: _dsh_plugin_shop_css_d74581c2_default.catalogStatsRow,
|
|
10765
10969
|
children: [
|
|
10766
10970
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10767
|
-
className:
|
|
10971
|
+
className: _dsh_plugin_shop_css_d74581c2_default.catalogStats,
|
|
10768
10972
|
"data-shop-catalog-stats": true,
|
|
10769
10973
|
children: t("catalogStats", {
|
|
10770
10974
|
count: String(browsable.length),
|
|
@@ -10773,7 +10977,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10773
10977
|
}),
|
|
10774
10978
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10775
10979
|
type: "button",
|
|
10776
|
-
className:
|
|
10980
|
+
className: _dsh_plugin_shop_css_d74581c2_default.catalogRefreshButton,
|
|
10777
10981
|
"data-shop-catalog-refresh": true,
|
|
10778
10982
|
disabled: reloading,
|
|
10779
10983
|
onClick: () => {
|
|
@@ -10785,26 +10989,49 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10785
10989
|
children: reloading ? t("refreshing") : t("refresh")
|
|
10786
10990
|
}),
|
|
10787
10991
|
reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10788
|
-
className:
|
|
10992
|
+
className: _dsh_plugin_shop_css_d74581c2_default.catalogRefreshFailed,
|
|
10789
10993
|
"data-shop-catalog-refresh-failed": true,
|
|
10790
10994
|
children: t("refreshFailed")
|
|
10995
|
+
}),
|
|
10996
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10997
|
+
className: _dsh_plugin_shop_css_d74581c2_default.sortGroup,
|
|
10998
|
+
role: "group",
|
|
10999
|
+
"aria-labelledby": sortLabelId,
|
|
11000
|
+
"data-shop-sort": true,
|
|
11001
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11002
|
+
className: _dsh_plugin_shop_css_d74581c2_default.sortLabel,
|
|
11003
|
+
id: sortLabelId,
|
|
11004
|
+
children: t("sortLabel")
|
|
11005
|
+
}), SHELF_ORDERS.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11006
|
+
type: "button",
|
|
11007
|
+
className: order === name ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
|
|
11008
|
+
"aria-pressed": order === name,
|
|
11009
|
+
"data-shop-order": name,
|
|
11010
|
+
onClick: () => {
|
|
11011
|
+
setOrder(name);
|
|
11012
|
+
setVisibleCount(48);
|
|
11013
|
+
},
|
|
11014
|
+
children: t(shelfOrderLocaleKey(name))
|
|
11015
|
+
}, name))]
|
|
10791
11016
|
})
|
|
10792
11017
|
]
|
|
10793
11018
|
}),
|
|
10794
11019
|
result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10795
|
-
className:
|
|
11020
|
+
className: _dsh_plugin_shop_css_d74581c2_default.emptyLine,
|
|
10796
11021
|
children: t("empty")
|
|
10797
11022
|
}) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10798
|
-
className:
|
|
11023
|
+
className: _dsh_plugin_shop_css_d74581c2_default.emptyLine,
|
|
10799
11024
|
"data-shop-empty": true,
|
|
10800
11025
|
children: matched.length > 0 ? t("emptyIncompatibleFiltered") : t("emptySearch")
|
|
10801
11026
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
10802
|
-
className:
|
|
11027
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cards,
|
|
10803
11028
|
children: [visible.map((entry) => {
|
|
10804
11029
|
const key = entryKey(entry);
|
|
10805
11030
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
|
|
10806
11031
|
entry,
|
|
10807
11032
|
stars: starsOf(entry, stars),
|
|
11033
|
+
order,
|
|
11034
|
+
shelfDay: shelfDayOf(entry),
|
|
10808
11035
|
installed: installedByKey.get(key),
|
|
10809
11036
|
missing: missingByKey.get(key) ?? [],
|
|
10810
11037
|
harness: harnessVerdictOf(harnessVerdicts, key),
|
|
@@ -10821,12 +11048,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10821
11048
|
}) }, key);
|
|
10822
11049
|
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
10823
11050
|
ref: sentinelRef,
|
|
10824
|
-
className:
|
|
11051
|
+
className: _dsh_plugin_shop_css_d74581c2_default.cardsSentry,
|
|
10825
11052
|
"data-shop-sentry": true,
|
|
10826
11053
|
"aria-hidden": "true"
|
|
10827
11054
|
})]
|
|
10828
11055
|
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10829
|
-
className:
|
|
11056
|
+
className: _dsh_plugin_shop_css_d74581c2_default.showingLine,
|
|
10830
11057
|
"aria-live": "polite",
|
|
10831
11058
|
children: t("showing", {
|
|
10832
11059
|
shown: String(visibleCount),
|