- 全局字体统一(Outfit/DM Sans), 头部/按钮/Toast规范化 - 故事详情页: Genie Suck吸入动画(标题+卡片一起缩小模糊消失) - 书架页: bookPop弹出+粒子效果(三段式动画完整链路) - 音乐页面: 心情卡片emoji换Material图标+彩色圆块横排布局 - 音乐页面: 进度条胶囊宽度对齐, 播放按钮位置修复, 间距均匀化 - 音乐播放: 接入just_audio, 支持播放暂停进度拖拽自动切歌 - 新增: iOS风格毛玻璃Toast, 渐变背景组件, 通知页面 - 阶段总结文档更新 Co-authored-by: Cursor <cursoragent@cursor.com>
272 lines
7.6 KiB
Dart
272 lines
7.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
|
|
/// 颜色定义 - 精确还原 Profile PRD
|
|
class AppColors {
|
|
// 文字颜色
|
|
static const Color textPrimary = Color(0xFF374151);
|
|
static const Color textSecondary = Color(0xFF9CA3AF);
|
|
static const Color textHint = Color(0xFFD1D5DB); // Arrow icon color
|
|
|
|
// 背景颜色
|
|
static const Color background = Color(0xFFFAFBFC);
|
|
static const Color cardSurface = Color(
|
|
0xCCFFFFFF,
|
|
); // rgba(255, 255, 255, 0.8)
|
|
|
|
// Story Page
|
|
static const Color storyBackground = Color(0xFFFDF9F3);
|
|
static const Color storyTitle = Color(0xFF4B2404);
|
|
static const Color storyText = Color(0xFF374151);
|
|
|
|
// Bookshelf (Story Book) - CSS .story-book, .story-slot
|
|
static const Color bookshelfBg = Color(
|
|
0x8CFFFFFF,
|
|
); // rgba(255, 255, 255, 0.55)
|
|
static const Color bookshelfBorder = Color(
|
|
0x99FFFFFF,
|
|
); // rgba(255, 255, 255, 0.6)
|
|
static const Color bookCountBg = Color(
|
|
0x80FFFFFF,
|
|
); // rgba(255, 255, 255, 0.5)
|
|
static const Color slotBg = Color(0x99FFFFFF); // rgba(255, 255, 255, 0.6)
|
|
static const Color slotClickableBg = Color(
|
|
0x66FFFFFF,
|
|
); // rgba(255, 255, 255, 0.4)
|
|
static const Color slotBorder = Color(0x0D000000); // rgba(0, 0, 0, 0.05)
|
|
static const Color slotTitleBarBg = Color(0x99000000); // rgba(0, 0, 0, 0.6)
|
|
static const Color slotFilledShadow = Color(0x1A000000); // rgba(0, 0, 0, 0.1)
|
|
static const Color emptyPlusColor = Color(0xFF9CA3AF);
|
|
static const Color bookTitleColor = Color(0xFF374151);
|
|
static const Color bookCountColor = Color(0xFF6B7280);
|
|
|
|
// 状态颜色
|
|
static const Color notificationDot = Color(0xFFEF4444);
|
|
static const Color badgeNew = Color(0xFFEF4444);
|
|
|
|
// 按钮/交互 — 统一规范: 白底 0.6 透明度, 无边框
|
|
static const Color iconBtnBg = Color(0x99FFFFFF); // rgba(255, 255, 255, 0.6)
|
|
static const Color iconBtnBorder = Color(
|
|
0x66FFFFFF,
|
|
); // rgba(255, 255, 255, 0.4) — 保留定义但不再使用
|
|
|
|
// 危险操作
|
|
static const Color danger = Color(0xFFEF4444);
|
|
|
|
// 表单 & 列表
|
|
static const Color formLabel = Color(0xFF6B7280);
|
|
static const Color sectionTitle = Color(0xFF9CA3AF);
|
|
static const Color divider = Color(0x0D000000); // rgba(0, 0, 0, 0.05)
|
|
|
|
// 渐变色 (Avatar & Buttons)
|
|
static const List<Color> avatarGradient = [
|
|
Color(0xFFECCFA8),
|
|
Color(0xFFC99672),
|
|
];
|
|
static const List<Color> saveBtnGradient = [
|
|
Color(0xFFECCFA8),
|
|
Color(0xFFC99672),
|
|
];
|
|
static const List<Color> btnCapybaraGradient = [
|
|
Color(0xFFECCFA8),
|
|
Color(0xFFC99672),
|
|
];
|
|
|
|
// 产品卡片渐变
|
|
static const List<Color> gradientCapybara = [
|
|
Color(0xFFE6B98D),
|
|
Color(0xFFE8C9A8),
|
|
Color(0xFFD4A373),
|
|
Color(0xFFB07D5A),
|
|
];
|
|
static const List<Color> gradientBadgeAI = [
|
|
Color(0xFF22D3EE),
|
|
Color(0xFF60A5FA),
|
|
Color(0xFF818CF8),
|
|
Color(0xFFA78BFA),
|
|
];
|
|
static const List<Color> gradientBadgeBasic = [
|
|
Color(0xFFC084FC),
|
|
Color(0xFFD8B4FE),
|
|
Color(0xFFC4B5FD),
|
|
Color(0xFFA78BFA),
|
|
];
|
|
static const List<Color> gradientBracelet = [
|
|
Color(0xFFFDBA74),
|
|
Color(0xFFFB923C),
|
|
Color(0xFFFBAF85),
|
|
Color(0xFFE07B54),
|
|
];
|
|
static const List<Color> gradientVSinger = [
|
|
Color(0xFF34D399),
|
|
Color(0xFF5EEAD4),
|
|
Color(0xFF22D3EE),
|
|
Color(0xFF2DD4BF),
|
|
];
|
|
|
|
// 遮罩
|
|
static const Color overlay = Color(0x80000000); // implied for modal overlay
|
|
}
|
|
|
|
/// 字体样式 - PRD规范: Outfit(标题) + DM Sans(正文) + Press Start 2P(Logo)
|
|
class AppTextStyles {
|
|
// 页面标题 — 统一规范: 17px w600 #1F2937
|
|
static final TextStyle title = GoogleFonts.outfit(
|
|
fontSize: 17,
|
|
fontWeight: FontWeight.w600,
|
|
color: const Color(0xFF1F2937),
|
|
);
|
|
|
|
// User Name → Outfit (heading/display)
|
|
static final TextStyle userName = GoogleFonts.outfit(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppColors.textPrimary,
|
|
);
|
|
|
|
// User ID → DM Sans (body)
|
|
static final TextStyle userId = GoogleFonts.dmSans(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w400,
|
|
color: AppColors.textSecondary,
|
|
);
|
|
|
|
// Menu Text → DM Sans (body/UI)
|
|
static final TextStyle menuText = GoogleFonts.dmSans(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w400,
|
|
color: AppColors.textPrimary,
|
|
);
|
|
|
|
// Badge Text → DM Sans (small UI)
|
|
static final TextStyle badge = GoogleFonts.dmSans(
|
|
fontSize: 10,
|
|
fontWeight: FontWeight.w400,
|
|
color: Colors.white,
|
|
);
|
|
|
|
// Modal Title → Outfit (heading)
|
|
static final TextStyle modalTitle = GoogleFonts.outfit(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppColors.textPrimary,
|
|
);
|
|
|
|
// Book specific styles → Outfit (heading)
|
|
static final TextStyle bookTitle = GoogleFonts.outfit(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w700,
|
|
color: AppColors.textPrimary,
|
|
);
|
|
|
|
// Book count → DM Sans (body)
|
|
static final TextStyle bookCount = GoogleFonts.dmSans(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppColors.textSecondary,
|
|
);
|
|
|
|
// Slot title → DM Sans (small UI)
|
|
static final TextStyle slotTitle = GoogleFonts.dmSans(
|
|
fontSize: 10,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w400,
|
|
);
|
|
|
|
// PRD: font-size: 24px, color: #9CA3AF, font-weight: 300, opacity: 0.7
|
|
static final TextStyle emptyPlus = GoogleFonts.dmSans(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.w300,
|
|
color: const Color(0xB39CA3AF), // #9CA3AF with 0.7 opacity
|
|
);
|
|
|
|
// Button text → DM Sans (UI)
|
|
static final TextStyle createStoryBtn = GoogleFonts.dmSans(
|
|
fontSize: 17,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.white,
|
|
);
|
|
}
|
|
|
|
/// 间距定义
|
|
class AppSpacing {
|
|
static const double xs = 4.0;
|
|
static const double sm = 8.0;
|
|
static const double md = 16.0;
|
|
static const double lg = 20.0;
|
|
static const double xl = 24.0;
|
|
}
|
|
|
|
/// 圆角定义
|
|
class AppRadius {
|
|
static const double card = 20.0;
|
|
static const double button = 12.0; // 统一规范: 圆角 12
|
|
static const double avatar = 32.0; // 64px size / 2
|
|
static const double badge = 10.0;
|
|
}
|
|
|
|
/// 阴影定义
|
|
class AppShadows {
|
|
static const BoxShadow card = BoxShadow(
|
|
color: Color(0x148B5E3C), // rgba(139, 94, 60, 0.08)
|
|
blurRadius: 20,
|
|
offset: Offset(0, 4),
|
|
);
|
|
|
|
static const BoxShadow btnCapybara = BoxShadow(
|
|
color: Color(0x59C99672), // rgba(201, 150, 114, 0.35)
|
|
blurRadius: 15,
|
|
offset: Offset(0, 4),
|
|
);
|
|
|
|
static const BoxShadow storyBook = BoxShadow(
|
|
color: Color(0x08000000), // rgba(0,0,0,0.03)
|
|
blurRadius: 40,
|
|
offset: Offset(0, 10),
|
|
);
|
|
|
|
static const BoxShadow storySlotFilled = BoxShadow(
|
|
color: Color(0x1A000000), // rgba(0,0,0,0.1)
|
|
blurRadius: 12,
|
|
offset: Offset(0, 4),
|
|
);
|
|
|
|
static const List<BoxShadow> createBtn = [
|
|
BoxShadow(color: Color(0x59C99672), blurRadius: 15), // glow
|
|
BoxShadow(color: Color(0x40C99672), blurRadius: 30), // outer glow
|
|
BoxShadow(
|
|
color: Color(0x66C99672),
|
|
blurRadius: 20,
|
|
offset: Offset(0, 6),
|
|
), // depth
|
|
];
|
|
}
|
|
|
|
/// Story Book Spacing
|
|
class StoryBookSpacing {
|
|
static const double bookPadding = 24.0;
|
|
static const double gridGap = 12.0;
|
|
static const double bookCoverMarginBottom = 20.0;
|
|
static const EdgeInsets bookCountPadding = EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
vertical: 4,
|
|
);
|
|
static const EdgeInsets titleBarPadding = EdgeInsets.symmetric(
|
|
horizontal: 6,
|
|
vertical: 4,
|
|
);
|
|
// PRD: padding: 16px 48px
|
|
static const EdgeInsets createBtnPadding = EdgeInsets.symmetric(
|
|
horizontal: 48, // PRD: 48px
|
|
vertical: 16, // PRD: 16px
|
|
);
|
|
}
|
|
|
|
/// Story Book Radius
|
|
class StoryBookRadius {
|
|
static const double book = 24.0;
|
|
static const double slot = 12.0;
|
|
static const double bookCount = 12.0;
|
|
static const double createBtn = 29.0;
|
|
}
|