WIP: feat(ui): Migrate to new UI implementation
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:moonwell_launcher/core/moonwell_theme_variant.dart';
|
||||
import 'package:moonwell_launcher/features/preferences/domain/repositories/preferences_repository.dart';
|
||||
|
||||
export 'package:moonwell_launcher/core/moonwell_theme_variant.dart';
|
||||
|
||||
@immutable
|
||||
class MoonWellDesignTokens extends ThemeExtension<MoonWellDesignTokens> {
|
||||
const MoonWellDesignTokens({
|
||||
required this.background,
|
||||
required this.surfaceLow,
|
||||
required this.surface,
|
||||
required this.surfaceHigh,
|
||||
required this.accent,
|
||||
required this.accentMuted,
|
||||
required this.success,
|
||||
required this.warning,
|
||||
required this.border,
|
||||
required this.focusRing,
|
||||
required this.spacing,
|
||||
required this.radiusSmall,
|
||||
required this.radiusMedium,
|
||||
required this.radiusLarge,
|
||||
required this.panelShadow,
|
||||
required this.motionFast,
|
||||
required this.motionStandard,
|
||||
required this.brandFontFamily,
|
||||
required this.monospaceFontFamily,
|
||||
});
|
||||
|
||||
final Color background;
|
||||
final Color surfaceLow;
|
||||
final Color surface;
|
||||
final Color surfaceHigh;
|
||||
final Color accent;
|
||||
final Color accentMuted;
|
||||
final Color success;
|
||||
final Color warning;
|
||||
final BorderSide border;
|
||||
final Color focusRing;
|
||||
final double spacing;
|
||||
final double radiusSmall;
|
||||
final double radiusMedium;
|
||||
final double radiusLarge;
|
||||
final List<BoxShadow> panelShadow;
|
||||
final Duration motionFast;
|
||||
final Duration motionStandard;
|
||||
final String brandFontFamily;
|
||||
final String monospaceFontFamily;
|
||||
|
||||
static MoonWellDesignTokens of(BuildContext context) =>
|
||||
Theme.of(context).extension<MoonWellDesignTokens>()!;
|
||||
|
||||
@override
|
||||
MoonWellDesignTokens copyWith({
|
||||
Color? background,
|
||||
Color? surfaceLow,
|
||||
Color? surface,
|
||||
Color? surfaceHigh,
|
||||
Color? accent,
|
||||
Color? accentMuted,
|
||||
Color? success,
|
||||
Color? warning,
|
||||
BorderSide? border,
|
||||
Color? focusRing,
|
||||
double? spacing,
|
||||
double? radiusSmall,
|
||||
double? radiusMedium,
|
||||
double? radiusLarge,
|
||||
List<BoxShadow>? panelShadow,
|
||||
Duration? motionFast,
|
||||
Duration? motionStandard,
|
||||
String? brandFontFamily,
|
||||
String? monospaceFontFamily,
|
||||
}) {
|
||||
return MoonWellDesignTokens(
|
||||
background: background ?? this.background,
|
||||
surfaceLow: surfaceLow ?? this.surfaceLow,
|
||||
surface: surface ?? this.surface,
|
||||
surfaceHigh: surfaceHigh ?? this.surfaceHigh,
|
||||
accent: accent ?? this.accent,
|
||||
accentMuted: accentMuted ?? this.accentMuted,
|
||||
success: success ?? this.success,
|
||||
warning: warning ?? this.warning,
|
||||
border: border ?? this.border,
|
||||
focusRing: focusRing ?? this.focusRing,
|
||||
spacing: spacing ?? this.spacing,
|
||||
radiusSmall: radiusSmall ?? this.radiusSmall,
|
||||
radiusMedium: radiusMedium ?? this.radiusMedium,
|
||||
radiusLarge: radiusLarge ?? this.radiusLarge,
|
||||
panelShadow: panelShadow ?? this.panelShadow,
|
||||
motionFast: motionFast ?? this.motionFast,
|
||||
motionStandard: motionStandard ?? this.motionStandard,
|
||||
brandFontFamily: brandFontFamily ?? this.brandFontFamily,
|
||||
monospaceFontFamily: monospaceFontFamily ?? this.monospaceFontFamily,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
MoonWellDesignTokens lerp(covariant MoonWellDesignTokens? other, double t) {
|
||||
if (other == null) return this;
|
||||
return MoonWellDesignTokens(
|
||||
background: Color.lerp(background, other.background, t)!,
|
||||
surfaceLow: Color.lerp(surfaceLow, other.surfaceLow, t)!,
|
||||
surface: Color.lerp(surface, other.surface, t)!,
|
||||
surfaceHigh: Color.lerp(surfaceHigh, other.surfaceHigh, t)!,
|
||||
accent: Color.lerp(accent, other.accent, t)!,
|
||||
accentMuted: Color.lerp(accentMuted, other.accentMuted, t)!,
|
||||
success: Color.lerp(success, other.success, t)!,
|
||||
warning: Color.lerp(warning, other.warning, t)!,
|
||||
border: BorderSide.lerp(border, other.border, t),
|
||||
focusRing: Color.lerp(focusRing, other.focusRing, t)!,
|
||||
spacing: lerpDouble(spacing, other.spacing, t),
|
||||
radiusSmall: lerpDouble(radiusSmall, other.radiusSmall, t),
|
||||
radiusMedium: lerpDouble(radiusMedium, other.radiusMedium, t),
|
||||
radiusLarge: lerpDouble(radiusLarge, other.radiusLarge, t),
|
||||
panelShadow: t < .5 ? panelShadow : other.panelShadow,
|
||||
motionFast: t < .5 ? motionFast : other.motionFast,
|
||||
motionStandard: t < .5 ? motionStandard : other.motionStandard,
|
||||
brandFontFamily: t < .5 ? brandFontFamily : other.brandFontFamily,
|
||||
monospaceFontFamily: t < .5
|
||||
? monospaceFontFamily
|
||||
: other.monospaceFontFamily,
|
||||
);
|
||||
}
|
||||
|
||||
static double lerpDouble(double a, double b, double t) => a + (b - a) * t;
|
||||
}
|
||||
|
||||
abstract final class MoonWellTheme {
|
||||
static ThemeData create(MoonWellThemeVariant variant, {String? fontPackage}) {
|
||||
final isForest = variant == MoonWellThemeVariant.forest;
|
||||
const background = Color(0xFF070A18);
|
||||
const surfaceLow = Color(0xFF0A0D1F);
|
||||
const surface = Color(0xFF10142A);
|
||||
const surfaceHigh = Color(0xFF1A1F3A);
|
||||
final accent = isForest ? const Color(0xFF7FB8D4) : const Color(0xFF8A5CC8);
|
||||
const accentMuted = Color(0xFF5B3A8A);
|
||||
const outline = Color(0xFF34455E);
|
||||
const foreground = Color(0xFFECE4D0);
|
||||
const error = Color(0xFFFF8A86);
|
||||
const success = Color(0xFF70D7A5);
|
||||
const warning = Color(0xFFFFC865);
|
||||
|
||||
final scheme = ColorScheme.dark(
|
||||
primary: accent,
|
||||
onPrimary: background,
|
||||
secondary: accentMuted,
|
||||
onSecondary: foreground,
|
||||
tertiary: const Color(0xFF91C7D0),
|
||||
onTertiary: background,
|
||||
error: error,
|
||||
onError: background,
|
||||
surface: surface,
|
||||
onSurface: foreground,
|
||||
outline: outline,
|
||||
shadow: Colors.black,
|
||||
scrim: Colors.black87,
|
||||
);
|
||||
String font(String family) =>
|
||||
fontPackage == null ? family : 'packages/$fontPackage/$family';
|
||||
|
||||
final base = ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: scheme,
|
||||
scaffoldBackgroundColor: background,
|
||||
canvasColor: background,
|
||||
fontFamily: font('Inter'),
|
||||
focusColor: accent.withAlpha(60),
|
||||
visualDensity: VisualDensity.standard,
|
||||
);
|
||||
final radius = BorderRadius.circular(10);
|
||||
final textTheme = base.textTheme
|
||||
.apply(bodyColor: foreground, displayColor: foreground)
|
||||
.copyWith(
|
||||
displayLarge: base.textTheme.displayLarge?.copyWith(
|
||||
fontFamily: font('Cormorant Garamond'),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
displayMedium: base.textTheme.displayMedium?.copyWith(
|
||||
fontFamily: font('Cormorant Garamond'),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
headlineLarge: base.textTheme.headlineLarge?.copyWith(
|
||||
fontFamily: font('Cormorant Garamond'),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
headlineMedium: base.textTheme.headlineMedium?.copyWith(
|
||||
fontFamily: font('Cormorant Garamond'),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
titleLarge: base.textTheme.titleLarge?.copyWith(
|
||||
fontFamily: font('Cormorant Garamond'),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
labelLarge: base.textTheme.labelLarge?.copyWith(
|
||||
fontFamily: font('Inter'),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
);
|
||||
|
||||
return base.copyWith(
|
||||
textTheme: textTheme,
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: surfaceHigh,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 14,
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: radius,
|
||||
borderSide: BorderSide(color: outline),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: radius,
|
||||
borderSide: BorderSide(color: accent, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: radius,
|
||||
borderSide: const BorderSide(color: error),
|
||||
),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: const Size(44, 44),
|
||||
backgroundColor: accent,
|
||||
foregroundColor: background,
|
||||
disabledBackgroundColor: outline.withAlpha(90),
|
||||
disabledForegroundColor: foreground.withAlpha(120),
|
||||
shape: RoundedRectangleBorder(borderRadius: radius),
|
||||
textStyle: TextStyle(
|
||||
fontFamily: font('Inter'),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(44, 44),
|
||||
foregroundColor: foreground,
|
||||
side: BorderSide(color: outline),
|
||||
shape: RoundedRectangleBorder(borderRadius: radius),
|
||||
),
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
minimumSize: const Size(44, 44),
|
||||
foregroundColor: accent,
|
||||
),
|
||||
),
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
side: BorderSide(color: outline),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
extensions: [
|
||||
MoonWellDesignTokens(
|
||||
background: background,
|
||||
surfaceLow: surfaceLow,
|
||||
surface: surface,
|
||||
surfaceHigh: surfaceHigh,
|
||||
accent: accent,
|
||||
accentMuted: accentMuted,
|
||||
success: success,
|
||||
warning: warning,
|
||||
border: BorderSide(color: outline.withAlpha(190)),
|
||||
focusRing: accent,
|
||||
spacing: 8,
|
||||
radiusSmall: 6,
|
||||
radiusMedium: 10,
|
||||
radiusLarge: 16,
|
||||
panelShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0x66000000),
|
||||
blurRadius: 24,
|
||||
offset: Offset(0, 12),
|
||||
),
|
||||
],
|
||||
motionFast: const Duration(milliseconds: 120),
|
||||
motionStandard: const Duration(milliseconds: 220),
|
||||
brandFontFamily: font('Cinzel'),
|
||||
monospaceFontFamily: font('JetBrains Mono'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LauncherThemeController extends ChangeNotifier {
|
||||
LauncherThemeController(this._preferencesRepository);
|
||||
|
||||
final PreferencesRepository _preferencesRepository;
|
||||
MoonWellThemeVariant _variant = MoonWellThemeVariant.forest;
|
||||
|
||||
MoonWellThemeVariant get variant => _variant;
|
||||
|
||||
Future<void> load() async {
|
||||
_variant = await _preferencesRepository.getThemeVariant();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setVariant(MoonWellThemeVariant variant) async {
|
||||
if (_variant == variant) return;
|
||||
_variant = variant;
|
||||
notifyListeners();
|
||||
await _preferencesRepository.setThemeVariant(variant);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
part of 'mw_theme.dart';
|
||||
|
||||
/// Core palette
|
||||
class MWColors {
|
||||
// Surface & background
|
||||
static const Color abyss = Color(0xFF090F2B); // page bg
|
||||
static const Color deepNavy = Color(0xFF111840); // surfaces
|
||||
static const Color stormNavy = Color(0xFF1A2759); // elevated surfaces
|
||||
|
||||
// Primary & secondary
|
||||
static const Color primary = Color(0xFF5460A2);
|
||||
static const Color secondary = Color(0xFF5F6BD2);
|
||||
static const Color tertiary = Color(0xFF6494EB);
|
||||
|
||||
// Lines & states
|
||||
static const Color outline = Color(0xFF4B4E6E);
|
||||
|
||||
// Semantic
|
||||
static const Color success = Color(0xFF3DDC97);
|
||||
static const Color warning = Color(0xFFF0B429);
|
||||
static const Color error = Color(0xFFD86A8A);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
part of 'mw_theme.dart';
|
||||
|
||||
class MoonWellDecorations extends ThemeExtension<MoonWellDecorations> {
|
||||
final Gradient goldBevel; // for gilded headers/buttons
|
||||
final Shadow textGlow; // subtle moonlight glow
|
||||
final List<BoxShadow> cardGlow;
|
||||
|
||||
const MoonWellDecorations({
|
||||
required this.goldBevel,
|
||||
required this.textGlow,
|
||||
required this.cardGlow,
|
||||
});
|
||||
|
||||
@override
|
||||
MoonWellDecorations copyWith({
|
||||
Gradient? goldBevel,
|
||||
Shadow? textGlow,
|
||||
List<BoxShadow>? cardGlow,
|
||||
}) => MoonWellDecorations(
|
||||
goldBevel: goldBevel ?? this.goldBevel,
|
||||
textGlow: textGlow ?? this.textGlow,
|
||||
cardGlow: cardGlow ?? this.cardGlow,
|
||||
);
|
||||
|
||||
@override
|
||||
ThemeExtension<MoonWellDecorations> lerp(
|
||||
ThemeExtension<MoonWellDecorations>? other,
|
||||
double t,
|
||||
) {
|
||||
if (other is! MoonWellDecorations) return this;
|
||||
return MoonWellDecorations(
|
||||
goldBevel: Gradient.lerp(goldBevel, other.goldBevel, t)!,
|
||||
textGlow: Shadow.lerp(textGlow, other.textGlow, t)!,
|
||||
cardGlow: [
|
||||
for (int i = 0; i < cardGlow.length; i++)
|
||||
BoxShadow.lerp(cardGlow[i], other.cardGlow[i], t)!,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
part 'mw_colors.dart';
|
||||
part 'mw_decorations.dart';
|
||||
|
||||
ThemeData moonWellTheme() {
|
||||
const cs = ColorScheme.dark(
|
||||
brightness: Brightness.dark,
|
||||
primary: Color(0xFF5460A2),
|
||||
onPrimary: Color(0xFFDDE0FB),
|
||||
|
||||
secondary: Color(0xFF5F6BD2),
|
||||
onSecondary: Color(0xFFDDE0FB),
|
||||
|
||||
tertiary: Color(0xFF6494EB),
|
||||
onTertiary: Color(0xFF090F2B),
|
||||
|
||||
error: Color(0xFFD86A8A),
|
||||
onError: Color(0xFF090F2B),
|
||||
|
||||
surface: Color(0xFF1A2759),
|
||||
onSurface: Color(0xFFDDE0FB),
|
||||
|
||||
outline: Color(0xFF4B4E6E),
|
||||
shadow: Color(0xFF000000),
|
||||
scrim: Color(0xCC000000),
|
||||
);
|
||||
|
||||
final base = ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: cs,
|
||||
scaffoldBackgroundColor: cs.surface,
|
||||
canvasColor: cs.surface,
|
||||
);
|
||||
|
||||
final text = base.textTheme
|
||||
.apply(
|
||||
fontFamily: 'Cinzel',
|
||||
bodyColor: cs.onSurface,
|
||||
displayColor: cs.onSurface,
|
||||
)
|
||||
.copyWith(
|
||||
displayLarge: base.textTheme.displayLarge?.copyWith(
|
||||
letterSpacing: 0.5,
|
||||
fontWeight: FontWeight.w700,
|
||||
shadows: const [Shadow(blurRadius: 10, color: Color(0x336BA3FF))],
|
||||
),
|
||||
headlineMedium: base.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
titleLarge: base.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
);
|
||||
|
||||
return base.copyWith(
|
||||
textTheme: text,
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
foregroundColor: cs.onSurface,
|
||||
centerTitle: true,
|
||||
titleTextStyle: text.titleLarge,
|
||||
toolbarHeight: 64,
|
||||
),
|
||||
|
||||
cardTheme: CardThemeData(
|
||||
color: cs.surface.withAlpha(50),
|
||||
elevation: 0,
|
||||
margin: const EdgeInsets.all(12),
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(color: MWColors.outline.withAlpha(150)),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
shadowColor: MWColors.tertiary.withAlpha(63),
|
||||
),
|
||||
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
padding: const WidgetStatePropertyAll(
|
||||
EdgeInsets.symmetric(horizontal: 18, vertical: 14),
|
||||
),
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
),
|
||||
textStyle: WidgetStatePropertyAll(
|
||||
TextStyle(fontWeight: FontWeight.bold, fontFamily: 'Cinzel'),
|
||||
),
|
||||
elevation: const WidgetStatePropertyAll(6),
|
||||
shadowColor: WidgetStatePropertyAll(MWColors.tertiary.withAlpha(89)),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return MWColors.primary.withAlpha(115);
|
||||
}
|
||||
return cs.primary;
|
||||
}),
|
||||
foregroundColor: const WidgetStatePropertyAll(Color(0xFFDDE0FB)),
|
||||
),
|
||||
),
|
||||
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStatePropertyAll(cs.tertiary),
|
||||
overlayColor: WidgetStatePropertyAll(cs.tertiary.withAlpha(10)),
|
||||
),
|
||||
),
|
||||
|
||||
filledButtonTheme: FilledButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(cs.tertiaryContainer),
|
||||
foregroundColor: WidgetStatePropertyAll(cs.onTertiaryContainer),
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(
|
||||
BorderSide(color: MWColors.outline.withAlpha(230)),
|
||||
),
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
),
|
||||
foregroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return cs.primary.withAlpha(100);
|
||||
}
|
||||
return cs.primary;
|
||||
}),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return MWColors.stormNavy.withAlpha(100);
|
||||
}
|
||||
return MWColors.stormNavy;
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: cs.surfaceContainerHighest,
|
||||
hintStyle: TextStyle(color: cs.onSurfaceVariant.withAlpha(179)),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
borderSide: BorderSide(color: MWColors.outline),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
borderSide: BorderSide(color: cs.primary, width: 1.6),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
borderSide: BorderSide(color: cs.error),
|
||||
),
|
||||
prefixIconColor: cs.onSurfaceVariant,
|
||||
suffixIconColor: cs.onSurfaceVariant,
|
||||
),
|
||||
|
||||
chipTheme: base.chipTheme.copyWith(
|
||||
backgroundColor: cs.surfaceContainerHighest,
|
||||
side: BorderSide(color: MWColors.outline),
|
||||
selectedColor: cs.primaryContainer,
|
||||
labelStyle: TextStyle(color: cs.onSurface),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
|
||||
sliderTheme: base.sliderTheme.copyWith(
|
||||
activeTrackColor: cs.primary,
|
||||
inactiveTrackColor: cs.primary.withAlpha(63),
|
||||
thumbColor: cs.primary,
|
||||
),
|
||||
|
||||
dividerTheme: DividerThemeData(
|
||||
color: MWColors.outline,
|
||||
thickness: 1,
|
||||
space: 24,
|
||||
),
|
||||
|
||||
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
||||
backgroundColor: cs.surface,
|
||||
selectedItemColor: cs.primary,
|
||||
unselectedItemColor: cs.onSurface.withAlpha(153),
|
||||
elevation: 8,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
),
|
||||
|
||||
extensions: <ThemeExtension<dynamic>>[
|
||||
const MoonWellDecorations(
|
||||
goldBevel: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFF7A85CC), // highlight
|
||||
Color(0xFF5460A2), // body
|
||||
Color(0xFF3E4880), // edge
|
||||
],
|
||||
stops: [0.0, 0.55, 1.0],
|
||||
),
|
||||
textGlow: Shadow(
|
||||
color: Color(0x446494EB),
|
||||
blurRadius: 14,
|
||||
offset: Offset(0, 0),
|
||||
),
|
||||
cardGlow: [
|
||||
BoxShadow(
|
||||
color: Color(0x33143666), // cool rim light
|
||||
blurRadius: 28,
|
||||
spreadRadius: 2,
|
||||
offset: Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user