270 lines
8.4 KiB
Dart
270 lines
8.4 KiB
Dart
// AUTO-GENERATED from tokens.json — do not edit directly
|
||
// Run: node design/generate.js
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:google_fonts/google_fonts.dart';
|
||
|
||
/// inou Design System
|
||
/// Single source of truth: design/tokens.json
|
||
class InouTheme {
|
||
InouTheme._();
|
||
|
||
// ============================================
|
||
// COLORS
|
||
// ============================================
|
||
static const Color bg = Color(0xFFF8F7F6);
|
||
static const Color bgCard = Color(0xFFFFFFFF);
|
||
static const Color border = Color(0xFFE5E2DE);
|
||
static const Color borderHover = Color(0xFFC4BFB8);
|
||
static const Color text = Color(0xFF1C1917);
|
||
static const Color textMuted = Color(0xFF78716C);
|
||
static const Color textSubtle = Color(0xFFA8A29E);
|
||
static const Color accent = Color(0xFFB45309);
|
||
static const Color accentHover = Color(0xFF92400E);
|
||
static const Color accentLight = Color(0xFFFEF3C7);
|
||
static const Color danger = Color(0xFFDC2626);
|
||
static const Color dangerLight = Color(0xFFFEF2F2);
|
||
static const Color success = Color(0xFF059669);
|
||
static const Color successLight = Color(0xFFECFDF5);
|
||
|
||
// Indicator colors (data sections)
|
||
static const Color indicatorImaging = Color(0xFFB45309);
|
||
static const Color indicatorLabs = Color(0xFF059669);
|
||
static const Color indicatorUploads = Color(0xFF6366F1);
|
||
static const Color indicatorVitals = Color(0xFFEC4899);
|
||
static const Color indicatorMedications = Color(0xFF8B5CF6);
|
||
static const Color indicatorRecords = Color(0xFF06B6D4);
|
||
static const Color indicatorJournal = Color(0xFFF59E0B);
|
||
static const Color indicatorPrivacy = Color(0xFF64748B);
|
||
static const Color indicatorGenetics = Color(0xFF10B981);
|
||
|
||
// ============================================
|
||
// SPACING
|
||
// ============================================
|
||
static const double spaceXs = 4.0;
|
||
static const double spaceSm = 8.0;
|
||
static const double spaceMd = 12.0;
|
||
static const double spaceLg = 16.0;
|
||
static const double spaceXl = 24.0;
|
||
static const double spaceXxl = 32.0;
|
||
static const double spaceXxxl = 48.0;
|
||
|
||
// ============================================
|
||
// BORDER RADIUS
|
||
// ============================================
|
||
static const double radiusSm = 4.0;
|
||
static const double radiusMd = 6.0;
|
||
static const double radiusLg = 8.0;
|
||
static const double radiusXl = 12.0;
|
||
static const double radiusFull = 9999.0;
|
||
static BorderRadius get borderRadiusSm => BorderRadius.circular(radiusSm);
|
||
static BorderRadius get borderRadiusMd => BorderRadius.circular(radiusMd);
|
||
static BorderRadius get borderRadiusLg => BorderRadius.circular(radiusLg);
|
||
|
||
// ============================================
|
||
// LAYOUT
|
||
// ============================================
|
||
static const double maxWidth = 1200.0;
|
||
static const double maxWidthNarrow = 800.0;
|
||
static const double maxWidthForm = 360.0;
|
||
|
||
// ============================================
|
||
// TYPOGRAPHY — matches inou.com/static/style.css
|
||
// Base: 15px (body)
|
||
// ============================================
|
||
static String get fontFamily => 'Sora';
|
||
|
||
// Page Title: 2.5rem / 700 = 37.5px
|
||
static TextStyle get pageTitle => GoogleFonts.sora(
|
||
fontSize: 37.5,
|
||
fontWeight: FontWeight.w700,
|
||
color: text,
|
||
);
|
||
|
||
// h1: 2.25rem / 300 / -0.03em = 33.75px (used in forms, etc.)
|
||
static TextStyle get h1 => GoogleFonts.sora(
|
||
fontSize: 33.75,
|
||
fontWeight: FontWeight.w300,
|
||
color: text,
|
||
letterSpacing: -0.45, // -0.03em × 15px
|
||
);
|
||
|
||
// h1.small: 1.5rem / 300 = 22.5px
|
||
static TextStyle get h1Small => GoogleFonts.sora(
|
||
fontSize: 22.5,
|
||
fontWeight: FontWeight.w300,
|
||
color: text,
|
||
);
|
||
|
||
// Section Title: 1.4rem / 600 = 21px (.privacy-container h2)
|
||
static TextStyle get sectionTitle => GoogleFonts.sora(
|
||
fontSize: 21.0,
|
||
fontWeight: FontWeight.w600,
|
||
color: text,
|
||
);
|
||
|
||
// h2 (regular): 1.5rem / 300 / -0.02em = 22.5px
|
||
static TextStyle get h2 => GoogleFonts.sora(
|
||
fontSize: 22.5,
|
||
fontWeight: FontWeight.w300,
|
||
color: text,
|
||
letterSpacing: -0.3, // -0.02em × 15px
|
||
);
|
||
|
||
// Subsection Title: 1.1rem / 600 = 16.5px (.privacy-container h3)
|
||
static TextStyle get subsectionTitle => GoogleFonts.sora(
|
||
fontSize: 16.5,
|
||
fontWeight: FontWeight.w600,
|
||
color: text,
|
||
);
|
||
|
||
// h3 (regular): 1.125rem / 500 = 16.875px
|
||
static TextStyle get h3 => GoogleFonts.sora(
|
||
fontSize: 16.875,
|
||
fontWeight: FontWeight.w500,
|
||
color: text,
|
||
);
|
||
|
||
// Intro text: 1.15rem / 300 = 17.25px
|
||
static TextStyle get intro => GoogleFonts.sora(
|
||
fontSize: 17.25,
|
||
fontWeight: FontWeight.w300,
|
||
color: textMuted,
|
||
height: 1.8,
|
||
);
|
||
|
||
// Body light (long-form): 1rem / 300 = 15px
|
||
static TextStyle get bodyLight => GoogleFonts.sora(
|
||
fontSize: 15.0,
|
||
fontWeight: FontWeight.w300,
|
||
color: textMuted,
|
||
height: 1.8,
|
||
);
|
||
|
||
// Body regular (UI labels): 1rem / 400 = 15px
|
||
static TextStyle get body => GoogleFonts.sora(
|
||
fontSize: 15.0,
|
||
fontWeight: FontWeight.w400,
|
||
color: text,
|
||
);
|
||
|
||
// Label / Category: 0.75rem / 600 / caps / 0.1em = 11.25px
|
||
static TextStyle get label => GoogleFonts.sora(
|
||
fontSize: 11.25,
|
||
fontWeight: FontWeight.w600,
|
||
color: textSubtle,
|
||
letterSpacing: 1.125, // 0.1em × 11.25px
|
||
);
|
||
|
||
// Small text: 0.85rem / 400 = 12.75px
|
||
static TextStyle get small => GoogleFonts.sora(
|
||
fontSize: 12.75,
|
||
fontWeight: FontWeight.w400,
|
||
color: textMuted,
|
||
);
|
||
|
||
// Mono (SF Mono fallback)
|
||
static TextStyle get mono => const TextStyle(
|
||
fontFamily: 'SF Mono',
|
||
fontFamilyFallback: ['Monaco', 'Consolas', 'monospace'],
|
||
fontSize: 12.75,
|
||
color: text,
|
||
);
|
||
|
||
// Legacy aliases for compatibility
|
||
static TextStyle get h1Large => pageTitle;
|
||
static TextStyle get bodyLarge => intro;
|
||
static TextStyle get bodyMedium => body;
|
||
static TextStyle get bodySmall => small;
|
||
static TextStyle get labelLarge => GoogleFonts.sora(
|
||
fontSize: 15.0,
|
||
fontWeight: FontWeight.w500,
|
||
color: text,
|
||
);
|
||
static TextStyle get labelSmall => label;
|
||
|
||
// ============================================
|
||
// THEME DATA
|
||
// ============================================
|
||
static ThemeData get light => ThemeData(
|
||
useMaterial3: true,
|
||
brightness: Brightness.light,
|
||
scaffoldBackgroundColor: bg,
|
||
colorScheme: ColorScheme.light(
|
||
primary: accent,
|
||
onPrimary: Colors.white,
|
||
secondary: accentLight,
|
||
onSecondary: accent,
|
||
surface: bgCard,
|
||
onSurface: text,
|
||
error: danger,
|
||
onError: Colors.white,
|
||
outline: border,
|
||
),
|
||
textTheme: TextTheme(
|
||
displayLarge: pageTitle,
|
||
displayMedium: h1,
|
||
headlineMedium: sectionTitle,
|
||
headlineSmall: subsectionTitle,
|
||
bodyLarge: intro,
|
||
bodyMedium: body,
|
||
bodySmall: small,
|
||
labelLarge: labelLarge,
|
||
labelSmall: label,
|
||
),
|
||
appBarTheme: AppBarTheme(
|
||
backgroundColor: bg,
|
||
foregroundColor: text,
|
||
elevation: 0,
|
||
centerTitle: false,
|
||
),
|
||
cardTheme: CardTheme(
|
||
color: bgCard,
|
||
elevation: 0,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: borderRadiusLg,
|
||
side: BorderSide(color: border),
|
||
),
|
||
),
|
||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: accent,
|
||
foregroundColor: Colors.white,
|
||
elevation: 0,
|
||
padding: EdgeInsets.symmetric(horizontal: spaceLg, vertical: spaceMd),
|
||
shape: RoundedRectangleBorder(borderRadius: borderRadiusMd),
|
||
textStyle: labelLarge,
|
||
),
|
||
),
|
||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||
style: OutlinedButton.styleFrom(
|
||
foregroundColor: text,
|
||
side: BorderSide(color: border),
|
||
padding: EdgeInsets.symmetric(horizontal: spaceLg, vertical: spaceMd),
|
||
shape: RoundedRectangleBorder(borderRadius: borderRadiusMd),
|
||
textStyle: labelLarge,
|
||
),
|
||
),
|
||
inputDecorationTheme: InputDecorationTheme(
|
||
filled: true,
|
||
fillColor: bgCard,
|
||
border: OutlineInputBorder(
|
||
borderRadius: borderRadiusMd,
|
||
borderSide: BorderSide(color: border),
|
||
),
|
||
enabledBorder: OutlineInputBorder(
|
||
borderRadius: borderRadiusMd,
|
||
borderSide: BorderSide(color: border),
|
||
),
|
||
focusedBorder: OutlineInputBorder(
|
||
borderRadius: borderRadiusMd,
|
||
borderSide: BorderSide(color: accent, width: 2),
|
||
),
|
||
contentPadding: EdgeInsets.symmetric(horizontal: spaceMd, vertical: spaceMd),
|
||
),
|
||
dividerTheme: DividerThemeData(
|
||
color: border,
|
||
thickness: 1,
|
||
),
|
||
);
|
||
} |