@qilitt-mickey/vue3-temp-skill 1.1.75 → 1.1.76
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.
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
],
|
|
107
107
|
"preconditions": [
|
|
108
108
|
"出厂菜单项盒模型是「无横向 margin(margin: 4px 0)+ 胶囊用 inset 内缩」;指示条几何必须以这个宿主盒为基准计算偏移。照搬外部效果图上「依赖菜单项横向 margin」的负偏移量会落进容器外并被 overflow 裁掉(这是指示条「映射了却没效果」的根因:值搬了、让该值成立的宿主盒模型没搬)。",
|
|
109
|
-
"
|
|
109
|
+
"激活态消费者成对落地:--vts-theme-menu-active-before 出厂为透明且全项目无消费者;声明 indicator_* 形态必须成对落地「令牌显式供值(非 transparent)+ 新建消费者」,只改色值不建消费者 = 未施工;同名伪元素对决(出厂 sidebar.scss 也有 is-active::before 胶囊,specificity 更高且背景带 !important)输了 = 消费者整体不渲染,竖条照样消失。",
|
|
110
110
|
"激活态作用层级(active_scope,默认 leaf):胶囊与指示条**只作用于叶子菜单项**(.el-menu-item.is-active)。可展开分组的标题(.el-sub-menu__title)在「其下有激活子项」时会被 EP 打上 is-active,**不得**继承胶囊与指示条——否则分组标题同时长出胶囊、竖条并与右侧展开箭头叠压。设计层写激活态时必须把选择器锚定叶子项,禁止把 .el-sub-menu.is-active > .el-sub-menu__title 与 .el-menu-item.is-active 并列写成同一组激活声明。"
|
|
111
111
|
],
|
|
112
112
|
"priority": {
|
package/package.json
CHANGED
|
@@ -59,6 +59,8 @@ node parser/index.js match --batch <changesets-dir>
|
|
|
59
59
|
| **G5 几何语境** | 词典 preconditions 含「几何语境随值迁移」标记 ∧ `style` 含 padding/margin 族几何字段落宿主 ∧ 未声明 `suppress_inner` | 词典条目 preconditions 标记句 | `suppress_inner 缺口:…两层之和 ≠ 设计值` |
|
|
60
60
|
| **G6 层间令牌链对账** | 词典 preconditions 含「层间令牌链对账」标记 ∧ `style` 含 padding/margin 族几何字段 ∧ 未声明 `suppress_inner`——父子两层盒共享同一条间距令牌链(如 `.app-main` 与 `.main-content` 同链 `--layout-content-padding → --vts-margin`),同一间距只允许一个权威来源 | 词典条目 preconditions 标记句 | `suppress_inner 缺口:…父层设计值 + 子层同链令牌值物理叠加(24px + 8px = 32px/侧)` |
|
|
61
61
|
|
|
62
|
+
> 施工侧配套:设计审计(design-audit)另有 **E18 激活态消费者成对落地** 断言——声明 `indicator_*` 形态时,「竖条消费者存在 + `--vts-theme-menu-active-before` 非透明 + 与出厂胶囊伪元素对决权重足够」三者缺一即报(详见 step5-gates.md 审计清单)。声明指示条形态时,交付说明须同时写明这两项施工约定。
|
|
63
|
+
|
|
62
64
|
三闸与禁词校验同级阻断(`exit 1`)——「新旧形态叠加」「两层 padding 相加」「同链令牌双层叠加」「伪还原只换主题」都会导致实质错误(双竖条、28px 列挤压、内容区边距 32px/侧、「还原后布局细节零变化」),不允许靠观感兜底。G8 判据一句话:**「把系统 / 页面改成 X」默认是还原(restore),必须带齐 `scheme` + `oracle.mockup` + `coverage.registry`;只有「显式声明只改主题色、其它不动」才用 `design`**(还原项目若用无登记表、无基线的轻量变更集,会一路绿灯、落地后「只变了主题、布局细节零变化」;故须堵住 `oracle`/`coverage` 只给空壳、无 `mockup`/`registry` 芯的写法)。**降级不许静默发生**:变更集 `notes` 与交付说明都须显式写出本次 `mode` 与范围。restore 模式下 G9/G10/G11 同时生效(登记表身份、dims 维度兑现、oracle 基线三道复闸),三者判据细节见上表与「登记表覆盖率」小节。
|
|
63
65
|
|
|
64
66
|
**验收基线输出**:转换计划末尾另打印 `=== 验收基线 oracle ===`(效果图路径 + 待比对点位)与 `=== 覆盖率 coverage ===`(登记项 R / 适用 A / 已兑现 C)。有 `oracle` → 落地后必须跑第 6 步 `verify`;缺 `oracle` / `coverage` → 输出提示,把「补基线 / 补登记覆盖率」回流设计侧(场景还原应给)。
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
- E13 **固定尺寸内容度量** → 设计层出现「固定 `width` 小于内容需求、且未声明收口兜底」的规则(典型:页签位 40px 里还留着标题、图标位里塞着文案)。固定宽装不下内容时文字会换行、被压缩、甚至字符重叠渲染——**「设计说 40px 就固定 40px」必然复现**。判据:盒内还有文案却用 exact 宽度又无收口
|
|
55
55
|
- E14 **列宽预算链自洽** → 列宽(含公式推出的值)扣掉**实际生效的 td 水平内边距**后装不下该列内容(操作列 = 平铺槽数 × 槽宽);或同一列宽存在两个来源且值不一致(列定义死值 vs 模板公式)。**这是「按钮文字换行 / 重叠」的第一现场**
|
|
56
56
|
- E17 **层间令牌链对账** → 词典标记「层间令牌链对账」的条目(父子两层盒共享同链间距令牌,如 `.app-main` ↔ `.main-content` 同链 `--layout-content-padding → --vts-margin`)在设计层抢写了物理 padding/margin,而同链令牌在项目内仍有非零定义——父层设计值 + 子层令牌值叠加(24px + 8px = 32px/侧),**这是「内容区边距很大」的第一现场**。修复:改走令牌通道(重映射 `--layout-content-padding` / `--vts-margin`,两层同变),或把另一层同链间距归零
|
|
57
|
+
- E18 **激活态消费者成对落地** → 词典标记「激活态消费者成对落地」的条目(如 `admin.layout.sidebar.menu`)声明了指示条形态(form 含 `indicator` 或 style 含 `menu_active_indicator` / `active_indicator_*`),但设计层 ① 没有任何规则消费 `--vts-theme-menu-active-before`(只供值不建消费者);② 消费者建了但令牌最终定义仍是 transparent(消费者在渲染、色值透明);③ 消费者与出厂 sidebar.scss 同名 `::before` 胶囊对决权重不足(无 `!important` 背景且无 `html body` 提权,③ 为警告级)——三者任一命中,**竖条都不可见**。**这是「菜单激活态竖条消失」的第一现场**:同名伪元素是二选一对决,输 = 几何整体不渲染
|
|
57
58
|
- E16 **引用完整性** → 变更集 `oracle.mockup` / `coverage.registry` 指向的实物不存在(标识改名后未同步引用,全链路静默降级为无基线还原);`mode=restore` 缺顶层 `theme` 字段
|
|
58
59
|
- [ ] **列宽由表头文案反推(E5 落地口径)**:每个业务列(含选择列、序号列)都要显式声明 `width` 或 `min-width`,取值 ≥ 该列表头文案宽度 + 左右各 16px 内边距(CJK 按 1em、ASCII 按 0.6em 估)。无宽列只能拿出厂兜底宽度参与布局,会被相邻固定宽列挤压——**表头换行与省略号截断的唯一根因就在这里**,不接受「跑起来看着还行」
|
|
59
60
|
|
package/scripts/design-audit.mjs
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
* E14 列宽预算链自洽 列宽(含公式)扣掉实际 td 内边距后装不下内容 → 操作列按钮被压
|
|
34
34
|
* E16 引用完整性 变更集引用的实物不存在(改名未同步)/ restore 缺顶层 theme
|
|
35
35
|
* E17 层间令牌链对账 父子两层盒共享同链间距令牌:绕过令牌通道抢写物理 padding 且同链令牌幸存 → 双层叠加
|
|
36
|
+
* E18 激活态消费者成对落地 indicator_* 形态声明后:消费者缺失 / 令牌仍透明 / 伪元素对决权重不足 → 竖条不可见
|
|
36
37
|
* E15 结构声明兑现 form 值 / suppress 通道名必须在词典枚举内,且设计层有 @sid / @closed 落点证据(G3 双向对账)
|
|
37
38
|
*/
|
|
38
39
|
|
|
@@ -427,9 +428,14 @@ for (const r of scopedRules) {
|
|
|
427
428
|
info("E3", "层叠胜负:无同属性竞争的组件 scoped 规则");
|
|
428
429
|
return;
|
|
429
430
|
}
|
|
431
|
+
// 出厂暗色主题层(dark.scss)不属于「本次设计落地」:它与组件 scoped 的对决是出厂内部
|
|
432
|
+
// 行为(架构红线也禁止改出厂文件来「修复」),按设计层宣判会永久卡死交付闸。
|
|
433
|
+
const FACTORY_THEME_LAYERS = new Set(["dark.scss"]);
|
|
434
|
+
const isFactoryLayer = (file) => FACTORY_THEME_LAYERS.has(path.basename(String(file || "")));
|
|
430
435
|
const hits = [];
|
|
431
436
|
const seen = new Set();
|
|
432
437
|
for (const r of designRules) {
|
|
438
|
+
if (isFactoryLayer(r.file)) continue;
|
|
433
439
|
const pe = pseudoElOf(r.selector);
|
|
434
440
|
for (const part of splitList(r.selector)) {
|
|
435
441
|
const last = lastCompound(part);
|
|
@@ -871,12 +877,23 @@ function extractSuppressRulesAudit(entry) {
|
|
|
871
877
|
return rules;
|
|
872
878
|
}
|
|
873
879
|
|
|
874
|
-
const channelNamesOf = (entry) =>
|
|
875
|
-
new Set([
|
|
880
|
+
const channelNamesOf = (entry) => {
|
|
881
|
+
const names = new Set([
|
|
876
882
|
...Object.keys(entry?.forms || {}),
|
|
877
883
|
...Object.keys(entry?.css_vars || {}),
|
|
878
884
|
...Object.keys(entry?.custom_style_map || {}),
|
|
879
885
|
]);
|
|
886
|
+
// suppress_rules 的「值域通道」也是合法收口目标(与 parser G1 同源):如 dropdown_popper / tool_divider
|
|
887
|
+
for (const channels of Object.values(entry?.suppress_rules || {})) {
|
|
888
|
+
if (Array.isArray(channels)) for (const ch of channels) if (typeof ch === "string") names.add(ch);
|
|
889
|
+
}
|
|
890
|
+
// forms 描述里「suppress 必含 x」内联标记的通道同样合法
|
|
891
|
+
for (const desc of Object.values(entry?.forms || {})) {
|
|
892
|
+
if (typeof desc !== "string") continue;
|
|
893
|
+
for (const m of desc.matchAll(/suppress\s*必含\s*([a-z][a-z0-9_]*)/gi)) names.add(m[1]);
|
|
894
|
+
}
|
|
895
|
+
return names;
|
|
896
|
+
};
|
|
880
897
|
|
|
881
898
|
/** 通道收口证据:@closed 标记 或(css_vars 键)关闭值覆写 */
|
|
882
899
|
function channelEvidence(entry, ch) {
|
|
@@ -926,7 +943,18 @@ function visibleClosureRule(change) {
|
|
|
926
943
|
if (typeof change.form === "string" && change.form) {
|
|
927
944
|
const forms = entry.forms && typeof entry.forms === "object" ? Object.keys(entry.forms) : [];
|
|
928
945
|
const rules = entry.suppress_rules || {};
|
|
929
|
-
|
|
946
|
+
// modes 型条目(forms 值为数组的枚举字典,如 admin.content.container 的 mode: ["fixed","scroll","auto"]):
|
|
947
|
+
// form 合法值取数组并集
|
|
948
|
+
const modeValues = [];
|
|
949
|
+
for (const v of Object.values(entry.forms || {})) {
|
|
950
|
+
if (Array.isArray(v)) for (const x of v) if (typeof x === "string") modeValues.push(x);
|
|
951
|
+
}
|
|
952
|
+
if (
|
|
953
|
+
forms.length &&
|
|
954
|
+
!forms.includes(change.form) &&
|
|
955
|
+
!(change.form in rules) &&
|
|
956
|
+
!modeValues.includes(change.form)
|
|
957
|
+
) {
|
|
930
958
|
err(
|
|
931
959
|
"E15",
|
|
932
960
|
`${change.id} 的 form="${change.form}" 不在词典 forms 枚举 [${forms.join("、")}] 内 —— 项目侧无规则可挂(壳层零规则),声明悬空。形态值只能取词典已支持的枚举;确需新形态先走 pending 补词典。`,
|
|
@@ -1392,6 +1420,8 @@ const MIN_ANY_BOX = 24;
|
|
|
1392
1420
|
path.resolve(SKILL_ROOT, val),
|
|
1393
1421
|
path.resolve(SKILL_ROOT, "..", val),
|
|
1394
1422
|
path.resolve(PROJECT, "..", val),
|
|
1423
|
+
// 设计侧 page-specs 根(效果图 / 登记表以 page-specs 根为相对基座交付)
|
|
1424
|
+
path.resolve(SKILL_ROOT, "..", "project-ui-design", "references", "page-specs", val),
|
|
1395
1425
|
];
|
|
1396
1426
|
if (!cands.some((p) => fs.existsSync(p))) {
|
|
1397
1427
|
err(
|
|
@@ -1483,6 +1513,107 @@ const MIN_ANY_BOX = 24;
|
|
|
1483
1513
|
}
|
|
1484
1514
|
})();
|
|
1485
1515
|
|
|
1516
|
+
// ── E18 激活态消费者存活断言(成对落地 + 伪元素对决)──────────
|
|
1517
|
+
// 失效模式:菜单激活态令牌 --vts-theme-menu-active-before 出厂 transparent 且全项目无消费者。
|
|
1518
|
+
// 设计侧声明 indicator_* 形态(或 menu_active_indicator 字段)后:
|
|
1519
|
+
// ① 设计层不新建 ::before/::after 消费者 → 令牌仍透明、无消费点,竖条不可见;
|
|
1520
|
+
// ② 建了消费者但令牌从未供值(仍 transparent)→ 消费者渲染但不可见;
|
|
1521
|
+
// ③ 消费者与出厂 sidebar.scss 的同名 ::before 胶囊(specificity 更高 + !important 背景)
|
|
1522
|
+
// 对决输了 → 竖条几何整体不渲染。
|
|
1523
|
+
// 判据(词典「激活态消费者成对落地」标记驱动):三者缺一即 ERROR。
|
|
1524
|
+
(function checkE18() {
|
|
1525
|
+
const marked = dictEntries
|
|
1526
|
+
.filter(({ entry }) =>
|
|
1527
|
+
Array.isArray(entry.preconditions) &&
|
|
1528
|
+
entry.preconditions.some((p) => typeof p === "string" && p.includes("激活态消费者成对落地")))
|
|
1529
|
+
.map(({ sid, entry }) => ({ sid, entry }));
|
|
1530
|
+
if (!marked.length) {
|
|
1531
|
+
info("E18", "激活态消费者成对落地:词典无标记条目,跳过");
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
// 令牌最终定义值(projectText → designCss 顺序近似层叠,取最后定义;支持一层 var 链解析)
|
|
1536
|
+
const finalVarValue = (name, seen = new Set()) => {
|
|
1537
|
+
let last = null;
|
|
1538
|
+
for (const t of [projectText, designCss].filter(Boolean)) {
|
|
1539
|
+
const re = new RegExp(`${name.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&")}\\s*:\\s*([^;]+);`, "g");
|
|
1540
|
+
for (const m of t.matchAll(re)) last = m[1].trim();
|
|
1541
|
+
}
|
|
1542
|
+
if (last == null) return null;
|
|
1543
|
+
const varRef = last.match(/^var\(\s*(--[\w-]+)/);
|
|
1544
|
+
if (varRef && !seen.has(name)) {
|
|
1545
|
+
seen.add(name);
|
|
1546
|
+
const inner = finalVarValue(varRef[1], seen);
|
|
1547
|
+
return inner != null ? inner : last;
|
|
1548
|
+
}
|
|
1549
|
+
return last;
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
for (const { sid, entry } of marked) {
|
|
1553
|
+
const change = (changeset?.changes || []).find((c) => c.id === sid);
|
|
1554
|
+
if (!change) continue;
|
|
1555
|
+
const form = String(change.form || "");
|
|
1556
|
+
const style = change.style && typeof change.style === "object" ? change.style : {};
|
|
1557
|
+
const declaresIndicator =
|
|
1558
|
+
/indicator/.test(form) ||
|
|
1559
|
+
"menu_active_indicator" in style ||
|
|
1560
|
+
Object.keys(style).some((k) => /^active_indicator/.test(k));
|
|
1561
|
+
if (!declaresIndicator) continue;
|
|
1562
|
+
|
|
1563
|
+
const vars = Object.values(entry.css_vars || {})
|
|
1564
|
+
.filter((v) => typeof v === "string" && /active/.test(v));
|
|
1565
|
+
const indicatorVar = vars.find((v) => /before/.test(v)) || vars[0];
|
|
1566
|
+
if (!indicatorVar) continue;
|
|
1567
|
+
|
|
1568
|
+
// 断言①:设计层存在该令牌的消费者(var() 引用)
|
|
1569
|
+
const consumedInDesign = designRules.some((r) =>
|
|
1570
|
+
Object.values(r.decls).some((v) => String(v).includes(`var(${indicatorVar}`)),
|
|
1571
|
+
);
|
|
1572
|
+
if (!consumedInDesign) {
|
|
1573
|
+
err(
|
|
1574
|
+
"E18",
|
|
1575
|
+
`激活态消费者成对落地:${sid} 声明了指示条形态(form=${form || "—"}),但设计层没有任何规则消费 ` +
|
|
1576
|
+
`${indicatorVar} —— 只供值不建消费者 = 未施工(令牌出厂 transparent,全项目无消费点),竖条不可见。` +
|
|
1577
|
+
`修复:在 design-shell 新建 ::before/::after 消费者引用 var(${indicatorVar})。`,
|
|
1578
|
+
);
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// 断言②:令牌最终定义非 transparent/none/初始值
|
|
1583
|
+
const finalVal = finalVarValue(indicatorVar);
|
|
1584
|
+
if (finalVal && /^(transparent|none|initial|unset|inherit)$/i.test(finalVal.replace(/!important\s*$/i, "").trim())) {
|
|
1585
|
+
err(
|
|
1586
|
+
"E18",
|
|
1587
|
+
`激活态消费者成对落地:${indicatorVar} 消费者已建,但最终定义仍为 ${finalVal.trim()}(出厂中性基线)——` +
|
|
1588
|
+
`消费者在渲染,色值透明 = 竖条不可见。修复:在条目 style_scope(如 .sidebar-container)内显式供值 ` +
|
|
1589
|
+
`(非透明设计色),或在对应 html[data-theme] 主题块确认已有非透明定义。`,
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// 断言③(警告级):消费者是伪元素规则且与出厂胶囊对决——无 !important 背景 / 无提权链则提示
|
|
1594
|
+
const consumerRules = designRules.filter((r) =>
|
|
1595
|
+
Object.values(r.decls).some((v) => String(v).includes(`var(${indicatorVar}`)),
|
|
1596
|
+
);
|
|
1597
|
+
for (const r of consumerRules) {
|
|
1598
|
+
const isPseudo = /::(before|after)/.test(r.selector);
|
|
1599
|
+
const bgImportant = /important/i.test(String(r.decls["background"] || r.decls["background-color"] || ""));
|
|
1600
|
+
const elevated = /(^|\s)html\b[\s>]*body\b/.test(r.selector) || /body\s+\./.test(r.selector);
|
|
1601
|
+
if (isPseudo && !bgImportant && !elevated) {
|
|
1602
|
+
warn(
|
|
1603
|
+
"E18",
|
|
1604
|
+
`激活态消费者成对落地:${r.selector} 消费 ${indicatorVar} 但既无 !important 背景也无 html body 提权链——` +
|
|
1605
|
+
`出厂 sidebar.scss 的同名 ::before 胶囊(!important 背景)对决大概率获胜,指示条几何可能整体不渲染。` +
|
|
1606
|
+
`修复:背景加 !important 或用 html body 前缀提权(词典 priority.strategy=deep_qualified)。`,
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
const checkedAny = marked.some(({ sid }) => (changeset?.changes || []).some((c) => c.id === sid));
|
|
1612
|
+
if (checkedAny && !errors.some((e) => e.id === "E18") && !warnings.some((w) => w.id === "E18")) {
|
|
1613
|
+
info("E18", "激活态消费者成对落地:消费者存在、令牌非透明、对决权重足够 ✓");
|
|
1614
|
+
}
|
|
1615
|
+
})();
|
|
1616
|
+
|
|
1486
1617
|
const result = { project: PROJECT, errors, warnings, infos };
|
|
1487
1618
|
|
|
1488
1619
|
const CHECK_TITLES = {
|
|
@@ -1502,6 +1633,7 @@ const CHECK_TITLES = {
|
|
|
1502
1633
|
E14: "列宽预算链自洽",
|
|
1503
1634
|
E16: "引用完整性",
|
|
1504
1635
|
E17: "层间令牌链对账",
|
|
1636
|
+
E18: "激活态消费者成对落地",
|
|
1505
1637
|
SID: "@sid 覆盖率",
|
|
1506
1638
|
};
|
|
1507
1639
|
|