skills/material3-expressive-flutter/scripts/generate_theme.dart

252 lines
7.8 KiB
Dart

// generate_theme.dart
//
// Helper script to generate Material 3 Expressive theme configuration
//
// Usage:
// dart run scripts/generate_theme.dart --seed-color 0xFF6200EE --output lib/theme/
//
import 'dart:io';
void main(List<String> args) {
// Parse arguments
String seedColorHex = '0xFF6200EE'; // Default purple
String outputPath = 'lib/theme/';
for (var i = 0; i < args.length; i++) {
if (args[i] == '--seed-color' && i + 1 < args.length) {
seedColorHex = args[i + 1];
} else if (args[i] == '--output' && i + 1 < args.length) {
outputPath = args[i + 1];
}
}
// Ensure output directory exists
final outputDir = Directory(outputPath);
if (!outputDir.existsSync()) {
outputDir.createSync(recursive: true);
}
// Generate theme file
final themeContent = generateThemeFile(seedColorHex);
final themeFile = File('${outputPath}app_theme.dart');
themeFile.writeAsStringSync(themeContent);
print('✅ Theme generated at: ${themeFile.path}');
print('🎨 Seed color: $seedColorHex');
print('\nNext steps:');
print('1. Import in main.dart: import \'theme/app_theme.dart\';');
print('2. Use: MaterialApp(theme: AppTheme.light, darkTheme: AppTheme.dark)');
}
String generateThemeFile(String seedColorHex) {
return '''
// app_theme.dart
// Generated Material 3 Expressive theme configuration
import 'package:flutter/material.dart';
class AppTheme {
// Seed color for theme generation
static const Color _seedColor = Color($seedColorHex);
// Light theme
static ThemeData get light => ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: _seedColor,
brightness: Brightness.light,
),
// Expressive button themes
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100), // Fully rounded
),
minimumSize: const Size(88, 48), // Larger touch targets
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
// Expressive FAB theme
floatingActionButtonTheme: FloatingActionButtonThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28), // Large corner radius
),
sizeConstraints: const BoxConstraints.tightFor(
width: 56,
height: 56,
),
),
// Expressive card theme
cardTheme: CardTheme(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), // More rounded
),
),
// App bar theme
appBarTheme: const AppBarTheme(
centerTitle: false,
elevation: 0,
),
// Navigation bar theme
navigationBarTheme: NavigationBarThemeData(
height: 80, // Larger for M3E
labelBehavior: NavigationDestinationLabelBehavior.alwaysShow,
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
// Navigation rail theme
navigationRailTheme: NavigationRailThemeData(
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
// Input decoration theme
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
),
);
// Dark theme
static ThemeData get dark => ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: _seedColor,
brightness: Brightness.dark,
),
// Same expressive customizations as light theme
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
minimumSize: const Size(88, 48),
),
),
floatingActionButtonTheme: FloatingActionButtonThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
sizeConstraints: const BoxConstraints.tightFor(
width: 56,
height: 56,
),
),
cardTheme: CardTheme(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
appBarTheme: const AppBarTheme(
centerTitle: false,
elevation: 0,
),
navigationBarTheme: NavigationBarThemeData(
height: 80,
labelBehavior: NavigationDestinationLabelBehavior.alwaysShow,
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
navigationRailTheme: NavigationRailThemeData(
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
),
);
// Helper to get current theme based on brightness
static ThemeData getTheme(Brightness brightness) {
return brightness == Brightness.light ? light : dark;
}
}
''';
}