import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'app_colors.dart'; /// 渐变背景 Scaffold(紫→蓝 4:6 渐变) class GradientScaffold extends StatelessWidget { final PreferredSizeWidget? appBar; final Widget? body; final Widget? floatingActionButton; final Widget? drawer; final Widget? bottomNavigationBar; final bool extendBody; const GradientScaffold({super.key, this.appBar, this.body, this.floatingActionButton, this.drawer, this.bottomNavigationBar, this.extendBody = false}); @override Widget build(BuildContext context) => Container( decoration: const BoxDecoration(gradient: AppColors.bgGradient), child: Scaffold( backgroundColor: Colors.transparent, appBar: appBar, body: body, floatingActionButton: floatingActionButton, drawer: drawer, bottomNavigationBar: bottomNavigationBar, extendBody: extendBody, ), ); } /// 健康管家 — 设计规范 v1.0:紫色系 + 干净白灰 + 12px圆角 class AppTheme { AppTheme._(); // ── 主色调 ── static const Color primary = AppColors.primary; static const Color primaryLight = AppColors.primaryLight; static const Color primaryDark = AppColors.primaryDark; static const Color primaryMid = AppColors.primaryLight; static const Color accent = AppColors.success; static const Color info = AppColors.blueMeasure; // ── 中性色 ── static const Color bg = AppColors.background; static const Color bgSoft = AppColors.background; static const Color surface = AppColors.cardBackground; static const Color surfaceInner = AppColors.cardInner; static const Color text = AppColors.textPrimary; static const Color textSub = AppColors.textSecondary; static const Color textHint = AppColors.textHint; static const Color border = AppColors.border; static const Color divider = AppColors.borderLight; // ── 语义色 ── static const Color success = AppColors.success; static const Color successLight = AppColors.successLight; static const Color error = AppColors.error; static const Color errorLight = AppColors.errorLight; static const Color warning = AppColors.warning; static const Color warningLight = AppColors.warningLight; // ── 圆角(规范:12px 卡片)── static const double rXs = 4; static const double rSm = 8; static const double rMd = 12; static const double rLg = 16; static const double rXl = 20; static const double rPill = 999; // ── 间距(8px 网格)── static const double sXs = 4; static const double sSm = 8; static const double sMd = 12; static const double sLg = 16; static const double sXl = 20; static const double sXxl = 24; // ── 阴影(轻阴影)── static BoxShadow get shadowCard => BoxShadow( color: Colors.black.withOpacity(0.06), blurRadius: 8, offset: const Offset(0, 2), ); static BoxShadow get shadowLight => BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 6, offset: const Offset(0, 1), ); static BoxShadow get shadowElevated => BoxShadow( color: primary.withOpacity(0.08), blurRadius: 12, offset: const Offset(0, 4), ); static BoxShadow get shadowButton => BoxShadow( color: primary.withOpacity(0.25), blurRadius: 12, offset: const Offset(0, 4), ); // ── 智能体配色 ── static const Map agentColors = { 'default': Color(0xFFEDE9FE), 'consultation': Color(0xFFE0E7FF), 'health': Color(0xFFD1FAE5), 'diet': Color(0xFFFEF3C7), 'medication': Color(0xFFFEE2E2), 'report': Color(0xFFDBEAFE), 'exercise': Color(0xFFEDE9FE), }; static Color agentLight(String? name) => agentColors[name] ?? primaryLight; // ── Material 主题 ── static ThemeData get lightTheme => ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: primary, primary: primary, primaryContainer: primaryLight, onPrimary: Colors.white, secondary: accent, surface: surface, brightness: Brightness.light, ), scaffoldBackgroundColor: bg, splashColor: Colors.transparent, highlightColor: Colors.transparent, hoverColor: primaryLight.withOpacity(0.3), fontFamily: null, appBarTheme: AppBarTheme( backgroundColor: surface, foregroundColor: text, elevation: 0, centerTitle: true, scrolledUnderElevation: 0, titleTextStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: text), toolbarHeight: 44, ), cardTheme: CardThemeData( color: surface, elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rMd)), margin: EdgeInsets.zero, ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: bgSoft, contentPadding: const EdgeInsets.symmetric(horizontal: sLg, vertical: 12), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: primary, width: 1), ), hintStyle: TextStyle(color: textHint, fontSize: 15), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: primary, foregroundColor: Colors.white, minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rMd)), textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), elevation: 0, ), ), dialogTheme: DialogThemeData(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rLg))), textTheme: const TextTheme( headlineLarge: TextStyle(fontSize: 24, fontWeight: FontWeight.w700, color: text), titleLarge: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: text), titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: text), bodyLarge: TextStyle(fontSize: 15, color: text, height: 1.5), bodyMedium: TextStyle(fontSize: 13, color: textSub, height: 1.4), labelMedium: TextStyle(fontSize: 13, color: textSub), labelSmall: TextStyle(fontSize: 12, color: textHint), ), ); // ── Shadcn UI 主题 ── static ShadThemeData get shadTheme => ShadThemeData( brightness: Brightness.light, colorScheme: ShadVioletColorScheme.light( background: bg, foreground: text, card: surface, cardForeground: text, popover: surface, popoverForeground: text, primary: primary, primaryForeground: Colors.white, secondary: primaryLight, secondaryForeground: primaryDark, muted: bgSoft, mutedForeground: textSub, accent: accent, accentForeground: Colors.white, destructive: error, destructiveForeground: Colors.white, border: border, input: border, ring: primary, selection: primaryLight, ), radius: BorderRadius.circular(rMd), ); }