srs/lib/core/theme.dart
Aswin Biju 749d18192a
All checks were successful
deploy / deploy (push) Successful in 4m58s
refactor: updated UI and other trivial fixes
2026-11-05 10:13:32 +05:30

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)),
),
),
);
}