@zl-ui-kit/theme 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1185,8 +1185,8 @@ function initThemeFromStorage() {
1185
1185
  return "light";
1186
1186
  }
1187
1187
  }
1188
- function buildCssVars(resolved, themeName) {
1189
- const isDark = themeName.includes("dark");
1188
+ function buildCssVars(resolved, themeName, baseName = themeName) {
1189
+ const isDark = themeName.includes("dark") || baseName.includes("dark");
1190
1190
  const get = (k, fallback = "") => resolved[`color-${k}`] ?? fallback;
1191
1191
  const getLevel = (name, level) => resolved[`color-${name}-${level}`] ?? "";
1192
1192
  const decls = [];
@@ -1202,6 +1202,9 @@ function buildCssVars(resolved, themeName) {
1202
1202
  ["success", getLevel("green", 6)],
1203
1203
  ["warning", getLevel("orange", 6)],
1204
1204
  ["danger", getLevel("red", 6)],
1205
+ // EP 2.14 起 error 是规范名(el-tag--error / el-message--error 走它),
1206
+ // 只给 danger 会让这些组件回落到 EP 默认浅色底,深色主题下尤其刺眼
1207
+ ["error", getLevel("red", 6)],
1205
1208
  ["info", getLevel("gray", 6)]
1206
1209
  ];
1207
1210
  for (const [name, hex] of semantic) {
@@ -1215,14 +1218,18 @@ function buildCssVars(resolved, themeName) {
1215
1218
  regular: "text-2",
1216
1219
  secondary: "text-3",
1217
1220
  placeholder: "text-4",
1218
- disabled: "text-5"
1221
+ // 没有 text-5:留空会产出 `--el-text-color-disabled: ;` 这种非法声明,
1222
+ // 浏览器整条丢弃,EP 内部又会回落默认值 —— 直接复用 placeholder
1223
+ disabled: "text-4"
1219
1224
  };
1220
1225
  for (const [el, token] of Object.entries(textMap)) decls.push(`--el-text-color-${el}: ${get(token)};`);
1221
1226
  const borderMap = [
1222
1227
  ["extra-light", "border-1"],
1223
1228
  ["lighter", "border-2"],
1224
1229
  ["light", "border-3"],
1225
- ["", "border-4"]
1230
+ ["", "border-4"],
1231
+ ["dark", "border-4"],
1232
+ ["darker", "border-4"]
1226
1233
  ];
1227
1234
  for (const [suffix, token] of borderMap)
1228
1235
  decls.push(`--el-border-color${suffix ? `-${suffix}` : ""}: ${get(token)};`);
@@ -1230,7 +1237,8 @@ function buildCssVars(resolved, themeName) {
1230
1237
  ["extra-light", "fill-1"],
1231
1238
  ["lighter", "fill-2"],
1232
1239
  ["light", "fill-3"],
1233
- ["", "fill-4"]
1240
+ ["", "fill-4"],
1241
+ ["dark", "fill-4"]
1234
1242
  ];
1235
1243
  for (const [suffix, token] of fillMap)
1236
1244
  decls.push(`--el-fill-color${suffix ? `-${suffix}` : ""}: ${get(token)};`);
@@ -1240,7 +1248,19 @@ function buildCssVars(resolved, themeName) {
1240
1248
  decls.push(`--el-bg-color-overlay: ${get("bg-3")};`);
1241
1249
  decls.push(`--el-color-white: ${isDark ? "#141414" : "#ffffff"};`);
1242
1250
  decls.push(`--el-color-black: ${isDark ? "#ffffff" : "#000000"};`);
1251
+ decls.push(`--el-mask-color: rgb(0, 0, 0, ${isDark ? "0.8" : "0.5"});`);
1243
1252
  decls.push(`color-scheme: ${isDark ? "dark" : "light"};`);
1253
+ const isPlainBase = baseName === "light" || baseName === "dark";
1254
+ decls.push(`--zl-menu-hover-bg: ${isPlainBase ? "var(--zl-fill-2)" : "rgba(255, 255, 255, 0.2)"};`);
1255
+ decls.push(`--zl-menu-text-color: ${isPlainBase ? "var(--zl-text-1)" : "var(--zl-white)"};`);
1256
+ decls.push(`--zl-menu-trigger-arrow-color: ${isDark ? "#253044" : "#f6fafc"};`);
1257
+ decls.push(`--zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));`);
1258
+ decls.push(
1259
+ `--zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);`
1260
+ );
1261
+ decls.push(
1262
+ `--zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);`
1263
+ );
1244
1264
  return decls.join("\n ");
1245
1265
  }
1246
1266
  function injectStyle(name, cssText) {
@@ -1254,6 +1274,7 @@ function injectStyle(name, cssText) {
1254
1274
  style.textContent = cssText;
1255
1275
  }
1256
1276
  function defineTheme(options) {
1277
+ var _a;
1257
1278
  const { name, base = "light", colors = {}, tokens = {}, apply = false } = options;
1258
1279
  if (THEMES.includes(name) && !customThemes.has(name)) {
1259
1280
  throw new Error(`\u4E3B\u9898 ${name} \u4E3A\u5185\u7F6E\u4E3B\u9898\uFF0C\u4E0D\u53EF\u8986\u76D6`);
@@ -1262,6 +1283,19 @@ function defineTheme(options) {
1262
1283
  for (const [key, value] of Object.entries(tokens)) {
1263
1284
  resolved[`color-${key.replace(/^color-/, "")}`] = value;
1264
1285
  }
1286
+ const shapeTokens = {
1287
+ "radius-small": "2px",
1288
+ "radius-base": "4px",
1289
+ "radius-medium": "4px",
1290
+ "radius-large": "6px",
1291
+ "radius-xl": "12px",
1292
+ "radius-round": "99px",
1293
+ "font-family-code": "Consolas, 'SFMono-Regular', Menlo, monospace",
1294
+ "slogan-font-family": "'PingFang SC', 'Microsoft YaHei', sans-serif"
1295
+ };
1296
+ for (const [key, value] of Object.entries(shapeTokens)) {
1297
+ resolved[_a = `color-${key}`] ?? (resolved[_a] = value);
1298
+ }
1265
1299
  const colorEntries = [
1266
1300
  ["primary", "modo", "6"],
1267
1301
  ["success", "green", "6"],
@@ -1286,7 +1320,7 @@ function defineTheme(options) {
1286
1320
  resolved["color-bg-2"] = colors.bg;
1287
1321
  }
1288
1322
  const cssText = `body[data-theme='${name}'] {
1289
- ${buildCssVars(resolved, name)}
1323
+ ${buildCssVars(resolved, name, base)}
1290
1324
  }`;
1291
1325
  injectStyle(name, cssText);
1292
1326
  customThemes.set(name, { cssText });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zl-ui-kit/theme",
3
- "version": "0.6.3",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "description": "ZL UI 主题引擎:内置 5 套主题(light/dark/red-light/red-dark/blue),--zl-* 业务变量 + --el-* Element Plus 变量三层体系,支持运行时自定义主题(defineTheme/setTheme)",
6
6
  "license": "MIT",
@@ -41,8 +41,8 @@
41
41
  "cross-env": "^7.0.3",
42
42
  "tsup": "^8.3.5",
43
43
  "typescript": "^5.7.3",
44
- "@jichuang/eslint-config": "1.0.0",
45
- "@jichuang/tsconfig": "1.0.0"
44
+ "@jichuang/tsconfig": "1.0.0",
45
+ "@jichuang/eslint-config": "1.0.0"
46
46
  },
47
47
  "repository": {
48
48
  "type": "git",
@@ -312,7 +312,7 @@ body[data-theme='blue'] {
312
312
  --el-text-color-regular: #4D5E7D;
313
313
  --el-text-color-secondary: #79879C;
314
314
  --el-text-color-placeholder: #B3C0CC;
315
- --el-text-color-disabled: ;
315
+ --el-text-color-disabled: #B3C0CC;
316
316
  --el-border-color-extra-light: #EFF4F9;
317
317
  --el-border-color-lighter: #E3E9EF;
318
318
  --el-border-color-light: #B3C0CC;
@@ -338,6 +338,14 @@ body[data-theme='blue'] {
338
338
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
339
339
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
340
340
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
341
+ --zl-radius-small: 2px;
342
+ --zl-radius-base: 4px;
343
+ --zl-radius-medium: 4px;
344
+ --zl-radius-large: 6px;
345
+ --zl-radius-xl: 12px;
346
+ --zl-radius-round: 99px;
347
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
348
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
341
349
  }
342
350
 
343
351
  /*
@@ -312,7 +312,7 @@ body[data-theme='dark'] {
312
312
  --el-text-color-regular: rgba(255,255,255,0.7);
313
313
  --el-text-color-secondary: rgba(255,255,255,0.5);
314
314
  --el-text-color-placeholder: rgba(255,255,255,0.3);
315
- --el-text-color-disabled: ;
315
+ --el-text-color-disabled: rgba(255,255,255,0.3);
316
316
  --el-border-color-extra-light: #35435E;
317
317
  --el-border-color-lighter: #4D5E7D;
318
318
  --el-border-color-light: #5E708A;
@@ -338,6 +338,14 @@ body[data-theme='dark'] {
338
338
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
339
339
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
340
340
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
341
+ --zl-radius-small: 2px;
342
+ --zl-radius-base: 4px;
343
+ --zl-radius-medium: 4px;
344
+ --zl-radius-large: 6px;
345
+ --zl-radius-xl: 12px;
346
+ --zl-radius-round: 99px;
347
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
348
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
341
349
  }
342
350
 
343
351
  /*
@@ -312,7 +312,7 @@ body {
312
312
  --el-text-color-regular: #4D5E7D;
313
313
  --el-text-color-secondary: #79879C;
314
314
  --el-text-color-placeholder: #B3C0CC;
315
- --el-text-color-disabled: ;
315
+ --el-text-color-disabled: #B3C0CC;
316
316
  --el-border-color-extra-light: #EFF4F9;
317
317
  --el-border-color-lighter: #E3E9EF;
318
318
  --el-border-color-light: #B3C0CC;
@@ -338,6 +338,14 @@ body {
338
338
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
339
339
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
340
340
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
341
+ --zl-radius-small: 2px;
342
+ --zl-radius-base: 4px;
343
+ --zl-radius-medium: 4px;
344
+ --zl-radius-large: 6px;
345
+ --zl-radius-xl: 12px;
346
+ --zl-radius-round: 99px;
347
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
348
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
341
349
  }
342
350
 
343
351
  /*
@@ -312,7 +312,7 @@ body[data-theme='red-dark'] {
312
312
  --el-text-color-regular: rgba(255,255,255,0.7);
313
313
  --el-text-color-secondary: rgba(255,255,255,0.5);
314
314
  --el-text-color-placeholder: rgba(255,255,255,0.3);
315
- --el-text-color-disabled: ;
315
+ --el-text-color-disabled: rgba(255,255,255,0.3);
316
316
  --el-border-color-extra-light: #35435E;
317
317
  --el-border-color-lighter: #4D5E7D;
318
318
  --el-border-color-light: #5E708A;
@@ -338,6 +338,14 @@ body[data-theme='red-dark'] {
338
338
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
339
339
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
340
340
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
341
+ --zl-radius-small: 2px;
342
+ --zl-radius-base: 4px;
343
+ --zl-radius-medium: 4px;
344
+ --zl-radius-large: 6px;
345
+ --zl-radius-xl: 12px;
346
+ --zl-radius-round: 99px;
347
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
348
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
341
349
  }
342
350
 
343
351
  /*
@@ -312,7 +312,7 @@ body[data-theme='red-light'] {
312
312
  --el-text-color-regular: #4D5E7D;
313
313
  --el-text-color-secondary: #79879C;
314
314
  --el-text-color-placeholder: #B3C0CC;
315
- --el-text-color-disabled: ;
315
+ --el-text-color-disabled: #B3C0CC;
316
316
  --el-border-color-extra-light: #EFF4F9;
317
317
  --el-border-color-lighter: #E3E9EF;
318
318
  --el-border-color-light: #B3C0CC;
@@ -338,6 +338,14 @@ body[data-theme='red-light'] {
338
338
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
339
339
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
340
340
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
341
+ --zl-radius-small: 2px;
342
+ --zl-radius-base: 4px;
343
+ --zl-radius-medium: 4px;
344
+ --zl-radius-large: 6px;
345
+ --zl-radius-xl: 12px;
346
+ --zl-radius-round: 99px;
347
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
348
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
341
349
  }
342
350
 
343
351
  /*
@@ -312,7 +312,7 @@ body[data-theme='blue'] {
312
312
  --el-text-color-regular: #4D5E7D;
313
313
  --el-text-color-secondary: #79879C;
314
314
  --el-text-color-placeholder: #B3C0CC;
315
- --el-text-color-disabled: ;
315
+ --el-text-color-disabled: #B3C0CC;
316
316
  --el-border-color-extra-light: #EFF4F9;
317
317
  --el-border-color-lighter: #E3E9EF;
318
318
  --el-border-color-light: #B3C0CC;
@@ -338,6 +338,14 @@ body[data-theme='blue'] {
338
338
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
339
339
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
340
340
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
341
+ --zl-radius-small: 2px;
342
+ --zl-radius-base: 4px;
343
+ --zl-radius-medium: 4px;
344
+ --zl-radius-large: 6px;
345
+ --zl-radius-xl: 12px;
346
+ --zl-radius-round: 99px;
347
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
348
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
341
349
  }
342
350
 
343
351
  /* dark 主题(由 scripts/themegen.mjs 生成,DO NOT EDIT) */
@@ -654,7 +662,7 @@ body[data-theme='dark'] {
654
662
  --el-text-color-regular: rgba(255,255,255,0.7);
655
663
  --el-text-color-secondary: rgba(255,255,255,0.5);
656
664
  --el-text-color-placeholder: rgba(255,255,255,0.3);
657
- --el-text-color-disabled: ;
665
+ --el-text-color-disabled: rgba(255,255,255,0.3);
658
666
  --el-border-color-extra-light: #35435E;
659
667
  --el-border-color-lighter: #4D5E7D;
660
668
  --el-border-color-light: #5E708A;
@@ -680,6 +688,14 @@ body[data-theme='dark'] {
680
688
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
681
689
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
682
690
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
691
+ --zl-radius-small: 2px;
692
+ --zl-radius-base: 4px;
693
+ --zl-radius-medium: 4px;
694
+ --zl-radius-large: 6px;
695
+ --zl-radius-xl: 12px;
696
+ --zl-radius-round: 99px;
697
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
698
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
683
699
  }
684
700
 
685
701
  /* light 主题(由 scripts/themegen.mjs 生成,DO NOT EDIT) */
@@ -996,7 +1012,7 @@ body {
996
1012
  --el-text-color-regular: #4D5E7D;
997
1013
  --el-text-color-secondary: #79879C;
998
1014
  --el-text-color-placeholder: #B3C0CC;
999
- --el-text-color-disabled: ;
1015
+ --el-text-color-disabled: #B3C0CC;
1000
1016
  --el-border-color-extra-light: #EFF4F9;
1001
1017
  --el-border-color-lighter: #E3E9EF;
1002
1018
  --el-border-color-light: #B3C0CC;
@@ -1022,6 +1038,14 @@ body {
1022
1038
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
1023
1039
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
1024
1040
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
1041
+ --zl-radius-small: 2px;
1042
+ --zl-radius-base: 4px;
1043
+ --zl-radius-medium: 4px;
1044
+ --zl-radius-large: 6px;
1045
+ --zl-radius-xl: 12px;
1046
+ --zl-radius-round: 99px;
1047
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
1048
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
1025
1049
  }
1026
1050
 
1027
1051
  /* red-dark 主题(由 scripts/themegen.mjs 生成,DO NOT EDIT) */
@@ -1338,7 +1362,7 @@ body[data-theme='red-dark'] {
1338
1362
  --el-text-color-regular: rgba(255,255,255,0.7);
1339
1363
  --el-text-color-secondary: rgba(255,255,255,0.5);
1340
1364
  --el-text-color-placeholder: rgba(255,255,255,0.3);
1341
- --el-text-color-disabled: ;
1365
+ --el-text-color-disabled: rgba(255,255,255,0.3);
1342
1366
  --el-border-color-extra-light: #35435E;
1343
1367
  --el-border-color-lighter: #4D5E7D;
1344
1368
  --el-border-color-light: #5E708A;
@@ -1364,6 +1388,14 @@ body[data-theme='red-dark'] {
1364
1388
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
1365
1389
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
1366
1390
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
1391
+ --zl-radius-small: 2px;
1392
+ --zl-radius-base: 4px;
1393
+ --zl-radius-medium: 4px;
1394
+ --zl-radius-large: 6px;
1395
+ --zl-radius-xl: 12px;
1396
+ --zl-radius-round: 99px;
1397
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
1398
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
1367
1399
  }
1368
1400
 
1369
1401
  /* red-light 主题(由 scripts/themegen.mjs 生成,DO NOT EDIT) */
@@ -1680,7 +1712,7 @@ body[data-theme='red-light'] {
1680
1712
  --el-text-color-regular: #4D5E7D;
1681
1713
  --el-text-color-secondary: #79879C;
1682
1714
  --el-text-color-placeholder: #B3C0CC;
1683
- --el-text-color-disabled: ;
1715
+ --el-text-color-disabled: #B3C0CC;
1684
1716
  --el-border-color-extra-light: #EFF4F9;
1685
1717
  --el-border-color-lighter: #E3E9EF;
1686
1718
  --el-border-color-light: #B3C0CC;
@@ -1706,4 +1738,12 @@ body[data-theme='red-light'] {
1706
1738
  --zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));
1707
1739
  --zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);
1708
1740
  --zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);
1741
+ --zl-radius-small: 2px;
1742
+ --zl-radius-base: 4px;
1743
+ --zl-radius-medium: 4px;
1744
+ --zl-radius-large: 6px;
1745
+ --zl-radius-xl: 12px;
1746
+ --zl-radius-round: 99px;
1747
+ --zl-font-family-code: Consolas, 'SFMono-Regular', Menlo, monospace;
1748
+ --zl-slogan-font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
1709
1749
  }
@@ -56,8 +56,8 @@ function initThemeFromStorage(): string {
56
56
  }
57
57
 
58
58
  /** 生成某主题完整变量声明文本(--zl-* + --el-* + 布局资产变量) */
59
- function buildCssVars(resolved: Record<string, string>, themeName: string): string {
60
- const isDark = themeName.includes('dark')
59
+ function buildCssVars(resolved: Record<string, string>, themeName: string, baseName = themeName): string {
60
+ const isDark = themeName.includes('dark') || baseName.includes('dark')
61
61
  const get = (k: string, fallback = '') => resolved[`color-${k}`] ?? fallback
62
62
  const getLevel = (name: string, level: number) => resolved[`color-${name}-${level}`] ?? ''
63
63
 
@@ -78,6 +78,9 @@ function buildCssVars(resolved: Record<string, string>, themeName: string): stri
78
78
  ['success', getLevel('green', 6)],
79
79
  ['warning', getLevel('orange', 6)],
80
80
  ['danger', getLevel('red', 6)],
81
+ // EP 2.14 起 error 是规范名(el-tag--error / el-message--error 走它),
82
+ // 只给 danger 会让这些组件回落到 EP 默认浅色底,深色主题下尤其刺眼
83
+ ['error', getLevel('red', 6)],
81
84
  ['info', getLevel('gray', 6)],
82
85
  ]
83
86
  for (const [name, hex] of semantic) {
@@ -92,7 +95,9 @@ function buildCssVars(resolved: Record<string, string>, themeName: string): stri
92
95
  regular: 'text-2',
93
96
  secondary: 'text-3',
94
97
  placeholder: 'text-4',
95
- disabled: 'text-5',
98
+ // 没有 text-5:留空会产出 `--el-text-color-disabled: ;` 这种非法声明,
99
+ // 浏览器整条丢弃,EP 内部又会回落默认值 —— 直接复用 placeholder
100
+ disabled: 'text-4',
96
101
  }
97
102
  for (const [el, token] of Object.entries(textMap)) decls.push(`--el-text-color-${el}: ${get(token)};`)
98
103
 
@@ -101,6 +106,8 @@ function buildCssVars(resolved: Record<string, string>, themeName: string): stri
101
106
  ['lighter', 'border-2'],
102
107
  ['light', 'border-3'],
103
108
  ['', 'border-4'],
109
+ ['dark', 'border-4'],
110
+ ['darker', 'border-4'],
104
111
  ]
105
112
  for (const [suffix, token] of borderMap)
106
113
  decls.push(`--el-border-color${suffix ? `-${suffix}` : ''}: ${get(token)};`)
@@ -110,6 +117,7 @@ function buildCssVars(resolved: Record<string, string>, themeName: string): stri
110
117
  ['lighter', 'fill-2'],
111
118
  ['light', 'fill-3'],
112
119
  ['', 'fill-4'],
120
+ ['dark', 'fill-4'],
113
121
  ]
114
122
  for (const [suffix, token] of fillMap)
115
123
  decls.push(`--el-fill-color${suffix ? `-${suffix}` : ''}: ${get(token)};`)
@@ -120,8 +128,25 @@ function buildCssVars(resolved: Record<string, string>, themeName: string): stri
120
128
  decls.push(`--el-bg-color-overlay: ${get('bg-3')};`)
121
129
  decls.push(`--el-color-white: ${isDark ? '#141414' : '#ffffff'};`)
122
130
  decls.push(`--el-color-black: ${isDark ? '#ffffff' : '#000000'};`)
131
+ decls.push(`--el-mask-color: rgb(0, 0, 0, ${isDark ? '0.8' : '0.5'});`)
123
132
  decls.push(`color-scheme: ${isDark ? 'dark' : 'light'};`)
124
133
 
134
+ // 布局 / 菜单资产变量:内置主题由 scripts/themegen.mjs 产出,运行时主题必须同构,
135
+ // 否则 defineTheme 造出的主题会把侧栏与菜单底色整块丢掉(退化成透明)。
136
+ // 浅色/深色基线用弱对比底色;以彩色主题(red-light/blue…)为基线时侧栏是深色渐变,
137
+ // 菜单文字必须转白 —— 所以这里要看基线名,不能只看自定义主题名。
138
+ const isPlainBase = baseName === 'light' || baseName === 'dark'
139
+ decls.push(`--zl-menu-hover-bg: ${isPlainBase ? 'var(--zl-fill-2)' : 'rgba(255, 255, 255, 0.2)'};`)
140
+ decls.push(`--zl-menu-text-color: ${isPlainBase ? 'var(--zl-text-1)' : 'var(--zl-white)'};`)
141
+ decls.push(`--zl-menu-trigger-arrow-color: ${isDark ? '#253044' : '#f6fafc'};`)
142
+ decls.push(`--zl-menu-trigger-bg: linear-gradient(135deg, var(--zl-modo-5), var(--zl-modo-7));`)
143
+ decls.push(
144
+ `--zl-layout-vertical-aside-bg: linear-gradient(180deg, var(--zl-modo-7) 0%, var(--zl-modo-9) 100%);`,
145
+ )
146
+ decls.push(
147
+ `--zl-layout-horizontal-header-bg: linear-gradient(90deg, var(--zl-modo-7) 0%, var(--zl-modo-6) 60%, var(--zl-modo-5) 100%);`,
148
+ )
149
+
125
150
  return decls.join('\n ')
126
151
  }
127
152
 
@@ -152,6 +177,23 @@ export function defineTheme(options: DefineThemeOptions): void {
152
177
  resolved[`color-${key.replace(/^color-/, '')}`] = value
153
178
  }
154
179
 
180
+ // 形状 / 字体 token:与内置主题同构产出。组件里写的是 `var(--zl-radius-large, 6px)`
181
+ // 这类带兜底的形式,此前这些 token 从未产出,等于「值被兜底写死、宿主改不了」。
182
+ // 用 `??=` 播种:`tokens: { 'radius-large': '10px' }` 这类覆盖仍然生效。
183
+ const shapeTokens: Record<string, string> = {
184
+ 'radius-small': '2px',
185
+ 'radius-base': '4px',
186
+ 'radius-medium': '4px',
187
+ 'radius-large': '6px',
188
+ 'radius-xl': '12px',
189
+ 'radius-round': '99px',
190
+ 'font-family-code': "Consolas, 'SFMono-Regular', Menlo, monospace",
191
+ 'slogan-font-family': "'PingFang SC', 'Microsoft YaHei', sans-serif",
192
+ }
193
+ for (const [key, value] of Object.entries(shapeTokens)) {
194
+ resolved[`color-${key}`] ??= value
195
+ }
196
+
155
197
  const colorEntries: Array<[keyof DefineThemeColors, string, string]> = [
156
198
  ['primary', 'modo', '6'],
157
199
  ['success', 'green', '6'],
@@ -179,7 +221,7 @@ export function defineTheme(options: DefineThemeOptions): void {
179
221
  resolved['color-bg-2'] = colors.bg
180
222
  }
181
223
 
182
- const cssText = `body[data-theme='${name}'] {\n ${buildCssVars(resolved, name)}\n}`
224
+ const cssText = `body[data-theme='${name}'] {\n ${buildCssVars(resolved, name, base)}\n}`
183
225
  injectStyle(name, cssText)
184
226
  customThemes.set(name, { cssText })
185
227
  if (!THEMES.includes(name)) {