feat(design): 加 Ink/Silver 双主题色板 + 规格卡几何与字号令牌(M228)

规格卡 DevDocs/artifacts/components-ink.svg 的令牌化,只动 crates/design,零依赖不变。

- color::boards:BrandBoard(Ink 深 / Silver 浅)→ 49 角色 × 2 套固化色板。
  spec 直写值进 ANCHORS(测试逐条比 hex,规格卡改了代码不改会红);规格卡没给的
  角色按「同色相 + M3 tone 关系」推导后固化,规则写在 boards/ink.rs 的行注释里。
  Scheme::from_board / DesignTokens::brand 是两个新入口;Scheme::baseline 一字未改
  (它是 D38 取色链的中性锚点,改它等于同时改 app-iced 观感 + 取色语义)。
- palette::visibility:容器层可视性裁决,即债务台账「SecondaryContainer 对 Surface
  仅 1.06」的令牌层结论。状态容器(*-container)对 surface ≥1.20:1 是唯一数字门禁;
  容器层之间不设亮度门禁,改为「选中态 = 容器底 + 文字对比 + 形状/图标」三件套的构成
  要求(浅色板实测 1.05~1.24,任何有意义的门禁都过不了,详情见模块文档实测表)。
- inkcat:规格卡的尺寸与形状数据。ControlSize(按钮 XS~XL = 32/40/56/96/136,圆角
  一律半高)、FabSize(40/56/80/160×56,圆角 12/16/20/16)、控件方框(卡片 16、
  对话框 28、snackbar 52@16、列表行 60 药丸、chip 32@8、字段 4/28 + 内距 16/32、
  复选 18@4、单选 18、开关 52×32 + 拇指 24、进度 4/6)、SpecText(规格卡 11 个字号
  → 命中 / 落档 / 低于 11px 下限三类结论)。
  component_map 的表值一处未动:app-iced 的 pages/frame/tests.rs:42 与 shell/tests.rs:30
  按 Medium(12) pin 住卡片,改表等于连带改观感且破坏既有断言;差异在 inkcat 模块文档
  逐条登记,换肤时由 M229 一次切换 + 截图验收。
- 测试:186 lib(+13 条新单测)+ tests/ink_cat_boards.rs(10 条:完整性/锚点/双主题
  切换/26 对 WCAG AA/25 组规格卡用法/状态容器 1.2 门禁/阶梯单调)+ tests/ink_cat_geometry.rs
  (3 条:按钮 FAB 几何、控件圆角、字号校核)。
This commit is contained in:
AskaEth committed 2026-11-10 22:34:05 +08:00
1 parent 7fe38fb240
commit 0169d4c8fb
14 files changed
+2047 -4

No files matched your search

+27 -4
View File
@@ -17,6 +17,10 @@
//!
//! - [`color`]:M3 语义色角色(49 个)× light/dark 双套 + tone 调色板(**真 HCT**:CAM16 色相/彩度
//! + CIELAB `L*`,官方 `ColorSpec2021` tone 表,与官方 Java 实现逐通道对齐——口径见模块文档)
//! - [`color::boards`]:**双主题色板**(Ink 深 / Silver 浅,用户规格卡 `components-ink.svg` 的固化值)
//! + [`BrandBoard`] 选择器;与 tone 派生的 `Scheme::baseline` 并列(理由见该模块文档)
//! - [`inkcat`]:规格卡的**形状 / 尺寸档 / 字号校核**——按钮 XS~XL、FAB 四态、控件方框几何、
//! 规格卡字号 → 官方 type scale 的命中/落档/低于下限结论
//! - [`palette`]:配色来源(D38/D40)——图片像素 → 种子 → 完整方案(Monet 式量化 + 打分)、
//! 内置色卡、三级优先与失败回落、对比度收敛。**只吃已解码的像素**,解码在 `crates/palette-extract`
//! - [`typography`]:M3 type scale 15 档 + 三平台字体族回退栈
@@ -91,13 +95,14 @@ pub mod color;
pub mod component_map;
pub mod elevation;
pub mod icons;
pub mod inkcat;
pub mod motion;
pub mod palette;
pub mod shape;
pub mod spacing;
pub mod typography;
pub use color::{Color, Role, Scheme, SchemeFlavor};
pub use color::{BrandBoard, Color, Role, Scheme, SchemeFlavor};
pub use motion::MotionScale;
pub use palette::{Card, CardKey, Level as SourceLevel, Provenance, Seed};
pub use spacing::stroke;
@@ -105,8 +110,9 @@ pub use typography::TypeRole;
/// 设计令牌的整体入口:一份「当前该长什么样」的聚合快照。
///
/// iced 适配层只持有这个结构(深浅切换 = 重新 `DesignTokens::baseline(mode)`),
/// 不要在适配层里缓存散装色值——那样深浅热切会有一半画对一半画错。
/// iced 适配层只持有这个结构(换肤 = 重新 `DesignTokens::brand(board)`,换强调色 =
/// `DesignTokens::with_accent(flavor, accent)`),不要在适配层里缓存散装色值——
/// 那样热切会有一半画对一半画错。
#[derive(Debug, Clone, Copy)]
pub struct DesignTokens {
/// 当前深浅模式。
@@ -118,9 +124,13 @@ pub struct DesignTokens {
}
impl DesignTokens {
/// 按模式给一套**产品默认**令牌:种子 `#3C8DBC`(M70 ④ 天蓝,用户 2026-11-01 拍板)
/// **tone 派生**的一套令牌:种子 `#3C8DBC`(M70 ④ 天蓝,用户 2026-11-01 拍板)
/// + 中性彩度 12,即 `color::palettes::DEFAULT_SEED` / `DEFAULT_NEUTRAL_CHROMA`。
///
/// 定位(M228 起):这是 **D38 取色链的锚点**——「莫奈关闭时机内色卡的底色」与
/// `with_accent` 的中性基准。**产品出厂外观请走 [`DesignTokens::brand`]**(Ink / Silver
/// 两套固化色板);两条路径并列而不是互相替换,理由见 `color::boards` 的模块文档。
///
/// 想要**官方 M3 baseline** 口径(种子 `#6750A4` + 中性彩度 6 / neutral-variant 8)请走
/// `color::Scheme::official_baseline(flavor)`——两条路径的算法完全相同,只差入参。
pub fn baseline(flavor: SchemeFlavor) -> Self {
@@ -140,6 +150,19 @@ impl DesignTokens {
}
}
/// **品牌色板**(Ink 深 / Silver 浅)的令牌:出厂外观的唯一入口。
///
/// `flavor` 由色板自己决定(`BrandBoard::flavor`),所以「跟随系统」只需
/// `DesignTokens::brand(BrandBoard::for_flavor(system_flavor))`——第三种设置态在设置层解析,
/// 令牌层只认两套板。
pub fn brand(board: BrandBoard) -> Self {
Self {
flavor: board.flavor(),
colors: board.scheme(),
motion_scale: MotionScale::STANDARD,
}
}
/// 便捷取色:`tokens.color(Role::Surface)`。
pub fn color(&self, role: Role) -> Color {
self.colors.get(role)