dshmarket 1.50.0 → 1.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/client.js +203 -27
- package/lib/types/registry.d.ts +6 -0
- package/package.json +1 -1
- package/src/client/Market.module.css +20 -7
- package/src/client/MarketSection.tsx +101 -31
- package/src/client/OperationsPanel.tsx +7 -5
- package/src/client/locales.ts +4 -0
- package/src/client/market-data.ts +93 -0
- package/src/registry.ts +6 -0
package/client/client.js
CHANGED
|
@@ -271,6 +271,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
271
271
|
hostRequirementUndeclared: "未声明宿主要求",
|
|
272
272
|
hostRequirementUnavailable: "宿主要求未知",
|
|
273
273
|
sortDownloads: "npm 下载量(近 30 天)",
|
|
274
|
+
/** Discover/theme card byline tooltip for catalog `version`. */
|
|
275
|
+
catalogNpmLatest: "npm 当前 latest",
|
|
274
276
|
sortStars: "Star 数",
|
|
275
277
|
sortAdded: "发布时间",
|
|
276
278
|
sortDesc: "降序",
|
|
@@ -804,6 +806,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
804
806
|
hostRequirementUndeclared: "Host requirement undeclared",
|
|
805
807
|
hostRequirementUnavailable: "Host requirement unknown",
|
|
806
808
|
sortDownloads: "npm downloads (30d)",
|
|
809
|
+
/** Discover/theme card byline tooltip for catalog `version`. */
|
|
810
|
+
catalogNpmLatest: "npm latest",
|
|
807
811
|
sortStars: "Stars",
|
|
808
812
|
sortAdded: "Release date",
|
|
809
813
|
sortDesc: "Descending",
|
|
@@ -1820,6 +1824,33 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1820
1824
|
if (/\.svg$/iu.test(parsed.pathname)) return null;
|
|
1821
1825
|
return value;
|
|
1822
1826
|
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Prepare a GitHub release body for the update-notes dialog's tiny markdown
|
|
1829
|
+
* renderer. HTML — especially pasted `<img>` tags — must not surface as
|
|
1830
|
+
* literal text; markdown syntax is left intact for the dialog to render.
|
|
1831
|
+
*/
|
|
1832
|
+
function sanitizeReleaseNotesBody(md) {
|
|
1833
|
+
let s = md.replace(/<!--[\s\S]*?-->/g, "");
|
|
1834
|
+
s = s.replace(/<img\b[^>]*>/gi, "");
|
|
1835
|
+
s = s.replace(/<\/?[a-zA-Z][\w:-]*\b[^>]*>/g, "");
|
|
1836
|
+
s = s.replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n");
|
|
1837
|
+
return s.trim();
|
|
1838
|
+
}
|
|
1839
|
+
/**
|
|
1840
|
+
* A whole-line markdown image with an allowlisted https URL, or null.
|
|
1841
|
+
* Relative paths and non-GitHub hosts stay out of the dialog (same gate as
|
|
1842
|
+
* install screenshots).
|
|
1843
|
+
*/
|
|
1844
|
+
function releaseNotesHttpsImage(line) {
|
|
1845
|
+
const match = /^!\[([^\]]*)\]\(\s*(?:<(https:\/\/[^>]+)>|(https:\/\/[^\s)]+))(?:\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\)$/u.exec(line.trim());
|
|
1846
|
+
if (match === null) return null;
|
|
1847
|
+
const src = safeScreenshot(match[2] ?? match[3] ?? "");
|
|
1848
|
+
if (src === null) return null;
|
|
1849
|
+
return {
|
|
1850
|
+
alt: match[1] ?? "",
|
|
1851
|
+
src
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1823
1854
|
/** Keep only https URLs on allowlisted image hosts; SVG dropped (logos/badges). */
|
|
1824
1855
|
function safeScreenshots(urls) {
|
|
1825
1856
|
if (!Array.isArray(urls)) return [];
|
|
@@ -2055,6 +2086,56 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
2055
2086
|
}
|
|
2056
2087
|
return kept.join("\n").trim();
|
|
2057
2088
|
}
|
|
2089
|
+
/** CJK ideographs — enough to tell a Chinese half from a Latin one. */
|
|
2090
|
+
const CJK_RE = /[\u3400-\u9FFF\uF900-\uFAFF]/gu;
|
|
2091
|
+
/** Count CJK code points in a string. */
|
|
2092
|
+
function cjkCount(text) {
|
|
2093
|
+
return text.match(CJK_RE)?.length ?? 0;
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Pick one language from a `中文 / English` (or reverse) pair. Ambiguous
|
|
2097
|
+
* strings stay unchanged. Callers that prepend `t(…)` must localize the
|
|
2098
|
+
* server half first, then concatenate — this function does not strip UI chrome.
|
|
2099
|
+
*/
|
|
2100
|
+
function pickBilingualPair(text, lang) {
|
|
2101
|
+
const sep = " / ";
|
|
2102
|
+
const parts = text.split(sep);
|
|
2103
|
+
if (parts.length < 2) return text;
|
|
2104
|
+
let bestLeft = parts[0];
|
|
2105
|
+
let bestRight = parts.slice(1).join(sep);
|
|
2106
|
+
let bestScore = Math.abs(cjkCount(bestLeft) - cjkCount(bestRight));
|
|
2107
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
2108
|
+
const left = parts.slice(0, i + 1).join(sep);
|
|
2109
|
+
const right = parts.slice(i + 1).join(sep);
|
|
2110
|
+
const score = Math.abs(cjkCount(left) - cjkCount(right));
|
|
2111
|
+
if (score > bestScore) {
|
|
2112
|
+
bestScore = score;
|
|
2113
|
+
bestLeft = left;
|
|
2114
|
+
bestRight = right;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
if (bestScore === 0) return text;
|
|
2118
|
+
const zhPart = cjkCount(bestLeft) > cjkCount(bestRight) ? bestLeft : bestRight;
|
|
2119
|
+
const enPart = cjkCount(bestLeft) > cjkCount(bestRight) ? bestRight : bestLeft;
|
|
2120
|
+
return lang === "zh" ? zhPart : enPart;
|
|
2121
|
+
}
|
|
2122
|
+
/**
|
|
2123
|
+
* Pick the locale half of a server bilingual string (`中文 / English` or
|
|
2124
|
+
* `English / 中文`). Multiline input is handled line by line. Ambiguous
|
|
2125
|
+
* strings are returned unchanged.
|
|
2126
|
+
*/
|
|
2127
|
+
function localizeBilingual(text, lang) {
|
|
2128
|
+
if (text.includes("\n")) return text.split("\n").map((line) => localizeBilingual(line, lang)).join("\n");
|
|
2129
|
+
return pickBilingualPair(text, lang);
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Localize each bilingual reason and join for display. Reasons are separate
|
|
2133
|
+
* diagnoses; do not rejoin them with ` / `, which is the bilingual separator.
|
|
2134
|
+
*/
|
|
2135
|
+
function localizeBilingualList(parts, lang) {
|
|
2136
|
+
const sep = lang === "zh" ? ";" : "; ";
|
|
2137
|
+
return parts.map((part) => localizeBilingual(part, lang)).filter((part) => part !== "").join(sep);
|
|
2138
|
+
}
|
|
2058
2139
|
/**
|
|
2059
2140
|
* The plugin's own name, for display.
|
|
2060
2141
|
*
|
|
@@ -2247,7 +2328,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
2247
2328
|
};
|
|
2248
2329
|
//#endregion
|
|
2249
2330
|
//#region \0dsh-css:src/client/Market.module.css.mjs
|
|
2250
|
-
const css = ".nUhMVa_root{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);flex-direction:column;display:flex;position:relative;container-type:inline-size}.nUhMVa_head{flex-direction:column;gap:12px;padding:4px 4px 6px;display:flex}.nUhMVa_title{margin:0;font-size:16px;font-weight:500;line-height:24px}.nUhMVa_sub{color:var(--dsw-alias-label-tertiary,#8b93a1);align-items:center;gap:8px;margin:0;font-size:12px;line-height:18px;display:flex}.nUhMVa_submitLink{color:var(--dsw-alias-label-tertiary,#8b93a1);white-space:nowrap;font-size:11px;line-height:18px;text-decoration:none}.nUhMVa_submitLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_tabs{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-end;gap:2px;display:flex}.nUhMVa_tab{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;padding:7px 12px;font-size:13px}.nUhMVa_tab.nUhMVa_on{color:var(--dsw-alias-brand-primary,#4f6ef7);border-bottom-color:var(--dsw-alias-brand-primary,#4f6ef7);font-weight:600}.nUhMVa_subTabs{align-items:flex-end;gap:2px;margin:-4px 0 4px;display:flex}.nUhMVa_banner{background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;align-items:center;gap:8px;margin:0;padding:8px 12px;font-size:12px;display:flex}.nUhMVa_bannerIcon{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0}.nUhMVa_bannerHint{color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:help;display:inline-flex}.nUhMVa_body{overflow-anchor:none;flex:1;padding:12px 4px 24px;overflow-x:hidden;overflow-y:auto}.nUhMVa_stickyHead{z-index:5;background:var(--dsw-alias-bg-layer-2,#f7f8fa);position:sticky;top:-1px}.nUhMVa_stickyHead:before{content:\"\";background:inherit;pointer-events:none;height:14px;position:absolute;bottom:100%;left:0;right:0}.nUhMVa_cats{margin:0 -4px 2px;padding:12px 4px 4px}.nUhMVa_catsRow{align-items:flex-start;gap:8px;display:flex;position:relative}.nUhMVa_star{color:var(--dsw-alias-label-secondary,#9ca3af);white-space:nowrap;flex:none;font-size:11px}.nUhMVa_top{z-index:20;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:var(--dsw-shadow-lv1,0 4px 12px #1f232814);border-radius:99px;display:inline-flex;position:absolute;bottom:18px;right:18px}.nUhMVa_topBtn{border-radius:99px;width:38px;height:38px;padding:0}.nUhMVa_tag{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:11px;line-height:16px}.nUhMVa_hostRequirement{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;min-width:0;max-width:100%;padding:1px 6px;font-size:11px;line-height:16px;overflow:hidden}.nUhMVa_hostFilterNote{color:var(--dsw-alias-label-tertiary,#8b93a1);margin-top:6px;font-size:11px;line-height:16px}.nUhMVa_okState{color:var(--dsw-alias-state-success-primary,#16a34a);white-space:nowrap;font-size:12px;font-weight:600}.nUhMVa_catsWrap{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.nUhMVa_catsCollapsed{max-height:62px;overflow:hidden}.nUhMVa_catsToggle.nUhMVa_catsToggle{height:26px;min-height:26px;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.nUhMVa_shots{-webkit-overflow-scrolling:touch;scrollbar-width:thin;gap:8px;margin:6px 0 8px;padding:2px 0 6px;display:flex;overflow-x:auto}.nUhMVa_shot{object-fit:cover;border:1px solid var(--dsw-alias-border-default,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);cursor:pointer;border-radius:8px;flex:none;width:220px;height:150px}.nUhMVa_cardShots{-webkit-overflow-scrolling:touch;scrollbar-width:thin;gap:6px;margin:0 0 6px;padding:0 0 2px;display:flex;overflow-x:auto}.nUhMVa_cardShot{object-fit:contain;border:1px solid var(--dsw-alias-border-default,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);cursor:pointer;border-radius:8px;flex:none;width:132px;height:88px;display:block}.nUhMVa_lightbox{z-index:10000;cursor:zoom-out;background:#000000d9;justify-content:center;align-items:center;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}.nUhMVa_lightboxImg{object-fit:contain;cursor:default;border-radius:4px;max-width:90vw;max-height:85vh}.nUhMVa_lightboxClose{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:99px;place-items:center;width:36px;height:36px;font-size:22px;line-height:1;display:grid;position:absolute;top:16px;right:16px}.nUhMVa_lightboxClose:hover{background:#ffffff38}.nUhMVa_lightboxNav{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:99px;place-items:center;width:44px;height:44px;display:grid;position:absolute;top:50%;transform:translateY(-50%)}.nUhMVa_lightboxNav:hover{background:#ffffff38}.nUhMVa_lightboxPrev{left:16px}.nUhMVa_lightboxNext{right:16px}.nUhMVa_lightboxDots{gap:8px;display:flex;position:absolute;bottom:20px;left:50%;transform:translate(-50%)}.nUhMVa_lightboxDot{cursor:pointer;background:#fff6;border-radius:99px;width:7px;height:7px}.nUhMVa_lightboxDotOn{background:#fff}.nUhMVa_cmd{background:var(--dsw-alias-bg-layer-2,#f3f4f6);word-break:break-all;border-radius:6px;margin:8px 0 0;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:18px}.nUhMVa_warnLine{color:var(--dsw-alias-state-warn-primary,#b45309);flex-wrap:wrap;align-items:center;gap:4px;margin:0;font-size:12px;font-weight:600;line-height:18px;display:flex}.nUhMVa_modalNote{color:var(--dsw-alias-label-tertiary,#8b93a1);align-items:center;gap:4px;margin:12px 0 0;font-size:12px;line-height:18px;display:flex}.nUhMVa_grid{grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:10px;display:grid}.nUhMVa_masonry{align-items:flex-start;gap:10px;display:flex}.nUhMVa_masonryCol{flex-direction:column;flex:1;gap:10px;min-width:0;display:flex}.nUhMVa_masonry>.nUhMVa_masonryCol>*{align-self:stretch;min-width:0}@media (max-width:680px){.nUhMVa_masonry{flex-direction:column}.nUhMVa_masonryCol{width:100%}.nUhMVa_grid{grid-template-columns:minmax(0,1fr)}}.nUhMVa_swatches{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;gap:0;height:34px;display:flex;overflow:hidden}.nUhMVa_themesGrid{margin-bottom:12px}.nUhMVa_swatches i{flex:1}.nUhMVa_themeToolbar{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px;padding:0 4px 12px;display:grid}.nUhMVa_themeSearch{box-sizing:border-box;width:100%;min-width:0}.nUhMVa_themeToolbarActions{justify-content:flex-end;align-items:center;gap:8px;display:flex}.nUhMVa_themeFullscreenBtn.nUhMVa_themeFullscreenBtn{width:28px;min-width:28px;padding:0}.nUhMVa_themeResultBar{min-height:24px;color:var(--dsw-alias-label-tertiary,#8b93a1);align-items:center;padding:0 4px 8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_favoritesSectionHead{color:var(--dsw-alias-label-primary,#1f2328);margin:16px 0 8px;padding:0 4px;font-size:13px;font-weight:600;line-height:20px}.nUhMVa_favoritesSectionHead:first-of-type{margin-top:0}.nUhMVa_favoritesStaleBar{border:1px solid var(--dsw-alias-state-warn-tertiary,#b4530933);background:var(--dsw-alias-state-warn-tertiary,#b453090f);color:var(--dsw-alias-state-warn-primary,#b45309);border-radius:8px;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;margin:0 0 8px;padding:8px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_favoritesStaleOnly{flex-direction:column;align-items:flex-start;gap:10px;display:flex}.nUhMVa_themeGallery{grid-template-columns:repeat(4,minmax(0,1fr));align-items:stretch;gap:10px;display:grid}.nUhMVa_themeCard{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:8px;flex-direction:column;min-width:0;transition:border-color .16s cubic-bezier(.16,1,.3,1),box-shadow .16s cubic-bezier(.16,1,.3,1),transform .16s cubic-bezier(.16,1,.3,1);display:flex;overflow:hidden}.nUhMVa_themeCard:hover{border-color:var(--dsw-alias-border-l3,#d9dde3);box-shadow:var(--dsw-shadow-lv1,0 4px 12px #1f232814);transform:translateY(-1px)}.nUhMVa_themeCover{aspect-ratio:16/10;border:0;border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);width:100%;color:var(--dsw-alias-label-secondary,#6b7280);cursor:zoom-in;border-radius:0;padding:0;display:block;position:relative;overflow:hidden}.nUhMVa_themeCover img{object-fit:contain;background:var(--dsw-alias-bg-layer-2,#f3f4f6);width:100%;height:100%;transition:transform .18s cubic-bezier(.16,1,.3,1);display:block}.nUhMVa_themeCover:hover img{transform:scale(1.012)}.nUhMVa_themeCover:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4f6ef7);outline-offset:-3px}.nUhMVa_themeCoverEmpty{cursor:default;color:var(--dsw-alias-label-tertiary,#8b93a1);flex-direction:column;justify-content:center;align-items:center;gap:8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_themePreviewAction,.nUhMVa_themePreviewCount{color:#fff;-webkit-backdrop-filter:blur(8px);background:#14181fc7;border:1px solid #ffffff57;border-radius:4px;align-items:center;height:24px;padding:0 8px;font-size:11px;line-height:16px;display:inline-flex;position:absolute;bottom:8px}.nUhMVa_themePreviewAction{gap:4px;right:8px}.nUhMVa_themePreviewCount{left:8px}.nUhMVa_themeCardBody{flex-direction:column;flex:1;gap:8px;padding:12px;display:flex}.nUhMVa_themeCardHead{align-items:flex-start;gap:8px;min-width:0;display:flex}.nUhMVa_themeIdentity{flex:1;min-width:0}.nUhMVa_themeStatus,.nUhMVa_themeStatusMuted{white-space:nowrap;border-radius:4px;flex:none;align-items:center;min-height:22px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_themeStatus{background:var(--dsw-alias-state-success-tertiary,#16a34a1a);color:var(--dsw-alias-state-success-primary,#15803d)}.nUhMVa_themeStatusMuted{background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280)}.nUhMVa_themeDescription{min-height:36px;color:var(--dsw-alias-label-tertiary,#8b93a1);-webkit-line-clamp:3;-webkit-box-orient:vertical;margin:0;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}.nUhMVa_themeCardFooter{justify-content:space-between;align-items:center;gap:8px;margin-top:auto;padding-top:4px;display:flex}.nUhMVa_themeLifecycle{min-width:0;color:var(--dsw-alias-label-tertiary,#8b93a1);text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:18px;overflow:hidden}.nUhMVa_themeActions{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;margin-left:auto;display:flex}@container (width<=900px){.nUhMVa_themeGallery{grid-template-columns:repeat(3,minmax(0,1fr))}}@container (width<=680px){.nUhMVa_themeGallery{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (width<=460px){.nUhMVa_themeGallery{grid-template-columns:minmax(0,1fr)}}@container (width<=420px){.nUhMVa_sub{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:2px 8px;display:grid}.nUhMVa_sub>span:first-child{grid-area:1/1}.nUhMVa_sub>.nUhMVa_grow{display:none}.nUhMVa_submitLink{grid-area:2/1}.nUhMVa_exportLogBtn{flex-shrink:0;grid-area:1/2/span 2}.nUhMVa_themeToolbar{grid-template-columns:minmax(0,1fr)}.nUhMVa_themeCardHead{flex-wrap:wrap}.nUhMVa_themeStatus,.nUhMVa_themeStatusMuted{order:3}}@container (width<=280px){.nUhMVa_themeCardFooter{flex-direction:column;align-items:flex-start}.nUhMVa_themeActions{justify-content:flex-start;width:100%;margin-left:0}}@media (max-width:560px){[role=dialog]:has([data-dsh-market-root])>nav{display:none}[role=dialog]:has([data-dsh-market-root])>div{flex:100%;width:100%;min-width:0}}[role=dialog]:has([data-dsh-market-fullscreen=true]){border-radius:0;width:100vw;max-width:none;height:100vh;max-height:none;position:fixed;top:0;bottom:0;left:0;right:0}@media (prefers-reduced-motion:reduce){.nUhMVa_themeCard,.nUhMVa_themeCover img{transition:none}.nUhMVa_themeCard:hover{transform:none}}.nUhMVa_card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;align-self:start;gap:12px;padding:12px 14px;display:flex}.nUhMVa_row1{align-items:flex-start;gap:10px;min-width:0;display:flex}.nUhMVa_cardAction{flex-shrink:0;align-items:center;display:inline-flex}.nUhMVa_installBtn.nUhMVa_installBtn{min-width:64px}.nUhMVa_av{color:#fff;object-fit:cover;background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:50%;flex-shrink:0;place-items:center;width:16px;height:16px;font-size:9px;font-weight:700;display:grid}.nUhMVa_nm{text-overflow:ellipsis;white-space:nowrap;font-size:15px;font-weight:600;line-height:22px;overflow:hidden}.nUhMVa_nmLink{color:inherit;text-decoration:none;display:block}.nUhMVa_nmLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_repoMark{color:var(--dsw-alias-label-secondary,#6b7280);vertical-align:-1px;flex-shrink:0;margin-left:5px;display:inline-block}.nUhMVa_nmLink:hover .nUhMVa_repoMark{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_byline{flex-wrap:wrap;align-items:center;gap:6px;min-width:0;margin-top:2px;display:flex}.nUhMVa_meta{color:var(--dsw-alias-label-secondary,#9ca3af);margin-top:2px;font-size:11px}.nUhMVa_metaInline{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.nUhMVa_owner{color:var(--dsw-alias-label-secondary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:44px;font-size:11px;overflow:hidden}.nUhMVa_desc{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:12px;line-height:18px}.nUhMVa_descClamp{-webkit-line-clamp:5;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.nUhMVa_descToggle{width:20px;height:16px;color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;margin-top:2px;padding:0;display:flex}.nUhMVa_descToggle:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_foot{flex-wrap:nowrap;align-items:flex-end;gap:8px;display:flex}.nUhMVa_foot .nUhMVa_metaInline,.nUhMVa_foot .nUhMVa_src{white-space:nowrap}.nUhMVa_footTags{flex-wrap:wrap;flex:1 1 0;align-items:center;gap:8px;min-width:0;display:flex}.nUhMVa_grow{flex:1}.nUhMVa_titleRow{align-items:center;gap:10px;display:flex}.nUhMVa_version{color:var(--dsw-alias-label-tertiary,#8b93a1);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:12px;line-height:20px}.nUhMVa_repoLink{color:var(--dsw-alias-label-tertiary,#8b93a1);flex-shrink:0;font-size:12px;line-height:20px;text-decoration:none}.nUhMVa_repoLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_noteRow{flex-wrap:wrap;align-items:baseline;gap:6px;min-width:0;display:flex}.nUhMVa_desc.nUhMVa_noteRow,.nUhMVa_desc.nUhMVa_noteRow+.nUhMVa_noteRow,.nUhMVa_noteEdit+.nUhMVa_noteRow{margin-top:6px}.nUhMVa_noteMine{color:var(--dsw-alias-label-primary,#1f2328)}.nUhMVa_noteToggle{font:inherit;color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:pointer;white-space:nowrap;background:0 0;border:none;flex-shrink:0;padding:0;font-size:11px;line-height:16px}.nUhMVa_noteToggle:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_noteAction{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:4px;align-items:center;padding:0 5px;font-weight:600;text-decoration:none;display:inline-flex}.nUhMVa_noteAction:hover{color:var(--dsw-alias-label-primary,#1f2328);border-color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:none}.nUhMVa_noteEdit{flex-wrap:wrap;align-items:center;gap:6px;min-width:0;margin-top:6px;display:flex}.nUhMVa_noteInput{flex:1;min-width:160px}.nUhMVa_descTight{min-height:0}.nUhMVa_src{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px;text-decoration:none}.nUhMVa_src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_dot{vertical-align:2px;margin-left:5px}.nUhMVa_act{flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px;font-size:11px;display:flex}.nUhMVa_actLive{color:var(--dsw-alias-state-success-primary,#16a34a);align-items:center;gap:4px;font-weight:600;display:inline-flex}.nUhMVa_actWarn{color:var(--dsw-alias-state-warn-primary,#b45309);align-items:center;gap:4px;font-weight:600;display:inline-flex}.nUhMVa_actBroken{color:var(--dsw-alias-state-error-primary,#dc2626);align-items:center;gap:4px;font-weight:600;display:inline-flex}.nUhMVa_actWhy{color:var(--dsw-alias-label-secondary,#6b7280);margin-top:2px}.nUhMVa_loading{color:var(--dsw-alias-label-secondary,#9ca3af);flex-direction:column;align-items:center;gap:12px;padding:48px;font-size:13px;display:flex}.nUhMVa_spin{color:var(--dsw-alias-brand-primary,#4f6ef7);flex-shrink:0;animation:.8s linear infinite nUhMVa_sp;display:inline-flex}.nUhMVa_logoMark{color:var(--dsw-alias-brand-primary,#4f6ef7);flex-shrink:0;display:inline-flex}.nUhMVa_logoPlug{transform-box:fill-box;transform-origin:50%;animation:1.5s cubic-bezier(.4,0,.2,1) infinite nUhMVa_dshmPlug}@keyframes nUhMVa_dshmPlug{0%,12%{transform:rotate(9deg)}45%,62%{transform:translate(-1.28px,1.27px)rotate(0)}95%,to{transform:rotate(9deg)}}@media (prefers-reduced-motion:reduce){.nUhMVa_logoPlug,.nUhMVa_spin{animation:1.5s ease-in-out infinite nUhMVa_dshmPlugFade}}@keyframes nUhMVa_dshmPlugFade{0%,to{opacity:1}50%{opacity:.35}}@keyframes nUhMVa_sp{to{transform:rotate(360deg)}}.nUhMVa_progress{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:8px;flex-wrap:wrap;align-items:center;gap:9px;margin:0;padding:8px 12px;font-size:12px;display:flex}.nUhMVa_bar{background:var(--dsw-alias-border-l1,#e5e7eb);border-radius:99px;width:100%;height:4px;overflow:hidden}.nUhMVa_barFill{background:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;height:100%;transition:width .6s}.nUhMVa_barWave{width:30%;animation:1.2s ease-in-out infinite nUhMVa_dshmSlide}@keyframes nUhMVa_dshmSlide{0%{margin-left:-30%}to{margin-left:100%}}.nUhMVa_irow .nUhMVa_progress{margin-top:8px}.nUhMVa_progress code{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.nUhMVa_empty{color:var(--dsw-alias-label-secondary,#9ca3af);text-align:center;padding:32px;font-size:13px}.nUhMVa_err{color:var(--dsw-alias-state-error-primary,#dc2626);white-space:pre-wrap;word-break:break-all;margin:8px 0;font-size:12px}.nUhMVa_cardBlocked{border-color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_conflictHead{align-items:flex-start;gap:8px;display:flex}.nUhMVa_conflictIcon{color:var(--dsw-alias-state-error-primary,#dc2626);flex-shrink:0;margin-top:1px}.nUhMVa_conflictTitle{color:var(--dsw-alias-state-error-primary,#dc2626);font-size:13px;font-weight:600;line-height:18px}.nUhMVa_conflictBody{margin:0;font-size:12px;line-height:19px}.nUhMVa_roster{background:var(--dsw-alias-border-l2,#e5e7eb);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;flex-direction:column;gap:1px;display:flex;overflow:hidden}.nUhMVa_rosterRow{background:var(--dsw-alias-bg-layer-1,#fff);align-items:center;gap:8px;padding:7px 10px;display:flex}.nUhMVa_rosterMain{flex-direction:column;min-width:0;display:flex}.nUhMVa_rosterName{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;font-weight:600;overflow:hidden}.nUhMVa_rosterAuthor{color:var(--dsw-alias-label-secondary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;font-size:10.5px;overflow:hidden}.nUhMVa_rosterTag{border-radius:4px;flex-shrink:0;margin-left:auto;padding:1px 6px;font-size:10.5px;font-weight:600}.nUhMVa_rosterTagKeep{color:var(--dsw-alias-state-success-primary,#16a34a);background:#16a34a1f}.nUhMVa_rosterTagDrop{color:var(--dsw-alias-state-error-primary,#dc2626);background:#dc26261f}.nUhMVa_rosterRowOut .nUhMVa_rosterName{text-decoration:line-through}.nUhMVa_rosterRowOut{opacity:.62}.nUhMVa_rosterSplit{background:var(--dsw-alias-border-l2,#e5e7eb);height:1px}.nUhMVa_reassure{color:var(--dsw-alias-label-secondary,#6b7280);align-items:center;gap:5px;margin:0;font-size:11.5px;line-height:17px;display:flex}.nUhMVa_reassureOk{color:var(--dsw-alias-state-success-primary,#16a34a);flex-shrink:0}.nUhMVa_conflictWhy{color:var(--dsw-alias-label-tertiary,#8b93a1);overflow-wrap:anywhere;margin-top:2px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:17px}.nUhMVa_conflictWhyText{margin-top:5px;font-family:-apple-system,BlinkMacSystemFont,PingFang SC,sans-serif}.nUhMVa_choices{flex-direction:column;gap:7px;display:flex}.nUhMVa_choice{text-align:left;font:inherit;cursor:pointer;background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:9px;align-items:flex-start;gap:9px;padding:9px 11px;display:flex}.nUhMVa_choice:has(input:disabled){cursor:default;opacity:.6}.nUhMVa_choiceOn{border-color:var(--dsw-alias-brand-primary,#4f6ef7);background:var(--dsw-alias-bg-layer-2,#f5f7ff)}.nUhMVa_choiceRadio{width:13px;height:13px;accent-color:var(--dsw-alias-brand-primary,#4f6ef7);flex-shrink:0;margin:2px 0 0}.nUhMVa_choiceMain{flex-direction:column;gap:3px;min-width:0;display:flex}.nUhMVa_choiceTitle{font-size:12px;font-weight:600;line-height:17px}.nUhMVa_choiceNote{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:11px;line-height:16px}.nUhMVa_choiceSafe{color:var(--dsw-alias-state-success-primary,#16a34a)}.nUhMVa_stateTag{white-space:nowrap;background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-height:20px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:5px;flex-shrink:0;align-items:center;gap:5px;padding:1px 7px;font-size:11px;line-height:16px;display:inline-flex}.nUhMVa_stateTag[data-on=true]{color:var(--dsw-alias-state-success-primary,#16a34a);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#16a34a) 10%, transparent)}.nUhMVa_stateDot{background:var(--dsw-alias-label-tertiary,#8b93a1);border-radius:999px;flex:none;width:6px;height:6px}.nUhMVa_stateDot[data-on=true]{background:var(--dsw-alias-state-success-primary,#16a34a)}.nUhMVa_metaTag{text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-width:0;max-width:100%;min-height:20px;color:var(--dsw-alias-label-tertiary,#8b93a1);border-radius:5px;flex-shrink:1;padding:1px 7px;font-size:11px;line-height:18px;display:inline-block;overflow:hidden}.nUhMVa_metaTagOk{color:var(--dsw-alias-state-success-primary,#16a34a);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#16a34a) 10%, transparent)}.nUhMVa_metaTagAction{font-family:inherit;font-size:11px;line-height:18px;font-weight:inherit;cursor:pointer;background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280);border:none;border-radius:5px;flex-shrink:0;padding:1px 7px}.nUhMVa_metaTagAction:hover:not(:disabled){color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_metaTagAction:disabled{opacity:.5;cursor:default}.nUhMVa_irowHead{align-items:flex-start;gap:8px;min-width:0;display:flex}.nUhMVa_irowHead .nUhMVa_irowName{flex:1 1 0;min-width:0}.nUhMVa_irowDevTag{letter-spacing:.02em;white-space:nowrap;cursor:default;-webkit-user-select:none;user-select:none;color:var(--dsw-alias-label-tertiary,#8b93a1);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#4f6ef7) 9%, var(--dsw-alias-bg-layer-2,#f3f4f6));border-radius:99px;flex-shrink:0;padding:2px 8px;font-size:10px;font-weight:600;line-height:14px}.nUhMVa_nameLink{color:inherit;text-decoration:none}.nUhMVa_irowName{text-overflow:clip;flex-wrap:wrap;align-items:baseline;gap:6px;min-width:0;display:flex;overflow:visible}.nUhMVa_irowNameText{overflow-wrap:anywhere;white-space:normal;min-width:0}.nUhMVa_irowName>.nUhMVa_owner{flex:none}.nUhMVa_nameLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_opWrap{flex-shrink:0;margin-bottom:6px;display:inline-flex;position:relative}.nUhMVa_opEntry{font:inherit;cursor:pointer;white-space:nowrap;color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:7px;align-items:center;gap:6px;padding:4px 10px;font-size:12px;display:inline-flex;position:relative}.nUhMVa_opEntryQuiet{color:var(--dsw-alias-label-secondary,#6b7280);background:0 0;border-color:#0000}.nUhMVa_opEntryAlert{border-color:var(--dsw-alias-state-error-primary,#dc2626);color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_opDot{background:var(--dsw-alias-state-error-primary,#dc2626);border-radius:99px;width:8px;height:8px;position:absolute;top:-3px;right:-3px}.nUhMVa_opPanel{z-index:40;background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:12px;width:460px;max-width:86vw;max-height:70vh;position:absolute;top:calc(100% + 6px);right:0;overflow-y:auto;box-shadow:0 20px 52px #00000047}.nUhMVa_opHead{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:center;gap:8px;padding:9px 14px;display:flex}.nUhMVa_opPanelTitle{font-size:12.5px;font-weight:600}.nUhMVa_opCloseBtn.nUhMVa_opCloseBtn{min-width:0;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.nUhMVa_opAggregate{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f7f8fa);padding:9px 14px}.nUhMVa_opAggregateTop{font-variant-numeric:tabular-nums;font-size:12px;font-weight:600}.nUhMVa_opAggregateHint{color:var(--dsw-alias-label-tertiary,#8b93a1);margin-top:4px;font-size:10.5px}.nUhMVa_opRow{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-start;gap:9px;padding:9px 14px;display:flex}.nUhMVa_opRow:last-child{border-bottom:none}.nUhMVa_opRowAlert{background:#dc26260f}.nUhMVa_opIcon{flex-shrink:0;place-items:center;width:14px;margin-top:1px;display:grid}.nUhMVa_opQueuedIcon{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:12px}.nUhMVa_opMain{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}.nUhMVa_opTop{align-items:baseline;gap:6px;min-width:0;display:flex}.nUhMVa_opVerb{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:12px}.nUhMVa_opName{text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600;overflow:hidden}.nUhMVa_opStatus{color:var(--dsw-alias-label-tertiary,#8b93a1);overflow-wrap:anywhere;font-size:10.5px;line-height:16px}.nUhMVa_opStatusBad{color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_opActions{flex-shrink:0;align-items:center;gap:6px;margin-top:1px;display:flex}.nUhMVa_opDecision{border-top:1px dashed var(--dsw-alias-border-l2,#e5e7eb);flex-direction:column;gap:8px;margin-top:8px;padding-top:8px;display:flex}.nUhMVa_opDecisionFoot{align-items:center;gap:8px;display:flex}.nUhMVa_conflictDetailsToggle{font:inherit;cursor:pointer;color:var(--dsw-alias-label-tertiary,#8b93a1);background:0 0;border:none;align-items:center;gap:4px;padding:2px 0;font-size:11px;display:inline-flex}.nUhMVa_conflictDetailsToggle:hover{color:var(--dsw-alias-label-secondary,#6b7280)}.nUhMVa_opEmpty{text-align:center;color:var(--dsw-alias-label-secondary,#6b7280);padding:30px 14px;font-size:12px}.nUhMVa_opEmptyHint{color:var(--dsw-alias-label-tertiary,#8b93a1);margin-top:4px;font-size:11px}.nUhMVa_cardBlockedMark{font:inherit;cursor:pointer;color:var(--dsw-alias-state-error-primary,#dc2626);border:1px solid var(--dsw-alias-state-error-primary,#dc2626);background:#dc262614;border-radius:7px;align-items:center;gap:5px;padding:4px 9px;font-size:11px;display:inline-flex}.nUhMVa_dangerBtn.nUhMVa_dangerBtn{color:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_dangerBtn.nUhMVa_dangerBtn:hover:not(:disabled){background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.nUhMVa_dangerArmed.nUhMVa_dangerArmed{background:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.nUhMVa_retryBtn{margin-top:4px}.nUhMVa_irow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:10px;flex-direction:column;gap:10px;min-width:0;padding:12px 14px;display:flex}.nUhMVa_irowActions{flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:8px;min-width:0;display:flex}.nUhMVa_irowTrailing{flex-wrap:nowrap;flex-shrink:0;align-items:center;gap:8px;min-width:0;display:inline-flex}.nUhMVa_irowTrailing .nUhMVa_metaTag{flex-shrink:1;min-width:0}.nUhMVa_irowTrailing .nUhMVa_metaTagAction{flex-shrink:0}.nUhMVa_irowMissing{filter:grayscale();opacity:.5}.nUhMVa_irow>.nUhMVa_src,.nUhMVa_irow>.nUhMVa_owner,.nUhMVa_irow button{white-space:nowrap;flex-shrink:0}.nUhMVa_tabSearchRow{padding:0 4px 6px;display:flex}.nUhMVa_tabSearch{width:100%}.nUhMVa_spec{color:var(--dsw-alias-label-secondary,#9ca3af);overflow-wrap:anywhere;min-width:0;font-family:ui-monospace,Menlo,monospace;font-size:11px}.nUhMVa_specTag{white-space:nowrap;border-radius:4px;flex-shrink:0;align-items:center;height:16px;padding:0 5px;font-size:10px;font-weight:600;display:inline-flex}.nUhMVa_specTagGit{color:#0b7285;background:#12a3c41f}.nUhMVa_specTagFile{color:#b07d1b;background:#f0b42924}.nUhMVa_backupCheckList .nUhMVa_grow{white-space:nowrap;text-overflow:ellipsis;flex:70%;min-width:0;overflow:hidden}.nUhMVa_backupCheckList .nUhMVa_spec{text-align:right;white-space:nowrap;text-overflow:ellipsis;flex:0 30%;max-width:30%;overflow:hidden}.nUhMVa_staleAction{word-break:normal;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px;display:flex}.nUhMVa_pct{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:11px;font-weight:600}.nUhMVa_pager{flex-wrap:nowrap;justify-content:space-between;align-items:center;gap:8px;margin:16px 0 4px;display:flex}.nUhMVa_pagerPages{flex-wrap:nowrap;flex:1;justify-content:center;align-items:center;gap:4px;min-width:0;display:flex}.nUhMVa_pagerMeta{flex-wrap:nowrap;flex-shrink:0;align-items:center;gap:6px;display:flex}.nUhMVa_pagerPages button,.nUhMVa_pagerMeta button{min-width:0;padding:0 8px}.nUhMVa_pageEllipsis{color:var(--dsw-alias-label-secondary,#9ca3af);padding:0 1px;font-size:12px}.nUhMVa_pageInfo{color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;font-size:12px}@container (width<=544px){.nUhMVa_pager{flex-wrap:wrap;justify-content:center;gap:8px}.nUhMVa_pagerPages{flex-basis:100%}}.nUhMVa_depBadge{border:1px solid var(--dsw-alias-state-warn-primary,#b45309);color:var(--dsw-alias-state-warn-primary,#b45309);white-space:nowrap;border-radius:4px;flex-shrink:0;margin-left:6px;padding:1px 6px;font-size:11px;font-weight:600;line-height:16px}.nUhMVa_deprecate{color:var(--dsw-alias-state-warn-primary,#b45309);background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;margin:0;padding:8px 10px;font-size:12px;line-height:18px}.nUhMVa_deprecate a{color:var(--dsw-alias-state-warn-primary,#b45309);text-decoration:underline}.nUhMVa_deprecate .nUhMVa_src{margin-left:8px}.nUhMVa_depLine{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.nUhMVa_switch{border:1px solid var(--dsw-alias-border-l2,#d9dde3);background:var(--dsw-alias-bg-layer-2,#e5e7eb);cursor:pointer;border-radius:99px;flex-shrink:0;width:38px;height:22px;padding:0;transition:background .15s,border-color .15s;position:relative}.nUhMVa_switchOn{background:var(--dsw-alias-state-success-primary,#16a34a);border-color:var(--dsw-alias-state-success-primary,#16a34a)}.nUhMVa_switchMixed{background:var(--dsw-alias-state-warn-primary,#b45309);border-color:var(--dsw-alias-state-warn-primary,#b45309)}.nUhMVa_switchKnob{background:#fff;border-radius:99px;width:16px;height:16px;transition:left .15s;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #00000040}.nUhMVa_switchOn .nUhMVa_switchKnob,.nUhMVa_switchMixed .nUhMVa_switchKnob{left:18px}.nUhMVa_switch:disabled{opacity:.5;cursor:default}.nUhMVa_viewBar{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;align-items:center;gap:2px;width:fit-content;margin-bottom:12px;padding:2px;display:flex}.nUhMVa_viewBtn{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:6px;padding:4px 10px;font-size:12px;line-height:18px}.nUhMVa_viewBtn:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_viewOn{background:var(--dsw-alias-bg-layer-2,#eef0f4);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}.nUhMVa_groupRow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;margin-bottom:10px;padding:12px 14px}.nUhMVa_groupHead{align-items:center;gap:10px;min-width:0;display:flex}.nUhMVa_groupName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}.nUhMVa_groupActions{flex-shrink:0;align-items:center;gap:6px;display:flex}.nUhMVa_groupMembers{flex-direction:column;gap:6px;margin-top:10px;display:flex}.nUhMVa_groupMember{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;align-items:center;gap:8px;padding:6px 8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_groupMember .nUhMVa_nm{flex:1;min-width:0;font-size:12px}.nUhMVa_groupAddPanel{border-top:1px dashed var(--dsw-alias-border-l2,#e5e7eb);flex-direction:column;gap:6px;margin-top:10px;padding-top:10px;display:flex}.nUhMVa_groupCreate{align-items:center;gap:8px;margin-bottom:10px;display:flex}.nUhMVa_inlineInput{flex:1;min-width:120px}.nUhMVa_assignRow{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.nUhMVa_assignSelect{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font:inherit;border-radius:6px;padding:3px 6px;font-size:12px;line-height:18px}.nUhMVa_groupHint{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:11px}.nUhMVa_sectAction{color:var(--dsw-alias-label-secondary,#6b7280);align-items:center;gap:8px;margin:14px 2px 8px;font-size:12px;font-weight:600;display:flex}.nUhMVa_backupGrid{grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;display:grid}.nUhMVa_backupCard{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:10px;padding:16px;display:flex}.nUhMVa_backupCard h3{margin:0;font-size:14px}.nUhMVa_backupCard p{color:var(--dsw-alias-label-secondary,#6b7280);margin:0;font-size:12px;line-height:18px}.nUhMVa_backupActions{flex-wrap:wrap;gap:8px;display:flex;position:relative}.nUhMVa_hiddenFile{opacity:0;pointer-events:none;width:1px;height:1px;position:absolute}.nUhMVa_backupInput{box-sizing:border-box;width:100%}.nUhMVa_backupCheck{cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.nUhMVa_backupWarn{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-state-warn-primary,#b45309)!important}.nUhMVa_backupMessage{color:var(--dsw-alias-label-secondary,#6b7280);grid-column:1/-1;font-size:12px}.nUhMVa_backupCheckList{flex-direction:column;gap:6px;max-height:260px;margin:10px 0 4px;padding-right:4px;display:flex;overflow-y:auto}.nUhMVa_backupCheckList .nUhMVa_backupCheck{justify-content:space-between;gap:8px}.nUhMVa_diagPage{flex-direction:column;gap:12px;height:100%;min-height:0;display:flex;overflow-y:auto}.nUhMVa_diagSummary{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-wrap:wrap;align-items:center;gap:12px;padding:10px 14px;font-size:12px;display:flex}.nUhMVa_diagSummaryItem{color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;align-items:center;gap:6px;display:inline-flex}.nUhMVa_diagSummaryMeta{color:var(--dsw-alias-label-tertiary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;max-width:320px;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.nUhMVa_diagSection{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:8px;padding:12px 14px;display:flex}.nUhMVa_diagSection h3{color:var(--dsw-alias-label-primary,#1f2328);margin:0;font-size:13px;font-weight:600}.nUhMVa_diagCount{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:11px;font-weight:400}.nUhMVa_diagEmpty{color:var(--dsw-alias-label-secondary,#9ca3af);padding:8px 0;font-size:12px}.nUhMVa_diagBundle{border-top:1px solid var(--dsw-alias-border-l2,#f0f1f3);flex-direction:column;gap:6px;padding-top:8px;display:flex}.nUhMVa_diagBundle:first-of-type{border-top:none;padding-top:0}.nUhMVa_diagRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;font-size:12px;line-height:18px;display:flex}.nUhMVa_diagMeta{align-items:baseline;gap:8px;min-width:0;font-size:12px;display:flex}.nUhMVa_diagKey{color:var(--dsw-alias-label-tertiary,#9ca3af);flex-shrink:0;min-width:64px;font-size:11px}.nUhMVa_diagVal{color:var(--dsw-alias-label-primary,#1f2328);overflow-wrap:anywhere;min-width:0;font-family:ui-monospace,Menlo,monospace;font-size:12px;font-weight:500}.nUhMVa_diagIndex{background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-width:18px;height:18px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:9px;flex-shrink:0;justify-content:center;align-items:center;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagArrow{color:var(--dsw-alias-label-tertiary,#9ca3af);flex-shrink:0;font-size:12px}.nUhMVa_diagBadgeOfficial{background:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagBadgeCommunity{background:var(--dsw-alias-bg-layer-2,#f3f4f6);height:18px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:9px;flex-shrink:0;align-items:center;padding:0 8px;font-size:11px;display:inline-flex}.nUhMVa_diagBadgeShadow{background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagBadgeWarn{background:var(--dsw-alias-state-warn-primary,#b45309);color:#fff;white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagBadgeInfo{background:var(--dsw-alias-bg-layer-2,#f3f4f6);height:18px;color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;padding:0 8px;font-size:11px;display:inline-flex}.nUhMVa_diagList{flex-direction:column;gap:6px;display:flex}.nUhMVa_sectionOverview{color:var(--dsw-alias-label-tertiary,#8b93a1);text-overflow:ellipsis;white-space:nowrap;max-width:100%;padding:2px 0 6px;font-size:12px;line-height:18px;overflow:hidden}.nUhMVa_diagAlert{color:var(--dsw-alias-state-warn-primary,#b45309)}.nUhMVa_ovRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;padding:6px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_ovArrow{color:var(--dsw-alias-label-tertiary,#9ca3af);flex-shrink:0;font-size:12px}.nUhMVa_ovByTag{background:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff;text-overflow:ellipsis;white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;max-width:260px;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex;overflow:hidden}.nUhMVa_ovFrom{color:var(--dsw-alias-label-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;overflow:hidden}.nUhMVa_orphRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;padding:6px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_orphBadge{background:var(--dsw-alias-state-warn-primary,#b45309);color:#fff;white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_dragHandle{width:20px;height:20px;color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:grab;-webkit-user-select:none;user-select:none;flex-shrink:0;justify-content:center;align-items:center;font-size:12px;line-height:20px;display:inline-flex}.nUhMVa_dragOver{outline:2px dashed var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:2px;background:var(--dsw-alias-bg-layer-2,#f0f2f8);border-radius:8px}.nUhMVa_dragging{opacity:.45;background:var(--dsw-alias-bg-layer-2,#f3f4f6)}.nUhMVa_collapseHead{font:inherit;color:var(--dsw-alias-label-primary,#1f2328);cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;width:100%;padding:0;font-size:13px;font-weight:600;display:flex}.nUhMVa_collapseIcon{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;display:inline-flex}.nUhMVa_collapseTitle{flex:1;min-width:0}.nUhMVa_collapseBody{border-top:1px solid var(--dsw-alias-border-l2,#f0f1f3);overflow-wrap:anywhere;flex-direction:column;gap:10px;min-width:0;margin-top:8px;padding-top:10px;display:flex}.nUhMVa_orderPanel{flex-direction:column;gap:10px;min-width:0;display:flex}.nUhMVa_panelNote{color:var(--dsw-alias-label-secondary,#6b7280);margin:0;font-size:12px;line-height:18px}.nUhMVa_panelActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.nUhMVa_presetList{flex-direction:column;gap:6px;min-width:0;display:flex}.nUhMVa_presetRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-direction:column;align-items:stretch;gap:6px;min-width:0;max-width:100%;padding:8px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_presetName{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:13px;font-weight:600;overflow:hidden}.nUhMVa_snapList{flex-direction:column;gap:6px;min-width:0;display:flex}.nUhMVa_snapRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-direction:column;align-items:stretch;gap:8px;padding:10px 12px;font-size:12px;line-height:18px;display:flex}.nUhMVa_snapMeta{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.nUhMVa_snapConfirmText{color:var(--dsw-alias-state-warn-primary,#b45309);margin:0;font-size:12px;line-height:18px}.nUhMVa_confirmRow{flex-wrap:wrap;align-items:center;gap:6px;display:inline-flex}.nUhMVa_fixFallback{flex-direction:column;gap:6px;margin:8px 0;display:flex}.nUhMVa_fixFallbackText{box-sizing:border-box;width:100%;color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);resize:vertical;white-space:pre-wrap;word-break:break-all;border-radius:6px;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:16px}.nUhMVa_setCard{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-3,#fff);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.nUhMVa_setCard:hover{border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}.nUhMVa_setCardOpen{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}.nUhMVa_setHeader{-webkit-appearance:none;appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.nUhMVa_setHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:-2px}.nUhMVa_setHeadText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.nUhMVa_setName{color:var(--dsw-alias-label-primary,#1f2328);font-size:15px;font-weight:600;line-height:1.4}.nUhMVa_setDesc{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:13px;line-height:1.5}.nUhMVa_setChevron{color:var(--dsw-alias-label-tertiary,#8b93a1);flex:none;transition:transform .16s;display:inline-flex}.nUhMVa_setChevronOpen{transform:rotate(180deg)}.nUhMVa_setBody{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);margin:0 16px;padding-bottom:8px}.nUhMVa_setRow{align-items:center;gap:12px;padding:12px 0;display:flex}.nUhMVa_setRow+.nUhMVa_setRow{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb)}.nUhMVa_setLabelBox{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}.nUhMVa_setLabel{font-size:13px;line-height:20px}.nUhMVa_setHint{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:12px;line-height:18px}.nUhMVa_setConfirm{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);flex-direction:column;gap:8px;padding:12px 0 4px;display:flex}.nUhMVa_setCheck{cursor:pointer;align-items:center;gap:8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_setActions{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.nUhMVa_setInlineActions{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px;display:flex}.nUhMVa_setProxyEditor{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);flex-wrap:wrap;align-items:flex-end;gap:10px;padding:12px 0;display:flex}.nUhMVa_setProxyLabel{min-width:180px;color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;flex:1;gap:5px;font-size:12px;line-height:18px;display:flex}.nUhMVa_setProxyInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-3,#fff);width:100%;min-width:0;color:var(--dsw-alias-label-primary,#1f2328);font:inherit;border-radius:7px;padding:6px 8px;font-size:12px;line-height:18px}.nUhMVa_setProxyInput:focus{border-color:var(--dsw-alias-brand-primary,#4f6ef7);outline:2px solid color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 18%,transparent)}.nUhMVa_setDanger{color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_setSeg{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;flex-shrink:0;gap:2px;padding:2px;display:inline-flex}.nUhMVa_setSegBtn{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:3px 10px;font-size:12px;line-height:18px}.nUhMVa_setSegBtn:disabled{cursor:default;opacity:.5}.nUhMVa_setSegOn{background:var(--dsw-alias-bg-layer-2,#eef0f4);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}.nUhMVa_setBetaTag{background:var(--dsw-alias-bg-module-platform,#eef0f4);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:9px;margin-left:6px;padding:0 6px;font-size:11px;font-weight:600;line-height:17px}.nUhMVa_commentsLink{cursor:pointer;white-space:nowrap;color:var(--dsw-alias-label-secondary,#9ca3af);background:0 0;border:0;padding:0;font-size:11px;line-height:16px}.nUhMVa_commentsLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_footActions{flex-shrink:0;align-items:center;gap:8px;display:inline-flex}.nUhMVa_favoriteBtn{cursor:pointer;color:var(--dsw-alias-label-secondary,#9ca3af);background:0 0;border:0;align-items:center;padding:0;display:inline-flex}.nUhMVa_favoriteBtn:hover,.nUhMVa_favoriteOn{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_commentsNote{color:var(--dsw-alias-label-secondary,#9ca3af);margin:0 0 8px;font-size:11px;line-height:16px}.nUhMVa_commentsGithubPrompt{border:1px solid color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 24%,transparent);background:color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 6%,transparent);border-radius:8px;margin:0 0 10px;padding:10px}.nUhMVa_commentsGithubHint{color:var(--dsw-alias-label-primary,#1f2328);margin:0 0 8px;font-size:12px;line-height:17px}.nUhMVa_commentsGithubAction{box-sizing:border-box;border:1px solid var(--dsw-alias-brand-primary,#4f6ef7);min-height:28px;color:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:6px;justify-content:center;align-items:center;padding:5px 10px;font-size:12px;font-weight:600;line-height:16px;text-decoration:none;display:inline-flex}.nUhMVa_commentsGithubAction:hover{background:color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 9%,transparent)}.nUhMVa_commentsStatus{color:var(--dsw-alias-label-secondary,#9ca3af);margin:0;font-size:12px}.nUhMVa_commentsStatus:empty{display:none}.nUhMVa_commentsError{color:var(--dsw-alias-label-primary,#1f2328);margin:0 0 8px;font-size:12px}.nUhMVa_commentsFail{flex-direction:column;align-items:flex-start;gap:8px;padding:12px 0;display:flex}.nUhMVa_commentsMount{width:100%;min-height:240px;max-height:56vh;overflow:auto}.nUhMVa_commentsMount iframe{width:100%}.nUhMVa_notesLink{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;text-align:left;background:0 0;border:none;margin:2px 0 0;padding:0;font-size:12px;line-height:18px;display:block}.nUhMVa_notesLink:hover{color:var(--dsw-alias-label-primary,#1f2328)}.nUhMVa_notesBody{flex-direction:column;gap:8px;min-width:0;display:flex}.nUhMVa_notesRange{align-items:center;gap:8px;margin-bottom:4px;font-size:12px;line-height:18px;display:flex}.nUhMVa_notesArrow{color:var(--dsw-alias-label-tertiary,#8b93a1)}.nUhMVa_notesMeta{letter-spacing:.02em;text-transform:uppercase;color:var(--dsw-alias-label-secondary,#6b7280);flex-wrap:wrap;align-items:baseline;gap:6px;margin-top:12px;font-size:12px;line-height:18px;display:flex}.nUhMVa_notesPre{white-space:pre-wrap;word-break:break-word;background:var(--dsw-alias-bg-layer-2,#eef0f4);border-radius:8px;max-height:40vh;margin:0;padding:10px 12px;font-size:13px;line-height:20px;overflow:auto}.nUhMVa_notesList{flex-direction:column;gap:6px;margin:0;padding-left:18px;font-size:13px;line-height:20px;display:flex}.nUhMVa_notesRendered{flex-direction:column;gap:6px;min-width:0;display:flex}.nUhMVa_notesH{margin-top:6px;font-size:13px;font-weight:650;line-height:20px}.nUhMVa_notesP{font-size:13px;line-height:20px}.nUhMVa_notesCode{font-family:var(--dsw-alias-font-mono,ui-monospace,monospace);background:var(--dsw-alias-bg-layer-2,#eef0f4);border-radius:5px;padding:1px 5px;font-size:12px}.nUhMVa_notesList{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.nUhMVa_notesRow{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:baseline;gap:12px;padding:6px 0;display:flex}.nUhMVa_notesRow:last-child{border-bottom:none}.nUhMVa_notesDate{color:var(--dsw-alias-label-tertiary,#8b93a1);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:12px}.nUhMVa_notesMsg{word-break:break-word;word-break:break-word;-webkit-line-clamp:3;-webkit-box-orient:vertical;min-width:0;font-size:13px;line-height:20px;display:-webkit-box;overflow:hidden}.nUhMVa_notesSha{color:var(--dsw-alias-label-secondary,#6b7280);font-variant-numeric:tabular-nums;flex-shrink:0;margin-left:auto;font-size:12px;text-decoration:none}.nUhMVa_notesSha:hover{color:var(--dsw-alias-label-primary,#1f2328);text-decoration:underline}.nUhMVa_notesVer{color:inherit;font-weight:600;text-decoration:none}.nUhMVa_notesVer:hover{text-decoration:underline}.nUhMVa_migrationSources{flex-direction:column;gap:8px;margin-top:4px;display:flex}.nUhMVa_migrationSource{border:1px solid var(--dsw-alias-border-default,#e5e7eb);border-radius:8px;flex-direction:column;gap:4px;padding:10px 12px;display:flex}.nUhMVa_migrationSource code{overflow-wrap:anywhere;font-family:ui-monospace,Menlo,monospace;font-size:12px}.nUhMVa_migrationLabel{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.nUhMVa_migrationArrow{text-align:center;color:var(--dsw-alias-label-secondary,#9ca3af)}.nUhMVa_migrationWarning{color:var(--dsw-alias-state-warn-primary,#b45309);align-items:flex-start;gap:6px;margin:12px 0 0;font-size:12px;line-height:18px;display:flex}";
|
|
2331
|
+
const css = ".nUhMVa_root{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);flex-direction:column;display:flex;position:relative;container-type:inline-size}.nUhMVa_head{flex-direction:column;gap:12px;padding:4px 4px 6px;display:flex}.nUhMVa_title{margin:0;font-size:16px;font-weight:500;line-height:24px}.nUhMVa_sub{color:var(--dsw-alias-label-tertiary,#8b93a1);align-items:center;gap:8px;margin:0;font-size:12px;line-height:18px;display:flex}.nUhMVa_submitLink{color:var(--dsw-alias-label-tertiary,#8b93a1);white-space:nowrap;font-size:11px;line-height:18px;text-decoration:none}.nUhMVa_submitLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_tabs{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-end;gap:2px;display:flex}.nUhMVa_tab{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;padding:7px 12px;font-size:13px}.nUhMVa_tab.nUhMVa_on{color:var(--dsw-alias-brand-primary,#4f6ef7);border-bottom-color:var(--dsw-alias-brand-primary,#4f6ef7);font-weight:600}.nUhMVa_subTabs{align-items:flex-end;gap:2px;margin:-4px 0 4px;display:flex}.nUhMVa_banner{background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;align-items:center;gap:8px;margin:0;padding:8px 12px;font-size:12px;display:flex}.nUhMVa_bannerIcon{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0}.nUhMVa_bannerHint{color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:help;display:inline-flex}.nUhMVa_body{overflow-anchor:none;flex:1;padding:12px 4px 24px;overflow-x:hidden;overflow-y:auto}.nUhMVa_stickyHead{z-index:5;background:var(--dsw-alias-bg-layer-2,#f7f8fa);position:sticky;top:-1px}.nUhMVa_stickyHead:before{content:\"\";background:inherit;pointer-events:none;height:14px;position:absolute;bottom:100%;left:0;right:0}.nUhMVa_cats{margin:0 -4px 2px;padding:12px 4px 4px}.nUhMVa_catsRow{align-items:flex-start;gap:8px;display:flex;position:relative}.nUhMVa_star{color:var(--dsw-alias-label-secondary,#9ca3af);white-space:nowrap;flex:none;font-size:11px}.nUhMVa_top{z-index:20;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:var(--dsw-shadow-lv1,0 4px 12px #1f232814);border-radius:99px;display:inline-flex;position:absolute;bottom:18px;right:18px}.nUhMVa_topBtn{border-radius:99px;width:38px;height:38px;padding:0}.nUhMVa_tag{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:4px;flex-shrink:0;padding:1px 6px;font-size:11px;line-height:16px}.nUhMVa_hostRequirement{border:1px solid var(--dsw-alias-border-l3,#d9dde3);color:var(--dsw-alias-label-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;min-width:0;max-width:100%;padding:1px 6px;font-size:11px;line-height:16px;overflow:hidden}.nUhMVa_hostFilterNote{color:var(--dsw-alias-label-tertiary,#8b93a1);margin-top:6px;font-size:11px;line-height:16px}.nUhMVa_okState{color:var(--dsw-alias-state-success-primary,#16a34a);white-space:nowrap;font-size:12px;font-weight:600}.nUhMVa_catsWrap{flex-wrap:wrap;flex:1;align-items:center;gap:6px;min-width:0;display:flex}.nUhMVa_catsCollapsed{max-height:62px;overflow:hidden}.nUhMVa_catsToggle.nUhMVa_catsToggle{height:26px;min-height:26px;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.nUhMVa_shots{-webkit-overflow-scrolling:touch;scrollbar-width:thin;gap:8px;margin:6px 0 8px;padding:2px 0 6px;display:flex;overflow-x:auto}.nUhMVa_shot{object-fit:cover;border:1px solid var(--dsw-alias-border-default,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);cursor:pointer;border-radius:8px;flex:none;width:220px;height:150px}.nUhMVa_cardShots{-webkit-overflow-scrolling:touch;scrollbar-width:thin;gap:6px;margin:0 0 6px;padding:0 0 2px;display:flex;overflow-x:auto}.nUhMVa_cardShot{object-fit:contain;border:1px solid var(--dsw-alias-border-default,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);cursor:pointer;border-radius:8px;flex:none;width:132px;height:88px;display:block}.nUhMVa_lightbox{z-index:10000;cursor:zoom-out;background:#000000d9;justify-content:center;align-items:center;display:flex;position:fixed;top:0;bottom:0;left:0;right:0}.nUhMVa_lightboxImg{object-fit:contain;cursor:default;border-radius:4px;max-width:90vw;max-height:85vh}.nUhMVa_lightboxClose{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:99px;place-items:center;width:36px;height:36px;font-size:22px;line-height:1;display:grid;position:absolute;top:16px;right:16px}.nUhMVa_lightboxClose:hover{background:#ffffff38}.nUhMVa_lightboxNav{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:99px;place-items:center;width:44px;height:44px;display:grid;position:absolute;top:50%;transform:translateY(-50%)}.nUhMVa_lightboxNav:hover{background:#ffffff38}.nUhMVa_lightboxPrev{left:16px}.nUhMVa_lightboxNext{right:16px}.nUhMVa_lightboxDots{gap:8px;display:flex;position:absolute;bottom:20px;left:50%;transform:translate(-50%)}.nUhMVa_lightboxDot{cursor:pointer;background:#fff6;border-radius:99px;width:7px;height:7px}.nUhMVa_lightboxDotOn{background:#fff}.nUhMVa_cmd{background:var(--dsw-alias-bg-layer-2,#f3f4f6);word-break:break-all;border-radius:6px;margin:8px 0 0;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:18px}.nUhMVa_warnLine{color:var(--dsw-alias-state-warn-primary,#b45309);flex-wrap:wrap;align-items:center;gap:4px;margin:0;font-size:12px;font-weight:600;line-height:18px;display:flex}.nUhMVa_modalNote{color:var(--dsw-alias-label-tertiary,#8b93a1);align-items:center;gap:4px;margin:12px 0 0;font-size:12px;line-height:18px;display:flex}.nUhMVa_grid{grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:10px;display:grid}.nUhMVa_masonry{align-items:flex-start;gap:10px;display:flex}.nUhMVa_masonryCol{flex-direction:column;flex:1;gap:10px;min-width:0;display:flex}.nUhMVa_masonry>.nUhMVa_masonryCol>*{align-self:stretch;min-width:0}@media (max-width:680px){.nUhMVa_masonry{flex-direction:column}.nUhMVa_masonryCol{width:100%}.nUhMVa_grid{grid-template-columns:minmax(0,1fr)}}.nUhMVa_swatches{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;gap:0;height:34px;display:flex;overflow:hidden}.nUhMVa_themesGrid{margin-bottom:12px}.nUhMVa_swatches i{flex:1}.nUhMVa_themeToolbar{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px;padding:0 4px 12px;display:grid}.nUhMVa_themeSearch{box-sizing:border-box;width:100%;min-width:0}.nUhMVa_themeToolbarActions{justify-content:flex-end;align-items:center;gap:8px;display:flex}.nUhMVa_themeFullscreenBtn.nUhMVa_themeFullscreenBtn{width:28px;min-width:28px;padding:0}.nUhMVa_themeResultBar{min-height:24px;color:var(--dsw-alias-label-tertiary,#8b93a1);align-items:center;padding:0 4px 8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_favoritesSectionHead{color:var(--dsw-alias-label-primary,#1f2328);margin:16px 0 8px;padding:0 4px;font-size:13px;font-weight:600;line-height:20px}.nUhMVa_favoritesSectionHead:first-of-type{margin-top:0}.nUhMVa_favoritesStaleBar{border:1px solid var(--dsw-alias-state-warn-tertiary,#b4530933);background:var(--dsw-alias-state-warn-tertiary,#b453090f);color:var(--dsw-alias-state-warn-primary,#b45309);border-radius:8px;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;margin:0 0 8px;padding:8px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_favoritesStaleOnly{flex-direction:column;align-items:flex-start;gap:10px;display:flex}.nUhMVa_themeGallery{grid-template-columns:repeat(4,minmax(0,1fr));align-items:stretch;gap:10px;display:grid}.nUhMVa_themeCard{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:8px;flex-direction:column;min-width:0;transition:border-color .16s cubic-bezier(.16,1,.3,1),box-shadow .16s cubic-bezier(.16,1,.3,1),transform .16s cubic-bezier(.16,1,.3,1);display:flex;overflow:hidden}.nUhMVa_themeCard:hover{border-color:var(--dsw-alias-border-l3,#d9dde3);box-shadow:var(--dsw-shadow-lv1,0 4px 12px #1f232814);transform:translateY(-1px)}.nUhMVa_themeCover{aspect-ratio:16/10;border:0;border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);width:100%;color:var(--dsw-alias-label-secondary,#6b7280);cursor:zoom-in;border-radius:0;padding:0;display:block;position:relative;overflow:hidden}.nUhMVa_themeCover img{object-fit:contain;background:var(--dsw-alias-bg-layer-2,#f3f4f6);width:100%;height:100%;transition:transform .18s cubic-bezier(.16,1,.3,1);display:block}.nUhMVa_themeCover:hover img{transform:scale(1.012)}.nUhMVa_themeCover:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4f6ef7);outline-offset:-3px}.nUhMVa_themeCoverEmpty{cursor:default;color:var(--dsw-alias-label-tertiary,#8b93a1);flex-direction:column;justify-content:center;align-items:center;gap:8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_themePreviewAction,.nUhMVa_themePreviewCount{color:#fff;-webkit-backdrop-filter:blur(8px);background:#14181fc7;border:1px solid #ffffff57;border-radius:4px;align-items:center;height:24px;padding:0 8px;font-size:11px;line-height:16px;display:inline-flex;position:absolute;bottom:8px}.nUhMVa_themePreviewAction{gap:4px;right:8px}.nUhMVa_themePreviewCount{left:8px}.nUhMVa_themeCardBody{flex-direction:column;flex:1;gap:8px;padding:12px;display:flex}.nUhMVa_themeCardHead{align-items:flex-start;gap:8px;min-width:0;display:flex}.nUhMVa_themeIdentity{flex:1;min-width:0}.nUhMVa_themeStatus,.nUhMVa_themeStatusMuted{white-space:nowrap;border-radius:4px;flex:none;align-items:center;min-height:22px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_themeStatus{background:var(--dsw-alias-state-success-tertiary,#16a34a1a);color:var(--dsw-alias-state-success-primary,#15803d)}.nUhMVa_themeStatusMuted{background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280)}.nUhMVa_themeDescription{min-height:36px;color:var(--dsw-alias-label-tertiary,#8b93a1);-webkit-line-clamp:3;-webkit-box-orient:vertical;margin:0;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}.nUhMVa_themeCardFooter{justify-content:space-between;align-items:center;gap:8px;margin-top:auto;padding-top:4px;display:flex}.nUhMVa_themeLifecycle{min-width:0;color:var(--dsw-alias-label-tertiary,#8b93a1);text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:18px;overflow:hidden}.nUhMVa_themeActions{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;margin-left:auto;display:flex}@container (width<=900px){.nUhMVa_themeGallery{grid-template-columns:repeat(3,minmax(0,1fr))}}@container (width<=680px){.nUhMVa_themeGallery{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (width<=460px){.nUhMVa_themeGallery{grid-template-columns:minmax(0,1fr)}}@container (width<=420px){.nUhMVa_sub{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:2px 8px;display:grid}.nUhMVa_sub>span:first-child{grid-area:1/1}.nUhMVa_sub>.nUhMVa_grow{display:none}.nUhMVa_submitLink{grid-area:2/1}.nUhMVa_exportLogBtn{flex-shrink:0;grid-area:1/2/span 2}.nUhMVa_themeToolbar{grid-template-columns:minmax(0,1fr)}.nUhMVa_themeCardHead{flex-wrap:wrap}.nUhMVa_themeStatus,.nUhMVa_themeStatusMuted{order:3}}@container (width<=280px){.nUhMVa_themeCardFooter{flex-direction:column;align-items:flex-start}.nUhMVa_themeActions{justify-content:flex-start;width:100%;margin-left:0}}@media (max-width:560px){[role=dialog]:has([data-dsh-market-root])>nav{display:none}[role=dialog]:has([data-dsh-market-root])>div{flex:100%;width:100%;min-width:0}}[role=dialog]:has([data-dsh-market-fullscreen=true]){border-radius:0;width:100vw;max-width:none;height:100vh;max-height:none;position:fixed;top:0;bottom:0;left:0;right:0}@media (prefers-reduced-motion:reduce){.nUhMVa_themeCard,.nUhMVa_themeCover img{transition:none}.nUhMVa_themeCard:hover{transform:none}}.nUhMVa_card{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;align-self:start;gap:12px;padding:12px 14px;display:flex}.nUhMVa_row1{align-items:flex-start;gap:10px;min-width:0;display:flex}.nUhMVa_cardAction{flex-shrink:0;align-items:center;display:inline-flex}.nUhMVa_installBtn.nUhMVa_installBtn{min-width:64px}.nUhMVa_av{color:#fff;object-fit:cover;background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:50%;flex-shrink:0;place-items:center;width:16px;height:16px;font-size:9px;font-weight:700;display:grid}.nUhMVa_nm{text-overflow:ellipsis;white-space:nowrap;font-size:15px;font-weight:600;line-height:22px;overflow:hidden}.nUhMVa_nmLink{color:inherit;text-decoration:none;display:block}.nUhMVa_nmLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_repoMark{color:var(--dsw-alias-label-secondary,#6b7280);vertical-align:-1px;flex-shrink:0;margin-left:5px;display:inline-block}.nUhMVa_nmLink:hover .nUhMVa_repoMark{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_byline{flex-wrap:wrap;align-items:center;gap:6px;min-width:0;margin-top:2px;display:flex}.nUhMVa_meta{color:var(--dsw-alias-label-secondary,#9ca3af);margin-top:2px;font-size:11px}.nUhMVa_metaInline{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.nUhMVa_owner{color:var(--dsw-alias-label-secondary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:44px;font-size:11px;overflow:hidden}.nUhMVa_desc{color:var(--dsw-alias-label-tertiary,#8b93a1);margin:0;font-size:12px;line-height:18px}.nUhMVa_descClamp{-webkit-line-clamp:5;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.nUhMVa_descToggle{width:20px;height:16px;color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;margin-top:2px;padding:0;display:flex}.nUhMVa_descToggle:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_foot{flex-wrap:nowrap;align-items:flex-end;gap:8px;display:flex}.nUhMVa_foot .nUhMVa_metaInline,.nUhMVa_foot .nUhMVa_src{white-space:nowrap}.nUhMVa_footTags{flex-wrap:wrap;flex:1 1 0;align-items:center;gap:8px;min-width:0;display:flex}.nUhMVa_grow{flex:1}.nUhMVa_titleRow{align-items:center;gap:10px;display:flex}.nUhMVa_version{color:var(--dsw-alias-label-tertiary,#8b93a1);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:12px;line-height:20px}.nUhMVa_repoLink{color:var(--dsw-alias-label-tertiary,#8b93a1);flex-shrink:0;font-size:12px;line-height:20px;text-decoration:none}.nUhMVa_repoLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_noteRow{flex-wrap:wrap;align-items:baseline;gap:6px;min-width:0;display:flex}.nUhMVa_desc.nUhMVa_noteRow,.nUhMVa_desc.nUhMVa_noteRow+.nUhMVa_noteRow,.nUhMVa_noteEdit+.nUhMVa_noteRow{margin-top:6px}.nUhMVa_noteMine{color:var(--dsw-alias-label-primary,#1f2328)}.nUhMVa_noteToggle{font:inherit;color:var(--dsw-alias-label-tertiary,#8b93a1);cursor:pointer;white-space:nowrap;background:0 0;border:none;flex-shrink:0;padding:0;font-size:11px;line-height:16px}.nUhMVa_noteToggle:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_noteAction{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:4px;align-items:center;padding:0 5px;font-weight:600;text-decoration:none;display:inline-flex}.nUhMVa_noteAction:hover{color:var(--dsw-alias-label-primary,#1f2328);border-color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:none}.nUhMVa_noteEdit{flex-wrap:wrap;align-items:center;gap:6px;min-width:0;margin-top:6px;display:flex}.nUhMVa_noteInput{flex:1;min-width:160px}.nUhMVa_descTight{min-height:0}.nUhMVa_src{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px;text-decoration:none}.nUhMVa_src:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_dot{vertical-align:2px;margin-left:5px}.nUhMVa_act{flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px;font-size:11px;display:flex}.nUhMVa_actLive{color:var(--dsw-alias-state-success-primary,#16a34a);align-items:center;gap:4px;font-weight:600;display:inline-flex}.nUhMVa_actWarn{color:var(--dsw-alias-state-warn-primary,#b45309);align-items:center;gap:4px;font-weight:600;display:inline-flex}.nUhMVa_actBroken{color:var(--dsw-alias-state-error-primary,#dc2626);align-items:center;gap:4px;font-weight:600;display:inline-flex}.nUhMVa_actWhy{color:var(--dsw-alias-label-secondary,#6b7280);margin-top:2px}.nUhMVa_loading{color:var(--dsw-alias-label-secondary,#9ca3af);flex-direction:column;align-items:center;gap:12px;padding:48px;font-size:13px;display:flex}.nUhMVa_spin{color:var(--dsw-alias-brand-primary,#4f6ef7);flex-shrink:0;animation:.8s linear infinite nUhMVa_sp;display:inline-flex}.nUhMVa_logoMark{color:var(--dsw-alias-brand-primary,#4f6ef7);flex-shrink:0;display:inline-flex}.nUhMVa_logoPlug{transform-box:fill-box;transform-origin:50%;animation:1.5s cubic-bezier(.4,0,.2,1) infinite nUhMVa_dshmPlug}@keyframes nUhMVa_dshmPlug{0%,12%{transform:rotate(9deg)}45%,62%{transform:translate(-1.28px,1.27px)rotate(0)}95%,to{transform:rotate(9deg)}}@media (prefers-reduced-motion:reduce){.nUhMVa_logoPlug,.nUhMVa_spin{animation:1.5s ease-in-out infinite nUhMVa_dshmPlugFade}}@keyframes nUhMVa_dshmPlugFade{0%,to{opacity:1}50%{opacity:.35}}@keyframes nUhMVa_sp{to{transform:rotate(360deg)}}.nUhMVa_progress{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:8px;flex-wrap:wrap;align-items:center;gap:9px;margin:0;padding:8px 12px;font-size:12px;display:flex}.nUhMVa_bar{background:var(--dsw-alias-border-l1,#e5e7eb);border-radius:99px;width:100%;height:4px;overflow:hidden}.nUhMVa_barFill{background:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:99px;height:100%;transition:width .6s}.nUhMVa_barWave{width:30%;animation:1.2s ease-in-out infinite nUhMVa_dshmSlide}@keyframes nUhMVa_dshmSlide{0%{margin-left:-30%}to{margin-left:100%}}.nUhMVa_irow .nUhMVa_progress{margin-top:8px}.nUhMVa_progress code{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.nUhMVa_empty{color:var(--dsw-alias-label-secondary,#9ca3af);text-align:center;padding:32px;font-size:13px}.nUhMVa_err{color:var(--dsw-alias-state-error-primary,#dc2626);white-space:pre-wrap;word-break:break-all;margin:8px 0;font-size:12px}.nUhMVa_cardBlocked{border-color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_conflictHead{align-items:flex-start;gap:8px;display:flex}.nUhMVa_conflictIcon{color:var(--dsw-alias-state-error-primary,#dc2626);flex-shrink:0;margin-top:1px}.nUhMVa_conflictTitle{color:var(--dsw-alias-state-error-primary,#dc2626);font-size:13px;font-weight:600;line-height:18px}.nUhMVa_conflictBody{margin:0;font-size:12px;line-height:19px}.nUhMVa_roster{background:var(--dsw-alias-border-l2,#e5e7eb);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;flex-direction:column;gap:1px;display:flex;overflow:hidden}.nUhMVa_rosterRow{background:var(--dsw-alias-bg-layer-1,#fff);align-items:center;gap:8px;padding:7px 10px;display:flex}.nUhMVa_rosterMain{flex-direction:column;min-width:0;display:flex}.nUhMVa_rosterName{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;font-weight:600;overflow:hidden}.nUhMVa_rosterAuthor{color:var(--dsw-alias-label-secondary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;font-size:10.5px;overflow:hidden}.nUhMVa_rosterTag{border-radius:4px;flex-shrink:0;margin-left:auto;padding:1px 6px;font-size:10.5px;font-weight:600}.nUhMVa_rosterTagKeep{color:var(--dsw-alias-state-success-primary,#16a34a);background:#16a34a1f}.nUhMVa_rosterTagDrop{color:var(--dsw-alias-state-error-primary,#dc2626);background:#dc26261f}.nUhMVa_rosterRowOut .nUhMVa_rosterName{text-decoration:line-through}.nUhMVa_rosterRowOut{opacity:.62}.nUhMVa_rosterSplit{background:var(--dsw-alias-border-l2,#e5e7eb);height:1px}.nUhMVa_reassure{color:var(--dsw-alias-label-secondary,#6b7280);align-items:center;gap:5px;margin:0;font-size:11.5px;line-height:17px;display:flex}.nUhMVa_reassureOk{color:var(--dsw-alias-state-success-primary,#16a34a);flex-shrink:0}.nUhMVa_conflictWhy{color:var(--dsw-alias-label-tertiary,#8b93a1);overflow-wrap:anywhere;margin-top:2px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:17px}.nUhMVa_conflictWhyText{margin-top:5px;font-family:-apple-system,BlinkMacSystemFont,PingFang SC,sans-serif}.nUhMVa_choices{flex-direction:column;gap:7px;display:flex}.nUhMVa_choice{text-align:left;font:inherit;cursor:pointer;background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:9px;align-items:flex-start;gap:9px;padding:9px 11px;display:flex}.nUhMVa_choice:has(input:disabled){cursor:default;opacity:.6}.nUhMVa_choiceOn{border-color:var(--dsw-alias-brand-primary,#4f6ef7);background:var(--dsw-alias-bg-layer-2,#f5f7ff)}.nUhMVa_choiceRadio{width:13px;height:13px;accent-color:var(--dsw-alias-brand-primary,#4f6ef7);flex-shrink:0;margin:2px 0 0}.nUhMVa_choiceMain{flex-direction:column;gap:3px;min-width:0;display:flex}.nUhMVa_choiceTitle{font-size:12px;font-weight:600;line-height:17px}.nUhMVa_choiceNote{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:11px;line-height:16px}.nUhMVa_choiceSafe{color:var(--dsw-alias-state-success-primary,#16a34a)}.nUhMVa_stateTag{white-space:nowrap;background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-height:20px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:5px;flex-shrink:0;align-items:center;gap:5px;padding:1px 7px;font-size:11px;line-height:16px;display:inline-flex}.nUhMVa_stateTag[data-on=true]{color:var(--dsw-alias-state-success-primary,#16a34a);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#16a34a) 10%, transparent)}.nUhMVa_stateDot{background:var(--dsw-alias-label-tertiary,#8b93a1);border-radius:999px;flex:none;width:6px;height:6px}.nUhMVa_stateDot[data-on=true]{background:var(--dsw-alias-state-success-primary,#16a34a)}.nUhMVa_metaTag{text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-width:0;max-width:100%;min-height:20px;color:var(--dsw-alias-label-tertiary,#8b93a1);border-radius:5px;flex-shrink:1;padding:1px 7px;font-size:11px;line-height:18px;display:inline-block;overflow:hidden}.nUhMVa_metaTagOk{color:var(--dsw-alias-state-success-primary,#16a34a);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#16a34a) 10%, transparent)}.nUhMVa_metaTagAction{font-family:inherit;font-size:11px;line-height:18px;font-weight:inherit;cursor:pointer;background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280);border:none;border-radius:5px;flex-shrink:0;padding:1px 7px}.nUhMVa_metaTagAction:hover:not(:disabled){color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_metaTagAction:disabled{opacity:.5;cursor:default}.nUhMVa_irowHead{align-items:flex-start;gap:8px;min-width:0;display:flex}.nUhMVa_irowHead .nUhMVa_irowName{flex:1 1 0;min-width:0}.nUhMVa_irowDevTag{letter-spacing:.02em;white-space:nowrap;cursor:default;-webkit-user-select:none;user-select:none;color:var(--dsw-alias-label-tertiary,#8b93a1);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#4f6ef7) 9%, var(--dsw-alias-bg-layer-2,#f3f4f6));border-radius:99px;flex-shrink:0;padding:2px 8px;font-size:10px;font-weight:600;line-height:14px}.nUhMVa_nameLink{color:inherit;text-decoration:none}.nUhMVa_irowName{text-overflow:clip;flex-wrap:wrap;align-items:baseline;gap:6px;min-width:0;display:flex;overflow:visible}.nUhMVa_irowNameText{overflow-wrap:anywhere;white-space:normal;min-width:0}.nUhMVa_irowName>.nUhMVa_owner{flex:none}.nUhMVa_nameLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:underline}.nUhMVa_opWrap{flex-shrink:0;margin-bottom:6px;display:inline-flex;position:relative}.nUhMVa_opEntry{font:inherit;cursor:pointer;white-space:nowrap;color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:7px;align-items:center;gap:6px;padding:4px 10px;font-size:12px;display:inline-flex;position:relative}.nUhMVa_opEntryQuiet{color:var(--dsw-alias-label-secondary,#6b7280);background:0 0;border-color:#0000}.nUhMVa_opEntryAlert{border-color:var(--dsw-alias-state-error-primary,#dc2626);color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_opDot{background:var(--dsw-alias-state-error-primary,#dc2626);border-radius:99px;width:8px;height:8px;position:absolute;top:-3px;right:-3px}.nUhMVa_opPanel{z-index:40;background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l3,#d9dde3);border-radius:12px;width:460px;max-width:86vw;max-height:70vh;position:absolute;top:calc(100% + 6px);right:0;overflow-y:auto;box-shadow:0 20px 52px #00000047}.nUhMVa_opHead{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:center;gap:8px;padding:9px 14px;display:flex}.nUhMVa_opPanelTitle{font-size:12.5px;font-weight:600}.nUhMVa_opCloseBtn.nUhMVa_opCloseBtn{min-width:0;color:var(--dsw-alias-label-secondary,#6b7280);padding:0 6px}.nUhMVa_opAggregate{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f7f8fa);padding:9px 14px}.nUhMVa_opAggregateTop{font-variant-numeric:tabular-nums;font-size:12px;font-weight:600}.nUhMVa_opAggregateHint{color:var(--dsw-alias-label-tertiary,#8b93a1);margin-top:4px;font-size:10.5px}.nUhMVa_opRow{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:flex-start;gap:9px;padding:9px 14px;display:flex}.nUhMVa_opRow:last-child{border-bottom:none}.nUhMVa_opRowAlert{background:#dc26260f}.nUhMVa_opIcon{flex-shrink:0;place-items:center;width:14px;margin-top:1px;display:grid}.nUhMVa_opQueuedIcon{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:12px}.nUhMVa_opMain{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}.nUhMVa_opTop{align-items:baseline;gap:6px;min-width:0;display:flex}.nUhMVa_opVerb{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:12px}.nUhMVa_opName{text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600;overflow:hidden}.nUhMVa_opStatus{color:var(--dsw-alias-label-tertiary,#8b93a1);overflow-wrap:anywhere;font-size:10.5px;line-height:16px}.nUhMVa_opStatusBad{color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_opActions{flex-shrink:0;align-items:center;gap:6px;margin-top:1px;display:flex}.nUhMVa_opDecision{border-top:1px dashed var(--dsw-alias-border-l2,#e5e7eb);flex-direction:column;gap:8px;margin-top:8px;padding-top:8px;display:flex}.nUhMVa_opDecisionFoot{align-items:center;gap:8px;display:flex}.nUhMVa_conflictDetailsToggle{font:inherit;cursor:pointer;color:var(--dsw-alias-label-tertiary,#8b93a1);background:0 0;border:none;align-items:center;gap:4px;padding:2px 0;font-size:11px;display:inline-flex}.nUhMVa_conflictDetailsToggle:hover{color:var(--dsw-alias-label-secondary,#6b7280)}.nUhMVa_opEmpty{text-align:center;color:var(--dsw-alias-label-secondary,#6b7280);padding:30px 14px;font-size:12px}.nUhMVa_opEmptyHint{color:var(--dsw-alias-label-tertiary,#8b93a1);margin-top:4px;font-size:11px}.nUhMVa_cardBlockedMark{font:inherit;cursor:pointer;color:var(--dsw-alias-state-error-primary,#dc2626);border:1px solid var(--dsw-alias-state-error-primary,#dc2626);background:#dc262614;border-radius:7px;align-items:center;gap:5px;padding:4px 9px;font-size:11px;display:inline-flex}.nUhMVa_dangerBtn.nUhMVa_dangerBtn{color:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_dangerBtn.nUhMVa_dangerBtn:hover:not(:disabled){background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.nUhMVa_dangerArmed.nUhMVa_dangerArmed{background:var(--dsw-alias-state-error-primary,#dc2626);border-color:var(--dsw-alias-state-error-primary,#dc2626);color:#fff}.nUhMVa_retryBtn{margin-top:4px}.nUhMVa_irow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:10px;flex-direction:column;gap:10px;min-width:0;padding:12px 14px;display:flex}.nUhMVa_irowActions{flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:8px;min-width:0;display:flex}.nUhMVa_irowTrailing{flex-wrap:nowrap;flex-shrink:0;align-items:center;gap:8px;min-width:0;display:inline-flex}.nUhMVa_irowTrailing .nUhMVa_metaTag{flex-shrink:1;min-width:0}.nUhMVa_irowTrailing .nUhMVa_metaTagAction{flex-shrink:0}.nUhMVa_irowMissing{filter:grayscale();opacity:.5}.nUhMVa_irow>.nUhMVa_src,.nUhMVa_irow>.nUhMVa_owner,.nUhMVa_irow button{white-space:nowrap;flex-shrink:0}.nUhMVa_tabSearchRow{padding:0 4px 6px;display:flex}.nUhMVa_tabSearch{width:100%}.nUhMVa_spec{color:var(--dsw-alias-label-secondary,#9ca3af);overflow-wrap:anywhere;min-width:0;font-family:ui-monospace,Menlo,monospace;font-size:11px}.nUhMVa_specTag{white-space:nowrap;border-radius:4px;flex-shrink:0;align-items:center;height:16px;padding:0 5px;font-size:10px;font-weight:600;display:inline-flex}.nUhMVa_specTagGit{color:#0b7285;background:#12a3c41f}.nUhMVa_specTagFile{color:#b07d1b;background:#f0b42924}.nUhMVa_backupCheckList .nUhMVa_grow{white-space:nowrap;text-overflow:ellipsis;flex:70%;min-width:0;overflow:hidden}.nUhMVa_backupCheckList .nUhMVa_spec{text-align:right;white-space:nowrap;text-overflow:ellipsis;flex:0 30%;max-width:30%;overflow:hidden}.nUhMVa_staleAction{word-break:normal;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px;display:flex}.nUhMVa_pct{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;font-size:11px;font-weight:600}.nUhMVa_pager{flex-wrap:nowrap;justify-content:space-between;align-items:center;gap:8px;margin:16px 0 4px;display:flex}.nUhMVa_pagerPages{flex-wrap:nowrap;flex:1;justify-content:center;align-items:center;gap:4px;min-width:0;display:flex}.nUhMVa_pagerMeta{flex-wrap:nowrap;flex-shrink:0;align-items:center;gap:6px;display:flex}.nUhMVa_pagerPages button,.nUhMVa_pagerMeta button{min-width:0;padding:0 8px}.nUhMVa_pageEllipsis{color:var(--dsw-alias-label-secondary,#9ca3af);padding:0 1px;font-size:12px}.nUhMVa_pageInfo{color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;font-size:12px}@container (width<=544px){.nUhMVa_pager{flex-wrap:wrap;justify-content:center;gap:8px}.nUhMVa_pagerPages{flex-basis:100%}}.nUhMVa_depBadge{border:1px solid var(--dsw-alias-state-warn-primary,#b45309);color:var(--dsw-alias-state-warn-primary,#b45309);white-space:nowrap;border-radius:4px;flex-shrink:0;margin-left:6px;padding:1px 6px;font-size:11px;font-weight:600;line-height:16px}.nUhMVa_deprecate{color:var(--dsw-alias-state-warn-primary,#b45309);background:var(--dsw-alias-bg-layer-2,#fdf3e3);border:1px solid var(--dsw-alias-border-l2,#f3e3c3);border-radius:8px;margin:0;padding:8px 10px;font-size:12px;line-height:18px}.nUhMVa_deprecate a{color:var(--dsw-alias-state-warn-primary,#b45309);text-decoration:underline}.nUhMVa_deprecate .nUhMVa_src{margin-left:8px}.nUhMVa_depLine{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.nUhMVa_switch{border:1px solid var(--dsw-alias-border-l2,#d9dde3);background:var(--dsw-alias-bg-layer-2,#e5e7eb);cursor:pointer;border-radius:99px;flex-shrink:0;width:38px;height:22px;padding:0;transition:background .15s,border-color .15s;position:relative}.nUhMVa_switchOn{background:var(--dsw-alias-state-success-primary,#16a34a);border-color:var(--dsw-alias-state-success-primary,#16a34a)}.nUhMVa_switchMixed{background:var(--dsw-alias-state-warn-primary,#b45309);border-color:var(--dsw-alias-state-warn-primary,#b45309)}.nUhMVa_switchKnob{background:#fff;border-radius:99px;width:16px;height:16px;transition:left .15s;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #00000040}.nUhMVa_switchOn .nUhMVa_switchKnob,.nUhMVa_switchMixed .nUhMVa_switchKnob{left:18px}.nUhMVa_switch:disabled{opacity:.5;cursor:default}.nUhMVa_viewBar{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;align-items:center;gap:2px;width:fit-content;margin-bottom:12px;padding:2px;display:flex}.nUhMVa_viewBtn{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:6px;padding:4px 10px;font-size:12px;line-height:18px}.nUhMVa_viewBtn:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_viewOn{background:var(--dsw-alias-bg-layer-2,#eef0f4);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}.nUhMVa_groupRow{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;margin-bottom:10px;padding:12px 14px}.nUhMVa_groupHead{align-items:center;gap:10px;min-width:0;display:flex}.nUhMVa_groupName{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}.nUhMVa_groupActions{flex-shrink:0;align-items:center;gap:6px;display:flex}.nUhMVa_groupMembers{flex-direction:column;gap:6px;margin-top:10px;display:flex}.nUhMVa_groupMember{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;align-items:center;gap:8px;padding:6px 8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_groupMember .nUhMVa_nm{flex:1;min-width:0;font-size:12px}.nUhMVa_groupAddPanel{border-top:1px dashed var(--dsw-alias-border-l2,#e5e7eb);flex-direction:column;gap:6px;margin-top:10px;padding-top:10px;display:flex}.nUhMVa_groupCreate{align-items:center;gap:8px;margin-bottom:10px;display:flex}.nUhMVa_inlineInput{flex:1;min-width:120px}.nUhMVa_assignRow{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.nUhMVa_assignSelect{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font:inherit;border-radius:6px;padding:3px 6px;font-size:12px;line-height:18px}.nUhMVa_groupHint{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:11px}.nUhMVa_sectAction{color:var(--dsw-alias-label-secondary,#6b7280);align-items:center;gap:8px;margin:14px 2px 8px;font-size:12px;font-weight:600;display:flex}.nUhMVa_backupGrid{grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;display:grid}.nUhMVa_backupCard{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:10px;padding:16px;display:flex}.nUhMVa_backupCard h3{margin:0;font-size:14px}.nUhMVa_backupCard p{color:var(--dsw-alias-label-secondary,#6b7280);margin:0;font-size:12px;line-height:18px}.nUhMVa_backupActions{flex-wrap:wrap;gap:8px;display:flex;position:relative}.nUhMVa_hiddenFile{opacity:0;pointer-events:none;width:1px;height:1px;position:absolute}.nUhMVa_backupInput{box-sizing:border-box;width:100%}.nUhMVa_backupCheck{cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.nUhMVa_backupWarn{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-state-warn-primary,#b45309)!important}.nUhMVa_backupMessage{color:var(--dsw-alias-label-secondary,#6b7280);grid-column:1/-1;font-size:12px}.nUhMVa_backupCheckList{flex-direction:column;gap:6px;max-height:260px;margin:10px 0 4px;padding-right:4px;display:flex;overflow-y:auto}.nUhMVa_backupCheckList .nUhMVa_backupCheck{justify-content:space-between;gap:8px}.nUhMVa_diagPage{flex-direction:column;gap:12px;height:100%;min-height:0;display:flex;overflow-y:auto}.nUhMVa_diagSummary{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-wrap:wrap;align-items:center;gap:12px;padding:10px 14px;font-size:12px;display:flex}.nUhMVa_diagSummaryItem{color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;align-items:center;gap:6px;display:inline-flex}.nUhMVa_diagSummaryMeta{color:var(--dsw-alias-label-tertiary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;max-width:320px;font-family:ui-monospace,Menlo,monospace;font-size:11px;overflow:hidden}.nUhMVa_diagSection{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;flex-direction:column;gap:8px;padding:12px 14px;display:flex}.nUhMVa_diagSection h3{color:var(--dsw-alias-label-primary,#1f2328);margin:0;font-size:13px;font-weight:600}.nUhMVa_diagCount{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:11px;font-weight:400}.nUhMVa_diagEmpty{color:var(--dsw-alias-label-secondary,#9ca3af);padding:8px 0;font-size:12px}.nUhMVa_diagBundle{border-top:1px solid var(--dsw-alias-border-l2,#f0f1f3);flex-direction:column;gap:6px;padding-top:8px;display:flex}.nUhMVa_diagBundle:first-of-type{border-top:none;padding-top:0}.nUhMVa_diagRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;font-size:12px;line-height:18px;display:flex}.nUhMVa_diagMeta{align-items:baseline;gap:8px;min-width:0;font-size:12px;display:flex}.nUhMVa_diagKey{color:var(--dsw-alias-label-tertiary,#9ca3af);flex-shrink:0;min-width:64px;font-size:11px}.nUhMVa_diagVal{color:var(--dsw-alias-label-primary,#1f2328);overflow-wrap:anywhere;min-width:0;font-family:ui-monospace,Menlo,monospace;font-size:12px;font-weight:500}.nUhMVa_diagIndex{background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-width:18px;height:18px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:9px;flex-shrink:0;justify-content:center;align-items:center;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagArrow{color:var(--dsw-alias-label-tertiary,#9ca3af);flex-shrink:0;font-size:12px}.nUhMVa_diagBadgeOfficial{background:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagBadgeCommunity{background:var(--dsw-alias-bg-layer-2,#f3f4f6);height:18px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:9px;flex-shrink:0;align-items:center;padding:0 8px;font-size:11px;display:inline-flex}.nUhMVa_diagBadgeShadow{background:var(--dsw-alias-state-error-primary,#dc2626);color:#fff;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagBadgeWarn{background:var(--dsw-alias-state-warn-primary,#b45309);color:#fff;white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_diagBadgeInfo{background:var(--dsw-alias-bg-layer-2,#f3f4f6);height:18px;color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;padding:0 8px;font-size:11px;display:inline-flex}.nUhMVa_diagList{flex-direction:column;gap:6px;display:flex}.nUhMVa_sectionOverview{color:var(--dsw-alias-label-tertiary,#8b93a1);text-overflow:ellipsis;white-space:nowrap;max-width:100%;padding:2px 0 6px;font-size:12px;line-height:18px;overflow:hidden}.nUhMVa_diagAlert{color:var(--dsw-alias-state-warn-primary,#b45309)}.nUhMVa_ovRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;padding:6px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_ovArrow{color:var(--dsw-alias-label-tertiary,#9ca3af);flex-shrink:0;font-size:12px}.nUhMVa_ovByTag{background:var(--dsw-alias-brand-primary,#4f6ef7);color:#fff;text-overflow:ellipsis;white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;max-width:260px;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex;overflow:hidden}.nUhMVa_ovFrom{color:var(--dsw-alias-label-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;overflow:hidden}.nUhMVa_orphRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;padding:6px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_orphBadge{background:var(--dsw-alias-state-warn-primary,#b45309);color:#fff;white-space:nowrap;border-radius:9px;flex-shrink:0;align-items:center;height:18px;padding:0 8px;font-size:11px;font-weight:600;display:inline-flex}.nUhMVa_dragHandle{width:20px;height:20px;color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:grab;-webkit-user-select:none;user-select:none;flex-shrink:0;justify-content:center;align-items:center;font-size:12px;line-height:20px;display:inline-flex}.nUhMVa_dragOver{outline:2px dashed var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:2px;background:var(--dsw-alias-bg-layer-2,#f0f2f8);border-radius:8px}.nUhMVa_dragging{opacity:.45;background:var(--dsw-alias-bg-layer-2,#f3f4f6)}.nUhMVa_collapseHead{font:inherit;color:var(--dsw-alias-label-primary,#1f2328);cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;width:100%;padding:0;font-size:13px;font-weight:600;display:flex}.nUhMVa_collapseIcon{color:var(--dsw-alias-label-secondary,#6b7280);flex-shrink:0;display:inline-flex}.nUhMVa_collapseTitle{flex:1;min-width:0}.nUhMVa_collapseBody{border-top:1px solid var(--dsw-alias-border-l2,#f0f1f3);overflow-wrap:anywhere;flex-direction:column;gap:10px;min-width:0;margin-top:8px;padding-top:10px;display:flex}.nUhMVa_orderPanel{flex-direction:column;gap:10px;min-width:0;display:flex}.nUhMVa_panelNote{color:var(--dsw-alias-label-secondary,#6b7280);margin:0;font-size:12px;line-height:18px}.nUhMVa_panelActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.nUhMVa_presetList{flex-direction:column;gap:6px;min-width:0;display:flex}.nUhMVa_presetRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-direction:column;align-items:stretch;gap:6px;min-width:0;max-width:100%;padding:8px 10px;font-size:12px;line-height:18px;display:flex}.nUhMVa_presetName{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:13px;font-weight:600;overflow:hidden}.nUhMVa_snapList{flex-direction:column;gap:6px;min-width:0;display:flex}.nUhMVa_snapRow{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:8px;flex-direction:column;align-items:stretch;gap:8px;padding:10px 12px;font-size:12px;line-height:18px;display:flex}.nUhMVa_snapMeta{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.nUhMVa_snapConfirmText{color:var(--dsw-alias-state-warn-primary,#b45309);margin:0;font-size:12px;line-height:18px}.nUhMVa_confirmRow{flex-wrap:wrap;align-items:center;gap:6px;display:inline-flex}.nUhMVa_fixFallback{flex-direction:column;gap:6px;margin:8px 0;display:flex}.nUhMVa_fixFallbackText{box-sizing:border-box;width:100%;color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);resize:vertical;white-space:pre-wrap;word-break:break-all;border-radius:6px;padding:8px 10px;font-family:ui-monospace,Menlo,monospace;font-size:11px;line-height:16px}.nUhMVa_setCard{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-3,#fff);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.nUhMVa_setCard:hover{border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}.nUhMVa_setCardOpen{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}.nUhMVa_setHeader{-webkit-appearance:none;appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.nUhMVa_setHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:-2px}.nUhMVa_setHeadText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.nUhMVa_setName{color:var(--dsw-alias-label-primary,#1f2328);font-size:15px;font-weight:600;line-height:1.4}.nUhMVa_setDesc{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:13px;line-height:1.5}.nUhMVa_setChevron{color:var(--dsw-alias-label-tertiary,#8b93a1);flex:none;transition:transform .16s;display:inline-flex}.nUhMVa_setChevronOpen{transform:rotate(180deg)}.nUhMVa_setBody{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);margin:0 16px;padding-bottom:8px}.nUhMVa_setRow{align-items:center;gap:12px;padding:12px 0;display:flex}.nUhMVa_setRow+.nUhMVa_setRow{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb)}.nUhMVa_setLabelBox{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}.nUhMVa_setLabel{font-size:13px;line-height:20px}.nUhMVa_setHint{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:12px;line-height:18px}.nUhMVa_setConfirm{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);flex-direction:column;gap:8px;padding:12px 0 4px;display:flex}.nUhMVa_setCheck{cursor:pointer;align-items:center;gap:8px;font-size:12px;line-height:18px;display:flex}.nUhMVa_setActions{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.nUhMVa_setInlineActions{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px;display:flex}.nUhMVa_setProxyEditor{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);flex-wrap:wrap;align-items:flex-end;gap:10px;padding:12px 0;display:flex}.nUhMVa_setProxyLabel{min-width:180px;color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;flex:1;gap:5px;font-size:12px;line-height:18px;display:flex}.nUhMVa_setProxyInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-3,#fff);width:100%;min-width:0;color:var(--dsw-alias-label-primary,#1f2328);font:inherit;border-radius:7px;padding:6px 8px;font-size:12px;line-height:18px}.nUhMVa_setProxyInput:focus{border-color:var(--dsw-alias-brand-primary,#4f6ef7);outline:2px solid color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 18%,transparent)}.nUhMVa_setDanger{color:var(--dsw-alias-state-error-primary,#dc2626)}.nUhMVa_setSeg{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;flex-shrink:0;gap:2px;padding:2px;display:inline-flex}.nUhMVa_setSegBtn{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:3px 10px;font-size:12px;line-height:18px}.nUhMVa_setSegBtn:disabled{cursor:default;opacity:.5}.nUhMVa_setSegOn{background:var(--dsw-alias-bg-layer-2,#eef0f4);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}.nUhMVa_setBetaTag{background:var(--dsw-alias-bg-module-platform,#eef0f4);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:9px;margin-left:6px;padding:0 6px;font-size:11px;font-weight:600;line-height:17px}.nUhMVa_commentsLink{cursor:pointer;white-space:nowrap;color:var(--dsw-alias-label-secondary,#9ca3af);background:0 0;border:0;padding:0;font-size:11px;line-height:16px}.nUhMVa_commentsLink:hover{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_footActions{flex-shrink:0;align-items:center;gap:8px;display:inline-flex}.nUhMVa_favoriteBtn{cursor:pointer;color:var(--dsw-alias-label-secondary,#9ca3af);background:0 0;border:0;align-items:center;padding:0;display:inline-flex}.nUhMVa_favoriteBtn:hover,.nUhMVa_favoriteOn{color:var(--dsw-alias-brand-primary,#4f6ef7)}.nUhMVa_commentsNote{color:var(--dsw-alias-label-secondary,#9ca3af);margin:0 0 8px;font-size:11px;line-height:16px}.nUhMVa_commentsGithubPrompt{border:1px solid color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 24%,transparent);background:color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 6%,transparent);border-radius:8px;margin:0 0 10px;padding:10px}.nUhMVa_commentsGithubHint{color:var(--dsw-alias-label-primary,#1f2328);margin:0 0 8px;font-size:12px;line-height:17px}.nUhMVa_commentsGithubAction{box-sizing:border-box;border:1px solid var(--dsw-alias-brand-primary,#4f6ef7);min-height:28px;color:var(--dsw-alias-brand-primary,#4f6ef7);border-radius:6px;justify-content:center;align-items:center;padding:5px 10px;font-size:12px;font-weight:600;line-height:16px;text-decoration:none;display:inline-flex}.nUhMVa_commentsGithubAction:hover{background:color-mix(in srgb,var(--dsw-alias-brand-primary,#4f6ef7) 9%,transparent)}.nUhMVa_commentsStatus{color:var(--dsw-alias-label-secondary,#9ca3af);margin:0;font-size:12px}.nUhMVa_commentsStatus:empty{display:none}.nUhMVa_commentsError{color:var(--dsw-alias-label-primary,#1f2328);margin:0 0 8px;font-size:12px}.nUhMVa_commentsFail{flex-direction:column;align-items:flex-start;gap:8px;padding:12px 0;display:flex}.nUhMVa_commentsMount{width:100%;min-height:240px;max-height:56vh;overflow:auto}.nUhMVa_commentsMount iframe{width:100%}.nUhMVa_notesLink{font:inherit;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;text-align:left;background:0 0;border:none;margin:2px 0 0;padding:0;font-size:12px;line-height:18px;display:block}.nUhMVa_notesLink:hover{color:var(--dsw-alias-label-primary,#1f2328)}.nUhMVa_notesModalWide{width:min(640px,92vw);max-width:min(640px,92vw)}.nUhMVa_notesBody{overscroll-behavior:contain;flex-direction:column;flex:0 auto;gap:10px;min-width:0;max-height:min(60vh,520px);padding:0 2px 8px 0;display:flex;overflow-y:auto}.nUhMVa_notesRange{align-items:center;gap:8px;margin-bottom:4px;font-size:12px;line-height:18px;display:flex}.nUhMVa_notesArrow{color:var(--dsw-alias-label-tertiary,#8b93a1)}.nUhMVa_notesMeta{letter-spacing:.02em;text-transform:uppercase;color:var(--dsw-alias-label-secondary,#6b7280);flex-wrap:wrap;align-items:baseline;gap:6px;margin-top:4px;font-size:12px;line-height:18px;display:flex}.nUhMVa_notesBody>.nUhMVa_notesMeta:first-child{margin-top:0}.nUhMVa_notesPre{white-space:pre-wrap;word-break:break-word;background:var(--dsw-alias-bg-layer-2,#eef0f4);border-radius:8px;max-height:40vh;margin:0;padding:10px 12px;font-size:13px;line-height:20px;overflow:auto}.nUhMVa_notesRendered{flex-direction:column;gap:8px;min-width:0;display:flex}.nUhMVa_notesImg{border-radius:6px;max-width:100%;height:auto;margin:4px 0;display:block}.nUhMVa_notesH{margin-top:4px;font-size:13px;font-weight:650;line-height:20px}.nUhMVa_notesP{font-size:13px;line-height:20px}.nUhMVa_notesQuote{border-left:3px solid var(--dsw-alias-border-l3,#d9dde3);background:var(--dsw-alias-bg-layer-2,#f7f8fa);color:var(--dsw-alias-label-primary,#1f2328);border-radius:0 6px 6px 0;margin:0;padding:8px 10px;font-size:13px;line-height:20px}.nUhMVa_notesFence{background:var(--dsw-alias-bg-layer-2,#eef0f4);font-family:var(--dsw-alias-font-mono,ui-monospace,Menlo,monospace);white-space:pre;border-radius:8px;margin:0;padding:10px 12px;font-size:12px;line-height:18px;overflow-x:auto}.nUhMVa_notesFence code{font:inherit;background:0 0;padding:0}.nUhMVa_notesBullets{flex-direction:column;gap:4px;margin:0;padding-left:18px;font-size:13px;line-height:20px;display:flex}.nUhMVa_notesA{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:none}.nUhMVa_notesA:hover{text-decoration:underline}.nUhMVa_notesCode{font-family:var(--dsw-alias-font-mono,ui-monospace,monospace);background:var(--dsw-alias-bg-layer-2,#eef0f4);border-radius:5px;padding:1px 5px;font-size:12px}.nUhMVa_notesList{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.nUhMVa_notesRow{border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb);align-items:baseline;gap:12px;padding:6px 0;display:flex}.nUhMVa_notesRow:last-child{border-bottom:none}.nUhMVa_notesDate{color:var(--dsw-alias-label-tertiary,#8b93a1);font-variant-numeric:tabular-nums;flex-shrink:0;font-size:12px}.nUhMVa_notesMsg{word-break:break-word;word-break:break-word;-webkit-line-clamp:3;-webkit-box-orient:vertical;min-width:0;font-size:13px;line-height:20px;display:-webkit-box;overflow:hidden}.nUhMVa_notesSha{color:var(--dsw-alias-label-secondary,#6b7280);font-variant-numeric:tabular-nums;flex-shrink:0;margin-left:auto;font-size:12px;text-decoration:none}.nUhMVa_notesSha:hover{color:var(--dsw-alias-label-primary,#1f2328);text-decoration:underline}.nUhMVa_notesVer{color:inherit;font-weight:600;text-decoration:none}.nUhMVa_notesVer:hover{text-decoration:underline}.nUhMVa_migrationSources{flex-direction:column;gap:8px;margin-top:4px;display:flex}.nUhMVa_migrationSource{border:1px solid var(--dsw-alias-border-default,#e5e7eb);border-radius:8px;flex-direction:column;gap:4px;padding:10px 12px;display:flex}.nUhMVa_migrationSource code{overflow-wrap:anywhere;font-family:ui-monospace,Menlo,monospace;font-size:12px}.nUhMVa_migrationLabel{color:var(--dsw-alias-label-secondary,#9ca3af);font-size:11px}.nUhMVa_migrationArrow{text-align:center;color:var(--dsw-alias-label-secondary,#9ca3af)}.nUhMVa_migrationWarning{color:var(--dsw-alias-state-warn-primary,#b45309);align-items:flex-start;gap:6px;margin:12px 0 0;font-size:12px;line-height:18px;display:flex}";
|
|
2251
2332
|
const tagId = "dshmarket/Market.module.css";
|
|
2252
2333
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
2253
2334
|
const tag = document.createElement("style");
|
|
@@ -2430,17 +2511,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
2430
2511
|
"noteInput": "nUhMVa_noteInput",
|
|
2431
2512
|
"noteMine": "nUhMVa_noteMine",
|
|
2432
2513
|
"noteRow": "nUhMVa_noteRow",
|
|
2514
|
+
"notesA": "nUhMVa_notesA",
|
|
2433
2515
|
"notesArrow": "nUhMVa_notesArrow",
|
|
2434
2516
|
"notesBody": "nUhMVa_notesBody",
|
|
2517
|
+
"notesBullets": "nUhMVa_notesBullets",
|
|
2435
2518
|
"notesCode": "nUhMVa_notesCode",
|
|
2436
2519
|
"notesDate": "nUhMVa_notesDate",
|
|
2520
|
+
"notesFence": "nUhMVa_notesFence",
|
|
2437
2521
|
"notesH": "nUhMVa_notesH",
|
|
2522
|
+
"notesImg": "nUhMVa_notesImg",
|
|
2438
2523
|
"notesLink": "nUhMVa_notesLink",
|
|
2439
2524
|
"notesList": "nUhMVa_notesList",
|
|
2440
2525
|
"notesMeta": "nUhMVa_notesMeta",
|
|
2526
|
+
"notesModalWide": "nUhMVa_notesModalWide",
|
|
2441
2527
|
"notesMsg": "nUhMVa_notesMsg",
|
|
2442
2528
|
"notesP": "nUhMVa_notesP",
|
|
2443
2529
|
"notesPre": "nUhMVa_notesPre",
|
|
2530
|
+
"notesQuote": "nUhMVa_notesQuote",
|
|
2444
2531
|
"notesRange": "nUhMVa_notesRange",
|
|
2445
2532
|
"notesRendered": "nUhMVa_notesRendered",
|
|
2446
2533
|
"notesRow": "nUhMVa_notesRow",
|
|
@@ -3050,13 +3137,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
3050
3137
|
});
|
|
3051
3138
|
}
|
|
3052
3139
|
/** The one-line status under a record's name; the bucket carries the rest. */
|
|
3053
|
-
function statusLine(t, record, ahead) {
|
|
3140
|
+
function statusLine(t, lang, record, ahead) {
|
|
3054
3141
|
switch (record.state) {
|
|
3055
3142
|
case "queued": return ahead === null || ahead === 0 ? t("opQueued") : `${t("opQueued")} · ${t("opQueuedAhead")} ${String(ahead)}`;
|
|
3056
3143
|
case "running": return record.detail ?? t("opRunning");
|
|
3057
3144
|
case "input": return t("opNeedsChoice");
|
|
3058
|
-
case "failed": return record.reason
|
|
3059
|
-
case "warned": return record.reason
|
|
3145
|
+
case "failed": return record.reason !== void 0 ? localizeBilingual(record.reason, lang) : t("installFail");
|
|
3146
|
+
case "warned": return record.reason !== void 0 ? localizeBilingual(record.reason, lang) : t("opDone");
|
|
3060
3147
|
case "done": return record.needsRefresh === true ? t("opDoneRefresh") : t("opDone");
|
|
3061
3148
|
}
|
|
3062
3149
|
}
|
|
@@ -3193,7 +3280,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
3193
3280
|
}),
|
|
3194
3281
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3195
3282
|
className: bucketOf(record.state) === "attention" ? `${Market_module_css_default.opStatus} ${Market_module_css_default.opStatusBad}` : Market_module_css_default.opStatus,
|
|
3196
|
-
children: statusLine(t, record, ahead)
|
|
3283
|
+
children: statusLine(t, props.lang, record, ahead)
|
|
3197
3284
|
}),
|
|
3198
3285
|
needsUser(record) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConflictChoice, {
|
|
3199
3286
|
t,
|
|
@@ -5355,9 +5442,17 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5355
5442
|
* Card avatar: the plugin owner's GitHub avatar (no API, browser-cached),
|
|
5356
5443
|
* falling back to the initial-letter tile when it can't load.
|
|
5357
5444
|
*/
|
|
5358
|
-
/** Inline pass: `code
|
|
5445
|
+
/** Inline pass: links, `code`, **bold**; everything else plain text. */
|
|
5359
5446
|
function mdInline(text) {
|
|
5360
|
-
return text.split(/(
|
|
5447
|
+
return text.split(/(\[[^\]]+\]\(\s*https:\/\/[^)\s]+\s*\)|\*\*[^*]+\*\*|`[^`]+`)/g).map((part, i) => {
|
|
5448
|
+
const link = /^\[([^\]]+)\]\(\s*(https:\/\/[^)\s]+)\s*\)$/u.exec(part);
|
|
5449
|
+
if (link !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
5450
|
+
className: Market_module_css_default.notesA,
|
|
5451
|
+
href: link[2],
|
|
5452
|
+
target: "_blank",
|
|
5453
|
+
rel: "noreferrer",
|
|
5454
|
+
children: link[1]
|
|
5455
|
+
}, i);
|
|
5361
5456
|
if (part.startsWith("**") && part.endsWith("**") && part.length > 4) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: part.slice(2, -2) }, i);
|
|
5362
5457
|
if (part.startsWith("`") && part.endsWith("`") && part.length > 2) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
5363
5458
|
className: Market_module_css_default.notesCode,
|
|
@@ -5368,28 +5463,60 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5368
5463
|
}
|
|
5369
5464
|
/**
|
|
5370
5465
|
* Release-body markdown, reduced to what a reading dialog needs: headings,
|
|
5371
|
-
* bullets, paragraphs, bold, inline code
|
|
5372
|
-
*
|
|
5373
|
-
*
|
|
5466
|
+
* bullets, quotes, fenced code, paragraphs, bold, inline code, https links,
|
|
5467
|
+
* and allowlisted https images. HTML from the repo is stripped first (never
|
|
5468
|
+
* interpreted as markup); remaining text arrives as React children or
|
|
5469
|
+
* controlled nodes only.
|
|
5374
5470
|
*/
|
|
5375
5471
|
function renderMarkdown(md) {
|
|
5376
5472
|
const out = [];
|
|
5377
5473
|
let bullets = null;
|
|
5474
|
+
let fence = null;
|
|
5378
5475
|
const flushList = () => {
|
|
5379
5476
|
if (bullets === null) return;
|
|
5380
5477
|
const items = bullets;
|
|
5381
5478
|
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
5382
|
-
className: Market_module_css_default.
|
|
5479
|
+
className: Market_module_css_default.notesBullets,
|
|
5383
5480
|
children: items.map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: mdInline(item) }, i))
|
|
5384
5481
|
}, `l${out.length}`));
|
|
5385
5482
|
bullets = null;
|
|
5386
5483
|
};
|
|
5387
|
-
|
|
5484
|
+
const flushFence = () => {
|
|
5485
|
+
if (fence === null) return;
|
|
5486
|
+
const body = fence.join("\n");
|
|
5487
|
+
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
5488
|
+
className: Market_module_css_default.notesFence,
|
|
5489
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: body })
|
|
5490
|
+
}, `c${out.length}`));
|
|
5491
|
+
fence = null;
|
|
5492
|
+
};
|
|
5493
|
+
for (const line of sanitizeReleaseNotesBody(md).split("\n")) {
|
|
5388
5494
|
const trimmed = line.trim();
|
|
5495
|
+
if (fence !== null) {
|
|
5496
|
+
if (/^```/.test(trimmed)) flushFence();
|
|
5497
|
+
else fence.push(line.replace(/\s+$/u, ""));
|
|
5498
|
+
continue;
|
|
5499
|
+
}
|
|
5500
|
+
if (/^```/.test(trimmed)) {
|
|
5501
|
+
flushList();
|
|
5502
|
+
fence = [];
|
|
5503
|
+
continue;
|
|
5504
|
+
}
|
|
5389
5505
|
if (trimmed === "") {
|
|
5390
5506
|
flushList();
|
|
5391
5507
|
continue;
|
|
5392
5508
|
}
|
|
5509
|
+
const image = releaseNotesHttpsImage(trimmed);
|
|
5510
|
+
if (image !== null) {
|
|
5511
|
+
flushList();
|
|
5512
|
+
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
5513
|
+
className: Market_module_css_default.notesImg,
|
|
5514
|
+
src: image.src,
|
|
5515
|
+
alt: image.alt,
|
|
5516
|
+
loading: "lazy"
|
|
5517
|
+
}, `i${out.length}`));
|
|
5518
|
+
continue;
|
|
5519
|
+
}
|
|
5393
5520
|
const heading = /^#{1,6}\s+(.*)$/.exec(trimmed);
|
|
5394
5521
|
if (heading !== null) {
|
|
5395
5522
|
flushList();
|
|
@@ -5399,6 +5526,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5399
5526
|
}, `h${out.length}`));
|
|
5400
5527
|
continue;
|
|
5401
5528
|
}
|
|
5529
|
+
const quote = /^>\s?(.*)$/u.exec(trimmed);
|
|
5530
|
+
if (quote !== null) {
|
|
5531
|
+
flushList();
|
|
5532
|
+
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5533
|
+
className: Market_module_css_default.notesQuote,
|
|
5534
|
+
children: mdInline(quote[1])
|
|
5535
|
+
}, `q${out.length}`));
|
|
5536
|
+
continue;
|
|
5537
|
+
}
|
|
5402
5538
|
const bullet = /^[-*]\s+(.*)$/.exec(trimmed);
|
|
5403
5539
|
if (bullet !== null) {
|
|
5404
5540
|
(bullets ??= []).push(bullet[1]);
|
|
@@ -5411,6 +5547,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5411
5547
|
}, `p${out.length}`));
|
|
5412
5548
|
}
|
|
5413
5549
|
flushList();
|
|
5550
|
+
flushFence();
|
|
5414
5551
|
return out;
|
|
5415
5552
|
}
|
|
5416
5553
|
/** Avatar fallback advances one service route at a time before using initials. */
|
|
@@ -6065,6 +6202,22 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
6065
6202
|
});
|
|
6066
6203
|
}
|
|
6067
6204
|
/**
|
|
6205
|
+
* Catalog npm latest in the card byline (#348). Same quiet style as ↓ / ★;
|
|
6206
|
+
* omitted when absent so github-only and not-yet-backfilled rows stay clean.
|
|
6207
|
+
*/
|
|
6208
|
+
function CatalogVersionMark({ version, tip }) {
|
|
6209
|
+
if (typeof version !== "string" || version.length === 0) return null;
|
|
6210
|
+
const label = /^v/i.test(version) ? version : `v${version}`;
|
|
6211
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
6212
|
+
label: tip,
|
|
6213
|
+
side: "top",
|
|
6214
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6215
|
+
className: Market_module_css_default.star,
|
|
6216
|
+
children: `· ${label}`
|
|
6217
|
+
})
|
|
6218
|
+
});
|
|
6219
|
+
}
|
|
6220
|
+
/**
|
|
6068
6221
|
* Module-scope caches so re-entering the section renders instantly instead
|
|
6069
6222
|
* of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
|
|
6070
6223
|
* state survives section switches; a background refetch keeps it current.
|
|
@@ -7237,14 +7390,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
7237
7390
|
return;
|
|
7238
7391
|
}
|
|
7239
7392
|
setRestarting(false);
|
|
7240
|
-
setInstallError(t("restartFail") + ": " + String(body.error || "HTTP " + String(status)));
|
|
7393
|
+
setInstallError(t("restartFail") + ": " + localizeBilingual(String(body.error || "HTTP " + String(status)), lang));
|
|
7241
7394
|
}).catch(awaitNewBoot);
|
|
7242
7395
|
};
|
|
7243
7396
|
requestRestart(10);
|
|
7244
7397
|
}, [
|
|
7245
7398
|
bootId,
|
|
7246
7399
|
restarting,
|
|
7247
|
-
t
|
|
7400
|
+
t,
|
|
7401
|
+
lang
|
|
7248
7402
|
]);
|
|
7249
7403
|
/** Cancel the running plugin command (#6 by @qichuang321). */
|
|
7250
7404
|
const doCancel = (0, react.useCallback)(() => {
|
|
@@ -7345,19 +7499,23 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
7345
7499
|
const orphans = Array.isArray(body.orphanBundles) ? body.orphanBundles.map(String) : [];
|
|
7346
7500
|
const failure = text(body.error) || humanOutput([text(body.stderr), text(body.stdout)].filter(Boolean).join("\n")) || "exit " + body.exitCode;
|
|
7347
7501
|
const staleEntry = typeof body.staleEntry === "string" ? body.staleEntry : null;
|
|
7348
|
-
const
|
|
7502
|
+
const clipped = [
|
|
7349
7503
|
orphans.length > 0 ? `${t("orphanBundle")} ${orphans.join(", ")}` : null,
|
|
7350
7504
|
staleEntry,
|
|
7351
7505
|
failure
|
|
7352
|
-
].filter(Boolean).join("\n");
|
|
7506
|
+
].filter(Boolean).join("\n").trim().slice(-600);
|
|
7353
7507
|
setRecords((list) => patch(list, updateRecordId, {
|
|
7354
7508
|
state: "failed",
|
|
7355
|
-
reason:
|
|
7509
|
+
reason: clipped
|
|
7356
7510
|
}));
|
|
7357
|
-
setInstallError((restore ? t("restoreFail") : t("updateFail")) + ": " + name + " — " +
|
|
7511
|
+
setInstallError((restore ? t("restoreFail") : t("updateFail")) + ": " + name + " — " + localizeBilingual(clipped, lang));
|
|
7358
7512
|
}
|
|
7359
7513
|
}).catch(() => {});
|
|
7360
|
-
}, [
|
|
7514
|
+
}, [
|
|
7515
|
+
refreshInstalled,
|
|
7516
|
+
t,
|
|
7517
|
+
lang
|
|
7518
|
+
]);
|
|
7361
7519
|
const doSourceMigration = (0, react.useCallback)((name) => {
|
|
7362
7520
|
setInstallError(null);
|
|
7363
7521
|
setActivationWarnings([]);
|
|
@@ -7389,12 +7547,16 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
7389
7547
|
setInstallError(t("agentBusyUpdate") + running);
|
|
7390
7548
|
return;
|
|
7391
7549
|
}
|
|
7392
|
-
setInstallError(t("migrateFail") + ": " + String(body.error || "HTTP " + String(status)));
|
|
7550
|
+
setInstallError(t("migrateFail") + ": " + localizeBilingual(String(body.error || "HTTP " + String(status)), lang));
|
|
7393
7551
|
}).catch((error) => {
|
|
7394
7552
|
setUpdatingName(null);
|
|
7395
7553
|
setInstallError(t("migrateFail") + ": " + String(error));
|
|
7396
7554
|
});
|
|
7397
|
-
}, [
|
|
7555
|
+
}, [
|
|
7556
|
+
refreshInstalled,
|
|
7557
|
+
t,
|
|
7558
|
+
lang
|
|
7559
|
+
]);
|
|
7398
7560
|
const askSourceMigration = (0, react.useCallback)((name) => {
|
|
7399
7561
|
const migration = updates[name]?.sourceMigration;
|
|
7400
7562
|
const source = installed[name];
|
|
@@ -8186,6 +8348,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
8186
8348
|
title: p.owner,
|
|
8187
8349
|
children: p.owner
|
|
8188
8350
|
}),
|
|
8351
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CatalogVersionMark, {
|
|
8352
|
+
version: p.version,
|
|
8353
|
+
tip: t("catalogNpmLatest")
|
|
8354
|
+
}),
|
|
8189
8355
|
typeof p.downloads === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
8190
8356
|
label: String(p.downloads),
|
|
8191
8357
|
side: "top",
|
|
@@ -8358,6 +8524,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
8358
8524
|
title: p.owner,
|
|
8359
8525
|
children: p.owner
|
|
8360
8526
|
}),
|
|
8527
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CatalogVersionMark, {
|
|
8528
|
+
version: p.version,
|
|
8529
|
+
tip: t("catalogNpmLatest")
|
|
8530
|
+
}),
|
|
8361
8531
|
typeof p.downloads === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
8362
8532
|
label: String(p.downloads),
|
|
8363
8533
|
side: "top",
|
|
@@ -8748,6 +8918,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
8748
8918
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.grow }),
|
|
8749
8919
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OperationsPanel, {
|
|
8750
8920
|
t,
|
|
8921
|
+
lang,
|
|
8751
8922
|
describe: describePlugin,
|
|
8752
8923
|
records,
|
|
8753
8924
|
open: operationsOpen,
|
|
@@ -8931,7 +9102,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
8931
9102
|
className: Market_module_css_default.spec,
|
|
8932
9103
|
children: [
|
|
8933
9104
|
"(",
|
|
8934
|
-
info.reasons
|
|
9105
|
+
localizeBilingualList(info.reasons, lang),
|
|
8935
9106
|
")"
|
|
8936
9107
|
]
|
|
8937
9108
|
})
|
|
@@ -9005,7 +9176,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
9005
9176
|
onClick: () => setTab("diagnostics"),
|
|
9006
9177
|
children: t("goDiagnose")
|
|
9007
9178
|
}),
|
|
9008
|
-
compatibilityNotice.rollbackId === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: compatibilityNotice.rollbackUnavailable
|
|
9179
|
+
compatibilityNotice.rollbackId === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: compatibilityNotice.rollbackUnavailable ? localizeBilingual(compatibilityNotice.rollbackUnavailable, lang) : t("rollbackUnavailable") }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
9009
9180
|
variant: "primary",
|
|
9010
9181
|
size: "sm",
|
|
9011
9182
|
disabled: rollingBack,
|
|
@@ -9016,7 +9187,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
9016
9187
|
}),
|
|
9017
9188
|
installError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9018
9189
|
className: Market_module_css_default.err,
|
|
9019
|
-
children: [installError, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9190
|
+
children: [localizeBilingual(installError, lang), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9020
9191
|
className: Market_module_css_default.staleAction,
|
|
9021
9192
|
children: [staleName !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
9022
9193
|
variant: "primary",
|
|
@@ -10051,7 +10222,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10051
10222
|
className: Market_module_css_default.actWhy,
|
|
10052
10223
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10053
10224
|
className: Market_module_css_default.spec,
|
|
10054
|
-
children: act.reasons
|
|
10225
|
+
children: localizeBilingualList(act.reasons, lang)
|
|
10055
10226
|
})
|
|
10056
10227
|
})]
|
|
10057
10228
|
}),
|
|
@@ -10263,6 +10434,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10263
10434
|
title: confirming.owner,
|
|
10264
10435
|
children: confirming.owner
|
|
10265
10436
|
}),
|
|
10437
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CatalogVersionMark, {
|
|
10438
|
+
version: confirming.version,
|
|
10439
|
+
tip: t("catalogNpmLatest")
|
|
10440
|
+
}),
|
|
10266
10441
|
typeof confirming.downloads === "number" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
10267
10442
|
label: String(confirming.downloads),
|
|
10268
10443
|
side: "top",
|
|
@@ -10477,6 +10652,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10477
10652
|
notesFor !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
10478
10653
|
open: true,
|
|
10479
10654
|
onClose: () => setNotesFor(null),
|
|
10655
|
+
className: notesState === "ready" && updateNotes?.kind === "release" ? Market_module_css_default.notesModalWide : void 0,
|
|
10480
10656
|
title: notesFor.repoUrl !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
10481
10657
|
className: Market_module_css_default.nameLink,
|
|
10482
10658
|
href: notesFor.repoUrl + "#readme",
|
|
@@ -10487,7 +10663,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10487
10663
|
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
10488
10664
|
variant: "ghost",
|
|
10489
10665
|
onClick: () => setNotesFor(null),
|
|
10490
|
-
children: t("
|
|
10666
|
+
children: t("gotIt")
|
|
10491
10667
|
}),
|
|
10492
10668
|
children: [
|
|
10493
10669
|
(notesFor.current !== null || notesFor.latest !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -10700,7 +10876,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10700
10876
|
onDone: exportToastDone
|
|
10701
10877
|
}),
|
|
10702
10878
|
favoriteError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
10703
|
-
text: favoriteError,
|
|
10879
|
+
text: localizeBilingual(favoriteError, lang),
|
|
10704
10880
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, { size: 14 }),
|
|
10705
10881
|
onDone: favoriteErrorDone
|
|
10706
10882
|
}),
|
package/lib/types/registry.d.ts
CHANGED
|
@@ -20,6 +20,12 @@ export interface RegistryPlugin {
|
|
|
20
20
|
* zero — so sorting must not read it as "less popular than 0".
|
|
21
21
|
*/
|
|
22
22
|
downloads?: number | null;
|
|
23
|
+
/**
|
|
24
|
+
* Registry `dist-tags.latest` from awesome-dsh-plugin (#348). A string when
|
|
25
|
+
* known; `null`/absent when github-only or not yet backfilled — the UI
|
|
26
|
+
* omits the byline segment rather than showing a placeholder.
|
|
27
|
+
*/
|
|
28
|
+
version?: string | null;
|
|
23
29
|
install: string;
|
|
24
30
|
added: string;
|
|
25
31
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dshmarket",
|
|
3
3
|
"description": "Visual plugin market inside DeepSeek Harness — browse, search, and one-click install community plugins. · DSH 可视化插件市场:逛一逛,点一下,装好。",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.51.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -796,19 +796,32 @@
|
|
|
796
796
|
an action competing with 更新/卸载 on the trailing edge. */
|
|
797
797
|
.notesLink{display:block;background:0 0;border:none;padding:0;margin:2px 0 0;font:inherit;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;text-align:left}
|
|
798
798
|
.notesLink:hover{color:var(--dsw-alias-label-primary,#1f2328)}
|
|
799
|
-
|
|
799
|
+
/* Wider only for prose release notes — npm/commit lists stay at the default
|
|
800
|
+
Modal width so a short changelog does not sit in a half-empty box. */
|
|
801
|
+
.notesModalWide{width:min(640px,92vw);max-width:min(640px,92vw)}
|
|
802
|
+
/* Cap height so a long release body scrolls inside the dialog instead of
|
|
803
|
+
stretching the Modal past the viewport (same idea as .notesPre / .commentsMount).
|
|
804
|
+
flex:0 keeps short lists from growing into empty space above the footer. */
|
|
805
|
+
.notesBody{display:flex;flex-direction:column;gap:10px;min-width:0;flex:0 1 auto;max-height:min(60vh,520px);overflow-y:auto;overscroll-behavior:contain;padding:0 2px 8px 0}
|
|
800
806
|
/* 弹窗内的层级:范围行弱化、区块标题小而重、正文有承载面 */
|
|
801
807
|
.notesRange{display:flex;align-items:center;gap:8px;font-size:12px;line-height:18px;margin-bottom:4px}
|
|
802
808
|
.notesArrow{color:var(--dsw-alias-label-tertiary,#8b93a1)}
|
|
803
|
-
.notesMeta{font-size:12px;line-height:18px;letter-spacing:.02em;text-transform:uppercase;color:var(--dsw-alias-label-secondary,#6b7280);display:flex;gap:6px;flex-wrap:wrap;align-items:baseline;margin-top:
|
|
809
|
+
.notesMeta{font-size:12px;line-height:18px;letter-spacing:.02em;text-transform:uppercase;color:var(--dsw-alias-label-secondary,#6b7280);display:flex;gap:6px;flex-wrap:wrap;align-items:baseline;margin-top:4px}
|
|
810
|
+
.notesBody>.notesMeta:first-child{margin-top:0}
|
|
804
811
|
.notesPre{margin:0;white-space:pre-wrap;word-break:break-word;font-size:13px;line-height:20px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,#eef0f4);border-radius:8px;max-height:40vh;overflow:auto}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
.
|
|
808
|
-
.notesH{font-size:13px;font-weight:650;line-height:20px;margin-top:
|
|
812
|
+
/* markdown轻渲染的层级:标题、段落、引用、围栏代码、行内代码与链接 */
|
|
813
|
+
.notesRendered{display:flex;flex-direction:column;gap:8px;min-width:0}
|
|
814
|
+
.notesImg{display:block;max-width:100%;height:auto;border-radius:6px;margin:4px 0}
|
|
815
|
+
.notesH{font-size:13px;font-weight:650;line-height:20px;margin-top:4px}
|
|
809
816
|
.notesP{font-size:13px;line-height:20px}
|
|
817
|
+
.notesQuote{font-size:13px;line-height:20px;margin:0;padding:8px 10px;border-left:3px solid var(--dsw-alias-border-l3,#d9dde3);background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-radius:0 6px 6px 0;color:var(--dsw-alias-label-primary,#1f2328)}
|
|
818
|
+
.notesFence{margin:0;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,#eef0f4);border-radius:8px;overflow-x:auto;font-family:var(--dsw-alias-font-mono,ui-monospace,Menlo,monospace);font-size:12px;line-height:18px;white-space:pre}
|
|
819
|
+
.notesFence code{font:inherit;background:transparent;padding:0}
|
|
820
|
+
.notesBullets{margin:0;padding-left:18px;display:flex;flex-direction:column;gap:4px;font-size:13px;line-height:20px}
|
|
821
|
+
.notesA{color:var(--dsw-alias-brand-primary,#4f6ef7);text-decoration:none}
|
|
822
|
+
.notesA:hover{text-decoration:underline}
|
|
810
823
|
.notesCode{font-family:var(--dsw-alias-font-mono,ui-monospace,monospace);font-size:12px;padding:1px 5px;border-radius:5px;background:var(--dsw-alias-bg-layer-2,#eef0f4)}
|
|
811
|
-
/* 列表行:日期一列弱化对齐,内容一列自适应换行 */
|
|
824
|
+
/* commit / npm 列表行:日期一列弱化对齐,内容一列自适应换行 */
|
|
812
825
|
.notesList{margin:0;padding:0;list-style:none;display:flex;flex-direction:column}
|
|
813
826
|
.notesRow{display:flex;gap:12px;align-items:baseline;padding:6px 0;border-bottom:1px solid var(--dsw-alias-border-l2,#e5e7eb)}
|
|
814
827
|
.notesRow:last-child{border-bottom:none}
|
|
@@ -42,8 +42,8 @@ import type { OperationRecord } from './operations.ts'
|
|
|
42
42
|
import { Diagnostics } from './Diagnostics.tsx'
|
|
43
43
|
import { exportMarketLog } from './self-check.ts'
|
|
44
44
|
import {
|
|
45
|
-
api, applyGithubRouting, avatarColor, catalogEntryForInstalled, entryForDep, githubRouteCandidates, groupSwitchState, humanOutput, installedForCatalog, isGenerationSpec, isInstalled, looksTerminal, matchInstalledName, orderedCategories, pluginCategories,
|
|
46
|
-
formatCount, pageItems, pluginName, pluginScreenshotCandidates, pluginScreenshots, pluginsForFavorites, rankThemeScreenshots, readSession, rememberGithubRoute, resetScreenshotsCache, resolveCatalogRestore, safeScreenshots, staleFavoriteUrls, themePlugins as themePluginsOf, themeSwatch, TIME_RANGE_DAYS, visiblePlugins,
|
|
45
|
+
api, applyGithubRouting, avatarColor, catalogEntryForInstalled, entryForDep, githubRouteCandidates, groupSwitchState, humanOutput, installedForCatalog, isGenerationSpec, isInstalled, localizeBilingual, localizeBilingualList, looksTerminal, matchInstalledName, orderedCategories, pluginCategories,
|
|
46
|
+
formatCount, pageItems, pluginName, pluginScreenshotCandidates, pluginScreenshots, pluginsForFavorites, rankThemeScreenshots, readSession, releaseNotesHttpsImage, rememberGithubRoute, resetScreenshotsCache, resolveCatalogRestore, safeScreenshots, sanitizeReleaseNotesBody, staleFavoriteUrls, themePlugins as themePluginsOf, themeSwatch, TIME_RANGE_DAYS, visiblePlugins,
|
|
47
47
|
} from './market-data.ts'
|
|
48
48
|
import type {
|
|
49
49
|
ActivationInfo, ActivationState, GistExportResult, InstalledMap, InstalledRepoHints, InstalledRepoIdentities, MarketStatus, Registry, RegistryPlugin,
|
|
@@ -354,9 +354,17 @@ function Pager({ currentPage, totalPages, pageSize, onGoToPage, onChangePageSize
|
|
|
354
354
|
* Card avatar: the plugin owner's GitHub avatar (no API, browser-cached),
|
|
355
355
|
* falling back to the initial-letter tile when it can't load.
|
|
356
356
|
*/
|
|
357
|
-
/** Inline pass: `code
|
|
357
|
+
/** Inline pass: links, `code`, **bold**; everything else plain text. */
|
|
358
358
|
function mdInline(text: string): Array<string | JSX.Element> {
|
|
359
|
-
return text.split(/(
|
|
359
|
+
return text.split(/(\[[^\]]+\]\(\s*https:\/\/[^)\s]+\s*\)|\*\*[^*]+\*\*|`[^`]+`)/g).map((part, i) => {
|
|
360
|
+
const link = /^\[([^\]]+)\]\(\s*(https:\/\/[^)\s]+)\s*\)$/u.exec(part)
|
|
361
|
+
if (link !== null) {
|
|
362
|
+
return (
|
|
363
|
+
<a key={i} className={css.notesA} href={link[2]} target="_blank" rel="noreferrer">
|
|
364
|
+
{link[1]}
|
|
365
|
+
</a>
|
|
366
|
+
)
|
|
367
|
+
}
|
|
360
368
|
if (part.startsWith('**') && part.endsWith('**') && part.length > 4) {
|
|
361
369
|
return <strong key={i}>{part.slice(2, -2)}</strong>
|
|
362
370
|
}
|
|
@@ -369,37 +377,79 @@ function mdInline(text: string): Array<string | JSX.Element> {
|
|
|
369
377
|
|
|
370
378
|
/**
|
|
371
379
|
* Release-body markdown, reduced to what a reading dialog needs: headings,
|
|
372
|
-
* bullets, paragraphs, bold, inline code
|
|
373
|
-
*
|
|
374
|
-
*
|
|
380
|
+
* bullets, quotes, fenced code, paragraphs, bold, inline code, https links,
|
|
381
|
+
* and allowlisted https images. HTML from the repo is stripped first (never
|
|
382
|
+
* interpreted as markup); remaining text arrives as React children or
|
|
383
|
+
* controlled nodes only.
|
|
375
384
|
*/
|
|
376
385
|
function renderMarkdown(md: string): Array<JSX.Element | string> {
|
|
377
386
|
const out: Array<JSX.Element | string> = []
|
|
378
387
|
let bullets: string[] | null = null
|
|
388
|
+
let fence: string[] | null = null
|
|
379
389
|
const flushList = (): void => {
|
|
380
390
|
if (bullets === null) return
|
|
381
391
|
const items = bullets
|
|
382
|
-
out.push(<ul key={`l${out.length}`} className={css.
|
|
392
|
+
out.push(<ul key={`l${out.length}`} className={css.notesBullets}>{items.map((item, i) => <li key={i}>{mdInline(item)}</li>)}</ul>)
|
|
383
393
|
bullets = null
|
|
384
394
|
}
|
|
385
|
-
|
|
395
|
+
const flushFence = (): void => {
|
|
396
|
+
if (fence === null) return
|
|
397
|
+
const body = fence.join('\n')
|
|
398
|
+
out.push(<pre key={`c${out.length}`} className={css.notesFence}><code>{body}</code></pre>)
|
|
399
|
+
fence = null
|
|
400
|
+
}
|
|
401
|
+
for (const line of sanitizeReleaseNotesBody(md).split('\n')) {
|
|
386
402
|
const trimmed = line.trim()
|
|
403
|
+
if (fence !== null) {
|
|
404
|
+
if (/^```/.test(trimmed)) {
|
|
405
|
+
flushFence()
|
|
406
|
+
} else {
|
|
407
|
+
fence.push(line.replace(/\s+$/u, ''))
|
|
408
|
+
}
|
|
409
|
+
continue
|
|
410
|
+
}
|
|
411
|
+
if (/^```/.test(trimmed)) {
|
|
412
|
+
flushList()
|
|
413
|
+
fence = []
|
|
414
|
+
continue
|
|
415
|
+
}
|
|
387
416
|
if (trimmed === '') { flushList(); continue }
|
|
417
|
+
const image = releaseNotesHttpsImage(trimmed)
|
|
418
|
+
if (image !== null) {
|
|
419
|
+
flushList()
|
|
420
|
+
out.push(
|
|
421
|
+
<img
|
|
422
|
+
key={`i${out.length}`}
|
|
423
|
+
className={css.notesImg}
|
|
424
|
+
src={image.src}
|
|
425
|
+
alt={image.alt}
|
|
426
|
+
loading="lazy"
|
|
427
|
+
/>,
|
|
428
|
+
)
|
|
429
|
+
continue
|
|
430
|
+
}
|
|
388
431
|
const heading = /^#{1,6}\s+(.*)$/.exec(trimmed)
|
|
389
432
|
if (heading !== null) {
|
|
390
433
|
flushList()
|
|
391
|
-
out.push(<div key={`h${out.length}`} className={css.notesH}>{mdInline(heading[1])}</div>)
|
|
434
|
+
out.push(<div key={`h${out.length}`} className={css.notesH}>{mdInline(heading[1]!)}</div>)
|
|
435
|
+
continue
|
|
436
|
+
}
|
|
437
|
+
const quote = /^>\s?(.*)$/u.exec(trimmed)
|
|
438
|
+
if (quote !== null) {
|
|
439
|
+
flushList()
|
|
440
|
+
out.push(<div key={`q${out.length}`} className={css.notesQuote}>{mdInline(quote[1]!)}</div>)
|
|
392
441
|
continue
|
|
393
442
|
}
|
|
394
443
|
const bullet = /^[-*]\s+(.*)$/.exec(trimmed)
|
|
395
444
|
if (bullet !== null) {
|
|
396
|
-
;(bullets ??= []).push(bullet[1])
|
|
445
|
+
;(bullets ??= []).push(bullet[1]!)
|
|
397
446
|
continue
|
|
398
447
|
}
|
|
399
448
|
flushList()
|
|
400
449
|
out.push(<div key={`p${out.length}`} className={css.notesP}>{mdInline(line)}</div>)
|
|
401
450
|
}
|
|
402
451
|
flushList()
|
|
452
|
+
flushFence()
|
|
403
453
|
return out
|
|
404
454
|
}
|
|
405
455
|
|
|
@@ -1063,6 +1113,20 @@ function BookmarkMark({ size = 14, filled = false, className }: { size?: number;
|
|
|
1063
1113
|
)
|
|
1064
1114
|
}
|
|
1065
1115
|
|
|
1116
|
+
/**
|
|
1117
|
+
* Catalog npm latest in the card byline (#348). Same quiet style as ↓ / ★;
|
|
1118
|
+
* omitted when absent so github-only and not-yet-backfilled rows stay clean.
|
|
1119
|
+
*/
|
|
1120
|
+
function CatalogVersionMark({ version, tip }: { version: string | null | undefined; tip: string }) {
|
|
1121
|
+
if (typeof version !== 'string' || version.length === 0) return null
|
|
1122
|
+
const label = /^v/i.test(version) ? version : `v${version}`
|
|
1123
|
+
return (
|
|
1124
|
+
<Tooltip label={tip} side="top">
|
|
1125
|
+
<span className={css.star}>{`· ${label}`}</span>
|
|
1126
|
+
</Tooltip>
|
|
1127
|
+
)
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1066
1130
|
/**
|
|
1067
1131
|
* Module-scope caches so re-entering the section renders instantly instead
|
|
1068
1132
|
* of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
|
|
@@ -2217,7 +2281,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
2217
2281
|
].filter(Boolean).join('\n')
|
|
2218
2282
|
// Carry the blocked names onto the record too: the panel is where
|
|
2219
2283
|
// this failure is read, so it is where the one-click way out has to
|
|
2220
|
-
// be (#314).
|
|
2284
|
+
// be (#314). The reason stays bilingual; the panel localizes it.
|
|
2221
2285
|
setRecords(list => patchRecord(list, recordId, {
|
|
2222
2286
|
state: 'failed', reason: detail.trim().slice(-600),
|
|
2223
2287
|
...(blocked.length > 0 ? { blockedBuilds: blocked } : {}),
|
|
@@ -2350,12 +2414,12 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
2350
2414
|
return
|
|
2351
2415
|
}
|
|
2352
2416
|
setRestarting(false)
|
|
2353
|
-
setInstallError(t('restartFail') + ': ' + String(body.error || ('HTTP ' + String(status))))
|
|
2417
|
+
setInstallError(t('restartFail') + ': ' + localizeBilingual(String(body.error || ('HTTP ' + String(status))), lang))
|
|
2354
2418
|
})
|
|
2355
2419
|
.catch(awaitNewBoot) // the host may die mid-response; keep polling
|
|
2356
2420
|
}
|
|
2357
2421
|
requestRestart(10)
|
|
2358
|
-
}, [bootId, restarting, t])
|
|
2422
|
+
}, [bootId, restarting, t, lang])
|
|
2359
2423
|
|
|
2360
2424
|
/** Cancel the running plugin command (#6 by @qichuang321). */
|
|
2361
2425
|
const doCancel = useCallback(() => {
|
|
@@ -2483,8 +2547,10 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
2483
2547
|
staleEntry,
|
|
2484
2548
|
failure,
|
|
2485
2549
|
].filter(Boolean).join('\n')
|
|
2486
|
-
|
|
2487
|
-
|
|
2550
|
+
const clipped = detail.trim().slice(-600)
|
|
2551
|
+
setRecords(list => patchRecord(list, updateRecordId, { state: 'failed', reason: clipped }))
|
|
2552
|
+
// Localize the server half before prepending t() chrome.
|
|
2553
|
+
setInstallError((restore ? t('restoreFail') : t('updateFail')) + ': ' + name + ' — ' + localizeBilingual(clipped, lang))
|
|
2488
2554
|
}
|
|
2489
2555
|
})
|
|
2490
2556
|
.catch(() => {
|
|
@@ -2493,7 +2559,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
2493
2559
|
// running row, and let the status poll converge the outcome instead
|
|
2494
2560
|
// of declaring a false failure — mirroring the install flow's catch.
|
|
2495
2561
|
})
|
|
2496
|
-
}, [refreshInstalled, t])
|
|
2562
|
+
}, [refreshInstalled, t, lang])
|
|
2497
2563
|
|
|
2498
2564
|
|
|
2499
2565
|
const doSourceMigration = useCallback((name: string) => {
|
|
@@ -2525,13 +2591,13 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
2525
2591
|
setInstallError(t('agentBusyUpdate') + running)
|
|
2526
2592
|
return
|
|
2527
2593
|
}
|
|
2528
|
-
setInstallError(t('migrateFail') + ': ' + String(body.error || ('HTTP ' + String(status))))
|
|
2594
|
+
setInstallError(t('migrateFail') + ': ' + localizeBilingual(String(body.error || ('HTTP ' + String(status))), lang))
|
|
2529
2595
|
})
|
|
2530
2596
|
.catch(error => {
|
|
2531
2597
|
setUpdatingName(null)
|
|
2532
2598
|
setInstallError(t('migrateFail') + ': ' + String(error))
|
|
2533
2599
|
})
|
|
2534
|
-
}, [refreshInstalled, t])
|
|
2600
|
+
}, [refreshInstalled, t, lang])
|
|
2535
2601
|
|
|
2536
2602
|
const askSourceMigration = useCallback((name: string) => {
|
|
2537
2603
|
const migration = updates[name]?.sourceMigration
|
|
@@ -3355,6 +3421,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
3355
3421
|
<div className={css.byline}>
|
|
3356
3422
|
<OwnerAvatar name={p.name} owner={p.owner || ''} />
|
|
3357
3423
|
<span className={css.owner} title={p.owner}>{p.owner}</span>
|
|
3424
|
+
<CatalogVersionMark version={p.version} tip={t('catalogNpmLatest')} />
|
|
3358
3425
|
{typeof p.downloads === 'number' && (
|
|
3359
3426
|
<Tooltip label={String(p.downloads)} side="top">
|
|
3360
3427
|
<span className={css.star}>{'· ↓ ' + formatCount(p.downloads)}</span>
|
|
@@ -3488,6 +3555,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
3488
3555
|
<div className={css.byline}>
|
|
3489
3556
|
<OwnerAvatar name={p.name} owner={p.owner || ''} />
|
|
3490
3557
|
<span className={css.owner} title={p.owner}>{p.owner}</span>
|
|
3558
|
+
<CatalogVersionMark version={p.version} tip={t('catalogNpmLatest')} />
|
|
3491
3559
|
{typeof p.downloads === 'number' && (
|
|
3492
3560
|
<Tooltip label={String(p.downloads)} side="top">
|
|
3493
3561
|
<span className={css.star}>{'· ↓ ' + formatCount(p.downloads)}</span>
|
|
@@ -3816,6 +3884,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
3816
3884
|
switching tab all leave it — and any pending decision — in place. */}
|
|
3817
3885
|
<OperationsPanel
|
|
3818
3886
|
t={t}
|
|
3887
|
+
lang={lang}
|
|
3819
3888
|
describe={describePlugin}
|
|
3820
3889
|
records={records}
|
|
3821
3890
|
open={operationsOpen}
|
|
@@ -3941,7 +4010,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
3941
4010
|
{activationWarnings.map(({ name, info }) => (
|
|
3942
4011
|
<div key={name}>
|
|
3943
4012
|
<b>{name}</b> — {activationMeta(info.state, t).label}
|
|
3944
|
-
{info.reasons.length > 0 && <span className={css.spec}>({info.reasons
|
|
4013
|
+
{info.reasons.length > 0 && <span className={css.spec}>({localizeBilingualList(info.reasons, lang)})</span>}
|
|
3945
4014
|
</div>
|
|
3946
4015
|
))}
|
|
3947
4016
|
</span>
|
|
@@ -3994,7 +4063,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
3994
4063
|
</span>
|
|
3995
4064
|
<Button variant="outline" size="sm" onClick={() => setTab('diagnostics')}>{t('goDiagnose')}</Button>
|
|
3996
4065
|
{compatibilityNotice.rollbackId === undefined
|
|
3997
|
-
? <span>{compatibilityNotice.rollbackUnavailable
|
|
4066
|
+
? <span>{compatibilityNotice.rollbackUnavailable ? localizeBilingual(compatibilityNotice.rollbackUnavailable, lang) : t('rollbackUnavailable')}</span>
|
|
3998
4067
|
: (
|
|
3999
4068
|
<Button variant="primary" size="sm" disabled={rollingBack} onClick={() => void doRollback(compatibilityNotice.rollbackId!)}>
|
|
4000
4069
|
{rollingBack ? t('rollingBack') : t('rollbackNow')}
|
|
@@ -4004,7 +4073,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
4004
4073
|
)}
|
|
4005
4074
|
{installError !== null && (
|
|
4006
4075
|
<div className={css.err}>
|
|
4007
|
-
{installError}
|
|
4076
|
+
{localizeBilingual(installError, lang)}
|
|
4008
4077
|
<div className={css.staleAction}>
|
|
4009
4078
|
{/* Primary, because the banner's own words point at it ("点
|
|
4010
4079
|
「立即更新」不再等待") and it is the way out of the wait. With
|
|
@@ -4777,7 +4846,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
4777
4846
|
onToggle={() => setWhyOpen(whyOpen === name ? null : name)}
|
|
4778
4847
|
className={css.actWhy}
|
|
4779
4848
|
>
|
|
4780
|
-
<div className={css.spec}>{act.reasons
|
|
4849
|
+
<div className={css.spec}>{localizeBilingualList(act.reasons, lang)}</div>
|
|
4781
4850
|
</DisclosureRow>
|
|
4782
4851
|
)}
|
|
4783
4852
|
</div>
|
|
@@ -4952,12 +5021,13 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
4952
5021
|
)}
|
|
4953
5022
|
>
|
|
4954
5023
|
{/* The detail dialog has to show at LEAST what the card already
|
|
4955
|
-
does — owner, downloads, stars, published date, category —
|
|
4956
|
-
"detail" view that shows less than the summary it opened from
|
|
5024
|
+
does — owner, version, downloads, stars, published date, category —
|
|
5025
|
+
a "detail" view that shows less than the summary it opened from
|
|
4957
5026
|
is backwards. */}
|
|
4958
5027
|
<div className={css.byline}>
|
|
4959
5028
|
<OwnerAvatar name={confirming.name} owner={confirming.owner || ''} />
|
|
4960
5029
|
<span className={css.owner} title={confirming.owner}>{confirming.owner}</span>
|
|
5030
|
+
<CatalogVersionMark version={confirming.version} tip={t('catalogNpmLatest')} />
|
|
4961
5031
|
{typeof confirming.downloads === 'number' && (
|
|
4962
5032
|
<Tooltip label={String(confirming.downloads)} side="top">
|
|
4963
5033
|
<span className={css.star}>{'· ↓ ' + formatCount(confirming.downloads)}</span>
|
|
@@ -5159,6 +5229,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
5159
5229
|
<Modal
|
|
5160
5230
|
open
|
|
5161
5231
|
onClose={() => setNotesFor(null)}
|
|
5232
|
+
className={notesState === 'ready' && updateNotes?.kind === 'release' ? css.notesModalWide : undefined}
|
|
5162
5233
|
/* The host's Modal renders its title node verbatim; the hand-written
|
|
5163
5234
|
primitives.d.ts narrows the prop to string, so this cast documents
|
|
5164
5235
|
intent rather than defeating a runtime check. */
|
|
@@ -5166,7 +5237,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
5166
5237
|
? <a className={css.nameLink} href={notesFor.repoUrl + '#readme'} target="_blank" rel="noreferrer">{notesFor.name}</a>
|
|
5167
5238
|
: notesFor.name) as unknown as string}
|
|
5168
5239
|
footer={(
|
|
5169
|
-
<Button variant="ghost" onClick={() => setNotesFor(null)}>{t('
|
|
5240
|
+
<Button variant="ghost" onClick={() => setNotesFor(null)}>{t('gotIt')}</Button>
|
|
5170
5241
|
)}
|
|
5171
5242
|
>
|
|
5172
5243
|
{/* The version line reads as versions when both ends are semver and
|
|
@@ -5193,10 +5264,9 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
5193
5264
|
{updateNotes.release.tag !== null && <span>{' ' + updateNotes.release.tag}</span>}
|
|
5194
5265
|
{updateNotes.release.publishedAt !== null && <span>{' · ' + updateNotes.release.publishedAt.slice(0, 10)}</span>}
|
|
5195
5266
|
</div>
|
|
5196
|
-
{/* Author-written markdown
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
markup — headings, bullets, bold and inline code only. */}
|
|
5267
|
+
{/* Author-written markdown through the tiny converter: HTML is
|
|
5268
|
+
stripped first; headings, quotes, fences, bullets, bold,
|
|
5269
|
+
inline code, https links and allowlisted images only. */}
|
|
5200
5270
|
<div className={css.notesRendered}>{renderMarkdown(updateNotes.release.body || t('notesNone'))}</div>
|
|
5201
5271
|
</div>
|
|
5202
5272
|
)
|
|
@@ -5315,7 +5385,7 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
5315
5385
|
<Toast text={t('exportLogFail')} icon={<IconWarningOutline16 size={14} />} onDone={exportToastDone} />
|
|
5316
5386
|
)}
|
|
5317
5387
|
{favoriteError !== null && (
|
|
5318
|
-
<Toast text={favoriteError} icon={<IconWarningOutline16 size={14} />} onDone={favoriteErrorDone} />
|
|
5388
|
+
<Toast text={localizeBilingual(favoriteError, lang)} icon={<IconWarningOutline16 size={14} />} onDone={favoriteErrorDone} />
|
|
5319
5389
|
)}
|
|
5320
5390
|
{toggled !== null && (
|
|
5321
5391
|
<Toast
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { useEffect, useRef, useState } from 'react'
|
|
20
20
|
import type { ReactNode } from 'react'
|
|
21
21
|
import css from './Market.module.css'
|
|
22
|
-
import type
|
|
22
|
+
import { localizeBilingual, type Translate } from './market-data.ts'
|
|
23
23
|
import type { ConflictGroup, OperationRecord } from './operations.ts'
|
|
24
24
|
import { bucketOf, isSettled, needsUser, queuePosition, sortForPanel, summarize } from './operations.ts'
|
|
25
25
|
|
|
@@ -41,6 +41,8 @@ export type DescribePlugin = (name: string) => {
|
|
|
41
41
|
|
|
42
42
|
export interface OperationsPanelProps {
|
|
43
43
|
t: Translate
|
|
44
|
+
/** Active UI language — used to pick one half of bilingual wire errors. */
|
|
45
|
+
lang: 'zh' | 'en'
|
|
44
46
|
/** Resolves a package name to the identity a card would show for it. */
|
|
45
47
|
describe: DescribePlugin
|
|
46
48
|
records: readonly OperationRecord[]
|
|
@@ -195,7 +197,7 @@ function BucketIcon(props: { record: OperationRecord }) {
|
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
/** The one-line status under a record's name; the bucket carries the rest. */
|
|
198
|
-
function statusLine(t: Translate, record: OperationRecord, ahead: number | null): string {
|
|
200
|
+
function statusLine(t: Translate, lang: 'zh' | 'en', record: OperationRecord, ahead: number | null): string {
|
|
199
201
|
switch (record.state) {
|
|
200
202
|
case 'queued':
|
|
201
203
|
return ahead === null || ahead === 0 ? t('opQueued') : `${t('opQueued')} · ${t('opQueuedAhead')} ${String(ahead)}`
|
|
@@ -204,9 +206,9 @@ function statusLine(t: Translate, record: OperationRecord, ahead: number | null)
|
|
|
204
206
|
case 'input':
|
|
205
207
|
return t('opNeedsChoice')
|
|
206
208
|
case 'failed':
|
|
207
|
-
return record.reason
|
|
209
|
+
return record.reason !== undefined ? localizeBilingual(record.reason, lang) : t('installFail')
|
|
208
210
|
case 'warned':
|
|
209
|
-
return record.reason
|
|
211
|
+
return record.reason !== undefined ? localizeBilingual(record.reason, lang) : t('opDone')
|
|
210
212
|
case 'done':
|
|
211
213
|
return record.needsRefresh === true ? t('opDoneRefresh') : t('opDone')
|
|
212
214
|
}
|
|
@@ -322,7 +324,7 @@ export function OperationsPanel(props: OperationsPanelProps) {
|
|
|
322
324
|
</div>
|
|
323
325
|
)}
|
|
324
326
|
<div className={bucketOf(record.state) === 'attention' ? `${css.opStatus} ${css.opStatusBad}` : css.opStatus}>
|
|
325
|
-
{statusLine(t, record, ahead)}
|
|
327
|
+
{statusLine(t, props.lang, record, ahead)}
|
|
326
328
|
</div>
|
|
327
329
|
{needsUser(record) && (
|
|
328
330
|
<ConflictChoice
|
package/src/client/locales.ts
CHANGED
|
@@ -238,6 +238,8 @@ export const zh = {
|
|
|
238
238
|
hostRequirementUndeclared: '未声明宿主要求',
|
|
239
239
|
hostRequirementUnavailable: '宿主要求未知',
|
|
240
240
|
sortDownloads: 'npm 下载量(近 30 天)',
|
|
241
|
+
/** Discover/theme card byline tooltip for catalog `version`. */
|
|
242
|
+
catalogNpmLatest: 'npm 当前 latest',
|
|
241
243
|
sortStars: 'Star 数',
|
|
242
244
|
sortAdded: '发布时间',
|
|
243
245
|
sortDesc: '降序',
|
|
@@ -779,6 +781,8 @@ export const en: Record<MarketKey, string> = {
|
|
|
779
781
|
hostRequirementUndeclared: 'Host requirement undeclared',
|
|
780
782
|
hostRequirementUnavailable: 'Host requirement unknown',
|
|
781
783
|
sortDownloads: 'npm downloads (30d)',
|
|
784
|
+
/** Discover/theme card byline tooltip for catalog `version`. */
|
|
785
|
+
catalogNpmLatest: 'npm latest',
|
|
782
786
|
sortStars: 'Stars',
|
|
783
787
|
sortAdded: 'Release date',
|
|
784
788
|
sortDesc: 'Descending',
|
|
@@ -48,6 +48,11 @@ export interface RegistryPlugin {
|
|
|
48
48
|
* package. Absent means "no npm package" — a coverage gap, not a zero.
|
|
49
49
|
*/
|
|
50
50
|
downloads?: number | null
|
|
51
|
+
/**
|
|
52
|
+
* Catalog npm `latest` (awesome-dsh-plugin / dsh-market#348). Shown in the
|
|
53
|
+
* discover byline only when it is a non-empty string.
|
|
54
|
+
*/
|
|
55
|
+
version?: string | null
|
|
51
56
|
added?: string
|
|
52
57
|
install?: string
|
|
53
58
|
/**
|
|
@@ -980,6 +985,34 @@ function safeScreenshot(value: unknown): string | null {
|
|
|
980
985
|
return value
|
|
981
986
|
}
|
|
982
987
|
|
|
988
|
+
/**
|
|
989
|
+
* Prepare a GitHub release body for the update-notes dialog's tiny markdown
|
|
990
|
+
* renderer. HTML — especially pasted `<img>` tags — must not surface as
|
|
991
|
+
* literal text; markdown syntax is left intact for the dialog to render.
|
|
992
|
+
*/
|
|
993
|
+
export function sanitizeReleaseNotesBody(md: string): string {
|
|
994
|
+
let s = md.replace(/<!--[\s\S]*?-->/g, '')
|
|
995
|
+
s = s.replace(/<img\b[^>]*>/gi, '')
|
|
996
|
+
// Drop remaining tags, keep inner text (`<a href=…>label</a>` → `label`).
|
|
997
|
+
s = s.replace(/<\/?[a-zA-Z][\w:-]*\b[^>]*>/g, '')
|
|
998
|
+
s = s.replace(/[ \t]+\n/g, '\n').replace(/\n{3,}/g, '\n\n')
|
|
999
|
+
return s.trim()
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* A whole-line markdown image with an allowlisted https URL, or null.
|
|
1004
|
+
* Relative paths and non-GitHub hosts stay out of the dialog (same gate as
|
|
1005
|
+
* install screenshots).
|
|
1006
|
+
*/
|
|
1007
|
+
export function releaseNotesHttpsImage(line: string): { alt: string; src: string } | null {
|
|
1008
|
+
const match = /^!\[([^\]]*)\]\(\s*(?:<(https:\/\/[^>]+)>|(https:\/\/[^\s)]+))(?:\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\)$/u
|
|
1009
|
+
.exec(line.trim())
|
|
1010
|
+
if (match === null) return null
|
|
1011
|
+
const src = safeScreenshot(match[2] ?? match[3] ?? '')
|
|
1012
|
+
if (src === null) return null
|
|
1013
|
+
return { alt: match[1] ?? '', src }
|
|
1014
|
+
}
|
|
1015
|
+
|
|
983
1016
|
/** Keep only https URLs on allowlisted image hosts; SVG dropped (logos/badges). */
|
|
984
1017
|
export function safeScreenshots(urls: unknown): string[] {
|
|
985
1018
|
if (!Array.isArray(urls)) return []
|
|
@@ -1265,6 +1298,66 @@ export function humanOutput(raw: string): string {
|
|
|
1265
1298
|
return kept.join('\n').trim()
|
|
1266
1299
|
}
|
|
1267
1300
|
|
|
1301
|
+
/** CJK ideographs — enough to tell a Chinese half from a Latin one. */
|
|
1302
|
+
const CJK_RE = /[\u3400-\u9FFF\uF900-\uFAFF]/gu
|
|
1303
|
+
|
|
1304
|
+
/** Count CJK code points in a string. */
|
|
1305
|
+
function cjkCount(text: string): number {
|
|
1306
|
+
return text.match(CJK_RE)?.length ?? 0
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* Pick one language from a `中文 / English` (or reverse) pair. Ambiguous
|
|
1311
|
+
* strings stay unchanged. Callers that prepend `t(…)` must localize the
|
|
1312
|
+
* server half first, then concatenate — this function does not strip UI chrome.
|
|
1313
|
+
*/
|
|
1314
|
+
function pickBilingualPair(text: string, lang: 'zh' | 'en'): string {
|
|
1315
|
+
const sep = ' / '
|
|
1316
|
+
const parts = text.split(sep)
|
|
1317
|
+
if (parts.length < 2) return text
|
|
1318
|
+
|
|
1319
|
+
// Prefer the split with the largest CJK contrast when the text has more
|
|
1320
|
+
// than one ` / ` (English prose can contain the same separator).
|
|
1321
|
+
let bestLeft = parts[0]
|
|
1322
|
+
let bestRight = parts.slice(1).join(sep)
|
|
1323
|
+
let bestScore = Math.abs(cjkCount(bestLeft) - cjkCount(bestRight))
|
|
1324
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
1325
|
+
const left = parts.slice(0, i + 1).join(sep)
|
|
1326
|
+
const right = parts.slice(i + 1).join(sep)
|
|
1327
|
+
const score = Math.abs(cjkCount(left) - cjkCount(right))
|
|
1328
|
+
if (score > bestScore) {
|
|
1329
|
+
bestScore = score
|
|
1330
|
+
bestLeft = left
|
|
1331
|
+
bestRight = right
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
if (bestScore === 0) return text
|
|
1335
|
+
const zhPart = cjkCount(bestLeft) > cjkCount(bestRight) ? bestLeft : bestRight
|
|
1336
|
+
const enPart = cjkCount(bestLeft) > cjkCount(bestRight) ? bestRight : bestLeft
|
|
1337
|
+
return lang === 'zh' ? zhPart : enPart
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
/**
|
|
1341
|
+
* Pick the locale half of a server bilingual string (`中文 / English` or
|
|
1342
|
+
* `English / 中文`). Multiline input is handled line by line. Ambiguous
|
|
1343
|
+
* strings are returned unchanged.
|
|
1344
|
+
*/
|
|
1345
|
+
export function localizeBilingual(text: string, lang: 'zh' | 'en'): string {
|
|
1346
|
+
if (text.includes('\n')) {
|
|
1347
|
+
return text.split('\n').map(line => localizeBilingual(line, lang)).join('\n')
|
|
1348
|
+
}
|
|
1349
|
+
return pickBilingualPair(text, lang)
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* Localize each bilingual reason and join for display. Reasons are separate
|
|
1354
|
+
* diagnoses; do not rejoin them with ` / `, which is the bilingual separator.
|
|
1355
|
+
*/
|
|
1356
|
+
export function localizeBilingualList(parts: string[], lang: 'zh' | 'en'): string {
|
|
1357
|
+
const sep = lang === 'zh' ? ';' : '; '
|
|
1358
|
+
return parts.map(part => localizeBilingual(part, lang)).filter(part => part !== '').join(sep)
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1268
1361
|
/**
|
|
1269
1362
|
* The plugin's own name, for display.
|
|
1270
1363
|
*
|
package/src/registry.ts
CHANGED
|
@@ -24,6 +24,12 @@ export interface RegistryPlugin {
|
|
|
24
24
|
* zero — so sorting must not read it as "less popular than 0".
|
|
25
25
|
*/
|
|
26
26
|
downloads?: number | null
|
|
27
|
+
/**
|
|
28
|
+
* Registry `dist-tags.latest` from awesome-dsh-plugin (#348). A string when
|
|
29
|
+
* known; `null`/absent when github-only or not yet backfilled — the UI
|
|
30
|
+
* omits the byline segment rather than showing a placeholder.
|
|
31
|
+
*/
|
|
32
|
+
version?: string | null
|
|
27
33
|
install: string
|
|
28
34
|
added: string
|
|
29
35
|
/**
|