iter(g229): 混色浓度令牌化并入视觉棘轮
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-26T12:29:16.234Z",
|
"generatedAt": "2026-10-26T12:39:15.584Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -3884,7 +3884,7 @@
|
|||||||
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)",
|
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 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 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 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 输出结构化数组;写样式前先查,禁止硬编码。令牌分十二组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,color-mix 混入浓度用 --ua-alpha-soft/tint/line/mid/strong/heavy,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
"改完清单跑 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"
|
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"weight-literal": 0,
|
"weight-literal": 0,
|
||||||
"leading-literal": 0,
|
"leading-literal": 0,
|
||||||
"z-literal": 0,
|
"z-literal": 0,
|
||||||
"border-literal": 0
|
"border-literal": 0,
|
||||||
|
"mix-literal": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-26T12:29:16.234Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-26T12:39:15.584Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
1. 接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)
|
1. 接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 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 出原始清单)
|
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)
|
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 输出结构化数组;写样式前先查,禁止硬编码。令牌分十二组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,color-mix 混入浓度用 --ua-alpha-soft/tint/line/mid/strong/heavy,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)
|
||||||
5. 改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)
|
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
|
7. 在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe
|
||||||
@@ -2230,11 +2230,17 @@ node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id>|docs|tokens
|
|||||||
- --ua-color-accent: #185fa5(暗色 #378add)
|
- --ua-color-accent: #185fa5(暗色 #378add)
|
||||||
- --ua-color-accent-contrast: #ffffff(暗色 #042c53)
|
- --ua-color-accent-contrast: #ffffff(暗色 #042c53)
|
||||||
- --ua-color-accent-soft: color-mix(in srgb, var(--ua-color-accent) 72%, var(--ua-color-bg))(暗色 color-mix(in srgb, var(--ua-color-accent) 82%, var(--ua-color-bg)))
|
- --ua-color-accent-soft: color-mix(in srgb, var(--ua-color-accent) 72%, var(--ua-color-bg))(暗色 color-mix(in srgb, var(--ua-color-accent) 82%, var(--ua-color-bg)))
|
||||||
- --ua-color-tint-accent: color-mix(in srgb, var(--ua-color-accent) 10%, transparent)(暗色 color-mix(in srgb, var(--ua-color-accent) 14%, transparent))
|
- --ua-color-tint-accent: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-soft), transparent)(暗色 color-mix(in srgb, var(--ua-color-accent) 14%, transparent))
|
||||||
- --ua-color-tint-accent-weak: color-mix(in srgb, var(--ua-color-accent) 5%, transparent)(暗色 color-mix(in srgb, var(--ua-color-accent) 8%, transparent))
|
- --ua-color-tint-accent-weak: color-mix(in srgb, var(--ua-color-accent) 5%, transparent)(暗色 color-mix(in srgb, var(--ua-color-accent) 8%, transparent))
|
||||||
- --ua-color-danger: #a32d2d(暗色 #d96a6a)
|
- --ua-color-danger: #a32d2d(暗色 #d96a6a)
|
||||||
- --ua-color-success: #0f6e56(暗色 #4fc39e)
|
- --ua-color-success: #0f6e56(暗色 #4fc39e)
|
||||||
- --ua-color-warning: #9a6b1f(暗色 #d9a94f)
|
- --ua-color-warning: #9a6b1f(暗色 #d9a94f)
|
||||||
|
- --ua-alpha-soft: 10%
|
||||||
|
- --ua-alpha-tint: 18%
|
||||||
|
- --ua-alpha-line: 30%
|
||||||
|
- --ua-alpha-mid: 45%
|
||||||
|
- --ua-alpha-strong: 55%
|
||||||
|
- --ua-alpha-heavy: 70%
|
||||||
- --ua-radius-sm: 4px
|
- --ua-radius-sm: 4px
|
||||||
- --ua-radius-md: 8px
|
- --ua-radius-md: 8px
|
||||||
- --ua-radius-lg: 12px
|
- --ua-radius-lg: 12px
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* @ui-arch design tokens - light theme defaults + dark theme overrides
|
/* @ui-arch design tokens - light theme defaults + dark theme overrides
|
||||||
分组:颜色 / 圆角 / 间距 / 字号 / 字距 / 字重与行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级
|
分组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字距 / 字重与行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级
|
||||||
约定:皮肤包(packages/skin/ui/ui.css)只能消费 var(--ua-*),禁止硬编码颜色、阴影、时长、字号;
|
约定:皮肤包(packages/skin/ui/ui.css)只能消费 var(--ua-*),禁止硬编码颜色、阴影、时长、字号;
|
||||||
本文件是令牌唯一来源,ua tokens / llms-full.txt / MCP get_tokens 全部从这里派生。 */
|
本文件是令牌唯一来源,ua tokens / llms-full.txt / MCP get_tokens 全部从这里派生。 */
|
||||||
:root {
|
:root {
|
||||||
@@ -22,12 +22,20 @@
|
|||||||
--ua-color-accent: #185fa5; /* 强调色:主操作、选中态、焦点环底色 */
|
--ua-color-accent: #185fa5; /* 强调色:主操作、选中态、焦点环底色 */
|
||||||
--ua-color-accent-contrast: #ffffff; /* 强调色上的文字色:保证主按钮对比度 */
|
--ua-color-accent-contrast: #ffffff; /* 强调色上的文字色:保证主按钮对比度 */
|
||||||
--ua-color-accent-soft: color-mix(in srgb, var(--ua-color-accent) 72%, var(--ua-color-bg)); /* 柔和强调色:细线 / 指示条 / 内嵌焦点环用,纯 accent 做 2px 实线会发刺 */
|
--ua-color-accent-soft: color-mix(in srgb, var(--ua-color-accent) 72%, var(--ua-color-bg)); /* 柔和强调色:细线 / 指示条 / 内嵌焦点环用,纯 accent 做 2px 实线会发刺 */
|
||||||
--ua-color-tint-accent: color-mix(in srgb, var(--ua-color-accent) 10%, transparent); /* 语义淡底标准档:选中底、激活项底 */
|
--ua-color-tint-accent: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-soft), transparent); /* 语义淡底标准档:选中底、激活项底 */
|
||||||
--ua-color-tint-accent-weak: color-mix(in srgb, var(--ua-color-accent) 5%, transparent); /* 语义淡底弱档:悬停底、极弱强调底 */
|
--ua-color-tint-accent-weak: color-mix(in srgb, var(--ua-color-accent) 5%, transparent); /* 语义淡底弱档:悬停底、极弱强调底 */
|
||||||
--ua-color-danger: #a32d2d; /* 危险色:错误、删除、校验失败 */
|
--ua-color-danger: #a32d2d; /* 危险色:错误、删除、校验失败 */
|
||||||
--ua-color-success: #0f6e56; /* 成功色:完成、通过、正向结果 */
|
--ua-color-success: #0f6e56; /* 成功色:完成、通过、正向结果 */
|
||||||
--ua-color-warning: #9a6b1f; /* 警告色:提醒、需注意但不阻断 */
|
--ua-color-warning: #9a6b1f; /* 警告色:提醒、需注意但不阻断 */
|
||||||
|
|
||||||
|
/* ---- 混色浓度:color-mix 里「混入多少」的档位,百分比亮暗通用(近档已就近收敛:12→10、16/20/24→18、40→45、65/80→70) ---- */
|
||||||
|
--ua-alpha-soft: 10%; /* 淡底档:选中底、激活项底、语义色淡底 */
|
||||||
|
--ua-alpha-tint: 18%; /* 弱强调档:hover 淡底、警示淡底、白色细纹 */
|
||||||
|
--ua-alpha-line: 30%; /* 描边调和档:边框色里混入文本色加深 */
|
||||||
|
--ua-alpha-mid: 45%; /* 中浓档:半透虚线边、淡化滚动条底 */
|
||||||
|
--ua-alpha-strong: 55%; /* 强调档:语义色图标底、强调描边 */
|
||||||
|
--ua-alpha-heavy: 70%; /* 重档:渐变端点、近实色的弱化描边 */
|
||||||
|
|
||||||
/* ---- 圆角:三档,控件用小、卡片用中、弹层用大 ---- */
|
/* ---- 圆角:三档,控件用小、卡片用中、弹层用大 ---- */
|
||||||
--ua-radius-sm: 4px; /* 小圆角:按钮 / 输入框 / 标签等控件 */
|
--ua-radius-sm: 4px; /* 小圆角:按钮 / 输入框 / 标签等控件 */
|
||||||
--ua-radius-md: 8px; /* 中圆角:卡片 / 面板 / 分组容器 */
|
--ua-radius-md: 8px; /* 中圆角:卡片 / 面板 / 分组容器 */
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
"dark": "rgba(0, 0, 0, 0.7)"
|
"dark": "rgba(0, 0, 0, 0.7)"
|
||||||
},
|
},
|
||||||
"tintAccent": {
|
"tintAccent": {
|
||||||
"light": "color-mix(in srgb, var(--ua-color-accent) 10%, transparent)",
|
"light": "color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-soft), transparent)",
|
||||||
"dark": "color-mix(in srgb, var(--ua-color-accent) 14%, transparent)"
|
"dark": "color-mix(in srgb, var(--ua-color-accent) 14%, transparent)"
|
||||||
},
|
},
|
||||||
"tintAccentWeak": {
|
"tintAccentWeak": {
|
||||||
@@ -94,6 +94,14 @@
|
|||||||
"dark": "color-mix(in srgb, var(--ua-color-accent) 82%, var(--ua-color-bg))"
|
"dark": "color-mix(in srgb, var(--ua-color-accent) 82%, var(--ua-color-bg))"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"alpha": {
|
||||||
|
"soft": "10%",
|
||||||
|
"tint": "18%",
|
||||||
|
"line": "30%",
|
||||||
|
"mid": "45%",
|
||||||
|
"strong": "55%",
|
||||||
|
"heavy": "70%"
|
||||||
|
},
|
||||||
"radius": {
|
"radius": {
|
||||||
"sm": "4px",
|
"sm": "4px",
|
||||||
"md": "8px",
|
"md": "8px",
|
||||||
@@ -245,4 +253,4 @@
|
|||||||
"modal": 400,
|
"modal": 400,
|
||||||
"toast": 500
|
"toast": 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-45
@@ -81,7 +81,7 @@
|
|||||||
}
|
}
|
||||||
/* 输入类悬停:边框加深一档,提示可交互但不抢焦点 */
|
/* 输入类悬停:边框加深一档,提示可交互但不抢焦点 */
|
||||||
.ua-input:hover:not(:disabled):not(:focus-visible) {
|
.ua-input:hover:not(:disabled):not(:focus-visible) {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-text) 30%, var(--ua-color-border));
|
border-color: color-mix(in srgb, var(--ua-color-text) var(--ua-alpha-line), var(--ua-color-border));
|
||||||
}
|
}
|
||||||
.ua-input:focus-visible {
|
.ua-input:focus-visible {
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
.ua-card-hoverable:hover {
|
.ua-card-hoverable:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: var(--ua-shadow-2); /* 悬停浮起:从 1 档升到 2 档,一档之差刚好可感 */
|
box-shadow: var(--ua-shadow-2); /* 悬停浮起:从 1 档升到 2 档,一档之差刚好可感 */
|
||||||
border-color: color-mix(in srgb, var(--ua-color-border) 55%, transparent); /* 阴影接手层次,边框同步减淡,两者配合而非叠加 */
|
border-color: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-strong), transparent); /* 阴影接手层次,边框同步减淡,两者配合而非叠加 */
|
||||||
}
|
}
|
||||||
.ua-table table {
|
.ua-table table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -205,7 +205,7 @@ body.ua-col-resizing {
|
|||||||
transition: background var(--ua-duration-fast) var(--ua-ease);
|
transition: background var(--ua-duration-fast) var(--ua-ease);
|
||||||
}
|
}
|
||||||
.ua-table tbody tr:nth-child(even) {
|
.ua-table tbody tr:nth-child(even) {
|
||||||
background: color-mix(in srgb, var(--ua-color-border) 18%, transparent);
|
background: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-tint), transparent);
|
||||||
}
|
}
|
||||||
.ua-table tbody tr:hover {
|
.ua-table tbody tr:hover {
|
||||||
background: var(--ua-color-tint-accent-weak);
|
background: var(--ua-color-tint-accent-weak);
|
||||||
@@ -338,7 +338,7 @@ body.ua-col-resizing {
|
|||||||
.ua-switch.is-loading .ua-switch-thumb {
|
.ua-switch.is-loading .ua-switch-thumb {
|
||||||
box-sizing: border-box; /* 滑块换成转圈环:border 计入尺寸 */
|
box-sizing: border-box; /* 滑块换成转圈环:border 计入尺寸 */
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 2px solid color-mix(in srgb, var(--ua-color-bg) 40%, transparent);
|
border: 2px solid color-mix(in srgb, var(--ua-color-bg) var(--ua-alpha-mid), transparent);
|
||||||
border-top-color: var(--ua-color-bg);
|
border-top-color: var(--ua-color-bg);
|
||||||
animation: ua-spin var(--ua-duration-loop-mid) linear infinite; /* 复用全局转圈:同一帧体不再各写一份 */
|
animation: ua-spin var(--ua-duration-loop-mid) linear infinite; /* 复用全局转圈:同一帧体不再各写一份 */
|
||||||
}
|
}
|
||||||
@@ -370,7 +370,7 @@ body.ua-col-resizing {
|
|||||||
transition: border-color var(--ua-duration-fast) var(--ua-ease), box-shadow var(--ua-duration-fast) var(--ua-ease), background var(--ua-duration-fast) var(--ua-ease);
|
transition: border-color var(--ua-duration-fast) var(--ua-ease), box-shadow var(--ua-duration-fast) var(--ua-ease), background var(--ua-duration-fast) var(--ua-ease);
|
||||||
}
|
}
|
||||||
.ua-select-trigger:hover {
|
.ua-select-trigger:hover {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-accent) 55%, var(--ua-color-border));
|
border-color: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-strong), var(--ua-color-border));
|
||||||
}
|
}
|
||||||
/* 按下:底色加深一档,与悬停的描边反馈形成两段式 */
|
/* 按下:底色加深一档,与悬停的描边反馈形成两段式 */
|
||||||
.ua-select-trigger:active:not(:disabled) {
|
.ua-select-trigger:active:not(:disabled) {
|
||||||
@@ -584,7 +584,7 @@ body.ua-col-resizing {
|
|||||||
color: var(--ua-color-danger);
|
color: var(--ua-color-danger);
|
||||||
}
|
}
|
||||||
.ua-menu-item.is-danger:hover:not(:disabled) {
|
.ua-menu-item.is-danger:hover:not(:disabled) {
|
||||||
background: color-mix(in srgb, var(--ua-color-danger) 10%, transparent);
|
background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-soft), transparent);
|
||||||
}
|
}
|
||||||
.ua-menu-label {
|
.ua-menu-label {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -811,15 +811,15 @@ body.ua-col-resizing {
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
.ua-avatar-success {
|
.ua-avatar-success {
|
||||||
background: color-mix(in srgb, var(--ua-color-success) 16%, transparent);
|
background: color-mix(in srgb, var(--ua-color-success) var(--ua-alpha-tint), transparent);
|
||||||
color: var(--ua-color-success);
|
color: var(--ua-color-success);
|
||||||
}
|
}
|
||||||
.ua-avatar-warning {
|
.ua-avatar-warning {
|
||||||
background: color-mix(in srgb, var(--ua-color-warning) 18%, transparent);
|
background: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-tint), transparent);
|
||||||
color: var(--ua-color-warning);
|
color: var(--ua-color-warning);
|
||||||
}
|
}
|
||||||
.ua-avatar-danger {
|
.ua-avatar-danger {
|
||||||
background: color-mix(in srgb, var(--ua-color-danger) 16%, transparent);
|
background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-tint), transparent);
|
||||||
color: var(--ua-color-danger);
|
color: var(--ua-color-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,19 +838,19 @@ body.ua-col-resizing {
|
|||||||
transition: border-color var(--ua-duration-fast) var(--ua-ease), background var(--ua-duration-fast) var(--ua-ease);
|
transition: border-color var(--ua-duration-fast) var(--ua-ease), background var(--ua-duration-fast) var(--ua-ease);
|
||||||
}
|
}
|
||||||
.ua-tag-success {
|
.ua-tag-success {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-success) 55%, transparent);
|
border-color: color-mix(in srgb, var(--ua-color-success) var(--ua-alpha-strong), transparent);
|
||||||
background: color-mix(in srgb, var(--ua-color-success) 10%, var(--ua-color-bg));
|
background: color-mix(in srgb, var(--ua-color-success) var(--ua-alpha-soft), var(--ua-color-bg));
|
||||||
}
|
}
|
||||||
.ua-tag-warning {
|
.ua-tag-warning {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-warning) 55%, transparent);
|
border-color: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-strong), transparent);
|
||||||
background: color-mix(in srgb, var(--ua-color-warning) 12%, var(--ua-color-bg));
|
background: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-soft), var(--ua-color-bg));
|
||||||
}
|
}
|
||||||
.ua-tag-danger {
|
.ua-tag-danger {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-danger) 55%, transparent);
|
border-color: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-strong), transparent);
|
||||||
background: color-mix(in srgb, var(--ua-color-danger) 10%, var(--ua-color-bg));
|
background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-soft), var(--ua-color-bg));
|
||||||
}
|
}
|
||||||
.ua-tag-info {
|
.ua-tag-info {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-accent) 55%, transparent);
|
border-color: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-strong), transparent);
|
||||||
background: var(--ua-color-tint-accent);
|
background: var(--ua-color-tint-accent);
|
||||||
}
|
}
|
||||||
.ua-tag-close {
|
.ua-tag-close {
|
||||||
@@ -884,11 +884,11 @@ body.ua-col-resizing {
|
|||||||
transform: scale(0.97);
|
transform: scale(0.97);
|
||||||
}
|
}
|
||||||
.ua-tag.is-checkable:focus-visible {
|
.ua-tag.is-checkable:focus-visible {
|
||||||
outline: 2px solid color-mix(in srgb, var(--ua-color-accent) 45%, transparent);
|
outline: 2px solid color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-mid), transparent);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
.ua-tag.is-checked {
|
.ua-tag.is-checked {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-accent) 55%, transparent);
|
border-color: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-strong), transparent);
|
||||||
background: var(--ua-color-tint-accent);
|
background: var(--ua-color-tint-accent);
|
||||||
color: var(--ua-color-text);
|
color: var(--ua-color-text);
|
||||||
}
|
}
|
||||||
@@ -911,7 +911,7 @@ body.ua-col-resizing {
|
|||||||
height: 4px;
|
height: 4px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
background: color-mix(in srgb, var(--ua-color-border) 70%, transparent);
|
background: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-heavy), transparent);
|
||||||
accent-color: var(--ua-color-accent);
|
accent-color: var(--ua-color-accent);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: opacity var(--ua-duration-fast) var(--ua-ease);
|
transition: opacity var(--ua-duration-fast) var(--ua-ease);
|
||||||
@@ -944,7 +944,7 @@ body.ua-col-resizing {
|
|||||||
right: 0;
|
right: 0;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
background: color-mix(in srgb, var(--ua-color-border) 70%, transparent);
|
background: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-heavy), transparent);
|
||||||
}
|
}
|
||||||
.ua-slider-seg {
|
.ua-slider-seg {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -988,7 +988,7 @@ body.ua-col-resizing {
|
|||||||
}
|
}
|
||||||
/* 输入类悬停:边框加深一档,与 .ua-input 同步 */
|
/* 输入类悬停:边框加深一档,与 .ua-input 同步 */
|
||||||
.ua-textarea:hover:not(:disabled):not(:focus-visible) {
|
.ua-textarea:hover:not(:disabled):not(:focus-visible) {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-text) 30%, var(--ua-color-border));
|
border-color: color-mix(in srgb, var(--ua-color-text) var(--ua-alpha-line), var(--ua-color-border));
|
||||||
}
|
}
|
||||||
.ua-textarea-count-group {
|
.ua-textarea-count-group {
|
||||||
display: flex; /* 字数统计 + 原有 suffix 并排靠右 */
|
display: flex; /* 字数统计 + 原有 suffix 并排靠右 */
|
||||||
@@ -1057,7 +1057,7 @@ body.ua-col-resizing {
|
|||||||
display: none; /* 末步没有下一段可连 */
|
display: none; /* 末步没有下一段可连 */
|
||||||
}
|
}
|
||||||
.ua-stepper.is-vertical .ua-step-done::after {
|
.ua-stepper.is-vertical .ua-step-done::after {
|
||||||
background: color-mix(in srgb, var(--ua-color-accent) 55%, transparent); /* 已走完的一段用主色,进度一眼可读 */
|
background: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-strong), transparent); /* 已走完的一段用主色,进度一眼可读 */
|
||||||
}
|
}
|
||||||
.ua-step {
|
.ua-step {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1102,7 +1102,7 @@ button.ua-step-dot:hover {
|
|||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
.ua-step-done .ua-step-dot {
|
.ua-step-done .ua-step-dot {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-accent) 55%, transparent);
|
border-color: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-strong), transparent);
|
||||||
background: var(--ua-color-tint-accent);
|
background: var(--ua-color-tint-accent);
|
||||||
color: var(--ua-color-accent);
|
color: var(--ua-color-accent);
|
||||||
}
|
}
|
||||||
@@ -1138,7 +1138,7 @@ button.ua-step-dot:hover {
|
|||||||
gap: var(--ua-space-05);
|
gap: var(--ua-space-05);
|
||||||
}
|
}
|
||||||
.ua-rate:focus-visible {
|
.ua-rate:focus-visible {
|
||||||
outline: 2px solid color-mix(in srgb, var(--ua-color-accent) 45%, transparent);
|
outline: 2px solid color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-mid), transparent);
|
||||||
outline-offset: 3px;
|
outline-offset: 3px;
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
}
|
}
|
||||||
@@ -1355,15 +1355,15 @@ button.ua-step-dot:hover {
|
|||||||
}
|
}
|
||||||
.ua-alert-success {
|
.ua-alert-success {
|
||||||
border-color: var(--ua-color-success);
|
border-color: var(--ua-color-success);
|
||||||
background: color-mix(in srgb, var(--ua-color-success) 12%, transparent);
|
background: color-mix(in srgb, var(--ua-color-success) var(--ua-alpha-soft), transparent);
|
||||||
}
|
}
|
||||||
.ua-alert-warning {
|
.ua-alert-warning {
|
||||||
border-color: var(--ua-color-warning);
|
border-color: var(--ua-color-warning);
|
||||||
background: color-mix(in srgb, var(--ua-color-warning) 12%, transparent);
|
background: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-soft), transparent);
|
||||||
}
|
}
|
||||||
.ua-alert-danger {
|
.ua-alert-danger {
|
||||||
border-color: var(--ua-color-danger);
|
border-color: var(--ua-color-danger);
|
||||||
background: color-mix(in srgb, var(--ua-color-danger) 12%, transparent);
|
background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-soft), transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* —— 独立分页器 —— */
|
/* —— 独立分页器 —— */
|
||||||
@@ -1452,14 +1452,14 @@ button.ua-step-dot:hover {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
background: color-mix(in srgb, var(--ua-color-border) 45%, transparent);
|
background: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-mid), transparent);
|
||||||
}
|
}
|
||||||
.ua-skeleton::after {
|
.ua-skeleton::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
transform: translateX(-100%);
|
transform: translateX(-100%);
|
||||||
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--ua-color-bg) 65%, transparent), transparent);
|
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--ua-color-bg) var(--ua-alpha-heavy), transparent), transparent);
|
||||||
animation: ua-shimmer var(--ua-duration-loop-slow) ease-in-out infinite;
|
animation: ua-shimmer var(--ua-duration-loop-slow) ease-in-out infinite;
|
||||||
}
|
}
|
||||||
@keyframes ua-shimmer {
|
@keyframes ua-shimmer {
|
||||||
@@ -1541,15 +1541,15 @@ button.ua-step-dot:hover {
|
|||||||
}
|
}
|
||||||
.ua-toast-success {
|
.ua-toast-success {
|
||||||
border-color: var(--ua-color-success);
|
border-color: var(--ua-color-success);
|
||||||
background: color-mix(in srgb, var(--ua-color-success) 10%, var(--ua-color-bg));
|
background: color-mix(in srgb, var(--ua-color-success) var(--ua-alpha-soft), var(--ua-color-bg));
|
||||||
}
|
}
|
||||||
.ua-toast-warning {
|
.ua-toast-warning {
|
||||||
border-color: var(--ua-color-warning);
|
border-color: var(--ua-color-warning);
|
||||||
background: color-mix(in srgb, var(--ua-color-warning) 10%, var(--ua-color-bg));
|
background: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-soft), var(--ua-color-bg));
|
||||||
}
|
}
|
||||||
.ua-toast-danger {
|
.ua-toast-danger {
|
||||||
border-color: var(--ua-color-danger);
|
border-color: var(--ua-color-danger);
|
||||||
background: color-mix(in srgb, var(--ua-color-danger) 10%, var(--ua-color-bg));
|
background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-soft), var(--ua-color-bg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* —— 加载指示器 —— */
|
/* —— 加载指示器 —— */
|
||||||
@@ -1577,7 +1577,7 @@ button.ua-step-dot:hover {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: color-mix(in srgb, var(--ua-color-border) 40%, transparent);
|
background: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-mid), transparent);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.ua-progress-fill {
|
.ua-progress-fill {
|
||||||
@@ -1585,14 +1585,14 @@ button.ua-step-dot:hover {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 0;
|
width: 0;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
background: linear-gradient(90deg, color-mix(in srgb, var(--ua-color-accent) 65%, transparent), var(--ua-color-accent));
|
background: linear-gradient(90deg, color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-heavy), transparent), var(--ua-color-accent));
|
||||||
transition: width var(--ua-duration-slower) var(--ua-ease-out);
|
transition: width var(--ua-duration-slower) var(--ua-ease-out);
|
||||||
}
|
}
|
||||||
.ua-progress-fill::after {
|
.ua-progress-fill::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.18) 0 6px, transparent 6px 12px);
|
background-image: repeating-linear-gradient(45deg, color-mix(in srgb, var(--ua-color-accent-contrast) var(--ua-alpha-tint), transparent) 0 6px, transparent 6px 12px);
|
||||||
background-size: 17px 100%;
|
background-size: 17px 100%;
|
||||||
animation: ua-stripe var(--ua-duration-loop-fast) linear infinite;
|
animation: ua-stripe var(--ua-duration-loop-fast) linear infinite;
|
||||||
}
|
}
|
||||||
@@ -2449,7 +2449,7 @@ button.ua-step-dot:hover {
|
|||||||
font-weight: var(--ua-weight-semibold);
|
font-weight: var(--ua-weight-semibold);
|
||||||
}
|
}
|
||||||
.ua-seg-btn:disabled {
|
.ua-seg-btn:disabled {
|
||||||
color: color-mix(in srgb, var(--ua-color-text-muted) 45%, transparent);
|
color: color-mix(in srgb, var(--ua-color-text-muted) var(--ua-alpha-mid), transparent);
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
.ua-segmented-sm .ua-seg-btn {
|
.ua-segmented-sm .ua-seg-btn {
|
||||||
@@ -3910,7 +3910,7 @@ button.ua-step-dot:hover {
|
|||||||
}
|
}
|
||||||
.ua-multiselect-tag.is-more {
|
.ua-multiselect-tag.is-more {
|
||||||
color: var(--ua-color-accent);
|
color: var(--ua-color-accent);
|
||||||
border: 1px dashed color-mix(in srgb, var(--ua-color-accent) 40%, transparent);
|
border: 1px dashed color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-mid), transparent);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
@@ -4124,9 +4124,9 @@ button.ua-step-dot:hover {
|
|||||||
/* —— 表单错误汇总条 —— */
|
/* —— 表单错误汇总条 —— */
|
||||||
.ua-form-summary {
|
.ua-form-summary {
|
||||||
padding: var(--ua-space-2) var(--ua-space-3);
|
padding: var(--ua-space-2) var(--ua-space-3);
|
||||||
border: 1px solid color-mix(in srgb, var(--ua-color-danger) 45%, transparent);
|
border: 1px solid color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-mid), transparent);
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
background: color-mix(in srgb, var(--ua-color-danger) 10%, transparent);
|
background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-soft), transparent);
|
||||||
color: var(--ua-color-danger);
|
color: var(--ua-color-danger);
|
||||||
font-size: var(--ua-font-size-md);
|
font-size: var(--ua-font-size-md);
|
||||||
}
|
}
|
||||||
@@ -4348,14 +4348,14 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
|
|||||||
.ua-type.is-delete { text-decoration: line-through; color: var(--ua-color-text-muted); }
|
.ua-type.is-delete { text-decoration: line-through; color: var(--ua-color-text-muted); }
|
||||||
.ua-type.is-underline.is-delete { text-decoration: underline line-through; }
|
.ua-type.is-underline.is-delete { text-decoration: underline line-through; }
|
||||||
.ua-type.is-mark {
|
.ua-type.is-mark {
|
||||||
background: color-mix(in srgb, var(--ua-color-warning) 24%, transparent);
|
background: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-tint), transparent);
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
padding: 0 var(--ua-space-05);
|
padding: 0 var(--ua-space-05);
|
||||||
}
|
}
|
||||||
.ua-type.is-code {
|
.ua-type.is-code {
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||||
font-size: var(--ua-font-size-scale-md);
|
font-size: var(--ua-font-size-scale-md);
|
||||||
background: color-mix(in srgb, var(--ua-color-border) 45%, transparent);
|
background: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-mid), transparent);
|
||||||
border-radius: var(--ua-radius-sm);
|
border-radius: var(--ua-radius-sm);
|
||||||
padding: 1px var(--ua-space-1);
|
padding: 1px var(--ua-space-1);
|
||||||
}
|
}
|
||||||
@@ -4609,7 +4609,7 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
|
|||||||
transition: border-color var(--ua-duration-fast) var(--ua-ease), box-shadow var(--ua-duration-fast) var(--ua-ease);
|
transition: border-color var(--ua-duration-fast) var(--ua-ease), box-shadow var(--ua-duration-fast) var(--ua-ease);
|
||||||
}
|
}
|
||||||
.ua-treeselect-trigger:hover {
|
.ua-treeselect-trigger:hover {
|
||||||
border-color: color-mix(in srgb, var(--ua-color-accent) 55%, var(--ua-color-border));
|
border-color: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-strong), var(--ua-color-border));
|
||||||
}
|
}
|
||||||
.ua-treeselect-trigger:focus-visible,
|
.ua-treeselect-trigger:focus-visible,
|
||||||
.ua-treeselect.is-open .ua-treeselect-trigger {
|
.ua-treeselect.is-open .ua-treeselect-trigger {
|
||||||
@@ -4719,7 +4719,7 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
.ua-datepicker-day.is-in-range:hover {
|
.ua-datepicker-day.is-in-range:hover {
|
||||||
background: color-mix(in srgb, var(--ua-color-accent) 20%, transparent);
|
background: color-mix(in srgb, var(--ua-color-accent) var(--ua-alpha-tint), transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* —— 可点击行:指针手型 + 键盘聚焦环,与选中行底色叠加不冲突 —— */
|
/* —— 可点击行:指针手型 + 键盘聚焦环,与选中行底色叠加不冲突 —— */
|
||||||
@@ -4791,7 +4791,7 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
|
|||||||
z-index: 1; /* 悬停的那个压在最上面,不被后一个盖住 */
|
z-index: 1; /* 悬停的那个压在最上面,不被后一个盖住 */
|
||||||
}
|
}
|
||||||
.ua-avatar-more {
|
.ua-avatar-more {
|
||||||
background: color-mix(in srgb, var(--ua-color-text-muted) 18%, transparent);
|
background: color-mix(in srgb, var(--ua-color-text-muted) var(--ua-alpha-tint), transparent);
|
||||||
color: var(--ua-color-text);
|
color: var(--ua-color-text);
|
||||||
font-weight: var(--ua-weight-medium);
|
font-weight: var(--ua-weight-medium);
|
||||||
}
|
}
|
||||||
@@ -4826,7 +4826,7 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
|
|||||||
height: 64px;
|
height: 64px;
|
||||||
}
|
}
|
||||||
.ua-progress-ring-track {
|
.ua-progress-ring-track {
|
||||||
stroke: color-mix(in srgb, var(--ua-color-border) 80%, transparent);
|
stroke: color-mix(in srgb, var(--ua-color-border) var(--ua-alpha-heavy), transparent);
|
||||||
}
|
}
|
||||||
.ua-progress-ring-arc {
|
.ua-progress-ring-arc {
|
||||||
stroke: var(--ua-color-accent);
|
stroke: var(--ua-color-accent);
|
||||||
|
|||||||
@@ -66,10 +66,20 @@ export const KIND_META = [
|
|||||||
label: '边框色字面值',
|
label: '边框色字面值',
|
||||||
hint: 'border/border-color 写死色值(rgba()/#hex),组件轮廓用 --ua-color-border、分割线用 --ua-border-subtle',
|
hint: 'border/border-color 写死色值(rgba()/#hex),组件轮廓用 --ua-color-border、分割线用 --ua-border-subtle',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'mix-literal',
|
||||||
|
label: '混色浓度字面值',
|
||||||
|
hint: 'color-mix 的混入浓度写死百分比,应改用 --ua-alpha-* 六档(soft/tint/line/mid/strong/heavy)',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/*** 作用:需要扫描的 CSS 属性白名单(其余属性本轮不动;用白名单顺带避开伪类选择器误判) ***/
|
/*** 作用:需要扫描的 CSS 属性白名单(其余属性本轮不动;用白名单顺带避开伪类选择器误判) ***/
|
||||||
const SCAN_PROPS = new Set([
|
const SCAN_PROPS = new Set([
|
||||||
|
'background-image',
|
||||||
|
'background',
|
||||||
|
'color',
|
||||||
|
'fill',
|
||||||
|
'stroke',
|
||||||
'font-size',
|
'font-size',
|
||||||
'transition',
|
'transition',
|
||||||
'animation',
|
'animation',
|
||||||
@@ -237,6 +247,74 @@ const LEADING_TOKENS = new Map([
|
|||||||
/*** 作用:下拉类 z-index 字面值集合(历史上下拉/气泡弹层用的 20/30/40 档,统一归 --ua-z-dropdown) ***/
|
/*** 作用:下拉类 z-index 字面值集合(历史上下拉/气泡弹层用的 20/30/40 档,统一归 --ua-z-dropdown) ***/
|
||||||
const Z_DROPDOWN_LIKE = new Set(['20', '30', '40']);
|
const Z_DROPDOWN_LIKE = new Set(['20', '30', '40']);
|
||||||
|
|
||||||
|
/*** 作用:混色浓度字面值 → --ua-alpha-* 档位(近档就近收敛:12→10、16/20/24→18、40→45、65/80→70,Δ≤6) ***/
|
||||||
|
const MIX_TOKENS = new Map([
|
||||||
|
['10', 'var(--ua-alpha-soft)'],
|
||||||
|
['12', 'var(--ua-alpha-soft)'],
|
||||||
|
['16', 'var(--ua-alpha-tint)'],
|
||||||
|
['18', 'var(--ua-alpha-tint)'],
|
||||||
|
['20', 'var(--ua-alpha-tint)'],
|
||||||
|
['24', 'var(--ua-alpha-tint)'],
|
||||||
|
['30', 'var(--ua-alpha-line)'],
|
||||||
|
['40', 'var(--ua-alpha-mid)'],
|
||||||
|
['45', 'var(--ua-alpha-mid)'],
|
||||||
|
['55', 'var(--ua-alpha-strong)'],
|
||||||
|
['65', 'var(--ua-alpha-heavy)'],
|
||||||
|
['70', 'var(--ua-alpha-heavy)'],
|
||||||
|
['80', 'var(--ua-alpha-heavy)'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
/*** 作用:提取值里所有 color-mix(...) 块(配平括号,嵌套 color-mix 逐层都算一条);返回全块文本与首色参(in srgb 之后的第一个顶层参数) ***/
|
||||||
|
function extractMixes(value) {
|
||||||
|
const out = [];
|
||||||
|
const src = String(value);
|
||||||
|
for (let i = src.indexOf('color-mix('); i !== -1; i = src.indexOf('color-mix(', i + 1)) {
|
||||||
|
let depth = 0;
|
||||||
|
let end = -1;
|
||||||
|
for (let k = i + 'color-mix'.length; k < src.length; k++) { // 从函数名后的 ( 起配平
|
||||||
|
if (src[k] === '(') depth++;
|
||||||
|
else if (src[k] === ')') { depth--; if (!depth) { end = k; break; } }
|
||||||
|
}
|
||||||
|
if (end === -1) break; // 未闭合:整值残缺,交给浏览器报错
|
||||||
|
const block = src.slice(i, end + 1);
|
||||||
|
const inner = block.slice('color-mix('.length, -1); // 去掉外壳与收尾括号
|
||||||
|
const args = splitTopLevel(inner).map((s) => s.trim());
|
||||||
|
out.push({ block, start: i, arg1: args[1] ?? '' }); // args[0] 是插值方法(in srgb),首色参跟在其后
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** 作用:首色参末尾的混入浓度:已是 --ua-alpha-* 令牌返回 null;写死百分比返回数字字符串(渐变停靠位不在 color-mix 首参末尾,天然豁免) ***/
|
||||||
|
function mixAmount(arg1) {
|
||||||
|
const s = String(arg1).trim();
|
||||||
|
if (/var\(--ua-alpha-[\w-]+\)\s*$/.test(s)) return null; // 已令牌化
|
||||||
|
const lit = s.match(/(\d+(?:\.\d+)?)%\s*$/);
|
||||||
|
return lit ? lit[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** 作用:迁移单条声明里的所有 color-mix 浓度字面量:逐块把首色参尾部的 NN% 换成 --ua-alpha-* 档位(表外浓度保留交人工归档) ***/
|
||||||
|
function migrateMix(core) {
|
||||||
|
const src = String(core);
|
||||||
|
const mixes = extractMixes(src);
|
||||||
|
if (!mixes.length) return null;
|
||||||
|
let hits = 0;
|
||||||
|
let out = '';
|
||||||
|
let cursor = 0;
|
||||||
|
for (const { block, start, arg1 } of mixes) {
|
||||||
|
const amt = mixAmount(arg1);
|
||||||
|
const token = amt !== null ? MIX_TOKENS.get(amt) : null;
|
||||||
|
if (!token) continue;
|
||||||
|
const nextArg1 = arg1 ? arg1.replace(/(\d+(?:\.\d+)?)%\s*$/, token) : arg1; // 复用原有的「色 浓度」间隔空格
|
||||||
|
const nextBlock = nextArg1 === arg1 || !arg1 ? block : block.replace(arg1, nextArg1); // arg1 是 block 的精确子串,整串替换安全
|
||||||
|
hits++;
|
||||||
|
out += src.slice(cursor, start) + nextBlock;
|
||||||
|
cursor = start + block.length;
|
||||||
|
}
|
||||||
|
if (!hits) return null;
|
||||||
|
out += src.slice(cursor);
|
||||||
|
return { kind: 'mix-literal', value: out };
|
||||||
|
}
|
||||||
|
|
||||||
/*** 作用:压缩空白,便于用稳定字符串比对(不改语义) ***/
|
/*** 作用:压缩空白,便于用稳定字符串比对(不改语义) ***/
|
||||||
export function squash(value) {
|
export function squash(value) {
|
||||||
return String(value).replace(/\s+/g, ' ').trim();
|
return String(value).replace(/\s+/g, ' ').trim();
|
||||||
@@ -262,7 +340,7 @@ export function blankComments(src) {
|
|||||||
|
|
||||||
/*** 作用:逐条产出「属性 + 值」及其在原文中的偏移;只认白名单属性且必须以分号收尾(避开伪类选择器) ***/
|
/*** 作用:逐条产出「属性 + 值」及其在原文中的偏移;只认白名单属性且必须以分号收尾(避开伪类选择器) ***/
|
||||||
export function eachDeclaration(code) {
|
export function eachDeclaration(code) {
|
||||||
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 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|background-image|background|color|fill|stroke)\s*:\s*([^;{}]*);/gi;
|
||||||
const list = [];
|
const list = [];
|
||||||
for (const m of code.matchAll(re)) {
|
for (const m of code.matchAll(re)) {
|
||||||
const prop = m[1].toLowerCase();
|
const prop = m[1].toLowerCase();
|
||||||
@@ -430,7 +508,7 @@ export function migrateDeclaration(prop, rawValue) {
|
|||||||
} else if (prop === 'z-index') {
|
} else if (prop === 'z-index') {
|
||||||
result = migrateZ(core);
|
result = migrateZ(core);
|
||||||
} else {
|
} else {
|
||||||
result = migrateBorder(prop, core); // 边框类:只收敛纯黑 rgba 边
|
result = migrateMix(core) ?? migrateBorder(prop, core); // 其余属性:先收敛 color-mix 浓度,再收敛纯黑 rgba 边
|
||||||
}
|
}
|
||||||
if (!result) return null;
|
if (!result) return null;
|
||||||
return { kind: result.kind, value: result.value + tail };
|
return { kind: result.kind, value: result.value + tail };
|
||||||
@@ -504,6 +582,9 @@ function detect(prop, rawValue, key) {
|
|||||||
const stripped = value.replace(/var\(--ua-[\w-]+\)/g, ' '); // 已是令牌的色先剔除
|
const stripped = value.replace(/var\(--ua-[\w-]+\)/g, ' '); // 已是令牌的色先剔除
|
||||||
return /(#[0-9a-f]{3,8}\b|rgba?\(|hsla?\()/i.test(stripped) ? 1 : 0;
|
return /(#[0-9a-f]{3,8}\b|rgba?\(|hsla?\()/i.test(stripped) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
if (key === 'mix-literal') {
|
||||||
|
return extractMixes(value).filter(({ arg1 }) => mixAmount(arg1) !== null).length; // 只认 color-mix 块内首色参的写死浓度;渐变停靠位与几何百分比天然不在口径内
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)",
|
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 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 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 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 输出结构化数组;写样式前先查,禁止硬编码。令牌分十二组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,color-mix 混入浓度用 --ua-alpha-soft/tint/line/mid/strong/heavy,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
"改完清单跑 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"
|
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||||
|
|||||||
Reference in New Issue
Block a user