feat(design): 加 unlucky-design 令牌 crate(M3 色彩/排版/形状/动效/图标)
D26 把视觉基线锁到 Material 3 Expressive,本 crate 是「UI 整体性」的地基: 令牌唯一真源,后续 iced 页面只消费不新增。零第三方依赖、零 UI 框架依赖 (cargo tree -p unlucky-design --edges normal 只有它自己一行)。 - 色彩:49 个 M3 语义角色 × light/dark,种子色派生 6 条 tone 调色板; tone 轴严格用 CIELAB L*(偏差 ≤1),色相/彩度用 OKLCh 近似 CAM16 并在 模块文档里写明口径与已知偏差(不宣称是标准 HCT 动态取色) - 对比度:26 组文字对 × 6 组种子 × 2 模式全部 ≥4.5:1;3 条例外显式登记 (Outline 非文字 3:1、OutlineVariant 装饰、SurfaceVariant 是容器色) - 排版:M3 type scale 15 档 + 三平台字体族回退栈(只写族名,不内嵌受限字体) - 形状/高程/动效:Expressive 形状刻度 + shape morph 数据、elevation 级别与 surface container 映射、时长/缓动/弹簧(纯函数可采样) - 图标:24 个从 Slint 版迁移的 SVG path + 4 个新增,IconKind 冻结只可末尾追加; 写明 Slint 的 stroke-width 是绝对像素、SVG 是 viewBox 用户单位的语义差异, 换算封装成 Icon::stroke_width - 组件档位表:20 个组件的形状/高程/字体/动效一次取全 TODO(M63):elevation shadow 的 blur/offset/alpha 与四组弹簧参数是占位值, 接口先定、数值待玻璃视觉规格表(tower 已通告边界)。
This commit is contained in:
1 parent
fef0922073
commit
65ca0ed29a
25 files changed
+4622
-1
No files matched your search
@@ -0,0 +1,95 @@
|
||||
//! # unlucky-design · ULL 设计令牌唯一真源
|
||||
//!
|
||||
//! 视觉基线 = **Material 3 Expressive**(D26 锁定,风格与框架不再更换)。这个 crate 只装
|
||||
//! **渲染无关的数据与纯函数**:色彩角色、排版 ramp、形状刻度、高程、动效参数、图标几何。
|
||||
//! 它不依赖任何 UI / 渲染框架(iced / slint / winit / wgpu / gtk …),也不依赖任何第三方 crate,
|
||||
//! 因此 iced 迁移、CLI、甚至离屏截图工具都能吃同一套值——这是「UI 整体性」的地基。
|
||||
//!
|
||||
//! ## 边界(谁负责什么)
|
||||
//!
|
||||
//! | 层 | 负责 | 不负责 |
|
||||
//! |---|---|---|
|
||||
//! | `unlucky-design`(本 crate) | 令牌的值与它们之间的纯函数关系(tone→色、type role→字号/行高/字重、shape→半径、spring→时长) | 布局、控件、绘制、字体加载、图片、动画驱动 |
|
||||
//! | iced 适配层(后续 mission) | 把令牌翻成 iced 的类型(`Color` / `Length` / `Font` / 动画时钟) | 自己发明新令牌名或新取值 |
|
||||
//! | 页面 mission | 消费令牌与 [`component_map`] 的档位约定 | 硬编码色值 / 字号 / 半径 / 时长 |
|
||||
//!
|
||||
//! ## 分模块
|
||||
//!
|
||||
//! - [`color`]:M3 语义色角色(49 个)× light/dark 双套 + tone 调色板(OKLCh 近似,口径见模块文档)
|
||||
//! - [`typography`]:M3 type scale 15 档 + 三平台字体族回退栈
|
||||
//! - [`shape`]:M3 Expressive 形状刻度 + shape morph 数据
|
||||
//! - [`elevation`]:elevation level 与 surface tint / surface container 规则
|
||||
//! - [`motion`]:时长、easing(可采样)、Expressive 弹簧参数
|
||||
//! - [`spacing`]:4px 栅格与骨架尺寸(原 `metrics.slint` 的框架无关部分)
|
||||
//! - [`icons`]:24 网格图标几何(SVG path 字符串)+ 描边语义
|
||||
//! - [`component_map`]:组件 → 档位映射表(哪个组件用哪档形状/高程/动效/字体)
|
||||
//!
|
||||
//! ## 最小用法
|
||||
//!
|
||||
//! ```
|
||||
//! use unlucky_design::color::{Role, Scheme, SchemeFlavor};
|
||||
//! use unlucky_design::typography::{FontFamily, Platform, TypeRole};
|
||||
//!
|
||||
//! let light = Scheme::baseline(SchemeFlavor::Light);
|
||||
//! let ratio = light.contrast(Role::OnSurface, Role::Surface);
|
||||
//! assert!(ratio >= 4.5, "正文对表面必须满足 WCAG AA");
|
||||
//!
|
||||
//! let title = TypeRole::TitleLarge.style();
|
||||
//! assert_eq!(title.size_px, 22.0);
|
||||
//! let stack = Platform::current().font_stack(FontFamily::Display);
|
||||
//! assert!(!stack.is_empty());
|
||||
//! ```
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod color;
|
||||
pub mod component_map;
|
||||
pub mod elevation;
|
||||
pub mod icons;
|
||||
pub mod motion;
|
||||
pub mod shape;
|
||||
pub mod spacing;
|
||||
pub mod typography;
|
||||
|
||||
pub use color::{Color, Role, Scheme, SchemeFlavor};
|
||||
pub use motion::MotionScale;
|
||||
pub use typography::TypeRole;
|
||||
|
||||
/// 设计令牌的整体入口:一份「当前该长什么样」的聚合快照。
|
||||
///
|
||||
/// iced 适配层只持有这个结构(深浅切换 = 重新 `DesignTokens::baseline(mode)`),
|
||||
/// 不要在适配层里缓存散装色值——那样深浅热切会有一半画对一半画错。
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DesignTokens {
|
||||
/// 当前深浅模式。
|
||||
pub flavor: SchemeFlavor,
|
||||
/// 当前模式的 M3 语义色角色全表。
|
||||
pub colors: Scheme,
|
||||
/// 动效时长的全局缩放(`1.0` = 标准;用户关掉动画时适配层传 `0.0`)。
|
||||
pub motion_scale: MotionScale,
|
||||
}
|
||||
|
||||
impl DesignTokens {
|
||||
/// 按模式给一套出厂令牌(baseline seed `#6750A4`,等价 M3 baseline 调色板)。
|
||||
pub fn baseline(flavor: SchemeFlavor) -> Self {
|
||||
Self {
|
||||
flavor,
|
||||
colors: Scheme::baseline(flavor),
|
||||
motion_scale: MotionScale::STANDARD,
|
||||
}
|
||||
}
|
||||
|
||||
/// 按用户强调色重建一套令牌(表面中性色仍走 baseline,强调色只驱动 primary/secondary/tertiary)。
|
||||
pub fn with_accent(flavor: SchemeFlavor, accent: Color) -> Self {
|
||||
Self {
|
||||
flavor,
|
||||
colors: Scheme::from_accent(flavor, accent),
|
||||
motion_scale: MotionScale::STANDARD,
|
||||
}
|
||||
}
|
||||
|
||||
/// 便捷取色:`tokens.color(Role::Surface)`。
|
||||
pub fn color(&self, role: Role) -> Color {
|
||||
self.colors.get(role)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user