iter(g185): 分割线统一改走细分边框令牌
This commit is contained in:
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "ui-arch-registry-index/0.1",
|
||||
"generatedAt": "2026-10-26T09:29:34.397Z",
|
||||
"generatedAt": "2026-10-26T09:45:15.809Z",
|
||||
"repoRoot": ".",
|
||||
"packages": [
|
||||
{
|
||||
@@ -3730,7 +3730,7 @@
|
||||
"ua style:注释规范门禁(导出必须 /*** ***/、接口字段行尾注释、行注释中文),违规退出码 1",
|
||||
"ua verify:清单一致性门禁(id 唯一 / exports 对应 / props 必带 n t d / steps≥3 / demo 锚点存在)",
|
||||
"ua commit-lint <文件|message>:提交信息门禁(type 枚举 / scope 规则 / subject 中文祈使 ≤50 字符),规范见 COMMITTING.md,违规退出码 1",
|
||||
"ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里五类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数",
|
||||
"ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里各类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环/内距/控件高度/字重/行高/层级/边框色)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数",
|
||||
"ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||
],
|
||||
"keyTypes": [
|
||||
@@ -3750,9 +3750,9 @@
|
||||
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)",
|
||||
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
||||
"查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)",
|
||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十一组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
||||
"改完样式跑 npm run audit:visual:五类硬编码计数不得高于 .ua/visual-baseline.json(棘轮只减不增);字面量可用 npm run visual:migrate 幂等改写成令牌",
|
||||
"改完样式跑 npm run audit:visual:各类硬编码计数不得高于 .ua/visual-baseline.json(棘轮只减不增);字面量可用 npm run visual:migrate 幂等改写成令牌",
|
||||
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||
],
|
||||
"components": []
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "视觉漂移基线:五类硬编码视觉字面量的允许上限,任一类超出即 ua audit:visual 退出码 1;迁移后用 --baseline 重写",
|
||||
"$schema": "视觉漂移基线:各类硬编码视觉字面量的允许上限,任一类超出即 ua audit:visual 退出码 1;迁移后用 --baseline 重写",
|
||||
"file": "packages/skin/ui/ui.css",
|
||||
"commit": "551b2f6",
|
||||
"generatedAt": "2026-10-26T09:40:14.168Z",
|
||||
"commit": "ecd24d5",
|
||||
"generatedAt": "2026-10-26T09:45:21.406Z",
|
||||
"lines": 4780,
|
||||
"total": 40,
|
||||
"counts": {
|
||||
@@ -15,6 +15,7 @@
|
||||
"control-h-literal": 0,
|
||||
"weight-literal": 0,
|
||||
"leading-literal": 0,
|
||||
"z-literal": 0
|
||||
"z-literal": 0,
|
||||
"border-literal": 0
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||
|
||||
> 自动生成于 2026-10-26T09:29:34.397Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||
> 自动生成于 2026-10-26T09:45:15.809Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||
|
||||
## 快速上手
|
||||
@@ -43,9 +43,9 @@
|
||||
1. 装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)
|
||||
2. 查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)
|
||||
3. 查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)
|
||||
4. 查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)
|
||||
4. 查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十一组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)
|
||||
5. 改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)
|
||||
6. 改完样式跑 npm run audit:visual:五类硬编码计数不得高于 .ua/visual-baseline.json(棘轮只减不增);字面量可用 npm run visual:migrate 幂等改写成令牌
|
||||
6. 改完样式跑 npm run audit:visual:各类硬编码计数不得高于 .ua/visual-baseline.json(棘轮只减不增);字面量可用 npm run visual:migrate 幂等改写成令牌
|
||||
7. 在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe
|
||||
|
||||
## @ui-arch/ui(skin-dom)v0.1.0
|
||||
@@ -2122,7 +2122,7 @@ API 速览:
|
||||
- ua style:注释规范门禁(导出必须 /*** ***/、接口字段行尾注释、行注释中文),违规退出码 1
|
||||
- ua verify:清单一致性门禁(id 唯一 / exports 对应 / props 必带 n t d / steps≥3 / demo 锚点存在)
|
||||
- ua commit-lint <文件|message>:提交信息门禁(type 枚举 / scope 规则 / subject 中文祈使 ≤50 字符),规范见 COMMITTING.md,违规退出码 1
|
||||
- ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里五类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数
|
||||
- ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里各类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环/内距/控件高度/字重/行高/层级/边框色)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数
|
||||
- ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe
|
||||
|
||||
一行用法:
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
- ua style:注释规范门禁(导出必须 /*** ***/、接口字段行尾注释、行注释中文),违规退出码 1
|
||||
- ua verify:清单一致性门禁(id 唯一 / exports 对应 / props 必带 n t d / steps≥3 / demo 锚点存在)
|
||||
- ua commit-lint <文件|message>:提交信息门禁(type 枚举 / scope 规则 / subject 中文祈使 ≤50 字符),规范见 COMMITTING.md,违规退出码 1
|
||||
- ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里五类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数
|
||||
- ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里各类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环/内距/控件高度/字重/行高/层级/边框色)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数
|
||||
- ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe
|
||||
- 用法: `node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id>|docs|tokens|style|verify|commit-lint|audit:visual|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual`
|
||||
- 约定: 零依赖:只用 node 标准库,Node >= 18
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
--ua-leading-normal: 1.55; /* 正文档:多行正文、说明文字 */
|
||||
|
||||
/* ---- 边框:细分(比基础边框更淡,用于分割线,避免 1px 线过重) ---- */
|
||||
--ua-border-subtle: color-mix(in srgb, var(--ua-color-border) 60%, transparent); /* 细分边框色:表格分割线、卡片内分隔 */
|
||||
--ua-border-subtle: color-mix(in srgb, var(--ua-color-border) 60%, transparent); /* 细分边框色(专用于分割线):表格行线 / 卡片页脚 / 弹窗抽屉页头页脚 / 列表项 / 选项卡底边 / 折叠面板与步骤条连接线 / 分隔线组件 */
|
||||
|
||||
/* ---- 阴影:四档 elevation,柔和优先(扩散大、透明度低) ---- */
|
||||
--ua-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.06); /* 1 档:贴地投影,用于卡片 / 输入组 / 轻浮起 */
|
||||
|
||||
+19
-19
@@ -102,7 +102,7 @@
|
||||
gap: var(--ua-space-1);
|
||||
margin-top: var(--ua-space-3);
|
||||
padding-top: var(--ua-space-2);
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-card-borderless {
|
||||
border: none;
|
||||
@@ -121,7 +121,7 @@
|
||||
.ua-table th,
|
||||
.ua-table td {
|
||||
padding: var(--ua-space-table-cell);
|
||||
border-bottom: 1px solid var(--ua-color-border);
|
||||
border-bottom: 1px solid var(--ua-border-subtle);
|
||||
text-align: left;
|
||||
font-size: var(--ua-font-size-md);
|
||||
white-space: nowrap;
|
||||
@@ -134,7 +134,7 @@
|
||||
background: var(--ua-color-surface);
|
||||
font-weight: var(--ua-weight-medium);
|
||||
color: var(--ua-color-text-muted);
|
||||
box-shadow: inset 0 -1px 0 var(--ua-color-border);
|
||||
box-shadow: inset 0 -1px 0 var(--ua-border-subtle);
|
||||
}
|
||||
.ua-table th.ua-sortable {
|
||||
cursor: pointer;
|
||||
@@ -439,7 +439,7 @@ body.ua-col-resizing {
|
||||
}
|
||||
.ua-option-group:not(:first-child) {
|
||||
margin-top: var(--ua-space-1);
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
padding-top: var(--ua-space-2);
|
||||
}
|
||||
.ua-option {
|
||||
@@ -563,7 +563,7 @@ body.ua-col-resizing {
|
||||
.ua-menu-divider {
|
||||
height: 1px;
|
||||
margin: var(--ua-space-1) var(--ua-space-05);
|
||||
background: var(--ua-color-border);
|
||||
background: var(--ua-border-subtle);
|
||||
}
|
||||
|
||||
/* —— 面包屑 —— */
|
||||
@@ -666,7 +666,7 @@ body.ua-col-resizing {
|
||||
background: var(--ua-color-bg);
|
||||
}
|
||||
.ua-acc-item + .ua-acc-item {
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-acc-head {
|
||||
display: flex;
|
||||
@@ -976,7 +976,7 @@ body.ua-col-resizing {
|
||||
top: 30px;
|
||||
bottom: 2px;
|
||||
width: 1px;
|
||||
background: var(--ua-color-border);
|
||||
background: var(--ua-border-subtle);
|
||||
}
|
||||
.ua-stepper.is-vertical .ua-step:last-child::after {
|
||||
display: none; /* 末步没有下一段可连 */
|
||||
@@ -999,7 +999,7 @@ body.ua-col-resizing {
|
||||
height: 1px;
|
||||
margin-top: 13px;
|
||||
margin-right: var(--ua-space-2);
|
||||
background: var(--ua-color-border);
|
||||
background: var(--ua-border-subtle);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ua-step-dot {
|
||||
@@ -1140,12 +1140,12 @@ button.ua-step-dot:hover {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--ua-color-border);
|
||||
background: var(--ua-border-subtle);
|
||||
}
|
||||
.ua-divider-dashed::before,
|
||||
.ua-divider-dashed::after {
|
||||
background: none;
|
||||
border-top: 1px dashed var(--ua-color-border);
|
||||
border-top: 1px dashed var(--ua-border-subtle);
|
||||
}
|
||||
.ua-divider-label {
|
||||
font-size: var(--ua-font-size-sm);
|
||||
@@ -1165,7 +1165,7 @@ button.ua-step-dot:hover {
|
||||
}
|
||||
.ua-divider-vertical.ua-divider-dashed {
|
||||
background: none;
|
||||
border-left: 1px dashed var(--ua-color-border); /* 垂直虚线走边框 */
|
||||
border-left: 1px dashed var(--ua-border-subtle); /* 垂直虚线走边框 */
|
||||
}
|
||||
|
||||
/* —— 徽标 —— */
|
||||
@@ -1573,7 +1573,7 @@ button.ua-step-dot:hover {
|
||||
gap: var(--ua-space-1);
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border-bottom: 1px solid var(--ua-color-border);
|
||||
border-bottom: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-tab {
|
||||
padding: 7px var(--ua-space-35);
|
||||
@@ -1820,7 +1820,7 @@ button.ua-step-dot:hover {
|
||||
justify-content: flex-end;
|
||||
gap: var(--ua-space-2);
|
||||
padding: var(--ua-space-3) var(--ua-space-4);
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
|
||||
/* —— 弹窗 —— */
|
||||
@@ -1862,7 +1862,7 @@ button.ua-step-dot:hover {
|
||||
justify-content: flex-end;
|
||||
gap: var(--ua-space-2);
|
||||
padding: var(--ua-space-3) var(--ua-space-4);
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
@keyframes ua-fade {
|
||||
from {
|
||||
@@ -1880,7 +1880,7 @@ button.ua-step-dot:hover {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--ua-space-3) var(--ua-space-4);
|
||||
border-bottom: 1px solid var(--ua-color-border);
|
||||
border-bottom: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-modal-title {
|
||||
margin: 0;
|
||||
@@ -2157,7 +2157,7 @@ button.ua-step-dot:hover {
|
||||
top: 6px;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background: var(--ua-color-border);
|
||||
background: var(--ua-border-subtle);
|
||||
}
|
||||
.ua-tl-right::before {
|
||||
left: auto;
|
||||
@@ -2496,10 +2496,10 @@ button.ua-step-dot:hover {
|
||||
.ua-list-header {
|
||||
font-weight: var(--ua-weight-semibold);
|
||||
color: var(--ua-color-text);
|
||||
border-bottom: 1px solid var(--ua-color-border);
|
||||
border-bottom: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-list-footer {
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-list-body {
|
||||
display: flex;
|
||||
@@ -2513,7 +2513,7 @@ button.ua-step-dot:hover {
|
||||
transition: background var(--ua-duration-fast) ease;
|
||||
}
|
||||
.ua-list-item + .ua-list-item {
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
border-top: 1px solid var(--ua-border-subtle);
|
||||
}
|
||||
.ua-list-clickable {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -62,7 +62,7 @@ function writeBaseline(root, result) {
|
||||
const file = path.join(root, BASELINE_REL);
|
||||
const total = KIND_META.reduce((sum, meta) => sum + (result.counts[meta.key] ?? 0), 0);
|
||||
const data = {
|
||||
$schema: '视觉漂移基线:五类硬编码视觉字面量的允许上限,任一类超出即 ua audit:visual 退出码 1;迁移后用 --baseline 重写',
|
||||
$schema: '视觉漂移基线:各类硬编码视觉字面量的允许上限,任一类超出即 ua audit:visual 退出码 1;迁移后用 --baseline 重写',
|
||||
file: UI_CSS_REL,
|
||||
commit: shortCommit(root),
|
||||
generatedAt: new Date().toISOString(),
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/*** 皮肤包样式表相对仓库根的路径(迁移与审计共同的目标文件) ***/
|
||||
export const UI_CSS_REL = 'packages/skin/ui/ui.css';
|
||||
|
||||
/*** 作用:五类硬编码的键名、中文名与判定口径,审计输出与报告都按这个顺序 ***/
|
||||
/*** 作用:各类硬编码的键名、中文名与判定口径,审计输出与报告都按这个顺序 ***/
|
||||
export const KIND_META = [
|
||||
{
|
||||
key: 'font-size-literal',
|
||||
@@ -61,6 +61,11 @@ export const KIND_META = [
|
||||
label: '层级字面值',
|
||||
hint: 'z-index 写死数字,应改用 --ua-z-* 五档(组件内 1/2 微排序豁免)',
|
||||
},
|
||||
{
|
||||
key: 'border-literal',
|
||||
label: '边框色字面值',
|
||||
hint: 'border/border-color 写死色值(rgba()/#hex),组件轮廓用 --ua-color-border、分割线用 --ua-border-subtle',
|
||||
},
|
||||
];
|
||||
|
||||
/*** 作用:需要扫描的 CSS 属性白名单(其余属性本轮不动;用白名单顺带避开伪类选择器误判) ***/
|
||||
@@ -92,6 +97,30 @@ const SCAN_PROPS = new Set([
|
||||
'font-weight',
|
||||
'line-height',
|
||||
'z-index',
|
||||
'border',
|
||||
'border-top',
|
||||
'border-right',
|
||||
'border-bottom',
|
||||
'border-left',
|
||||
'border-color',
|
||||
'border-top-color',
|
||||
'border-right-color',
|
||||
'border-bottom-color',
|
||||
'border-left-color',
|
||||
]);
|
||||
|
||||
/*** 作用:边框类属性集合(轮廓与分割线共用一套色值口径,禁用字面色) ***/
|
||||
const BORDER_PROPS = new Set([
|
||||
'border',
|
||||
'border-top',
|
||||
'border-right',
|
||||
'border-bottom',
|
||||
'border-left',
|
||||
'border-color',
|
||||
'border-top-color',
|
||||
'border-right-color',
|
||||
'border-bottom-color',
|
||||
'border-left-color',
|
||||
]);
|
||||
|
||||
/*** 作用:内距类属性集合(迁移与统计共用同一判定) ***/
|
||||
@@ -217,7 +246,7 @@ export function blankComments(src) {
|
||||
|
||||
/*** 作用:逐条产出「属性 + 值」及其在原文中的偏移;只认白名单属性且必须以分号收尾(避开伪类选择器) ***/
|
||||
export function eachDeclaration(code) {
|
||||
const re = /(padding-top|padding-right|padding-bottom|padding-left|padding|margin-top|margin-right|margin-bottom|margin-left|margin|row-gap|column-gap|gap|font-weight|line-height|z-index|min-height|max-height|height|transition-duration|animation-duration|transition|animation|font-size|box-shadow|border-radius|outline)\s*:\s*([^;{}]*);/gi;
|
||||
const re = /(border-top-color|border-right-color|border-bottom-color|border-left-color|border-color|border-top|border-right|border-bottom|border-left|border|padding-top|padding-right|padding-bottom|padding-left|padding|margin-top|margin-right|margin-bottom|margin-left|margin|row-gap|column-gap|gap|font-weight|line-height|z-index|min-height|max-height|height|transition-duration|animation-duration|transition|animation|font-size|box-shadow|border-radius|outline)\s*:\s*([^;{}]*);/gi;
|
||||
const list = [];
|
||||
for (const m of code.matchAll(re)) {
|
||||
const prop = m[1].toLowerCase();
|
||||
@@ -350,6 +379,15 @@ function migrateZ(core) {
|
||||
return { kind: 'z-literal', value: token };
|
||||
}
|
||||
|
||||
/*** 作用:迁移单条边框:纯黑 rgba 边(历史上手写的「深一层黑边」)归到基础边框色;其余留在门禁里由人按轮廓/分割线语义定位 ***/
|
||||
function migrateBorder(prop, core) {
|
||||
if (!BORDER_PROPS.has(prop)) return null;
|
||||
const value = squash(core);
|
||||
const next = value.replace(/rgba\(\s*0\s*,\s*0\s*,\s*0\s*,\s*[\d.]+\s*\)/g, 'var(--ua-color-border)'); // 空格宽容,避免只认一种写法
|
||||
if (next === value) return null;
|
||||
return { kind: 'border-literal', value: next };
|
||||
}
|
||||
|
||||
/*** 作用:判定单条声明是否需要迁移,返回 { kind, value } 或 null(幂等:已是令牌就返回 null) ***/
|
||||
export function migrateDeclaration(prop, rawValue) {
|
||||
const { core, tail } = splitImportant(rawValue);
|
||||
@@ -374,6 +412,8 @@ export function migrateDeclaration(prop, rawValue) {
|
||||
result = migrateLeading(core);
|
||||
} else if (prop === 'z-index') {
|
||||
result = migrateZ(core);
|
||||
} else {
|
||||
result = migrateBorder(prop, core); // 边框类:只收敛纯黑 rgba 边
|
||||
}
|
||||
if (!result) return null;
|
||||
return { kind: result.kind, value: result.value + tail };
|
||||
@@ -441,10 +481,16 @@ function detect(prop, rawValue, key) {
|
||||
if (value === '1' || value === '2') return 0; // 组件内微排序(表头压行、水印叠层、头像悬停),不是全局层级
|
||||
return /^\d+$/.test(value) ? 1 : 0;
|
||||
}
|
||||
if (key === 'border-literal') {
|
||||
if (!BORDER_PROPS.has(prop)) return 0;
|
||||
if (value === 'none' || value === '0' || value === 'inherit') return 0; // 无边框与继承不算色值漂移
|
||||
const stripped = value.replace(/var\(--ua-[\w-]+\)/g, ' '); // 已是令牌的色先剔除
|
||||
return /(#[0-9a-f]{3,8}\b|rgba?\(|hsla?\()/i.test(stripped) ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** 作用:扫描整段 CSS,返回五类硬编码的计数与命中行号(审计命令的唯一统计口径) ***/
|
||||
/*** 作用:扫描整段 CSS,返回各类硬编码的计数与命中行号(审计命令的唯一统计口径) ***/
|
||||
export function scanSource(src) {
|
||||
const code = blankComments(src);
|
||||
const lineAt = (offset) => {
|
||||
@@ -487,7 +533,7 @@ export function migrateSource(src) {
|
||||
return { text: out, counts };
|
||||
}
|
||||
|
||||
/*** 作用:把五类计数拍平成「类别: 数量」数组,供审计报告与基线文件共用同一顺序 ***/
|
||||
/*** 作用:把各类计数拍平成「类别: 数量」数组,供审计报告与基线文件共用同一顺序 ***/
|
||||
export function countRows(counts) {
|
||||
return KIND_META.map((meta) => ({ ...meta, count: counts[meta.key] ?? 0 }));
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"ua style:注释规范门禁(导出必须 /*** ***/、接口字段行尾注释、行注释中文),违规退出码 1",
|
||||
"ua verify:清单一致性门禁(id 唯一 / exports 对应 / props 必带 n t d / steps≥3 / demo 锚点存在)",
|
||||
"ua commit-lint <文件|message>:提交信息门禁(type 枚举 / scope 规则 / subject 中文祈使 ≤50 字符),规范见 COMMITTING.md,违规退出码 1",
|
||||
"ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里五类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数",
|
||||
"ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里各类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环/内距/控件高度/字重/行高/层级/边框色)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数",
|
||||
"ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||
],
|
||||
"keyTypes": [
|
||||
@@ -39,9 +39,9 @@
|
||||
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)",
|
||||
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
||||
"查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)",
|
||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十一组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
||||
"改完样式跑 npm run audit:visual:五类硬编码计数不得高于 .ua/visual-baseline.json(棘轮只减不增);字面量可用 npm run visual:migrate 幂等改写成令牌",
|
||||
"改完样式跑 npm run audit:visual:各类硬编码计数不得高于 .ua/visual-baseline.json(棘轮只减不增);字面量可用 npm run visual:migrate 幂等改写成令牌",
|
||||
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||
],
|
||||
"components": []
|
||||
|
||||
Reference in New Issue
Block a user