From f9d4760e5e2290d5418c1873607b1a0c61d53e4f Mon Sep 17 00:00:00 2001 From: DK Date: Sun, 8 Mar 2026 15:30:37 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(Core=20UI):=20=20common=20=E5=B8=B8?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/im_app/lib/core/ui/base/radius.dart | 131 ++++++++++++++++++++++ apps/im_app/lib/core/ui/base/shadows.dart | 104 +++++++++++++++++ apps/im_app/lib/core/ui/base/spacing.dart | 72 ++++++++++++ 3 files changed, 307 insertions(+) create mode 100644 apps/im_app/lib/core/ui/base/radius.dart create mode 100644 apps/im_app/lib/core/ui/base/shadows.dart create mode 100644 apps/im_app/lib/core/ui/base/spacing.dart diff --git a/apps/im_app/lib/core/ui/base/radius.dart b/apps/im_app/lib/core/ui/base/radius.dart new file mode 100644 index 0000000..e93a157 --- /dev/null +++ b/apps/im_app/lib/core/ui/base/radius.dart @@ -0,0 +1,131 @@ +import 'package:flutter/widgets.dart'; + +/// 圆角设计 Token +/// +/// 统一管理项目中的圆角规范,避免在业务代码中直接写 +/// `Radius.circular()` 或 `BorderRadius.circular()` +/// +/// 使用方式: +/// +/// ```dart +/// Container( +/// decoration: BoxDecoration( +/// borderRadius: AppRadius.card, +/// ), +/// ) +/// ``` +/// +/// 设计规范来源: +/// 通常来自 UI 设计系统,例如 +/// 4 / 8 / 12 / 16 / 20 +class AppRadius { + /// 私有构造函数,防止被实例化 + AppRadius._(); + + // ================================ + // 基础 Radius Token + // ================================ + // 用于组合 BorderRadius + + /// 4px 圆角 + static const Radius r4 = Radius.circular(4); + + /// 6px 圆角 + static const Radius r6 = Radius.circular(6); + + /// 8px 圆角(常用于按钮) + static const Radius r8 = Radius.circular(8); + + /// 10px 圆角 + static const Radius r10 = Radius.circular(10); + + /// 12px 圆角(常用于卡片) + static const Radius r12 = Radius.circular(12); + + /// 14px 圆角 + static const Radius r14 = Radius.circular(14); + + /// 16px 圆角(常用于弹窗) + static const Radius r16 = Radius.circular(16); + + /// 18px 圆角 + static const Radius r18 = Radius.circular(18); + + /// 20px 圆角 + static const Radius r20 = Radius.circular(20); + + // ================================ + // 组件级设计 Token + // ================================ + // 推荐优先使用这些,而不是直接使用 brXX + + /// 卡片圆角 + /// + /// 示例:Card / 商品卡片 / 信息卡片 + static const BorderRadius card = BorderRadius.all(r12); + + /// 按钮圆角 + /// + /// 示例:PrimaryButton / SecondaryButton + static const BorderRadius button = BorderRadius.all(r8); + + /// 弹窗圆角 + /// + /// 示例:Dialog / Modal + static const BorderRadius dialog = BorderRadius.all(r16); + + // ================================ + // 通用 BorderRadius + // ================================ + // 当组件 Token 不满足需求时使用 + + static const BorderRadius br4 = BorderRadius.all(r4); + + static const BorderRadius br6 = BorderRadius.all(r6); + + static const BorderRadius br8 = BorderRadius.all(r8); + + static const BorderRadius br10 = BorderRadius.all(r10); + + static const BorderRadius br12 = BorderRadius.all(r12); + + static const BorderRadius br14 = BorderRadius.all(r14); + + static const BorderRadius br16 = BorderRadius.all(r16); + + static const BorderRadius br18 = BorderRadius.all(r18); + + static const BorderRadius br20 = BorderRadius.all(r20); + + // ================================ + // 辅助方法 + // ================================ + // 用于生成顶部或底部圆角 + + /// 生成顶部圆角 + /// + /// 常用于: + /// - BottomSheet + /// - 底部弹窗 + /// - 半屏弹层 + /// + /// 示例: + /// ```dart + /// borderRadius: AppRadius.top(AppRadius.r16) + /// ``` + static BorderRadius top(Radius r) => + BorderRadius.vertical(top: r); + + /// 生成底部圆角 + /// + /// 常用于: + /// - Header + /// - 顶部卡片 + /// + /// 示例: + /// ```dart + /// borderRadius: AppRadius.bottom(AppRadius.r16) + /// ``` + static BorderRadius bottom(Radius r) => + BorderRadius.vertical(bottom: r); +} \ No newline at end of file diff --git a/apps/im_app/lib/core/ui/base/shadows.dart b/apps/im_app/lib/core/ui/base/shadows.dart new file mode 100644 index 0000000..bbe540f --- /dev/null +++ b/apps/im_app/lib/core/ui/base/shadows.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; + +/// 阴影设计 Token +/// +/// 统一管理项目中的阴影规范,避免在业务代码中直接写 BoxShadow。 +/// +/// 使用示例: +/// +/// ```dart +/// Container( +/// decoration: BoxDecoration( +/// color: Colors.white, +/// boxShadow: AppShadows.bs8, +/// ), +/// ) +/// ``` +/// +/// 阴影一般用于: +/// - Card 卡片 +/// - Dialog 弹窗 +/// - Floating Button +/// - 悬浮面板 +/// +/// 设计通常遵循 UI 设计系统的 elevation 规则,例如: +/// 4 / 8 / 12 / 16 +class AppShadows { + /// 私有构造函数,防止实例化 + AppShadows._(); + + // ================================ + // 轻量阴影 + // ================================ + // 适用于轻微层级,例如小卡片 + + /// 轻阴影(4) + /// + /// 常用于: + /// - 小卡片 + /// - List item + static const List bs4 = [ + BoxShadow( + /// 阴影颜色(透明黑) + color: Color(0x14000000), + + /// 模糊半径 + blurRadius: 4, + + /// 阴影偏移 + offset: Offset(0, 2), + ) + ]; + + // ================================ + // 中等阴影 + // ================================ + + /// 中等阴影(8) + /// + /// 常用于: + /// - Card + /// - 商品卡片 + static const List bs8 = [ + BoxShadow( + color: Color(0x1F000000), + blurRadius: 8, + offset: Offset(0, 4), + ) + ]; + + // ================================ + // 强阴影 + // ================================ + + /// 强阴影(12) + /// + /// 常用于: + /// - 悬浮卡片 + /// - Dropdown + static const List bs12 = [ + BoxShadow( + color: Color(0x26000000), + blurRadius: 12, + offset: Offset(0, 8), + ) + ]; + + // ================================ + // 高层级阴影 + // ================================ + + /// 高层级阴影(16) + /// + /// 常用于: + /// - Dialog + /// - Modal + /// - Floating Panel + static const List bs16 = [ + BoxShadow( + color: Color(0x26000000), + blurRadius: 16, + offset: Offset(0, 8), + ) + ]; +} \ No newline at end of file diff --git a/apps/im_app/lib/core/ui/base/spacing.dart b/apps/im_app/lib/core/ui/base/spacing.dart new file mode 100644 index 0000000..d735c1c --- /dev/null +++ b/apps/im_app/lib/core/ui/base/spacing.dart @@ -0,0 +1,72 @@ +/// 间距设计 Token +/// +/// 统一管理项目中的间距规范,避免在业务代码中直接写 magic number,例如: +/// +/// ❌ 不推荐 +/// ```dart +/// Padding(padding: EdgeInsets.all(16)) +/// ``` +/// +/// ✅ 推荐 +/// ```dart +/// Padding(padding: EdgeInsets.all(AppSpacing.s16)) +/// ``` +/// +/// 常用于: +/// - Padding +/// - Margin +/// - SizedBox +/// - Sliver 间距 +/// +/// 设计规范通常来源于 UI 设计系统,例如: +/// 4 / 8 / 12 / 16 / 24 / 32 +class AppSpacing { + /// 私有构造函数,防止实例化 + AppSpacing._(); + + // ================================ + // 基础间距 Token + // ================================ + + /// 4px 间距(最小间距) + /// + /// 常用于: + /// - icon 与文字之间 + /// - 紧凑布局 + static const double s4 = 4; + + /// 8px 间距(小间距) + /// + /// 常用于: + /// - 列表 item 内间距 + /// - 小组件之间 + static const double s8 = 8; + + /// 12px 间距(中小间距) + /// + /// 常用于: + /// - 表单组件 + /// - 信息块之间 + static const double s12 = 12; + + /// 16px 间距(标准间距) + /// + /// 常用于: + /// - 页面 Padding + /// - Card 内边距 + static const double s16 = 16; + + /// 24px 间距(大间距) + /// + /// 常用于: + /// - 模块之间 + /// - Section 分隔 + static const double s24 = 24; + + /// 32px 间距(超大间距) + /// + /// 常用于: + /// - 页面大区块 + /// - 顶部/底部留白 + static const double s32 = 32; +} \ No newline at end of file From 59a866e5402087c86ce4e1b4e5feec79bc57d172 Mon Sep 17 00:00:00 2001 From: DK Date: Mon, 9 Mar 2026 15:39:46 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(Core=20UI):=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/core/ui/base/app_theme_ext.dart | 7 + apps/im_app/lib/core/ui/base/colors.dart | 17 ++ apps/im_app/lib/core/ui/base/shadows.dart | 160 ++++++++++-------- 3 files changed, 111 insertions(+), 73 deletions(-) create mode 100644 apps/im_app/lib/core/ui/base/app_theme_ext.dart diff --git a/apps/im_app/lib/core/ui/base/app_theme_ext.dart b/apps/im_app/lib/core/ui/base/app_theme_ext.dart new file mode 100644 index 0000000..3e8cc5d --- /dev/null +++ b/apps/im_app/lib/core/ui/base/app_theme_ext.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; +import 'package:im_app/core/ui/base/shadows.dart'; + + +extension AppThemeExt on BuildContext { + AppShadows get shadows => AppShadows(this); +} \ No newline at end of file diff --git a/apps/im_app/lib/core/ui/base/colors.dart b/apps/im_app/lib/core/ui/base/colors.dart index 6d1b2f5..7fc9e25 100644 --- a/apps/im_app/lib/core/ui/base/colors.dart +++ b/apps/im_app/lib/core/ui/base/colors.dart @@ -37,4 +37,21 @@ class AppColors { static const gray800 = Color(0xFF3C4043); static const gray900 = Color(0xFF202124); static const black = Color(0xFF000000); + + // ── Neutral black Scale ───────────────────────────────────────────────────── + static const black12 = Color(0x1F000000); // 12% opacity + static const black60 = Color(0x99000000); // 60% opacity + + /// 阴影颜色 Token + static Color shadow(BuildContext context) { + final brightness = Theme + .of(context) + .brightness; + + if (brightness == Brightness.dark) { + return black60; + } + + return black12; + } } diff --git a/apps/im_app/lib/core/ui/base/shadows.dart b/apps/im_app/lib/core/ui/base/shadows.dart index bbe540f..95aaf44 100644 --- a/apps/im_app/lib/core/ui/base/shadows.dart +++ b/apps/im_app/lib/core/ui/base/shadows.dart @@ -1,104 +1,118 @@ import 'package:flutter/material.dart'; +import 'colors.dart'; -/// 阴影设计 Token +/// 阴影 Design Token /// -/// 统一管理项目中的阴影规范,避免在业务代码中直接写 BoxShadow。 +/// 统一管理项目中的阴影规范,避免在业务代码中直接书写 `BoxShadow`。 +/// 所有阴影通过 Design Token 提供,保证: /// -/// 使用示例: +/// - UI 风格统一 +/// - 支持 Dark / Light Mode +/// - 与设计稿(Figma)保持一致 +/// +/// ## 数据流位置 +/// +/// ``` +/// AppColors(颜色常量) +/// → AppShadows(阴影 Token) +/// → Context Extension(context.shadows) +/// → View 层消费 +/// ``` +/// +/// ## 使用示例 /// /// ```dart /// Container( /// decoration: BoxDecoration( /// color: Colors.white, -/// boxShadow: AppShadows.bs8, +/// boxShadow: context.shadows.bs8, /// ), /// ) /// ``` /// -/// 阴影一般用于: -/// - Card 卡片 -/// - Dialog 弹窗 -/// - Floating Button -/// - 悬浮面板 +/// ## Elevation 体系 /// -/// 设计通常遵循 UI 设计系统的 elevation 规则,例如: -/// 4 / 8 / 12 / 16 +/// 阴影遵循常见 UI 设计系统的层级规范: +/// +/// - **4** : 小卡片 / List Item +/// - **8** : Card / 商品卡片 +/// - **12** : Dropdown / Popover +/// - **16** : Dialog / Modal / 悬浮面板 class AppShadows { - /// 私有构造函数,防止实例化 - AppShadows._(); + /// 构造函数,通过 BuildContext 获取当前主题 + AppShadows(this.context); - // ================================ - // 轻量阴影 - // ================================ - // 适用于轻微层级,例如小卡片 - - /// 轻阴影(4) + /// 当前 Widget 的 BuildContext /// - /// 常用于: + /// 用于根据 Theme 判断 Light / Dark Mode, + /// 从而动态获取阴影颜色。 + final BuildContext context; + + /// 内部统一阴影生成方法 + /// + /// 避免重复创建 `BoxShadow` 逻辑, + /// 所有阴影 Token 都通过该方法生成。 + List _shadow({ + required double blur, + required double dy, + }) { + return [ + BoxShadow( + + /// 阴影颜色来自 Design Token + color: AppColors.shadow(context), + + /// 模糊半径(影响阴影扩散范围) + blurRadius: blur, + + /// 阴影偏移 + offset: Offset(0, dy), + ) + ]; + } + + /// Elevation 4 + /// + /// 适用场景: + /// - List Item /// - 小卡片 - /// - List item - static const List bs4 = [ - BoxShadow( - /// 阴影颜色(透明黑) - color: Color(0x14000000), + List get bs4 => + _shadow( + blur: 4, + dy: 2, + ); - /// 模糊半径 - blurRadius: 4, - - /// 阴影偏移 - offset: Offset(0, 2), - ) - ]; - - // ================================ - // 中等阴影 - // ================================ - - /// 中等阴影(8) + /// Elevation 8 /// - /// 常用于: + /// 适用场景: /// - Card /// - 商品卡片 - static const List bs8 = [ - BoxShadow( - color: Color(0x1F000000), - blurRadius: 8, - offset: Offset(0, 4), - ) - ]; + List get bs8 => + _shadow( + blur: 8, + dy: 4, + ); - // ================================ - // 强阴影 - // ================================ - - /// 强阴影(12) + /// Elevation 12 /// - /// 常用于: - /// - 悬浮卡片 + /// 适用场景: /// - Dropdown - static const List bs12 = [ - BoxShadow( - color: Color(0x26000000), - blurRadius: 12, - offset: Offset(0, 8), - ) - ]; + /// - Popover + List get bs12 => + _shadow( + blur: 12, + dy: 8, + ); - // ================================ - // 高层级阴影 - // ================================ - - /// 高层级阴影(16) + /// Elevation 16 /// - /// 常用于: + /// 适用场景: /// - Dialog /// - Modal /// - Floating Panel - static const List bs16 = [ - BoxShadow( - color: Color(0x26000000), - blurRadius: 16, - offset: Offset(0, 8), - ) - ]; + List get bs16 => + _shadow( + blur: 16, + dy: 8, + ); } \ No newline at end of file From 68a43b36135255a9e5404211bbf960c72a62e19e Mon Sep 17 00:00:00 2001 From: DK Date: Mon, 9 Mar 2026 16:48:07 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat(Core=20UI):=20=20=E7=99=BD=E5=A4=A9?= =?UTF-8?q?=E9=BB=91=E5=A4=9C=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/im_app/lib/core/ui/base/colors.dart | 13 ------------- apps/im_app/lib/core/ui/base/shadows.dart | 13 ++++++++++++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/im_app/lib/core/ui/base/colors.dart b/apps/im_app/lib/core/ui/base/colors.dart index 7fc9e25..435e2ad 100644 --- a/apps/im_app/lib/core/ui/base/colors.dart +++ b/apps/im_app/lib/core/ui/base/colors.dart @@ -41,17 +41,4 @@ class AppColors { // ── Neutral black Scale ───────────────────────────────────────────────────── static const black12 = Color(0x1F000000); // 12% opacity static const black60 = Color(0x99000000); // 60% opacity - - /// 阴影颜色 Token - static Color shadow(BuildContext context) { - final brightness = Theme - .of(context) - .brightness; - - if (brightness == Brightness.dark) { - return black60; - } - - return black12; - } } diff --git a/apps/im_app/lib/core/ui/base/shadows.dart b/apps/im_app/lib/core/ui/base/shadows.dart index 95aaf44..93e6e2e 100644 --- a/apps/im_app/lib/core/ui/base/shadows.dart +++ b/apps/im_app/lib/core/ui/base/shadows.dart @@ -60,7 +60,7 @@ class AppShadows { BoxShadow( /// 阴影颜色来自 Design Token - color: AppColors.shadow(context), + color: _shadowColor, /// 模糊半径(影响阴影扩散范围) blurRadius: blur, @@ -115,4 +115,15 @@ class AppShadows { blur: 16, dy: 8, ); + + /// 阴影颜色 Token + Color get _shadowColor { + final brightness = Theme + .of(context) + .brightness; + + return brightness == Brightness.dark + ? AppColors.black60 + : AppColors.black12; + } } \ No newline at end of file