161 lines
5.0 KiB
Dart
161 lines
5.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
class C {
|
|
static const bg = Color(0xFFF4F2EC);
|
|
static const outer = Color(0xFFE7E4DB);
|
|
static const ink = Color(0xFF1F2A2E);
|
|
static const muted = Color(0xFF5E6C71); // 4.9:1 on bg, 5.4:1 on white
|
|
static const navy = Color(0xFF1B2A49);
|
|
static const navyDeep = Color(0xFF101B33);
|
|
static const chip = Color(0xFFE1E6F0);
|
|
static const green = Color(0xFF2F7656); // 5.5:1 on white, 4.7:1 on greenTint
|
|
static const greenTint = Color(0xFFE3F1EA);
|
|
static const gold = Color(0xFFD4A64A);
|
|
static const goldTint = Color(0xFFF7EBD0);
|
|
static const goldText = Color(0xFF735614); // 5.4:1 on goldTint
|
|
static const border = Color(0xFFE6E0D4);
|
|
static const border2 = Color(0xFFC9CED8);
|
|
static const placeholder = Color(0xFF7A8689); // hints and chevrons, 3.8:1
|
|
static const softOnNavy = Color(0xFFB8C2DA);
|
|
static const red = Color(0xFFB04A37); // 5.4:1 on white
|
|
static const redDeep = Color(0xFF953D2C);
|
|
static const redTint = Color(0xFFFBE9E5);
|
|
static const white = Colors.white;
|
|
static const hover = Color(0xFFF8F7F3);
|
|
static const focus = Color(0xFF3D5A99);
|
|
|
|
// Overlays, shadows and disabled fills
|
|
static const onNavy5 = Color(0x0DFFFFFF);
|
|
static const onNavy8 = Color(0x14FFFFFF);
|
|
static const onNavy20 = Color(0x33FFFFFF);
|
|
static const goldSoft = Color(0x26D4A64A);
|
|
static const goldGlow = Color(0x55D4A64A);
|
|
static const shadowNavy = Color(0x331B2A49);
|
|
static const shadowNav = Color(0x14101B33);
|
|
static const disabled = Color(0xFFF0EEE8);
|
|
static const fieldDisabled = Color(0xFFEFEDE6);
|
|
static const skeleton = Color(0xFFECE8DF);
|
|
}
|
|
|
|
/// Width breakpoints, measured on the window, not the device.
|
|
class Bp {
|
|
static const medium = 600.0; // rail navigation, wider gutters
|
|
static const expanded = 1024.0; // full sidebar
|
|
static const pageMax = 1120.0; // widest content column
|
|
static const readMax = 760.0; // detail and form screens
|
|
}
|
|
|
|
/// Horizontal padding that keeps content in a centred column of [max] width.
|
|
double pageGutter(double width, [double max = Bp.pageMax]) {
|
|
if (width < Bp.medium) return S.s20;
|
|
final side = (width - max) / 2;
|
|
return side > S.s32 ? side : S.s32;
|
|
}
|
|
|
|
/// Spacing scale (logical pixels).
|
|
class S {
|
|
static const s2 = 2.0;
|
|
static const s4 = 4.0;
|
|
static const s6 = 6.0;
|
|
static const s8 = 8.0;
|
|
static const s10 = 10.0;
|
|
static const s12 = 12.0;
|
|
static const s14 = 14.0;
|
|
static const s16 = 16.0;
|
|
static const s18 = 18.0;
|
|
static const s20 = 20.0;
|
|
static const s22 = 22.0;
|
|
static const s24 = 24.0;
|
|
static const s28 = 28.0;
|
|
static const s32 = 32.0;
|
|
static const s36 = 36.0;
|
|
}
|
|
|
|
/// Corner radii.
|
|
class R {
|
|
static const sm = 8.0; // checkbox, handles
|
|
static const md = 12.0; // chips, tiles
|
|
static const input = 14.0; // fields, small cards
|
|
static const button = 16.0;
|
|
static const card = 18.0;
|
|
static const dialog = 24.0;
|
|
static const hero = 28.0; // hero cards, sheets
|
|
static const pill = 99.0;
|
|
}
|
|
|
|
TextStyle ts(
|
|
double size, {
|
|
FontWeight w = FontWeight.w500,
|
|
Color c = C.ink,
|
|
double? h,
|
|
double? ls,
|
|
}) => TextStyle(
|
|
fontFamily: 'Inter',
|
|
fontSize: size,
|
|
fontWeight: w,
|
|
color: c,
|
|
height: h,
|
|
letterSpacing: ls,
|
|
// Tabular figures keep ticket counts, endings and rupee amounts aligned.
|
|
fontFeatures: const [FontFeature.tabularFigures()],
|
|
);
|
|
|
|
const w4 = FontWeight.w400;
|
|
const w5 = FontWeight.w500;
|
|
const w6 = FontWeight.w600;
|
|
const w7 = FontWeight.w700;
|
|
|
|
ThemeData buildTheme() {
|
|
final scheme =
|
|
ColorScheme.fromSeed(
|
|
seedColor: C.navy,
|
|
brightness: Brightness.light,
|
|
).copyWith(
|
|
primary: C.navy,
|
|
onPrimary: Colors.white,
|
|
surface: C.bg,
|
|
error: C.red,
|
|
);
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
fontFamily: 'Inter',
|
|
colorScheme: scheme,
|
|
scaffoldBackgroundColor: C.bg,
|
|
splashFactory: NoSplash.splashFactory,
|
|
highlightColor: Colors.transparent,
|
|
hoverColor: C.hover,
|
|
focusColor: C.chip,
|
|
tooltipTheme: TooltipThemeData(
|
|
waitDuration: const Duration(milliseconds: 500),
|
|
textStyle: ts(12, w: w5, c: Colors.white),
|
|
decoration: BoxDecoration(
|
|
color: C.navyDeep,
|
|
borderRadius: BorderRadius.circular(R.sm),
|
|
),
|
|
),
|
|
textSelectionTheme: const TextSelectionThemeData(cursorColor: C.navy),
|
|
snackBarTheme: SnackBarThemeData(
|
|
behavior: SnackBarBehavior.floating,
|
|
backgroundColor: C.navyDeep,
|
|
contentTextStyle: ts(13, w: w6, c: Colors.white),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(R.input),
|
|
),
|
|
),
|
|
dialogTheme: DialogThemeData(
|
|
backgroundColor: Colors.white,
|
|
surfaceTintColor: Colors.transparent,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(R.dialog),
|
|
),
|
|
),
|
|
bottomSheetTheme: const BottomSheetThemeData(
|
|
backgroundColor: Colors.white,
|
|
surfaceTintColor: Colors.transparent,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(R.hero)),
|
|
),
|
|
),
|
|
);
|
|
}
|