- 全局字体统一(Outfit/DM Sans), 头部/按钮/Toast规范化 - 故事详情页: Genie Suck吸入动画(标题+卡片一起缩小模糊消失) - 书架页: bookPop弹出+粒子效果(三段式动画完整链路) - 音乐页面: 心情卡片emoji换Material图标+彩色圆块横排布局 - 音乐页面: 进度条胶囊宽度对齐, 播放按钮位置修复, 间距均匀化 - 音乐播放: 接入just_audio, 支持播放暂停进度拖拽自动切歌 - 新增: iOS风格毛玻璃Toast, 渐变背景组件, 通知页面 - 阶段总结文档更新 Co-authored-by: Cursor <cursoragent@cursor.com>
100 lines
3.4 KiB
Dart
100 lines
3.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
import 'app_colors.dart';
|
|
|
|
class AppTheme {
|
|
static ThemeData get lightTheme {
|
|
// Base text theme with DM Sans (PRD: 正文/UI 字体)
|
|
final baseTextTheme = GoogleFonts.dmSansTextTheme(const TextTheme(
|
|
// h1 / Large Headings
|
|
displayLarge: TextStyle(
|
|
color: AppColors.textPrimary,
|
|
fontSize: 32,
|
|
fontWeight: FontWeight.w700,
|
|
letterSpacing: -0.5,
|
|
),
|
|
// h2 / Subheadings
|
|
displayMedium: TextStyle(
|
|
color: AppColors.textPrimary,
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
// Body Text
|
|
bodyLarge: TextStyle(
|
|
color: AppColors.textPrimary,
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w400,
|
|
height: 1.5,
|
|
),
|
|
bodyMedium: TextStyle(
|
|
color: AppColors.textSecondary,
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w400,
|
|
),
|
|
// Small captions
|
|
bodySmall: TextStyle(color: AppColors.textLight, fontSize: 12),
|
|
// Button Text
|
|
labelLarge: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
letterSpacing: 0.5,
|
|
),
|
|
));
|
|
|
|
// Apply Outfit to heading styles (PRD: 标题/Display 字体)
|
|
final textTheme = baseTextTheme.copyWith(
|
|
displayLarge: GoogleFonts.outfit(textStyle: baseTextTheme.displayLarge),
|
|
displayMedium: GoogleFonts.outfit(textStyle: baseTextTheme.displayMedium),
|
|
displaySmall: GoogleFonts.outfit(textStyle: baseTextTheme.displaySmall),
|
|
headlineLarge: GoogleFonts.outfit(textStyle: baseTextTheme.headlineLarge),
|
|
headlineMedium: GoogleFonts.outfit(textStyle: baseTextTheme.headlineMedium),
|
|
headlineSmall: GoogleFonts.outfit(textStyle: baseTextTheme.headlineSmall),
|
|
titleLarge: GoogleFonts.outfit(textStyle: baseTextTheme.titleLarge),
|
|
titleMedium: GoogleFonts.outfit(textStyle: baseTextTheme.titleMedium),
|
|
titleSmall: GoogleFonts.outfit(textStyle: baseTextTheme.titleSmall),
|
|
);
|
|
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
scaffoldBackgroundColor: AppColors.bgBase,
|
|
primaryColor: AppColors.primaryIndigo,
|
|
colorScheme: ColorScheme.fromSeed(
|
|
seedColor: AppColors.primaryIndigo,
|
|
primary: AppColors.primaryIndigo,
|
|
secondary: AppColors.primaryPurple,
|
|
surface: AppColors.bgBase,
|
|
background: AppColors.bgBase,
|
|
),
|
|
// PRD: DM Sans 为默认正文字体,回退到系统字体
|
|
fontFamily: GoogleFonts.dmSans().fontFamily,
|
|
fontFamilyFallback: const [
|
|
'Roboto',
|
|
'PingFang SC',
|
|
'Helvetica Neue',
|
|
],
|
|
textTheme: textTheme,
|
|
snackBarTheme: SnackBarThemeData(
|
|
backgroundColor: const Color(0xFFF9FAFB),
|
|
contentTextStyle: const TextStyle(
|
|
color: Color(0xFF374151),
|
|
fontSize: 14,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
behavior: SnackBarBehavior.floating,
|
|
elevation: 4,
|
|
insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Animation Curves from CSS
|
|
// --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
|
|
static const Curve easeSmooth = Cubic(0.4, 0, 0.2, 1);
|
|
|
|
// --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
static const Curve easeBounce = Cubic(0.34, 1.56, 0.64, 1);
|
|
}
|