@linxin666/dsh-client-ui-skin-center 0.3.0 → 0.3.2
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/contracts/README.md +1 -0
- package/contracts/primary-action-tokens-v1.md +70 -0
- package/contracts/semantic-attrs-v1.md +1 -1
- package/lib/client.js +31 -15
- package/lib/client.js.map +1 -1
- package/lib/index.js +293 -4
- package/package.json +1 -1
package/contracts/README.md
CHANGED
|
@@ -12,6 +12,7 @@ every official-DSH coupling behind them.
|
|
|
12
12
|
| `skin-manifest-v2.schema.json` | skin.json v2 structure. Editors/IDEs may point at it; validators must use this local copy and never fetch the `$id` URL. |
|
|
13
13
|
| `hooks-api.d.ts` | The `facets.client` escape-hatch API (`x-org.linxin666.skin-center/v1alpha1`): `SkinHooksContext`, `defineSkinHooks()`. |
|
|
14
14
|
| `semantic-attrs-v1.md` | The L2 semantic-attribute enumeration (`data-dsh-surface` / `data-dsh-part` / `data-dsh-plugin`) with owner, version and meaning per value. |
|
|
15
|
+
| `primary-action-tokens-v1.md` | The filled-primary-button token set (fill / hover / dimmed / foreground), the skin author rules, the loader completion matrix and the warning-only audit. |
|
|
15
16
|
|
|
16
17
|
The runtime validator (`src/core/manifest-v2/validate.ts`) is the
|
|
17
18
|
authoritative fail-closed check; the JSON Schema mirrors it for editors and
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Primary-Action Token Contract (v1) — issue #506 follow-up
|
|
2
|
+
|
|
3
|
+
The filled primary button (the "one-click install" CTA, every plugin's
|
|
4
|
+
primary action) renders from **one matched set** in every theme. This file is
|
|
5
|
+
the authoritative statement of that set, of what a skin must declare, and of
|
|
6
|
+
what the skin-center proves when a skin loads.
|
|
7
|
+
|
|
8
|
+
## The set
|
|
9
|
+
|
|
10
|
+
| Token | Role |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| `--dsw-alias-button-primary-fill` | Button background |
|
|
13
|
+
| `--dsw-alias-button-primary-hover` | Button background while hovered |
|
|
14
|
+
| `--dsw-alias-button-primary-dimmed` | Disabled-button tint |
|
|
15
|
+
| `--dsw-alias-label-primary-foreground` | Text on the fill |
|
|
16
|
+
|
|
17
|
+
The official shell declares all four (fill and dimmed derive from
|
|
18
|
+
`brand-primary` / statics). `--dsw-alias-brand-primary` and
|
|
19
|
+
`--dsw-alias-brand-primary-invert` are **accent and foreground tokens, not a
|
|
20
|
+
button pair**: in the current official theme both resolve to the same
|
|
21
|
+
theme-neutral, so using them as fill + text renders black-on-black (light) or
|
|
22
|
+
white-on-white (dark). Never consume them as a button fill.
|
|
23
|
+
|
|
24
|
+
## Skin author rules
|
|
25
|
+
|
|
26
|
+
1. Prefer declaring the full set per theme (light block and
|
|
27
|
+
`body[data-ds-dark-theme]` block), as matched colors.
|
|
28
|
+
2. The legacy pair (declare both `brand-primary` and
|
|
29
|
+
`brand-primary-invert`) is still honored: the loader derives fill from
|
|
30
|
+
the brand, derives hover/dimmed toward the surface, and uses the invert
|
|
31
|
+
as the foreground — because the pair is matched by the author.
|
|
32
|
+
3. Partial declarations warn (catalog warnings, `dsh-skin validate`,
|
|
33
|
+
`dsh-skin list`) but never fail: the loader completes what is missing,
|
|
34
|
+
and a skin with no brand and no button tokens at all deliberately keeps
|
|
35
|
+
the shell's own matched CTA.
|
|
36
|
+
4. The loader never overrides a token the skin defines, and hygiene-wise a
|
|
37
|
+
new skin's button set should be self-contained (explicit
|
|
38
|
+
`button-primary-hover` etc.) rather than relying on derivation.
|
|
39
|
+
|
|
40
|
+
## Completion matrix (loader, `css-safety/fallback.ts`)
|
|
41
|
+
|
|
42
|
+
| The skin declares | The loader adds |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| `brand-primary` | `button-primary-fill: var(brand-primary)` |
|
|
45
|
+
| fill available (explicit or derived) | `button-primary-hover` / `button-primary-dimmed`: `color-mix` toward `--dsw-alias-bg-layer-1` |
|
|
46
|
+
| `brand-primary` + `brand-primary-invert` | `label-primary-foreground: var(brand-primary-invert)` |
|
|
47
|
+
| nothing (no brand, no button tokens) | nothing — the official shell CTA applies |
|
|
48
|
+
|
|
49
|
+
## Audit (`css-safety/token-audit.ts`)
|
|
50
|
+
|
|
51
|
+
Warning-only, never fatal — the completion rules keep every outcome legible.
|
|
52
|
+
|
|
53
|
+
- Completeness: fill satisfied by `button-primary-fill` or `brand-primary`;
|
|
54
|
+
hover by `button-primary-hover` or the fill anchor; foreground by
|
|
55
|
+
`label-primary-foreground` or the legacy invert pair.
|
|
56
|
+
- Contrast: per theme, WCAG 2.x ratio of the resolved foreground vs fill
|
|
57
|
+
(skin values, one `var()` hop, official static palette for
|
|
58
|
+
`--dsw-static-*` references, shell defaults as the fallback stand-ins).
|
|
59
|
+
Below **3:1** warns. Unresolvable chains skip the ratio rather than guess.
|
|
60
|
+
- Enforcement points: catalog build (surfaces in `dsh-skin list` and the
|
|
61
|
+
Skin Center diagnostics), `dsh-skin validate` / `install`, and the
|
|
62
|
+
built-in-skins CI gate (zero contract warnings for shipped skins).
|
|
63
|
+
|
|
64
|
+
## Consumer rule (plugins)
|
|
65
|
+
|
|
66
|
+
A filled primary button uses the set — fill / hover / foreground — verbatim
|
|
67
|
+
(BG = `button-primary-fill`, label = `label-primary-foreground`, hover =
|
|
68
|
+
`button-primary-hover`). Do not use `brand-primary` as a button
|
|
69
|
+
background, do not introduce per-plugin hardcoded accents, and do not pair
|
|
70
|
+
the tokens across families (e.g. brand fill with shell foreground).
|
|
@@ -115,7 +115,7 @@ family / 插件区域:
|
|
|
115
115
|
| `skill-explorer` | dsh-skill-explorer | `[data-dsh-skill-explorer-view]` / `[data-dsh-skill-explorer-entry]` |
|
|
116
116
|
| `doctor` | dsh-doctor | web-ui.plugin.item 槽 entry id `doctor`(设置 → Web UI 插件 → Doctor 卡片);卡片内 `[data-dsh-plugin="doctor"]` |
|
|
117
117
|
| `aionui-panel` | dsh-aionui-panel(停更) | dock entry id `aionui-*` |
|
|
118
|
-
| `dsh-market` | dsh-market | 创意工坊商店一级页(settings.section id `dsh-market`),商店卡与目录条目容器 |
|
|
118
|
+
| `dsh-web-ui-market` | dsh-market | 创意工坊商店一级页(settings.section id `dsh-web-ui-market`),商店卡与目录条目容器 |
|
|
119
119
|
| `skin-center` | skins/skin-center | 一级设置分区 settings.section id `skin-center`(列已安装皮肤,属内置源时显式标记) |
|
|
120
120
|
| `session-id` | dsh-session-id | footer action slot entry id `session-id`;`[data-dsh-plugin="session-id"]`(面板 overlay 根 + 入口触发器) |
|
|
121
121
|
|
package/lib/client.js
CHANGED
|
@@ -668,8 +668,8 @@ window.__ModuleLoader__.load({
|
|
|
668
668
|
const manifestResponse = await fetchFn(payload.sceneUrl.replace("/scene-runtime/", "/scene-manifest/"));
|
|
669
669
|
const manifestPayload = manifestResponse.ok ? await manifestResponse.json().catch(() => null) : null;
|
|
670
670
|
const manifest = manifestPayload?.ok === true ? manifestPayload.manifest : void 0;
|
|
671
|
-
if (manifest && typeof manifest.width === "number" && typeof manifest.height === "number") {
|
|
672
|
-
const fullscreenIndex = manifest.layers?.findIndex((layer) => typeof layer.texUrl === "string" && Math.abs((layer.w ?? 0) - manifest.width) <= 1 && Math.abs((layer.h ?? 0) - manifest.height) <= 1 && Math.abs((layer.x ?? 0) - manifest.width / 2) <= 1 && Math.abs((layer.y ?? 0) - manifest.height / 2) <= 1) ?? -1;
|
|
671
|
+
if (manifest && manifest.timeSchedule === void 0 && typeof manifest.width === "number" && typeof manifest.height === "number") {
|
|
672
|
+
const fullscreenIndex = manifest.layers?.findIndex((layer) => typeof layer.texUrl === "string" && typeof layer.videoUrl !== "string" && Math.abs((layer.w ?? 0) - manifest.width) <= 1 && Math.abs((layer.h ?? 0) - manifest.height) <= 1 && Math.abs((layer.x ?? 0) - manifest.width / 2) <= 1 && Math.abs((layer.y ?? 0) - manifest.height / 2) <= 1) ?? -1;
|
|
673
673
|
if (fullscreenIndex >= 0) {
|
|
674
674
|
sceneBaseUrl = manifest.layers?.[fullscreenIndex]?.texUrl ?? null;
|
|
675
675
|
preferSceneBase = manifest.layers?.slice(fullscreenIndex + 1).some((layer) => (layer.w ?? 0) > manifest.width * 1.25 || (layer.h ?? 0) > manifest.height * 1.25) === true;
|
|
@@ -2149,7 +2149,11 @@ window.__ModuleLoader__.load({
|
|
|
2149
2149
|
setError(t("applyFailed"));
|
|
2150
2150
|
return;
|
|
2151
2151
|
}
|
|
2152
|
-
run(target, () => preview.runSkin(() =>
|
|
2152
|
+
run(target, () => preview.runSkin(async () => {
|
|
2153
|
+
const active = await switchAndDeactivateCustomTheme(target, entry);
|
|
2154
|
+
if (wallpaper.selection() !== "") wallpaper.clearSelection();
|
|
2155
|
+
return active;
|
|
2156
|
+
}));
|
|
2153
2157
|
};
|
|
2154
2158
|
const tryOnCustomTheme = () => {
|
|
2155
2159
|
run("custom-theme", () => preview.runCustomTheme(async () => {
|
|
@@ -4399,10 +4403,16 @@ window.__ModuleLoader__.load({
|
|
|
4399
4403
|
* @param ctx - client root context.
|
|
4400
4404
|
*/
|
|
4401
4405
|
function apply(ctx) {
|
|
4402
|
-
ctx.effect(() =>
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
+
ctx.effect(() => {
|
|
4407
|
+
try {
|
|
4408
|
+
return ctx.locale.register(NS, {
|
|
4409
|
+
zh,
|
|
4410
|
+
en
|
|
4411
|
+
});
|
|
4412
|
+
} catch {
|
|
4413
|
+
return () => {};
|
|
4414
|
+
}
|
|
4415
|
+
}, "ui-skin-center: dictionaries");
|
|
4406
4416
|
ctx.effect(() => {
|
|
4407
4417
|
document.body.dataset.dshSkinCenter = "";
|
|
4408
4418
|
return () => {
|
|
@@ -4530,14 +4540,20 @@ window.__ModuleLoader__.load({
|
|
|
4530
4540
|
dispose: () => wallpaper.dispose()
|
|
4531
4541
|
}
|
|
4532
4542
|
});
|
|
4533
|
-
ctx.slots.inject("settings.section", () =>
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4543
|
+
ctx.slots.inject("settings.section", () => {
|
|
4544
|
+
try {
|
|
4545
|
+
return ctx.slots.register({
|
|
4546
|
+
name: "settings.section",
|
|
4547
|
+
id: "skin-center",
|
|
4548
|
+
order: 120,
|
|
4549
|
+
label: () => ctx.locale.bind("skinCenter")("title"),
|
|
4550
|
+
locale: "skinCenter",
|
|
4551
|
+
inject: injected
|
|
4552
|
+
}, SkinCenterSection);
|
|
4553
|
+
} catch {
|
|
4554
|
+
return () => {};
|
|
4555
|
+
}
|
|
4556
|
+
});
|
|
4541
4557
|
}
|
|
4542
4558
|
//#endregion
|
|
4543
4559
|
exports.NS = NS;
|