feat(theme): 重构颜色系统为双主题设计并添加渐变组件
- 引入 "The Kinetic Vault"(深色)和 "The Ethereal Terminal"(浅色)双主题系统 - 重构颜色方案,使用层次化 surface 容器替代边框,遵循无边框设计规则 - 添加渐变预设(CTA、买入/卖出、资产卡片)和渐变按钮组件 - 更新圆角系统,明确按钮、卡片、输入框和标签的圆角规范 - 统一文本样式系统,使用 Space Grotesk(标题)和 Manrope(正文)字体 - 更新现有组件(AssetCard、CoinCard、TradeButton)以遵循新设计规范 - 添加向后兼容的已废弃常量,确保现有代码正常运行
This commit is contained in:
@@ -1,118 +1,171 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
/// 现代化颜色系统 - 支持明暗主题
|
||||
/// "The Kinetic Vault" & "The Ethereal Terminal" 双主题颜色系统
|
||||
///
|
||||
/// 深色主题: "The Kinetic Vault" - 高端加密编辑风格
|
||||
/// 浅色主题: "The Ethereal Terminal" - 高端金融科技风格
|
||||
///
|
||||
/// 设计原则:
|
||||
/// - Vercel/Linear 风格的现代简约设计
|
||||
/// - 深色主题:#0A0A0B 背景,微妙阴影
|
||||
/// - 浅色主题:纯白背景,清晰边框
|
||||
/// - 所有对比度 >= 4.5:1 (WCAG AA)
|
||||
/// - 无边框规则: 禁止 1px solid 边框,使用层次色变化
|
||||
/// - 层次化设计: 通过 surface-container 层次而非阴影
|
||||
/// - 渐变 CTA: primary → primary_container (135度)
|
||||
class AppColorScheme {
|
||||
AppColorScheme._();
|
||||
|
||||
// ============================================
|
||||
// 品牌色 - 青绿色 (明暗通用)
|
||||
// 深色主题 - "The Kinetic Vault"
|
||||
// ============================================
|
||||
|
||||
/// 主品牌色 - 深色主题
|
||||
static const Color primaryDark = Color(0xFF00D4AA);
|
||||
/// 背景基色 - 最深
|
||||
static const Color darkBackground = Color(0xFF0b0e14);
|
||||
|
||||
/// 主品牌色 - 浅色主题
|
||||
static const Color primaryLight = Color(0xFF00B894);
|
||||
/// Surface 层次 (从低到高)
|
||||
static const Color darkSurfaceLowest = Color(0xFF0d1017);
|
||||
static const Color darkSurfaceLow = Color(0xFF10131a);
|
||||
static const Color darkSurface = Color(0xFF151921);
|
||||
static const Color darkSurfaceHigh = Color(0xFF1a1f2a);
|
||||
static const Color darkSurfaceHighest = Color(0xFF22262f);
|
||||
|
||||
/// Ghost Border - 后备边框
|
||||
static const Color darkOutlineVariant = Color(0xFF45484f);
|
||||
|
||||
/// Primary - Neon Blue (主要交互)
|
||||
static const Color darkPrimary = Color(0xFF72dcff);
|
||||
static const Color darkPrimaryContainer = Color(0xFF4ac8f0);
|
||||
|
||||
/// Secondary - Electric Purple (次要强调)
|
||||
static const Color darkSecondary = Color(0xFFdd8bfb);
|
||||
static const Color darkSecondaryContainer = Color(0xFF2d1f3d);
|
||||
|
||||
/// Tertiary - Emerald Green (仅用于成功/盈利/买入)
|
||||
static const Color darkTertiary = Color(0xFFafffd1);
|
||||
static const Color darkTertiaryContainer = Color(0xFF1a3d2d);
|
||||
|
||||
/// 文本色
|
||||
static const Color darkOnSurface = Color(0xFFecedf6);
|
||||
static const Color darkOnSurfaceVariant = Color(0xFFa9abb3);
|
||||
static const Color darkOnSurfaceMuted = Color(0xFF6b6d75);
|
||||
|
||||
// ============================================
|
||||
// 语义色 - 涨跌 (明暗通用)
|
||||
// 浅色主题 - "The Ethereal Terminal"
|
||||
// ============================================
|
||||
|
||||
/// 涨/买入 - 绿色
|
||||
static const Color up = Color(0xFF00C853);
|
||||
/// 背景基色 - 珍珠白
|
||||
static const Color lightBackground = Color(0xFFf5f7f9);
|
||||
|
||||
/// 跌/卖出 - 红色
|
||||
/// Surface 层次 (从低到高)
|
||||
static const Color lightSurfaceLowest = Color(0xFFffffff); // Elevated (pop)
|
||||
static const Color lightSurfaceLow = Color(0xFFeef1f3); // Softly recessed
|
||||
static const Color lightSurface = Color(0xFFf5f7f9); // Base canvas
|
||||
static const Color lightSurfaceHigh = Color(0xFFe8ebef); // Elevated
|
||||
static const Color lightSurfaceHighest = Color(0xFFd9dde0); // Navigation anchor
|
||||
|
||||
/// Ghost Border
|
||||
static const Color lightOutlineVariant = Color(0xFFc4c8cc);
|
||||
|
||||
/// Primary - Plasma (主要交互)
|
||||
static const Color lightPrimary = Color(0xFF0050d4);
|
||||
static const Color lightPrimaryContainer = Color(0xFF7b9cff);
|
||||
|
||||
/// Secondary - Pulse indicator
|
||||
static const Color lightSecondary = Color(0xFF8319da);
|
||||
static const Color lightSecondaryContainer = Color(0xFFe8d4fa);
|
||||
|
||||
/// Tertiary - Success (买入/盈利)
|
||||
static const Color lightTertiary = Color(0xFF00a878);
|
||||
static const Color lightTertiaryContainer = Color(0xFFd4f5e9);
|
||||
|
||||
/// 文本色
|
||||
static const Color lightOnSurface = Color(0xFF2c2f31);
|
||||
static const Color lightOnSurfaceVariant = Color(0xFF5a5d60);
|
||||
static const Color lightOnSurfaceMuted = Color(0xFF8a8d90);
|
||||
|
||||
// ============================================
|
||||
// 语义色 - 明暗通用
|
||||
// ============================================
|
||||
|
||||
/// 涨/买入/成功
|
||||
static const Color up = darkTertiary;
|
||||
static const Color success = darkTertiary;
|
||||
|
||||
/// 跌/卖出/错误
|
||||
static const Color down = Color(0xFFFF5252);
|
||||
|
||||
/// 成功
|
||||
static const Color success = Color(0xFF00C853);
|
||||
static const Color error = down;
|
||||
|
||||
/// 警告
|
||||
static const Color warning = Color(0xFFFF9800);
|
||||
|
||||
/// 错误
|
||||
static const Color error = Color(0xFFFF5252);
|
||||
|
||||
/// 信息
|
||||
static const Color info = Color(0xFF2196F3);
|
||||
|
||||
// ============================================
|
||||
// 深色主题颜色 (Vercel/Linear 风格)
|
||||
// 渐变预设
|
||||
// ============================================
|
||||
|
||||
static const Color _darkBackground = Color(0xFF0A0A0B);
|
||||
static const Color _darkCardBackground = Color(0xFF111113);
|
||||
static const Color _darkSecondary = Color(0xFF1C1C1F);
|
||||
static const Color _darkMuted = Color(0xFF27272A);
|
||||
static const Color _darkBorder = Color(0xFF27272A);
|
||||
static const Color _darkTextPrimary = Color(0xFFFFFFFF);
|
||||
static const Color _darkTextSecondary = Color(0xFFA1A1AA);
|
||||
static const Color _darkTextHint = Color(0xFF71717A);
|
||||
/// 深色 CTA 渐变 (primary → primary_container, 135度)
|
||||
static const LinearGradient darkCtaGradient = LinearGradient(
|
||||
colors: [darkPrimary, darkPrimaryContainer],
|
||||
begin: Alignment(-0.7, -0.7),
|
||||
end: Alignment(0.7, 0.7),
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 浅色主题颜色
|
||||
// ============================================
|
||||
/// 浅色 CTA 渐变 (Plasma)
|
||||
static const LinearGradient lightCtaGradient = LinearGradient(
|
||||
colors: [lightPrimary, lightPrimaryContainer],
|
||||
begin: Alignment(-0.7, -0.7),
|
||||
end: Alignment(0.7, 0.7),
|
||||
);
|
||||
|
||||
static const Color _lightBackground = Color(0xFFFFFFFF);
|
||||
static const Color _lightCardBackground = Color(0xFFFAFAFA);
|
||||
static const Color _lightSecondary = Color(0xFFF4F4F5);
|
||||
static const Color _lightMuted = Color(0xFFE4E4E7);
|
||||
static const Color _lightBorder = Color(0xFFE4E4E7);
|
||||
static const Color _lightTextPrimary = Color(0xFF0A0A0B);
|
||||
static const Color _lightTextSecondary = Color(0xFF52525B);
|
||||
static const Color _lightTextHint = Color(0xFF71717A);
|
||||
/// 兼容别名
|
||||
static const LinearGradient ctaGradient = darkCtaGradient;
|
||||
|
||||
/// 买入按钮渐变
|
||||
static const LinearGradient buyGradient = LinearGradient(
|
||||
colors: [darkTertiary, Color(0xFF7de8b8)],
|
||||
begin: Alignment(-0.7, -0.7),
|
||||
end: Alignment(0.7, 0.7),
|
||||
);
|
||||
|
||||
/// 卖出按钮渐变
|
||||
static const LinearGradient sellGradient = LinearGradient(
|
||||
colors: [down, Color(0xFFe84545)],
|
||||
begin: Alignment(-0.7, -0.7),
|
||||
end: Alignment(0.7, 0.7),
|
||||
);
|
||||
|
||||
/// 资产卡片渐变
|
||||
static const LinearGradient assetCardGradient = LinearGradient(
|
||||
colors: [darkPrimary, darkSecondary],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// Shadcn ColorScheme - 深色主题
|
||||
// ============================================
|
||||
|
||||
static ShadColorScheme get darkShad => ShadColorScheme(
|
||||
// 背景与前景
|
||||
background: _darkBackground,
|
||||
foreground: _darkTextPrimary,
|
||||
|
||||
// 卡片
|
||||
card: _darkCardBackground,
|
||||
cardForeground: _darkTextPrimary,
|
||||
|
||||
// 弹出层
|
||||
popover: _darkCardBackground,
|
||||
popoverForeground: _darkTextPrimary,
|
||||
|
||||
// 主色
|
||||
primary: primaryDark,
|
||||
primaryForeground: _darkTextPrimary,
|
||||
|
||||
// 次要色
|
||||
secondary: _darkSecondary,
|
||||
secondaryForeground: _darkTextPrimary,
|
||||
|
||||
// 静音色
|
||||
muted: _darkMuted,
|
||||
mutedForeground: _darkTextSecondary,
|
||||
|
||||
// 强调色
|
||||
accent: primaryDark.withValues(alpha: 0.15),
|
||||
accentForeground: primaryDark,
|
||||
|
||||
// 危险色
|
||||
background: darkBackground,
|
||||
foreground: darkOnSurface,
|
||||
card: darkSurface,
|
||||
cardForeground: darkOnSurface,
|
||||
popover: darkSurfaceHigh,
|
||||
popoverForeground: darkOnSurface,
|
||||
primary: darkPrimary,
|
||||
primaryForeground: darkBackground,
|
||||
secondary: darkSecondary,
|
||||
secondaryForeground: darkOnSurface,
|
||||
muted: darkSurfaceHigh,
|
||||
mutedForeground: darkOnSurfaceVariant,
|
||||
accent: darkPrimary.withValues(alpha: 0.15),
|
||||
accentForeground: darkPrimary,
|
||||
destructive: error,
|
||||
destructiveForeground: _darkTextPrimary,
|
||||
|
||||
// 边框与输入
|
||||
border: _darkBorder,
|
||||
input: _darkBorder,
|
||||
ring: primaryDark,
|
||||
|
||||
// 选择色
|
||||
selection: primaryDark.withValues(alpha: 0.3),
|
||||
destructiveForeground: darkOnSurface,
|
||||
border: darkOutlineVariant.withValues(alpha: 0.15),
|
||||
input: darkOutlineVariant.withValues(alpha: 0.15),
|
||||
ring: darkPrimary,
|
||||
selection: darkPrimary.withValues(alpha: 0.3),
|
||||
);
|
||||
|
||||
// ============================================
|
||||
@@ -120,45 +173,26 @@ class AppColorScheme {
|
||||
// ============================================
|
||||
|
||||
static ShadColorScheme get lightShad => ShadColorScheme(
|
||||
// 背景与前景
|
||||
background: _lightBackground,
|
||||
foreground: _lightTextPrimary,
|
||||
|
||||
// 卡片
|
||||
card: _lightCardBackground,
|
||||
cardForeground: _lightTextPrimary,
|
||||
|
||||
// 弹出层
|
||||
popover: _lightBackground,
|
||||
popoverForeground: _lightTextPrimary,
|
||||
|
||||
// 主色
|
||||
primary: primaryLight,
|
||||
primaryForeground: _lightBackground,
|
||||
|
||||
// 次要色
|
||||
secondary: _lightSecondary,
|
||||
secondaryForeground: _lightTextPrimary,
|
||||
|
||||
// 静音色
|
||||
muted: _lightMuted,
|
||||
mutedForeground: _lightTextSecondary,
|
||||
|
||||
// 强调色
|
||||
accent: primaryLight.withValues(alpha: 0.15),
|
||||
accentForeground: primaryLight,
|
||||
|
||||
// 危险色
|
||||
background: lightBackground,
|
||||
foreground: lightOnSurface,
|
||||
card: lightSurfaceLowest,
|
||||
cardForeground: lightOnSurface,
|
||||
popover: lightSurfaceLowest,
|
||||
popoverForeground: lightOnSurface,
|
||||
primary: lightPrimary,
|
||||
primaryForeground: Color(0xFFFFFFFF),
|
||||
secondary: lightSecondary,
|
||||
secondaryForeground: lightOnSurface,
|
||||
muted: lightSurfaceHigh,
|
||||
mutedForeground: lightOnSurfaceVariant,
|
||||
accent: lightPrimary.withValues(alpha: 0.1),
|
||||
accentForeground: lightPrimary,
|
||||
destructive: error,
|
||||
destructiveForeground: _lightBackground,
|
||||
|
||||
// 边框与输入
|
||||
border: _lightBorder,
|
||||
input: _lightBorder,
|
||||
ring: primaryLight,
|
||||
|
||||
// 选择色
|
||||
selection: primaryLight.withValues(alpha: 0.3),
|
||||
destructiveForeground: Color(0xFFFFFFFF),
|
||||
border: lightOutlineVariant.withValues(alpha: 0.5),
|
||||
input: lightOutlineVariant.withValues(alpha: 0.3),
|
||||
ring: lightPrimary,
|
||||
selection: lightPrimary.withValues(alpha: 0.2),
|
||||
);
|
||||
|
||||
// ============================================
|
||||
@@ -166,15 +200,22 @@ class AppColorScheme {
|
||||
// ============================================
|
||||
|
||||
static ColorScheme get darkMaterial => ColorScheme.dark(
|
||||
primary: primaryDark,
|
||||
onPrimary: _darkTextPrimary,
|
||||
secondary: _darkSecondary,
|
||||
onSecondary: _darkTextPrimary,
|
||||
primary: darkPrimary,
|
||||
onPrimary: darkBackground,
|
||||
secondary: darkSecondary,
|
||||
onSecondary: darkOnSurface,
|
||||
tertiary: darkTertiary,
|
||||
onTertiary: darkBackground,
|
||||
error: error,
|
||||
onError: _darkTextPrimary,
|
||||
surface: _darkCardBackground,
|
||||
onSurface: _darkTextPrimary,
|
||||
surfaceContainerHighest: _darkBackground,
|
||||
onError: darkOnSurface,
|
||||
surface: darkSurface,
|
||||
onSurface: darkOnSurface,
|
||||
surfaceContainerLowest: darkSurfaceLowest,
|
||||
surfaceContainerLow: darkSurfaceLow,
|
||||
surfaceContainer: darkSurface,
|
||||
surfaceContainerHigh: darkSurfaceHigh,
|
||||
surfaceContainerHighest: darkSurfaceHighest,
|
||||
outlineVariant: darkOutlineVariant,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
@@ -182,16 +223,81 @@ class AppColorScheme {
|
||||
// ============================================
|
||||
|
||||
static ColorScheme get lightMaterial => ColorScheme.light(
|
||||
primary: primaryLight,
|
||||
onPrimary: _lightBackground,
|
||||
secondary: _lightSecondary,
|
||||
onSecondary: _lightTextPrimary,
|
||||
primary: lightPrimary,
|
||||
onPrimary: Color(0xFFFFFFFF),
|
||||
secondary: lightSecondary,
|
||||
onSecondary: Color(0xFFFFFFFF),
|
||||
tertiary: lightTertiary,
|
||||
onTertiary: Color(0xFFFFFFFF),
|
||||
error: error,
|
||||
onError: _lightBackground,
|
||||
surface: _lightCardBackground,
|
||||
onSurface: _lightTextPrimary,
|
||||
surfaceContainerHighest: _lightBackground,
|
||||
onError: Color(0xFFFFFFFF),
|
||||
surface: lightSurface,
|
||||
onSurface: lightOnSurface,
|
||||
surfaceContainerLowest: lightSurfaceLowest,
|
||||
surfaceContainerLow: lightSurfaceLow,
|
||||
surfaceContainer: lightSurface,
|
||||
surfaceContainerHigh: lightSurfaceHigh,
|
||||
surfaceContainerHighest: lightSurfaceHighest,
|
||||
outlineVariant: lightOutlineVariant,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 兼容性常量 (已废弃,保留向后兼容)
|
||||
// ============================================
|
||||
|
||||
@Deprecated('Use darkPrimary instead')
|
||||
static const Color primaryDark = darkPrimary;
|
||||
|
||||
@Deprecated('Use lightPrimary instead')
|
||||
static const Color primaryLight = lightPrimary;
|
||||
|
||||
@Deprecated('Use darkBackground instead')
|
||||
static const Color _darkBackground = darkBackground;
|
||||
|
||||
@Deprecated('Use darkSurface instead')
|
||||
static const Color _darkCardBackground = darkSurface;
|
||||
|
||||
@Deprecated('Use darkSurfaceHigh instead')
|
||||
static const Color _darkSecondary = darkSurfaceHigh;
|
||||
|
||||
@Deprecated('Use darkSurfaceHigh instead')
|
||||
static const Color _darkMuted = darkSurfaceHigh;
|
||||
|
||||
@Deprecated('Use darkOutlineVariant instead')
|
||||
static const Color _darkBorder = darkOutlineVariant;
|
||||
|
||||
@Deprecated('Use darkOnSurface instead')
|
||||
static const Color _darkTextPrimary = darkOnSurface;
|
||||
|
||||
@Deprecated('Use darkOnSurfaceVariant instead')
|
||||
static const Color _darkTextSecondary = darkOnSurfaceVariant;
|
||||
|
||||
@Deprecated('Use darkOnSurfaceMuted instead')
|
||||
static const Color _darkTextHint = darkOnSurfaceMuted;
|
||||
|
||||
@Deprecated('Use lightBackground instead')
|
||||
static const Color _lightBackground = lightBackground;
|
||||
|
||||
@Deprecated('Use lightSurfaceLowest instead')
|
||||
static const Color _lightCardBackground = lightSurfaceLowest;
|
||||
|
||||
@Deprecated('Use lightSurfaceHigh instead')
|
||||
static const Color _lightSecondary = lightSurfaceHigh;
|
||||
|
||||
@Deprecated('Use lightSurfaceHigh instead')
|
||||
static const Color _lightMuted = lightSurfaceHigh;
|
||||
|
||||
@Deprecated('Use lightOutlineVariant instead')
|
||||
static const Color _lightBorder = lightOutlineVariant;
|
||||
|
||||
@Deprecated('Use lightOnSurface instead')
|
||||
static const Color _lightTextPrimary = lightOnSurface;
|
||||
|
||||
@Deprecated('Use lightOnSurfaceVariant instead')
|
||||
static const Color _lightTextSecondary = lightOnSurfaceVariant;
|
||||
|
||||
@Deprecated('Use lightOnSurfaceMuted instead')
|
||||
static const Color _lightTextHint = lightOnSurfaceMuted;
|
||||
}
|
||||
|
||||
/// 创建 Shadcn 深色主题
|
||||
|
||||
@@ -67,7 +67,13 @@ class AppSpacing {
|
||||
static SizedBox vertical(double spacing) => SizedBox(height: spacing);
|
||||
}
|
||||
|
||||
/// 圆角系统 - 基于 modernization-v2.md 规范
|
||||
/// 圆角系统 - "The Kinetic Vault" & "The Ethereal Terminal" 规范
|
||||
///
|
||||
/// 设计规则:
|
||||
/// - 按钮: xxl (24px / 1.5rem)
|
||||
/// - 卡片: xl (16px)
|
||||
/// - 输入框: md (8px)
|
||||
/// - 标签: sm (4px)
|
||||
class AppRadius {
|
||||
AppRadius._();
|
||||
|
||||
@@ -78,19 +84,19 @@ class AppRadius {
|
||||
/// 小圆角 - 4px (标签、小组件)
|
||||
static const double sm = 4.0;
|
||||
|
||||
/// 中圆角 - 8px (按钮、输入框)
|
||||
/// 中圆角 - 8px (输入框)
|
||||
static const double md = 8.0;
|
||||
|
||||
/// 大圆角 - 12px (卡片)
|
||||
/// 大圆角 - 12px (卡片 - 旧版)
|
||||
static const double lg = 12.0;
|
||||
|
||||
/// 特大圆角 - 16px (大卡片)
|
||||
static const double xl = 16.0;
|
||||
|
||||
/// 超大圆角 - 24px (模态框、底部抽屉)
|
||||
/// 超大圆角 - 24px (按钮、模态框、底部抽屉)
|
||||
static const double xxl = 24.0;
|
||||
|
||||
/// 圆形 - 9999px
|
||||
/// 圆形 - 9999px (Pill buttons)
|
||||
static const double full = 9999.0;
|
||||
|
||||
// ============================================
|
||||
|
||||
@@ -3,294 +3,429 @@ import 'package:google_fonts/google_fonts.dart';
|
||||
import 'app_color_scheme.dart';
|
||||
import 'app_spacing.dart';
|
||||
|
||||
/// 应用主题配置 - 基于 modernization-v2.md 规范
|
||||
/// "The Kinetic Vault" & "The Ethereal Terminal" 主题配置
|
||||
class AppTheme {
|
||||
AppTheme._();
|
||||
|
||||
// ============================================
|
||||
// 深色主题
|
||||
// 深色主题 - "The Kinetic Vault"
|
||||
// ============================================
|
||||
|
||||
static ThemeData get darkTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
scaffoldBackgroundColor: AppColorScheme.darkShad.background,
|
||||
primaryColor: AppColorScheme.primaryDark,
|
||||
scaffoldBackgroundColor: AppColorScheme.darkBackground,
|
||||
primaryColor: AppColorScheme.darkPrimary,
|
||||
colorScheme: AppColorScheme.darkMaterial,
|
||||
|
||||
// AppBar - 无边框规则
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: AppColorScheme.darkShad.background,
|
||||
foregroundColor: AppColorScheme.darkShad.foreground,
|
||||
backgroundColor: AppColorScheme.darkBackground,
|
||||
foregroundColor: AppColorScheme.darkOnSurface,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
centerTitle: true,
|
||||
titleTextStyle: GoogleFonts.inter(
|
||||
titleTextStyle: GoogleFonts.spaceGrotesk(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColorScheme.darkShad.foreground,
|
||||
color: AppColorScheme.darkOnSurface,
|
||||
),
|
||||
),
|
||||
|
||||
// 卡片 - 无边框,使用 surface 层次
|
||||
cardTheme: CardThemeData(
|
||||
color: AppColorScheme.darkSurface,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.xl),
|
||||
),
|
||||
),
|
||||
|
||||
// 输入框 - Ghost Border 风格
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: AppColorScheme.darkShad.card,
|
||||
fillColor: AppColorScheme.darkSurfaceLow,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderSide: BorderSide(color: AppColorScheme.darkShad.border),
|
||||
borderSide: BorderSide(
|
||||
color: AppColorScheme.darkOutlineVariant.withValues(alpha: 0.15),
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderSide: BorderSide(color: AppColorScheme.darkShad.border),
|
||||
borderSide: BorderSide(
|
||||
color: AppColorScheme.darkOutlineVariant.withValues(alpha: 0.15),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderSide: BorderSide(color: AppColorScheme.primaryDark, width: 2),
|
||||
borderSide: const BorderSide(color: AppColorScheme.darkPrimary, width: 2),
|
||||
),
|
||||
hintStyle: TextStyle(color: AppColorScheme.darkShad.mutedForeground),
|
||||
hintStyle: TextStyle(color: AppColorScheme.darkOnSurfaceMuted),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.md,
|
||||
vertical: 14,
|
||||
),
|
||||
),
|
||||
|
||||
// 按钮 - 渐变 CTA,大圆角
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColorScheme.primaryDark,
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: AppColorScheme.darkPrimary,
|
||||
foregroundColor: AppColorScheme.darkBackground,
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderRadius: BorderRadius.circular(AppRadius.xxl),
|
||||
),
|
||||
textStyle: GoogleFonts.inter(
|
||||
elevation: 0,
|
||||
textStyle: GoogleFonts.manrope(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColorScheme.primaryDark,
|
||||
foregroundColor: AppColorScheme.darkPrimary,
|
||||
),
|
||||
),
|
||||
|
||||
// 分割线 - 使用层次而非边框
|
||||
dividerTheme: DividerThemeData(
|
||||
color: AppColorScheme.darkShad.border,
|
||||
color: AppColorScheme.darkOutlineVariant.withValues(alpha: 0.1),
|
||||
thickness: 1,
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
color: AppColorScheme.darkShad.card,
|
||||
|
||||
// 底部导航
|
||||
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
||||
backgroundColor: AppColorScheme.darkSurface,
|
||||
selectedItemColor: AppColorScheme.darkPrimary,
|
||||
unselectedItemColor: AppColorScheme.darkOnSurfaceVariant,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 浅色主题
|
||||
// 浅色主题 - "The Ethereal Terminal"
|
||||
// ============================================
|
||||
|
||||
static ThemeData get lightTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.light,
|
||||
scaffoldBackgroundColor: AppColorScheme.lightShad.background,
|
||||
primaryColor: AppColorScheme.primaryLight,
|
||||
scaffoldBackgroundColor: AppColorScheme.lightBackground,
|
||||
primaryColor: AppColorScheme.lightPrimary,
|
||||
colorScheme: AppColorScheme.lightMaterial,
|
||||
|
||||
// AppBar - 珍珠白
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: AppColorScheme.lightShad.background,
|
||||
foregroundColor: AppColorScheme.lightShad.foreground,
|
||||
backgroundColor: AppColorScheme.lightBackground,
|
||||
foregroundColor: AppColorScheme.lightOnSurface,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
centerTitle: true,
|
||||
titleTextStyle: GoogleFonts.inter(
|
||||
titleTextStyle: GoogleFonts.spaceGrotesk(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColorScheme.lightShad.foreground,
|
||||
color: AppColorScheme.lightOnSurface,
|
||||
),
|
||||
),
|
||||
|
||||
// 卡片 - Elevated (pop) on pearl background
|
||||
cardTheme: CardThemeData(
|
||||
color: AppColorScheme.lightSurfaceLowest,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.xl),
|
||||
),
|
||||
),
|
||||
|
||||
// 输入框 - 底部线条风格
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: AppColorScheme.lightShad.card,
|
||||
border: OutlineInputBorder(
|
||||
fillColor: AppColorScheme.lightSurfaceLow,
|
||||
border: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderSide: BorderSide(color: AppColorScheme.lightShad.border),
|
||||
borderSide: BorderSide(
|
||||
color: AppColorScheme.lightOutlineVariant.withValues(alpha: 0.5),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderSide: BorderSide(color: AppColorScheme.lightShad.border),
|
||||
borderSide: BorderSide(
|
||||
color: AppColorScheme.lightOutlineVariant.withValues(alpha: 0.5),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderSide: BorderSide(color: AppColorScheme.primaryLight, width: 2),
|
||||
borderSide: const BorderSide(color: AppColorScheme.lightPrimary, width: 2),
|
||||
),
|
||||
hintStyle: TextStyle(color: AppColorScheme.lightShad.mutedForeground),
|
||||
hintStyle: TextStyle(color: AppColorScheme.lightOnSurfaceMuted),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.md,
|
||||
vertical: 14,
|
||||
),
|
||||
),
|
||||
|
||||
// 按钮 - Plasma 渐变,full 圆角
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColorScheme.primaryLight,
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: AppColorScheme.lightPrimary,
|
||||
foregroundColor: const Color(0xFFFFFFFF),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
borderRadius: BorderRadius.circular(AppRadius.xxl),
|
||||
),
|
||||
textStyle: GoogleFonts.inter(
|
||||
elevation: 0,
|
||||
textStyle: GoogleFonts.manrope(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColorScheme.primaryLight,
|
||||
foregroundColor: AppColorScheme.lightPrimary,
|
||||
),
|
||||
),
|
||||
|
||||
// 分割线 - 不使用,用留白代替
|
||||
dividerTheme: DividerThemeData(
|
||||
color: AppColorScheme.lightShad.border,
|
||||
color: AppColorScheme.lightOutlineVariant.withValues(alpha: 0.2),
|
||||
thickness: 1,
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
color: AppColorScheme.lightShad.card,
|
||||
|
||||
// 底部导航
|
||||
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
||||
backgroundColor: AppColorScheme.lightSurfaceHighest,
|
||||
selectedItemColor: AppColorScheme.lightPrimary,
|
||||
unselectedItemColor: AppColorScheme.lightOnSurfaceVariant,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 文本样式 - 使用 Google Fonts
|
||||
/// "The Kinetic Vault" & "The Ethereal Terminal" 文字样式系统
|
||||
///
|
||||
/// Display/Headlines: Space Grotesk (编辑风格)
|
||||
/// Body/Labels: Manrope (实用风格)
|
||||
class AppTextStyles {
|
||||
AppTextStyles._();
|
||||
|
||||
// ============================================
|
||||
// 标题样式 - Inter 字体
|
||||
// Display - 编辑风格 (Space Grotesk)
|
||||
// ============================================
|
||||
|
||||
static TextStyle displayLarge(BuildContext context) => GoogleFonts.inter(
|
||||
fontSize: 32,
|
||||
/// D1 - 大标题 (48px) - Hero moments
|
||||
static TextStyle displayLarge(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.1,
|
||||
letterSpacing: -0.02,
|
||||
);
|
||||
|
||||
static TextStyle displayMedium(BuildContext context) => GoogleFonts.inter(
|
||||
/// D2 - 中标题 (36px)
|
||||
static TextStyle displayMedium(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.2,
|
||||
letterSpacing: -0.01,
|
||||
);
|
||||
|
||||
/// D3 - 小标题 (28px)
|
||||
static TextStyle displaySmall(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.25,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// Headline - 编辑风格 (Space Grotesk)
|
||||
// ============================================
|
||||
|
||||
static TextStyle headlineLarge(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.3,
|
||||
);
|
||||
|
||||
static TextStyle displaySmall(BuildContext context) => GoogleFonts.inter(
|
||||
static TextStyle headlineMedium(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.35,
|
||||
);
|
||||
|
||||
static TextStyle headlineSmall(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 正文样式 - Inter 字体
|
||||
// Body - 实用风格 (Manrope)
|
||||
// ============================================
|
||||
|
||||
static TextStyle bodyLarge(BuildContext context) => GoogleFonts.inter(
|
||||
static TextStyle bodyLarge(BuildContext context) => GoogleFonts.manrope(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
static TextStyle bodyMedium(BuildContext context) => GoogleFonts.inter(
|
||||
static TextStyle bodyMedium(BuildContext context) => GoogleFonts.manrope(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
static TextStyle bodySmall(BuildContext context) => GoogleFonts.inter(
|
||||
static TextStyle bodySmall(BuildContext context) => GoogleFonts.manrope(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
height: 1.45,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 数字样式 - JetBrains Mono 等宽字体
|
||||
// Label - 实用风格 (Manrope)
|
||||
// ============================================
|
||||
|
||||
static TextStyle numberLarge(BuildContext context) => GoogleFonts.jetBrainsMono(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
);
|
||||
|
||||
static TextStyle numberMedium(BuildContext context) => GoogleFonts.jetBrainsMono(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
);
|
||||
|
||||
static TextStyle numberSmall(BuildContext context) => GoogleFonts.jetBrainsMono(
|
||||
static TextStyle labelLarge(BuildContext context) => GoogleFonts.manrope(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
static TextStyle labelMedium(BuildContext context) => GoogleFonts.manrope(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
static TextStyle labelSmall(BuildContext context) => GoogleFonts.manrope(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 便捷静态样式(兼容旧代码)
|
||||
// 数字/金额 - Space Grotesk (等宽特性)
|
||||
// ============================================
|
||||
|
||||
static TextStyle numberLarge(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.2,
|
||||
fontFeatures: const [FontFeature.tabularFigures()],
|
||||
);
|
||||
|
||||
static TextStyle numberMedium(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.25,
|
||||
fontFeatures: const [FontFeature.tabularFigures()],
|
||||
);
|
||||
|
||||
static TextStyle numberSmall(BuildContext context) => GoogleFonts.spaceGrotesk(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.3,
|
||||
fontFeatures: const [FontFeature.tabularFigures()],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 兼容旧代码的静态样式 (已废弃)
|
||||
// ============================================
|
||||
|
||||
@Deprecated('Use displaySmall instead')
|
||||
static const TextStyle heading1 = TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use headlineLarge instead')
|
||||
static const TextStyle heading2 = TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use headlineMedium instead')
|
||||
static const TextStyle heading3 = TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use headlineSmall instead')
|
||||
static const TextStyle heading4 = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use bodyLarge instead')
|
||||
static const TextStyle body1 = TextStyle(
|
||||
fontSize: 16,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use bodyMedium instead')
|
||||
static const TextStyle body2 = TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use labelSmall instead')
|
||||
static const TextStyle caption = TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFFA1A1AA),
|
||||
);
|
||||
|
||||
@Deprecated('Use labelSmall instead')
|
||||
static const TextStyle hint = TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF71717A),
|
||||
);
|
||||
|
||||
@Deprecated('Use numberMedium instead')
|
||||
static const TextStyle price = TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
@Deprecated('Use numberSmall with color instead')
|
||||
static const TextStyle change = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
@Deprecated('Use numberSmall instead')
|
||||
static const TextStyle number = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
||||
Reference in New Issue
Block a user