111 lines
4.0 KiB
Dart
111 lines
4.0 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:google_fonts/google_fonts.dart';
|
||
|
|
|
||
|
|
/// BadNote design tokens — ink-desk academic aesthetic.
|
||
|
|
/// Warm paper field, graphite ink, single copper accent. No Inter / no purple.
|
||
|
|
abstract final class AppTokens {
|
||
|
|
static const Color paper = Color(0xFFF3EDE3);
|
||
|
|
static const Color paperDark = Color(0xFF1C1A17);
|
||
|
|
static const Color ink = Color(0xFF1F1B16);
|
||
|
|
static const Color inkMuted = Color(0xFF6B6358);
|
||
|
|
static const Color rule = Color(0xFFD9CFC0);
|
||
|
|
static const Color copper = Color(0xFFB45A2A);
|
||
|
|
static const Color copperSoft = Color(0xFFE8C4AE);
|
||
|
|
static const Color sticky = Color(0xFFF6E7A5);
|
||
|
|
|
||
|
|
static const double radiusSm = 6;
|
||
|
|
static const double radiusMd = 12;
|
||
|
|
static const double chromePad = 16;
|
||
|
|
}
|
||
|
|
|
||
|
|
abstract final class AppTheme {
|
||
|
|
static ThemeData light() {
|
||
|
|
final base = ColorScheme.fromSeed(
|
||
|
|
seedColor: AppTokens.copper,
|
||
|
|
brightness: Brightness.light,
|
||
|
|
surface: AppTokens.paper,
|
||
|
|
primary: AppTokens.copper,
|
||
|
|
onPrimary: Colors.white,
|
||
|
|
onSurface: AppTokens.ink,
|
||
|
|
secondary: AppTokens.inkMuted,
|
||
|
|
);
|
||
|
|
return _build(base, Brightness.light);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ThemeData dark() {
|
||
|
|
final base = ColorScheme.fromSeed(
|
||
|
|
seedColor: AppTokens.copperSoft,
|
||
|
|
brightness: Brightness.dark,
|
||
|
|
surface: AppTokens.paperDark,
|
||
|
|
primary: AppTokens.copperSoft,
|
||
|
|
onSurface: AppTokens.paper,
|
||
|
|
);
|
||
|
|
return _build(base, Brightness.dark);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ThemeData fromScheme(ColorScheme scheme) =>
|
||
|
|
_build(scheme, scheme.brightness);
|
||
|
|
|
||
|
|
static ThemeData _build(ColorScheme scheme, Brightness brightness) {
|
||
|
|
final display = GoogleFonts.sourceSerif4TextTheme(
|
||
|
|
ThemeData(brightness: brightness).textTheme,
|
||
|
|
);
|
||
|
|
final ui = GoogleFonts.ibmPlexSansTextTheme(
|
||
|
|
ThemeData(brightness: brightness).textTheme,
|
||
|
|
);
|
||
|
|
final merged = ui.copyWith(
|
||
|
|
displayLarge: display.displayLarge?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
displayMedium: display.displayMedium?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
displaySmall: display.displaySmall?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
headlineLarge: display.headlineLarge?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
headlineMedium: display.headlineMedium?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
headlineSmall: display.headlineSmall?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
titleLarge: display.titleLarge?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
);
|
||
|
|
|
||
|
|
return ThemeData(
|
||
|
|
useMaterial3: true,
|
||
|
|
colorScheme: scheme,
|
||
|
|
scaffoldBackgroundColor: scheme.surface,
|
||
|
|
textTheme: merged,
|
||
|
|
appBarTheme: AppBarTheme(
|
||
|
|
centerTitle: false,
|
||
|
|
backgroundColor: scheme.surface,
|
||
|
|
foregroundColor: scheme.onSurface,
|
||
|
|
elevation: 0,
|
||
|
|
scrolledUnderElevation: 0.5,
|
||
|
|
titleTextStyle: display.titleLarge?.copyWith(
|
||
|
|
color: scheme.onSurface,
|
||
|
|
fontWeight: FontWeight.w600,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
navigationBarTheme: NavigationBarThemeData(
|
||
|
|
backgroundColor: scheme.surface,
|
||
|
|
indicatorColor: AppTokens.copper.withValues(alpha: 0.18),
|
||
|
|
labelTextStyle: WidgetStatePropertyAll(
|
||
|
|
ui.labelMedium?.copyWith(fontWeight: FontWeight.w600),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
navigationRailTheme: NavigationRailThemeData(
|
||
|
|
backgroundColor: scheme.surface,
|
||
|
|
indicatorColor: AppTokens.copper.withValues(alpha: 0.18),
|
||
|
|
selectedIconTheme: IconThemeData(color: scheme.primary),
|
||
|
|
unselectedIconTheme: IconThemeData(color: scheme.onSurfaceVariant),
|
||
|
|
),
|
||
|
|
cardTheme: CardThemeData(
|
||
|
|
color: scheme.surface,
|
||
|
|
elevation: 0,
|
||
|
|
shape: RoundedRectangleBorder(
|
||
|
|
borderRadius: BorderRadius.circular(AppTokens.radiusMd),
|
||
|
|
side: BorderSide(color: AppTokens.rule.withValues(alpha: 0.7)),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
dividerColor: AppTokens.rule,
|
||
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||
|
|
backgroundColor: scheme.primary,
|
||
|
|
foregroundColor: scheme.onPrimary,
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|