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..435e2ad 100644 --- a/apps/im_app/lib/core/ui/base/colors.dart +++ b/apps/im_app/lib/core/ui/base/colors.dart @@ -37,4 +37,8 @@ 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 } 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..93e6e2e --- /dev/null +++ b/apps/im_app/lib/core/ui/base/shadows.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'colors.dart'; + +/// 阴影 Design Token +/// +/// 统一管理项目中的阴影规范,避免在业务代码中直接书写 `BoxShadow`。 +/// 所有阴影通过 Design Token 提供,保证: +/// +/// - UI 风格统一 +/// - 支持 Dark / Light Mode +/// - 与设计稿(Figma)保持一致 +/// +/// ## 数据流位置 +/// +/// ``` +/// AppColors(颜色常量) +/// → AppShadows(阴影 Token) +/// → Context Extension(context.shadows) +/// → View 层消费 +/// ``` +/// +/// ## 使用示例 +/// +/// ```dart +/// Container( +/// decoration: BoxDecoration( +/// color: Colors.white, +/// boxShadow: context.shadows.bs8, +/// ), +/// ) +/// ``` +/// +/// ## Elevation 体系 +/// +/// 阴影遵循常见 UI 设计系统的层级规范: +/// +/// - **4** : 小卡片 / List Item +/// - **8** : Card / 商品卡片 +/// - **12** : Dropdown / Popover +/// - **16** : Dialog / Modal / 悬浮面板 +class AppShadows { + /// 构造函数,通过 BuildContext 获取当前主题 + AppShadows(this.context); + + /// 当前 Widget 的 BuildContext + /// + /// 用于根据 Theme 判断 Light / Dark Mode, + /// 从而动态获取阴影颜色。 + final BuildContext context; + + /// 内部统一阴影生成方法 + /// + /// 避免重复创建 `BoxShadow` 逻辑, + /// 所有阴影 Token 都通过该方法生成。 + List _shadow({ + required double blur, + required double dy, + }) { + return [ + BoxShadow( + + /// 阴影颜色来自 Design Token + color: _shadowColor, + + /// 模糊半径(影响阴影扩散范围) + blurRadius: blur, + + /// 阴影偏移 + offset: Offset(0, dy), + ) + ]; + } + + /// Elevation 4 + /// + /// 适用场景: + /// - List Item + /// - 小卡片 + List get bs4 => + _shadow( + blur: 4, + dy: 2, + ); + + /// Elevation 8 + /// + /// 适用场景: + /// - Card + /// - 商品卡片 + List get bs8 => + _shadow( + blur: 8, + dy: 4, + ); + + /// Elevation 12 + /// + /// 适用场景: + /// - Dropdown + /// - Popover + List get bs12 => + _shadow( + blur: 12, + dy: 8, + ); + + /// Elevation 16 + /// + /// 适用场景: + /// - Dialog + /// - Modal + /// - Floating Panel + List get bs16 => + _shadow( + 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 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