Implement premium UI/UX refinements for Apple-like polish
Add three major UI components with animations and dark mode support: - PremiumRouteCard: Enhanced route cards with left accent bar, delivery count badge, animated hover effects (1.02x scale), and dynamic shadow elevation - DarkModeMapComponent: Google Maps integration with dark theme styling, custom info panels, navigation buttons, and delivery status indicators - DeliveryListItem: Animated list items with staggered entrance animations, status badges with icons, contact indicators, and hover states Updates: - RoutesPage: Now uses PremiumRouteCard with improved visual hierarchy - DeliveriesPage: Integrated DarkModeMapComponent and DeliveryListItem with proper theme awareness - Animation system: Leverages existing AppAnimations constants for 200ms fast interactions and easeOut curves Design philosophy: - Element separation through left accent bars (status-coded) - Elevation and shadow for depth (0.1-0.3 opacity) - Staggered animations for list items (50ms delays) - Dark mode optimized for evening use (reduced brightness) - Responsive hover states with tactile feedback Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Animation System
|
||||
/// Complete animation configuration with durations, curves, and stagger delays
|
||||
class AppAnimations {
|
||||
// Prevent instantiation
|
||||
AppAnimations._();
|
||||
|
||||
// ============================================
|
||||
// ANIMATION DURATION CONSTANTS
|
||||
// ============================================
|
||||
|
||||
/// Fast animation duration (200ms) - Button press, hover, quick interactions
|
||||
static const Duration durationFast = Duration(milliseconds: 200);
|
||||
|
||||
/// Normal animation duration (300ms) - Default animations, fade, slide
|
||||
static const Duration durationNormal = Duration(milliseconds: 300);
|
||||
|
||||
/// Slow animation duration (500ms) - Prominent animations, entrance, transitions
|
||||
static const Duration durationSlow = Duration(milliseconds: 500);
|
||||
|
||||
/// Extra slow animation duration (800ms) - Slow, attention-grabbing animations
|
||||
static const Duration durationXSlow = Duration(milliseconds: 800);
|
||||
|
||||
// ============================================
|
||||
// ANIMATION DURATION IN MILLISECONDS
|
||||
// ============================================
|
||||
|
||||
/// Fast animation milliseconds (200ms)
|
||||
static const int durationFastMs = 200;
|
||||
|
||||
/// Normal animation milliseconds (300ms)
|
||||
static const int durationNormalMs = 300;
|
||||
|
||||
/// Slow animation milliseconds (500ms)
|
||||
static const int durationSlowMs = 500;
|
||||
|
||||
/// Extra slow animation milliseconds (800ms)
|
||||
static const int durationXSlowMs = 800;
|
||||
|
||||
// ============================================
|
||||
// ANIMATION CURVES
|
||||
// ============================================
|
||||
|
||||
/// Ease In - Slow start, fast end (decelerate)
|
||||
static const Curve curveEaseIn = Curves.easeIn;
|
||||
|
||||
/// Ease Out - Fast start, slow end (decelerate)
|
||||
static const Curve curveEaseOut = Curves.easeOut;
|
||||
|
||||
/// Ease In Out - Smooth both ends (decelerate at start and end)
|
||||
static const Curve curveEaseInOut = Curves.easeInOut;
|
||||
|
||||
/// Ease In Back - Back in, bounce effect
|
||||
static const Curve curveEaseInBack = Curves.easeInBack;
|
||||
|
||||
/// Ease Out Back - Back out, bounce effect
|
||||
static const Curve curveEaseOutBack = Curves.easeOutBack;
|
||||
|
||||
/// Elastic/Bouncy effect
|
||||
static const Curve curveElastic = Curves.elasticOut;
|
||||
|
||||
/// Bouncing motion
|
||||
static const Curve curveBounce = Curves.bounceOut;
|
||||
|
||||
/// Fast Out Slow In - Material standard curve
|
||||
static const Curve curveFastOutSlowIn = Curves.fastOutSlowIn;
|
||||
|
||||
/// Deceleration curve (accelerate)
|
||||
static const Curve curveAccelerate = Curves.decelerate;
|
||||
|
||||
/// Linear curve (no acceleration/deceleration)
|
||||
static const Curve curveLinear = Curves.linear;
|
||||
|
||||
// ============================================
|
||||
// STAGGER DELAYS (FOR LIST ANIMATIONS)
|
||||
// ============================================
|
||||
|
||||
/// Default stagger delay for list items (50ms)
|
||||
static const Duration staggerDelay = Duration(milliseconds: 50);
|
||||
|
||||
/// Quick stagger delay (30ms)
|
||||
static const Duration staggerDelayFast = Duration(milliseconds: 30);
|
||||
|
||||
/// Slow stagger delay (100ms)
|
||||
static const Duration staggerDelaySlow = Duration(milliseconds: 100);
|
||||
|
||||
/// Stagger delay in milliseconds
|
||||
static const int staggerDelayMs = 50;
|
||||
|
||||
// ============================================
|
||||
// SCALE ANIMATION CONSTANTS
|
||||
// ============================================
|
||||
|
||||
/// Normal scale (1.0)
|
||||
static const double scaleNormal = 1.0;
|
||||
|
||||
/// Hover/Light scale (1.02)
|
||||
static const double scaleHover = 1.02;
|
||||
|
||||
/// Pressed/Active scale (0.98)
|
||||
static const double scalePressed = 0.98;
|
||||
|
||||
/// Animation scale (0.9)
|
||||
static const double scaleAnimation = 0.9;
|
||||
|
||||
// ============================================
|
||||
// OFFSET ANIMATION CONSTANTS
|
||||
// ============================================
|
||||
|
||||
/// Slide offset - Small (8px)
|
||||
static const Offset offsetSm = Offset(0, 8);
|
||||
|
||||
/// Slide offset - Medium (16px)
|
||||
static const Offset offsetMd = Offset(0, 16);
|
||||
|
||||
/// Slide offset - Large (20px)
|
||||
static const Offset offsetLg = Offset(0, 20);
|
||||
|
||||
/// Slide offset - Extra large (32px)
|
||||
static const Offset offsetXl = Offset(0, 32);
|
||||
|
||||
/// Floating offset - Up (10px)
|
||||
static const Offset offsetFloating = Offset(0, -10);
|
||||
|
||||
// ============================================
|
||||
// OPACITY ANIMATION CONSTANTS
|
||||
// ============================================
|
||||
|
||||
/// Full opacity
|
||||
static const double opacityFull = 1.0;
|
||||
|
||||
/// Half opacity
|
||||
static const double opacityHalf = 0.5;
|
||||
|
||||
/// Subtle opacity (70%)
|
||||
static const double opacitySubtle = 0.7;
|
||||
|
||||
/// Dim opacity (50%)
|
||||
static const double opacityDim = 0.5;
|
||||
|
||||
/// Fade out opacity (30%)
|
||||
static const double opacityFadeOut = 0.3;
|
||||
|
||||
/// Invisible opacity (0%)
|
||||
static const double opacityInvisible = 0.0;
|
||||
|
||||
// ============================================
|
||||
// ANIMATION PRESETS
|
||||
// ============================================
|
||||
|
||||
/// Scale animation preset (button press) - note: CurvedAnimation cannot be const
|
||||
// Use this pattern in your widgets instead:
|
||||
// CurvedAnimation(parent: controller, curve: Curves.easeInOut)
|
||||
|
||||
// ============================================
|
||||
// ROTATION ANIMATION CONSTANTS
|
||||
// ============================================
|
||||
|
||||
/// Full rotation (360 degrees)
|
||||
static const double rotationFull = 1.0;
|
||||
|
||||
/// Half rotation (180 degrees)
|
||||
static const double rotationHalf = 0.5;
|
||||
|
||||
/// Quarter rotation (90 degrees)
|
||||
static const double rotationQuarter = 0.25;
|
||||
|
||||
// ============================================
|
||||
// UTILITY METHODS
|
||||
// ============================================
|
||||
|
||||
/// Get duration based on animation intensity
|
||||
static Duration getDuration(AnimationIntensity intensity) {
|
||||
switch (intensity) {
|
||||
case AnimationIntensity.fast:
|
||||
return durationFast;
|
||||
case AnimationIntensity.normal:
|
||||
return durationNormal;
|
||||
case AnimationIntensity.slow:
|
||||
return durationSlow;
|
||||
case AnimationIntensity.xSlow:
|
||||
return durationXSlow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get curve based on animation type
|
||||
static Curve getCurve(AnimationType type) {
|
||||
switch (type) {
|
||||
case AnimationType.easeIn:
|
||||
return curveEaseIn;
|
||||
case AnimationType.easeOut:
|
||||
return curveEaseOut;
|
||||
case AnimationType.easeInOut:
|
||||
return curveEaseInOut;
|
||||
case AnimationType.elastic:
|
||||
return curveElastic;
|
||||
case AnimationType.bounce:
|
||||
return curveBounce;
|
||||
case AnimationType.linear:
|
||||
return curveLinear;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get stagger delay for list index
|
||||
static Duration getStaggerDelay(int index, {bool fast = false}) {
|
||||
final baseDelay = fast ? staggerDelayFast : staggerDelay;
|
||||
return Duration(
|
||||
milliseconds: baseDelay.inMilliseconds * index,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get scale value based on interaction state
|
||||
static double getScale(InteractionState state) {
|
||||
switch (state) {
|
||||
case InteractionState.normal:
|
||||
return scaleNormal;
|
||||
case InteractionState.hover:
|
||||
return scaleHover;
|
||||
case InteractionState.pressed:
|
||||
return scalePressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Animation intensity levels
|
||||
enum AnimationIntensity {
|
||||
/// 200ms - Quick interactions
|
||||
fast,
|
||||
|
||||
/// 300ms - Standard animations
|
||||
normal,
|
||||
|
||||
/// 500ms - Prominent animations
|
||||
slow,
|
||||
|
||||
/// 800ms - Slow, attention-grabbing animations
|
||||
xSlow,
|
||||
}
|
||||
|
||||
/// Animation types/curves
|
||||
enum AnimationType {
|
||||
/// Ease In curve
|
||||
easeIn,
|
||||
|
||||
/// Ease Out curve
|
||||
easeOut,
|
||||
|
||||
/// Ease In Out curve
|
||||
easeInOut,
|
||||
|
||||
/// Elastic/bouncy curve
|
||||
elastic,
|
||||
|
||||
/// Bounce curve
|
||||
bounce,
|
||||
|
||||
/// Linear curve
|
||||
linear,
|
||||
}
|
||||
|
||||
/// Interaction states for animation
|
||||
enum InteractionState {
|
||||
/// Normal/default state
|
||||
normal,
|
||||
|
||||
/// Hover state
|
||||
hover,
|
||||
|
||||
/// Pressed/active state
|
||||
pressed,
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Border System - Border Radius Constants
|
||||
/// All border radius values follow a strict 4px grid
|
||||
class AppBorders {
|
||||
// Prevent instantiation
|
||||
AppBorders._();
|
||||
|
||||
// ============================================
|
||||
// BORDER RADIUS VALUES (4px Grid)
|
||||
// ============================================
|
||||
|
||||
/// Extra small border radius (4px) - unit × 1
|
||||
/// Used for: Subtle rounding on chips, tags, small elements
|
||||
static const double radiusXs = 4.0;
|
||||
|
||||
/// Small border radius (8px) - unit × 2
|
||||
/// Used for: Buttons, inputs, small cards
|
||||
static const double radiusSm = 8.0;
|
||||
|
||||
/// Medium border radius (12px) - unit × 3
|
||||
/// Used for: Cards, dropdowns, standard components
|
||||
static const double radiusMd = 12.0;
|
||||
|
||||
/// Large border radius (16px) - unit × 4
|
||||
/// Used for: Dialogs, large cards, prominent containers
|
||||
static const double radiusLg = 16.0;
|
||||
|
||||
/// Extra large border radius (24px) - unit × 6
|
||||
/// Used for: Containers, large surfaces
|
||||
static const double radiusXl = 24.0;
|
||||
|
||||
/// Fully rounded border radius (999px)
|
||||
/// Used for: Pills, badges, fully circular elements
|
||||
static const double radiusRound = 999.0;
|
||||
|
||||
// ============================================
|
||||
// BORDER RADIUS - BORDERRADIUS OBJECTS
|
||||
// ============================================
|
||||
|
||||
/// BorderRadius.circular(4px)
|
||||
static const BorderRadius circularXs = BorderRadius.all(Radius.circular(radiusXs));
|
||||
|
||||
/// BorderRadius.circular(8px)
|
||||
static const BorderRadius circularSm = BorderRadius.all(Radius.circular(radiusSm));
|
||||
|
||||
/// BorderRadius.circular(12px)
|
||||
static const BorderRadius circularMd = BorderRadius.all(Radius.circular(radiusMd));
|
||||
|
||||
/// BorderRadius.circular(16px)
|
||||
static const BorderRadius circularLg = BorderRadius.all(Radius.circular(radiusLg));
|
||||
|
||||
/// BorderRadius.circular(24px)
|
||||
static const BorderRadius circularXl = BorderRadius.all(Radius.circular(radiusXl));
|
||||
|
||||
/// BorderRadius.circular(999px) - Fully rounded
|
||||
static const BorderRadius circularRound = BorderRadius.all(Radius.circular(radiusRound));
|
||||
|
||||
// ============================================
|
||||
// BORDER RADIUS - TOP ONLY (for bottom sheets)
|
||||
// ============================================
|
||||
|
||||
/// BorderRadius with top corners rounded (8px)
|
||||
static const BorderRadius topSmallRadius = BorderRadius.only(
|
||||
topLeft: Radius.circular(radiusSm),
|
||||
topRight: Radius.circular(radiusSm),
|
||||
);
|
||||
|
||||
/// BorderRadius with top corners rounded (12px)
|
||||
static const BorderRadius topMediumRadius = BorderRadius.only(
|
||||
topLeft: Radius.circular(radiusMd),
|
||||
topRight: Radius.circular(radiusMd),
|
||||
);
|
||||
|
||||
/// BorderRadius with top corners rounded (16px)
|
||||
static const BorderRadius topLargeRadius = BorderRadius.only(
|
||||
topLeft: Radius.circular(radiusLg),
|
||||
topRight: Radius.circular(radiusLg),
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// COMPONENT BORDER RADIUS MAPPING
|
||||
// ============================================
|
||||
|
||||
/// Button border radius (8px - radiusSm)
|
||||
static const double buttonRadius = radiusSm;
|
||||
|
||||
/// Input field border radius (8px - radiusSm)
|
||||
static const double inputRadius = radiusSm;
|
||||
|
||||
/// Card border radius (12px - radiusMd)
|
||||
static const double cardRadius = radiusMd;
|
||||
|
||||
/// Dialog border radius (16px - radiusLg)
|
||||
static const double dialogRadius = radiusLg;
|
||||
|
||||
/// Chip border radius (999px - radiusRound, fully rounded)
|
||||
static const double chipRadius = radiusRound;
|
||||
|
||||
/// Bottom sheet border radius (16px - radiusLg)
|
||||
static const double bottomSheetRadius = radiusLg;
|
||||
|
||||
/// Dropdown border radius (8px - radiusSm)
|
||||
static const double dropdownRadius = radiusSm;
|
||||
|
||||
/// Small component border radius (4px - radiusXs)
|
||||
static const double smallComponentRadius = radiusXs;
|
||||
|
||||
// ============================================
|
||||
// BORDER RADIUS SHAPE OBJECTS
|
||||
// ============================================
|
||||
|
||||
/// RoundedRectangleBorder for buttons (8px radius)
|
||||
static const ShapeBorder buttonShape = RoundedRectangleBorder(
|
||||
borderRadius: circularSm,
|
||||
);
|
||||
|
||||
/// RoundedRectangleBorder for cards (12px radius)
|
||||
static const ShapeBorder cardShape = RoundedRectangleBorder(
|
||||
borderRadius: circularMd,
|
||||
);
|
||||
|
||||
/// RoundedRectangleBorder for dialogs (16px radius)
|
||||
static const ShapeBorder dialogShape = RoundedRectangleBorder(
|
||||
borderRadius: circularLg,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// COMPONENT BORDER RADIUS OBJECTS
|
||||
// ============================================
|
||||
|
||||
/// Small component border radius (4px - Radius object)
|
||||
static const Radius smallRadius = Radius.circular(radiusXs);
|
||||
|
||||
/// Button border radius (8px - Radius object)
|
||||
static const Radius buttonBorderRadius = Radius.circular(radiusSm);
|
||||
|
||||
/// Card border radius (12px - Radius object)
|
||||
static const Radius cardBorderRadius = Radius.circular(radiusMd);
|
||||
|
||||
/// Dialog border radius (16px - Radius object)
|
||||
static const Radius dialogBorderRadius = Radius.circular(radiusLg);
|
||||
|
||||
/// Fully rounded (999px - Radius object)
|
||||
static const Radius fullRoundRadius = Radius.circular(radiusRound);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Brand Color System
|
||||
/// Complete color palette following Material Design 3 specifications
|
||||
class SvrntyColors {
|
||||
// Prevent instantiation
|
||||
SvrntyColors._();
|
||||
|
||||
// ============================================
|
||||
// CORE BRAND COLORS
|
||||
// ============================================
|
||||
|
||||
/// Crimson Red - Primary accent and brand signature
|
||||
static const Color crimsonRed = Color(0xDF2D45);
|
||||
|
||||
/// Almost Black - Primary dark background
|
||||
static const Color almostBlack = Color(0x06080C);
|
||||
|
||||
/// Dark Slate - Secondary dark tone
|
||||
static const Color darkSlate = Color(0x3A4958);
|
||||
|
||||
/// Slate Gray - Mid-tone gray
|
||||
static const Color slateGray = Color(0x506576);
|
||||
|
||||
/// Teal - Tertiary accent
|
||||
static const Color teal = Color(0x1D2C39);
|
||||
|
||||
/// Light Gray - Neutral light
|
||||
static const Color lightGray = Color(0xAEB8BE);
|
||||
|
||||
// ============================================
|
||||
// SEMANTIC COLORS
|
||||
// ============================================
|
||||
|
||||
/// Success - Green for positive actions and completed states
|
||||
static const Color success = Color(0x22C55E);
|
||||
|
||||
/// Warning - Amber for warnings and attention-needed states
|
||||
static const Color warning = Color(0xF59E0B);
|
||||
|
||||
/// Info - Blue for informational and in-progress states
|
||||
static const Color info = Color(0x3B82F6);
|
||||
|
||||
/// Error - Red for errors, failures, and destructive actions
|
||||
static const Color error = Color(0xEF4444);
|
||||
|
||||
// ============================================
|
||||
// DELIVERY STATUS COLORS
|
||||
// ============================================
|
||||
|
||||
/// Status Pending - Awaiting action (Slate Gray)
|
||||
static const Color statusPending = slateGray;
|
||||
|
||||
/// Status In Progress - Currently being delivered (Blue)
|
||||
static const Color statusInProgress = info;
|
||||
|
||||
/// Status Completed - Successfully delivered (Green)
|
||||
static const Color statusCompleted = success;
|
||||
|
||||
/// Status Skipped - Skipped/passed delivery (Amber)
|
||||
static const Color statusSkipped = warning;
|
||||
|
||||
/// Status Failed - Failed delivery (Red)
|
||||
static const Color statusFailed = error;
|
||||
|
||||
// ============================================
|
||||
// SURFACE VARIANTS
|
||||
// ============================================
|
||||
|
||||
/// Surface Elevated - Light elevated surface
|
||||
static const Color surfaceElevated = Color(0xF5F7FA);
|
||||
|
||||
/// Surface Subdued - Subdued light surface
|
||||
static const Color surfaceSubdued = Color(0xE8EAEE);
|
||||
|
||||
// ============================================
|
||||
// EXTENDED COLOR FAMILIES - SUCCESS (GREEN)
|
||||
// ============================================
|
||||
|
||||
/// Success color light theme
|
||||
static const Color successLight = Color(0x22C55E);
|
||||
|
||||
/// Success on color light theme
|
||||
static const Color onSuccessLight = Color(0xFFFFFF);
|
||||
|
||||
/// Success container light theme
|
||||
static const Color successContainerLight = Color(0xDCFCE7);
|
||||
|
||||
/// Success on container light theme
|
||||
static const Color onSuccessContainerLight = Color(0x14532D);
|
||||
|
||||
/// Success color dark theme
|
||||
static const Color successDark = Color(0x4ADE80);
|
||||
|
||||
/// Success on color dark theme
|
||||
static const Color onSuccessDark = Color(0x14532D);
|
||||
|
||||
/// Success container dark theme
|
||||
static const Color successContainerDark = Color(0x15803D);
|
||||
|
||||
/// Success on container dark theme
|
||||
static const Color onSuccessContainerDark = Color(0xDCFCE7);
|
||||
|
||||
// ============================================
|
||||
// EXTENDED COLOR FAMILIES - WARNING (AMBER)
|
||||
// ============================================
|
||||
|
||||
/// Warning color light theme
|
||||
static const Color warningLight = Color(0xF59E0B);
|
||||
|
||||
/// Warning on color light theme
|
||||
static const Color onWarningLight = Color(0xFFFFFF);
|
||||
|
||||
/// Warning container light theme
|
||||
static const Color warningContainerLight = Color(0xFEF3C7);
|
||||
|
||||
/// Warning on container light theme
|
||||
static const Color onWarningContainerLight = Color(0x78350F);
|
||||
|
||||
/// Warning color dark theme
|
||||
static const Color warningDark = Color(0xFBBF24);
|
||||
|
||||
/// Warning on color dark theme
|
||||
static const Color onWarningDark = Color(0x78350F);
|
||||
|
||||
/// Warning container dark theme
|
||||
static const Color warningContainerDark = Color(0xD97706);
|
||||
|
||||
/// Warning on container dark theme
|
||||
static const Color onWarningContainerDark = Color(0xFEF3C7);
|
||||
|
||||
// ============================================
|
||||
// EXTENDED COLOR FAMILIES - INFO (BLUE)
|
||||
// ============================================
|
||||
|
||||
/// Info color light theme
|
||||
static const Color infoLight = Color(0x3B82F6);
|
||||
|
||||
/// Info on color light theme
|
||||
static const Color onInfoLight = Color(0xFFFFFF);
|
||||
|
||||
/// Info container light theme
|
||||
static const Color infoContainerLight = Color(0xDEEEFF);
|
||||
|
||||
/// Info on container light theme
|
||||
static const Color onInfoContainerLight = Color(0x003DA1);
|
||||
|
||||
/// Info color dark theme
|
||||
static const Color infoDark = Color(0x90CAF9);
|
||||
|
||||
/// Info on color dark theme
|
||||
static const Color onInfoDark = Color(0x003DA1);
|
||||
|
||||
/// Info container dark theme
|
||||
static const Color infoContainerDark = Color(0x0D47A1);
|
||||
|
||||
/// Info on container dark theme
|
||||
static const Color onInfoContainerDark = Color(0xDEEEFF);
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'spacing_system.dart';
|
||||
import 'border_system.dart';
|
||||
import 'shadow_system.dart';
|
||||
import 'size_system.dart';
|
||||
|
||||
/// Component Theme Data Builders
|
||||
/// Centralized component theme definitions for consistent styling
|
||||
class ComponentThemes {
|
||||
static CardThemeData cardTheme(ColorScheme colorScheme) {
|
||||
return CardThemeData(
|
||||
elevation: AppShadow.cardElevation,
|
||||
shadowColor: AppShadow.getShadowColor(colorScheme.brightness),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularMd,
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
color: colorScheme.surface,
|
||||
);
|
||||
}
|
||||
|
||||
static AppBarTheme appBarTheme(ColorScheme colorScheme) {
|
||||
return AppBarTheme(
|
||||
backgroundColor: colorScheme.surface,
|
||||
foregroundColor: colorScheme.onSurface,
|
||||
elevation: AppShadow.appBarElevation,
|
||||
centerTitle: false,
|
||||
iconTheme: IconThemeData(
|
||||
color: colorScheme.onSurface,
|
||||
size: AppSizes.iconMd,
|
||||
),
|
||||
titleTextStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 20,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static FilledButtonThemeData filledButtonTheme(ColorScheme colorScheme) {
|
||||
return FilledButtonThemeData(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.onPrimary,
|
||||
elevation: AppShadow.elevationSm,
|
||||
padding: AppSpacing.paddingButton,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
),
|
||||
textStyle: const TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static ElevatedButtonThemeData elevatedButtonTheme(ColorScheme colorScheme) {
|
||||
return ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.onPrimary,
|
||||
elevation: AppShadow.elevationSm,
|
||||
padding: AppSpacing.paddingButton,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
),
|
||||
textStyle: const TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static OutlinedButtonThemeData outlinedButtonTheme(ColorScheme colorScheme) {
|
||||
return OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: colorScheme.primary,
|
||||
side: BorderSide(color: colorScheme.outline),
|
||||
padding: AppSpacing.paddingButton,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
),
|
||||
textStyle: const TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static InputDecorationTheme inputDecorationTheme(ColorScheme colorScheme) {
|
||||
return InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: colorScheme.surfaceContainerHighest.withOpacity(0.5),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.inputPadding,
|
||||
vertical: AppSpacing.md,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.outline.withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.outline.withOpacity(0.3),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.error,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.error,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
labelStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: colorScheme.onSurfaceVariant.withOpacity(0.6),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static SnackBarThemeData snackBarTheme(ColorScheme colorScheme) {
|
||||
return SnackBarThemeData(
|
||||
backgroundColor: colorScheme.inverseSurface,
|
||||
contentTextStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
color: colorScheme.onInverseSurface,
|
||||
),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static DialogThemeData dialogTheme(ColorScheme colorScheme) {
|
||||
return DialogThemeData(
|
||||
backgroundColor: colorScheme.surface,
|
||||
elevation: AppShadow.dialogElevation,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularLg,
|
||||
),
|
||||
contentTextStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static BottomNavigationBarThemeData bottomNavigationBarTheme(
|
||||
ColorScheme colorScheme,
|
||||
) {
|
||||
return BottomNavigationBarThemeData(
|
||||
backgroundColor: colorScheme.surface,
|
||||
selectedItemColor: colorScheme.primary,
|
||||
unselectedItemColor: colorScheme.onSurfaceVariant,
|
||||
showSelectedLabels: true,
|
||||
showUnselectedLabels: true,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
selectedLabelStyle: const TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
),
|
||||
unselectedLabelStyle: const TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static ChipThemeData chipTheme(ColorScheme colorScheme) {
|
||||
return ChipThemeData(
|
||||
backgroundColor: colorScheme.surfaceContainerHighest,
|
||||
deleteIconColor: colorScheme.onSurfaceVariant,
|
||||
disabledColor: colorScheme.surfaceContainerHighest.withOpacity(0.38),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: AppSpacing.xs,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularSm,
|
||||
),
|
||||
labelStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
secondaryLabelStyle: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
brightness: colorScheme.brightness,
|
||||
);
|
||||
}
|
||||
|
||||
static ProgressIndicatorThemeData progressIndicatorTheme(
|
||||
ColorScheme colorScheme,
|
||||
) {
|
||||
return ProgressIndicatorThemeData(
|
||||
color: colorScheme.primary,
|
||||
linearTrackColor: colorScheme.surfaceContainerHighest,
|
||||
circularTrackColor: colorScheme.surfaceContainerHighest,
|
||||
);
|
||||
}
|
||||
|
||||
static FloatingActionButtonThemeData floatingActionButtonTheme(
|
||||
ColorScheme colorScheme,
|
||||
) {
|
||||
return FloatingActionButtonThemeData(
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.onPrimary,
|
||||
elevation: AppShadow.fabElevation,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: AppBorders.circularMd,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static SliderThemeData sliderTheme(ColorScheme colorScheme) {
|
||||
return SliderThemeData(
|
||||
trackHeight: 4.0,
|
||||
activeTrackColor: colorScheme.primary,
|
||||
inactiveTrackColor: colorScheme.surfaceContainerHighest,
|
||||
thumbColor: colorScheme.primary,
|
||||
overlayColor: colorScheme.primary.withOpacity(0.12),
|
||||
valueIndicatorColor: colorScheme.primary,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'color_system.dart';
|
||||
|
||||
/// Svrnty Gradient System
|
||||
/// Predefined gradients for status bars, progress indicators, and backgrounds
|
||||
class AppGradients {
|
||||
// Prevent instantiation
|
||||
AppGradients._();
|
||||
|
||||
// ============================================
|
||||
// DELIVERY STATUS GRADIENTS
|
||||
// ============================================
|
||||
|
||||
/// Pending status gradient (Slate Gray)
|
||||
static const LinearGradient gradientStatusPending = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.statusPending,
|
||||
Color(0x506576), // Slightly different shade for gradient effect
|
||||
],
|
||||
);
|
||||
|
||||
/// In Progress status gradient (Blue/Info)
|
||||
static const LinearGradient gradientStatusInProgress = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.statusInProgress,
|
||||
Color(0x5B9BFF), // Lighter blue for gradient
|
||||
],
|
||||
);
|
||||
|
||||
/// Completed status gradient (Green/Success)
|
||||
static const LinearGradient gradientStatusCompleted = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.statusCompleted,
|
||||
Color(0x4ADE80), // Lighter green for gradient
|
||||
],
|
||||
);
|
||||
|
||||
/// Skipped status gradient (Amber/Warning)
|
||||
static const LinearGradient gradientStatusSkipped = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.statusSkipped,
|
||||
Color(0xFBBF24), // Lighter amber for gradient
|
||||
],
|
||||
);
|
||||
|
||||
/// Failed status gradient (Red/Error)
|
||||
static const LinearGradient gradientStatusFailed = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.statusFailed,
|
||||
Color(0xFF7D7D), // Lighter red for gradient
|
||||
],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// PROGRESS INDICATOR GRADIENTS
|
||||
// ============================================
|
||||
|
||||
/// Progress bar gradient (Blue to transparent)
|
||||
static LinearGradient gradientProgress({
|
||||
required Color color,
|
||||
bool horizontal = true,
|
||||
}) {
|
||||
return LinearGradient(
|
||||
begin: horizontal ? Alignment.centerLeft : Alignment.topCenter,
|
||||
end: horizontal ? Alignment.centerRight : Alignment.bottomCenter,
|
||||
colors: [
|
||||
color,
|
||||
color.withOpacity(0.8),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Success progress gradient
|
||||
static const LinearGradient gradientProgressSuccess = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.success,
|
||||
Color(0x4ADE80), // Lighter green
|
||||
],
|
||||
);
|
||||
|
||||
/// Warning progress gradient
|
||||
static const LinearGradient gradientProgressWarning = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.warning,
|
||||
Color(0xFBBF24), // Lighter amber
|
||||
],
|
||||
);
|
||||
|
||||
/// Error progress gradient
|
||||
static const LinearGradient gradientProgressError = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.error,
|
||||
Color(0xFF7D7D), // Lighter red
|
||||
],
|
||||
);
|
||||
|
||||
/// Info progress gradient
|
||||
static const LinearGradient gradientProgressInfo = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
SvrntyColors.info,
|
||||
Color(0x5B9BFF), // Lighter blue
|
||||
],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// BRAND GRADIENTS
|
||||
// ============================================
|
||||
|
||||
/// Primary brand gradient (Crimson Red)
|
||||
static const LinearGradient gradientPrimary = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
SvrntyColors.crimsonRed,
|
||||
Color(0xC44D58), // Slightly darker shade
|
||||
],
|
||||
);
|
||||
|
||||
/// Secondary brand gradient (Slate Blue)
|
||||
static const LinearGradient gradientSecondary = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
SvrntyColors.darkSlate,
|
||||
SvrntyColors.slateGray,
|
||||
],
|
||||
);
|
||||
|
||||
/// Accent gradient (Crimson to Slate)
|
||||
static const LinearGradient gradientAccent = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
SvrntyColors.crimsonRed,
|
||||
SvrntyColors.darkSlate,
|
||||
],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// BACKGROUND GRADIENTS
|
||||
// ============================================
|
||||
|
||||
/// Light background gradient
|
||||
static const LinearGradient gradientBackgroundLight = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Color(0xFAFAFC),
|
||||
Color(0xF5F7FA),
|
||||
],
|
||||
);
|
||||
|
||||
/// Dark background gradient
|
||||
static const LinearGradient gradientBackgroundDark = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Color(0x1A1C1E),
|
||||
Color(0x2A2D34),
|
||||
],
|
||||
);
|
||||
|
||||
/// Elevated surface gradient (light)
|
||||
static const LinearGradient gradientElevatedLight = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0xFFFFFF),
|
||||
Color(0xF5F7FA),
|
||||
],
|
||||
);
|
||||
|
||||
/// Elevated surface gradient (dark)
|
||||
static const LinearGradient gradientElevatedDark = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0x2A2D34),
|
||||
Color(0x1F2123),
|
||||
],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// OVERLAY GRADIENTS
|
||||
// ============================================
|
||||
|
||||
/// Dark overlay gradient (for images)
|
||||
static const LinearGradient gradientOverlayDark = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0x00000000), // Transparent at top
|
||||
Color(0x4D000000), // Dark at bottom
|
||||
],
|
||||
);
|
||||
|
||||
/// Light overlay gradient
|
||||
static const LinearGradient gradientOverlayLight = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0x00FFFFFF), // Transparent at top
|
||||
Color(0x4DFFFFFF), // Light at bottom
|
||||
],
|
||||
);
|
||||
|
||||
/// Vignette gradient (darkened edges)
|
||||
static const RadialGradient gradientVignette = RadialGradient(
|
||||
center: Alignment.center,
|
||||
radius: 1.2,
|
||||
colors: [
|
||||
Color(0x00000000),
|
||||
Color(0x80000000),
|
||||
],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// SHIMMER GRADIENTS (for loading states)
|
||||
// ============================================
|
||||
|
||||
/// Shimmer gradient light theme
|
||||
static const LinearGradient gradientShimmerLight = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
Color(0xFFFFFFFF),
|
||||
Color(0x80F0F0F0),
|
||||
Color(0xFFFFFFFF),
|
||||
],
|
||||
stops: [0.1, 0.5, 0.9],
|
||||
);
|
||||
|
||||
/// Shimmer gradient dark theme
|
||||
static const LinearGradient gradientShimmerDark = LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
Color(0xFF2A2D34),
|
||||
Color(0x80383940),
|
||||
Color(0xFF2A2D34),
|
||||
],
|
||||
stops: [0.1, 0.5, 0.9],
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// UTILITY METHODS
|
||||
// ============================================
|
||||
|
||||
/// Get status gradient based on delivery status
|
||||
static LinearGradient getStatusGradient(String status) {
|
||||
switch (status.toLowerCase()) {
|
||||
case 'pending':
|
||||
return gradientStatusPending;
|
||||
case 'in_progress':
|
||||
case 'inprogress':
|
||||
return gradientStatusInProgress;
|
||||
case 'completed':
|
||||
case 'done':
|
||||
return gradientStatusCompleted;
|
||||
case 'skipped':
|
||||
return gradientStatusSkipped;
|
||||
case 'failed':
|
||||
return gradientStatusFailed;
|
||||
default:
|
||||
return gradientStatusPending;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get progress gradient based on status
|
||||
static LinearGradient getProgressGradient(String status) {
|
||||
switch (status.toLowerCase()) {
|
||||
case 'success':
|
||||
return gradientProgressSuccess;
|
||||
case 'warning':
|
||||
return gradientProgressWarning;
|
||||
case 'error':
|
||||
return gradientProgressError;
|
||||
case 'info':
|
||||
return gradientProgressInfo;
|
||||
default:
|
||||
return gradientProgressSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a custom gradient with opacity
|
||||
static LinearGradient withOpacity(
|
||||
LinearGradient gradient,
|
||||
double opacity,
|
||||
) {
|
||||
return LinearGradient(
|
||||
begin: gradient.begin,
|
||||
end: gradient.end,
|
||||
colors: gradient.colors
|
||||
.map((color) => color.withOpacity(opacity))
|
||||
.toList(),
|
||||
stops: gradient.stops,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a directional gradient
|
||||
static LinearGradient directional({
|
||||
required List<Color> colors,
|
||||
required Alignment begin,
|
||||
required Alignment end,
|
||||
List<double>? stops,
|
||||
}) {
|
||||
return LinearGradient(
|
||||
begin: begin,
|
||||
end: end,
|
||||
colors: colors,
|
||||
stops: stops,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Shadow & Elevation System
|
||||
/// Comprehensive shadow and elevation definitions for light and dark themes
|
||||
class AppShadow {
|
||||
// Prevent instantiation
|
||||
AppShadow._();
|
||||
|
||||
// ============================================
|
||||
// ELEVATION CONSTANTS
|
||||
// ============================================
|
||||
|
||||
/// No elevation/shadow
|
||||
static const double elevationNone = 0.0;
|
||||
|
||||
/// Minimal depth elevation
|
||||
static const double elevationXs = 1.0;
|
||||
|
||||
/// Small shadow elevation (default for cards)
|
||||
static const double elevationSm = 2.0;
|
||||
|
||||
/// Medium shadow elevation (hover states)
|
||||
static const double elevationMd = 4.0;
|
||||
|
||||
/// Large shadow elevation
|
||||
static const double elevationLg = 8.0;
|
||||
|
||||
/// Extra large shadow elevation (dialogs, prominent surfaces)
|
||||
static const double elevationXl = 16.0;
|
||||
|
||||
// ============================================
|
||||
// SHADOW DEFINITIONS - LIGHT THEME
|
||||
// ============================================
|
||||
|
||||
/// Light theme shadow color (10% opacity black)
|
||||
static const Color _shadowColorLight = Color(0x1A000000);
|
||||
|
||||
/// No shadow for light theme
|
||||
static const List<BoxShadow> shadowNoneLight = [];
|
||||
|
||||
/// Minimal shadow for light theme
|
||||
static const List<BoxShadow> shadowXsLight = [
|
||||
BoxShadow(
|
||||
color: _shadowColorLight,
|
||||
blurRadius: 1,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
/// Small shadow for light theme (default for cards)
|
||||
static const List<BoxShadow> shadowSmLight = [
|
||||
BoxShadow(
|
||||
color: _shadowColorLight,
|
||||
blurRadius: 2,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
/// Medium shadow for light theme (hover states)
|
||||
static const List<BoxShadow> shadowMdLight = [
|
||||
BoxShadow(
|
||||
color: _shadowColorLight,
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
];
|
||||
|
||||
/// Large shadow for light theme
|
||||
static const List<BoxShadow> shadowLgLight = [
|
||||
BoxShadow(
|
||||
color: _shadowColorLight,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Extra large shadow for light theme (dialogs)
|
||||
static const List<BoxShadow> shadowXlLight = [
|
||||
BoxShadow(
|
||||
color: _shadowColorLight,
|
||||
blurRadius: 16,
|
||||
offset: Offset(0, 8),
|
||||
),
|
||||
];
|
||||
|
||||
// ============================================
|
||||
// SHADOW DEFINITIONS - DARK THEME
|
||||
// ============================================
|
||||
|
||||
/// Dark theme shadow color (pure black)
|
||||
static const Color _shadowColorDark = Color(0x4D000000);
|
||||
|
||||
/// No shadow for dark theme
|
||||
static const List<BoxShadow> shadowNoneDark = [];
|
||||
|
||||
/// Minimal shadow for dark theme
|
||||
static const List<BoxShadow> shadowXsDark = [
|
||||
BoxShadow(
|
||||
color: _shadowColorDark,
|
||||
blurRadius: 1,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
/// Small shadow for dark theme (default for cards)
|
||||
static const List<BoxShadow> shadowSmDark = [
|
||||
BoxShadow(
|
||||
color: _shadowColorDark,
|
||||
blurRadius: 2,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
/// Medium shadow for dark theme (hover states)
|
||||
static const List<BoxShadow> shadowMdDark = [
|
||||
BoxShadow(
|
||||
color: _shadowColorDark,
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
];
|
||||
|
||||
/// Large shadow for dark theme
|
||||
static const List<BoxShadow> shadowLgDark = [
|
||||
BoxShadow(
|
||||
color: _shadowColorDark,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Extra large shadow for dark theme (dialogs)
|
||||
static const List<BoxShadow> shadowXlDark = [
|
||||
BoxShadow(
|
||||
color: _shadowColorDark,
|
||||
blurRadius: 16,
|
||||
offset: Offset(0, 8),
|
||||
),
|
||||
];
|
||||
|
||||
// ============================================
|
||||
// SHADOW UTILITY METHODS
|
||||
// ============================================
|
||||
|
||||
/// Get shadow list based on brightness and elevation level
|
||||
static List<BoxShadow> getShadow(
|
||||
Brightness brightness,
|
||||
double elevation,
|
||||
) {
|
||||
final isDark = brightness == Brightness.dark;
|
||||
|
||||
switch (elevation) {
|
||||
case elevationNone:
|
||||
return isDark ? shadowNoneDark : shadowNoneLight;
|
||||
case elevationXs:
|
||||
return isDark ? shadowXsDark : shadowXsLight;
|
||||
case elevationSm:
|
||||
return isDark ? shadowSmDark : shadowSmLight;
|
||||
case elevationMd:
|
||||
return isDark ? shadowMdDark : shadowMdLight;
|
||||
case elevationLg:
|
||||
return isDark ? shadowLgDark : shadowLgLight;
|
||||
case elevationXl:
|
||||
return isDark ? shadowXlDark : shadowXlLight;
|
||||
default:
|
||||
return isDark ? shadowSmDark : shadowSmLight;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get shadow color based on brightness
|
||||
static Color getShadowColor(Brightness brightness) {
|
||||
return brightness == Brightness.dark ? _shadowColorDark : _shadowColorLight;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// COMPONENT ELEVATION MAPPING
|
||||
// ============================================
|
||||
|
||||
/// Card elevation (2)
|
||||
static const double cardElevation = elevationSm;
|
||||
|
||||
/// Card hover elevation (4)
|
||||
static const double cardHoverElevation = elevationMd;
|
||||
|
||||
/// AppBar elevation (0 - flat design)
|
||||
static const double appBarElevation = elevationNone;
|
||||
|
||||
/// Dialog elevation (8)
|
||||
static const double dialogElevation = elevationLg;
|
||||
|
||||
/// FAB elevation (8)
|
||||
static const double fabElevation = elevationLg;
|
||||
|
||||
/// FAB hover elevation (16)
|
||||
static const double fabHoverElevation = elevationXl;
|
||||
|
||||
/// Bottom sheet elevation (8)
|
||||
static const double bottomSheetElevation = elevationLg;
|
||||
|
||||
/// Floating action button pressed elevation (12)
|
||||
static const double fabPressedElevation = elevationXl;
|
||||
|
||||
/// Menu/Dropdown elevation (8)
|
||||
static const double menuElevation = elevationLg;
|
||||
|
||||
/// Tooltip elevation (16)
|
||||
static const double tooltipElevation = elevationXl;
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Size System
|
||||
/// Standard sizing constants for icons, buttons, containers, and other components
|
||||
class AppSizes {
|
||||
// Prevent instantiation
|
||||
AppSizes._();
|
||||
|
||||
// ============================================
|
||||
// ICON SIZES
|
||||
// ============================================
|
||||
|
||||
/// Extra small icon (16px)
|
||||
static const double iconXs = 16.0;
|
||||
|
||||
/// Small icon (20px)
|
||||
static const double iconSm = 20.0;
|
||||
|
||||
/// Standard icon size (24px)
|
||||
static const double iconMd = 24.0;
|
||||
|
||||
/// Large icon size (32px)
|
||||
static const double iconLg = 32.0;
|
||||
|
||||
/// Extra large icon (40px)
|
||||
static const double iconXl = 40.0;
|
||||
|
||||
/// Huge icon (48px)
|
||||
static const double iconXxl = 48.0;
|
||||
|
||||
/// Extra huge icon (56px)
|
||||
static const double iconXxxl = 56.0;
|
||||
|
||||
// ============================================
|
||||
// BUTTON SIZES
|
||||
// ============================================
|
||||
|
||||
/// Small button height (32px)
|
||||
static const double buttonHeightSm = 32.0;
|
||||
|
||||
/// Medium button height (40px) - Default
|
||||
static const double buttonHeightMd = 40.0;
|
||||
|
||||
/// Large button height (48px)
|
||||
static const double buttonHeightLg = 48.0;
|
||||
|
||||
/// Extra large button height (56px)
|
||||
static const double buttonHeightXl = 56.0;
|
||||
|
||||
// ============================================
|
||||
// INPUT FIELD SIZES
|
||||
// ============================================
|
||||
|
||||
/// Input field height
|
||||
static const double inputHeight = 56.0;
|
||||
|
||||
/// Compact input field height (no vertical padding)
|
||||
static const double inputHeightCompact = 40.0;
|
||||
|
||||
/// Input field min width
|
||||
static const double inputMinWidth = 48.0;
|
||||
|
||||
// ============================================
|
||||
// CONTAINER & LAYOUT SIZES
|
||||
// ============================================
|
||||
|
||||
/// Standard card minimum height
|
||||
static const double cardMinHeight = 80.0;
|
||||
|
||||
/// Standard dialog max width (mobile)
|
||||
static const double dialogMaxWidthMobile = 280.0;
|
||||
|
||||
/// Standard dialog max width (tablet/desktop)
|
||||
static const double dialogMaxWidthDesktop = 560.0;
|
||||
|
||||
/// Maximum content width for centered layouts
|
||||
static const double maxContentWidth = 1200.0;
|
||||
|
||||
/// Compact content width (forms, focused layouts)
|
||||
static const double compactContentWidth = 600.0;
|
||||
|
||||
/// Standard container max width
|
||||
static const double containerMaxWidth = 900.0;
|
||||
|
||||
// ============================================
|
||||
// APPBAR & HEADER SIZES
|
||||
// ============================================
|
||||
|
||||
/// Standard app bar height
|
||||
static const double appBarHeight = 56.0;
|
||||
|
||||
/// Large app bar height
|
||||
static const double appBarHeightLarge = 72.0;
|
||||
|
||||
/// Compact app bar height
|
||||
static const double appBarHeightCompact = 48.0;
|
||||
|
||||
// ============================================
|
||||
// BOTTOM SHEET SIZES
|
||||
// ============================================
|
||||
|
||||
/// Bottom sheet max width
|
||||
static const double bottomSheetMaxWidth = 540.0;
|
||||
|
||||
/// Bottom sheet default height (auto)
|
||||
static const double bottomSheetHeightAuto = 0.0;
|
||||
|
||||
/// Bottom sheet half screen height
|
||||
static const double bottomSheetHeightHalf = 0.5;
|
||||
|
||||
/// Bottom sheet 3/4 screen height
|
||||
static const double bottomSheetHeight3Quarter = 0.75;
|
||||
|
||||
// ============================================
|
||||
// ELEVATION & Z-INDEX
|
||||
// ============================================
|
||||
|
||||
/// Standard z-index for floating elements
|
||||
static const int zIndexFloating = 100;
|
||||
|
||||
/// Z-index for modals/dialogs
|
||||
static const int zIndexModal = 50;
|
||||
|
||||
/// Z-index for tooltips
|
||||
static const int zIndexTooltip = 150;
|
||||
|
||||
// ============================================
|
||||
// DIVIDER & LINE SIZES
|
||||
// ============================================
|
||||
|
||||
/// Divider thickness
|
||||
static const double dividerThickness = 1.0;
|
||||
|
||||
/// Thin divider thickness (0.5px)
|
||||
static const double dividerThicknessThin = 0.5;
|
||||
|
||||
/// Thick divider thickness (2px)
|
||||
static const double dividerThicknessThick = 2.0;
|
||||
|
||||
/// Horizontal divider height
|
||||
static const double dividerHeightHorizontal = 1.0;
|
||||
|
||||
/// Vertical divider width
|
||||
static const double dividerWidthVertical = 1.0;
|
||||
|
||||
// ============================================
|
||||
// PROGRESS INDICATOR SIZES
|
||||
// ============================================
|
||||
|
||||
/// Progress indicator thickness
|
||||
static const double progressIndicatorThickness = 4.0;
|
||||
|
||||
/// Circular progress indicator size
|
||||
static const double circularProgressSize = 48.0;
|
||||
|
||||
/// Linear progress indicator height (thin)
|
||||
static const double linearProgressHeightThin = 2.0;
|
||||
|
||||
/// Linear progress indicator height (standard)
|
||||
static const double linearProgressHeightStandard = 4.0;
|
||||
|
||||
/// Linear progress indicator height (thick)
|
||||
static const double linearProgressHeightThick = 8.0;
|
||||
|
||||
// ============================================
|
||||
// CHIP & BADGE SIZES
|
||||
// ============================================
|
||||
|
||||
/// Chip height
|
||||
static const double chipHeight = 32.0;
|
||||
|
||||
/// Small chip height
|
||||
static const double chipHeightSm = 24.0;
|
||||
|
||||
/// Badge size (for counter badges)
|
||||
static const double badgeSize = 24.0;
|
||||
|
||||
/// Badge size (small)
|
||||
static const double badgeSizeSm = 16.0;
|
||||
|
||||
// ============================================
|
||||
// AVATAR SIZES
|
||||
// ============================================
|
||||
|
||||
/// Small avatar size
|
||||
static const double avatarSizeSm = 32.0;
|
||||
|
||||
/// Medium avatar size
|
||||
static const double avatarSizeMd = 48.0;
|
||||
|
||||
/// Large avatar size
|
||||
static const double avatarSizeLg = 64.0;
|
||||
|
||||
/// Extra large avatar size
|
||||
static const double avatarSizeXl = 80.0;
|
||||
|
||||
// ============================================
|
||||
// RESPONSIVE SIZING
|
||||
// ============================================
|
||||
|
||||
/// Minimum tap target size (Material guidelines - 48px)
|
||||
static const double minTapTarget = 48.0;
|
||||
|
||||
/// Minimum tap target size for desktop (36px)
|
||||
static const double minTapTargetDesktop = 36.0;
|
||||
|
||||
/// Standard element spacing
|
||||
static const double elementSpacing = 8.0;
|
||||
|
||||
/// Large element spacing
|
||||
static const double elementSpacingLarge = 16.0;
|
||||
|
||||
// ============================================
|
||||
// UTILITY METHODS
|
||||
// ============================================
|
||||
|
||||
/// Get responsive button height based on device type
|
||||
static double getButtonHeight(bool isCompact) {
|
||||
return isCompact ? buttonHeightMd : buttonHeightLg;
|
||||
}
|
||||
|
||||
/// Get responsive dialog max width based on screen width
|
||||
static double getDialogMaxWidth(double screenWidth) {
|
||||
return screenWidth < 600 ? dialogMaxWidthMobile : dialogMaxWidthDesktop;
|
||||
}
|
||||
|
||||
/// Get responsive icon size
|
||||
static double getIconSize({
|
||||
required bool isCompact,
|
||||
required bool isLarge,
|
||||
}) {
|
||||
if (isLarge) return iconLg;
|
||||
if (isCompact) return iconSm;
|
||||
return iconMd;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Spacing System - 4px Grid
|
||||
/// All spacing, sizing, and border radius values follow a strict 4px grid
|
||||
class AppSpacing {
|
||||
// Prevent instantiation
|
||||
AppSpacing._();
|
||||
|
||||
// ============================================
|
||||
// BASE SPACING SCALE (4px grid)
|
||||
// ============================================
|
||||
|
||||
/// Extra small spacing (4px) - unit × 1
|
||||
static const double xs = 4.0;
|
||||
|
||||
/// Small spacing (8px) - unit × 2
|
||||
static const double sm = 8.0;
|
||||
|
||||
/// Medium spacing (16px) - unit × 4 - DEFAULT
|
||||
static const double md = 16.0;
|
||||
|
||||
/// Large spacing (24px) - unit × 6
|
||||
static const double lg = 24.0;
|
||||
|
||||
/// Extra large spacing (32px) - unit × 8
|
||||
static const double xl = 32.0;
|
||||
|
||||
/// Double extra large (48px) - unit × 12
|
||||
static const double xxl = 48.0;
|
||||
|
||||
/// Triple extra large (64px) - unit × 16
|
||||
static const double xxxl = 64.0;
|
||||
|
||||
// ============================================
|
||||
// COMPONENT-SPECIFIC SPACING
|
||||
// ============================================
|
||||
|
||||
/// Padding inside cards
|
||||
static const double cardPadding = md; // 16px
|
||||
|
||||
/// Horizontal button padding
|
||||
static const double buttonPaddingX = lg; // 24px
|
||||
|
||||
/// Vertical button padding
|
||||
static const double buttonPaddingY = 12.0; // sm × 1.5
|
||||
|
||||
/// Padding in input fields
|
||||
static const double inputPadding = md; // 16px
|
||||
|
||||
/// Standard icon size
|
||||
static const double iconSize = lg; // 24px
|
||||
|
||||
/// Large icon size
|
||||
static const double iconSizeLarge = xl; // 32px
|
||||
|
||||
/// Dialog content padding
|
||||
static const double dialogPadding = lg; // 24px
|
||||
|
||||
/// Standard app bar height
|
||||
static const double appBarHeight = 56.0;
|
||||
|
||||
/// List item padding
|
||||
static const double listItemPadding = md; // 16px
|
||||
|
||||
// ============================================
|
||||
// PRE-BUILT EDGEINSETS - ALL SIDES
|
||||
// ============================================
|
||||
|
||||
/// EdgeInsets.all(4px)
|
||||
static const EdgeInsets paddingAllXs = EdgeInsets.all(xs);
|
||||
|
||||
/// EdgeInsets.all(8px)
|
||||
static const EdgeInsets paddingAllSm = EdgeInsets.all(sm);
|
||||
|
||||
/// EdgeInsets.all(16px)
|
||||
static const EdgeInsets paddingAllMd = EdgeInsets.all(md);
|
||||
|
||||
/// EdgeInsets.all(24px)
|
||||
static const EdgeInsets paddingAllLg = EdgeInsets.all(lg);
|
||||
|
||||
/// EdgeInsets.all(32px)
|
||||
static const EdgeInsets paddingAllXl = EdgeInsets.all(xl);
|
||||
|
||||
/// EdgeInsets.all(48px)
|
||||
static const EdgeInsets paddingAllXxl = EdgeInsets.all(xxl);
|
||||
|
||||
// ============================================
|
||||
// PRE-BUILT EDGEINSETS - HORIZONTAL
|
||||
// ============================================
|
||||
|
||||
/// EdgeInsets.symmetric(horizontal: 4px)
|
||||
static const EdgeInsets paddingHorizontalXs =
|
||||
EdgeInsets.symmetric(horizontal: xs);
|
||||
|
||||
/// EdgeInsets.symmetric(horizontal: 8px)
|
||||
static const EdgeInsets paddingHorizontalSm =
|
||||
EdgeInsets.symmetric(horizontal: sm);
|
||||
|
||||
/// EdgeInsets.symmetric(horizontal: 16px)
|
||||
static const EdgeInsets paddingHorizontalMd =
|
||||
EdgeInsets.symmetric(horizontal: md);
|
||||
|
||||
/// EdgeInsets.symmetric(horizontal: 24px)
|
||||
static const EdgeInsets paddingHorizontalLg =
|
||||
EdgeInsets.symmetric(horizontal: lg);
|
||||
|
||||
/// EdgeInsets.symmetric(horizontal: 32px)
|
||||
static const EdgeInsets paddingHorizontalXl =
|
||||
EdgeInsets.symmetric(horizontal: xl);
|
||||
|
||||
// ============================================
|
||||
// PRE-BUILT EDGEINSETS - VERTICAL
|
||||
// ============================================
|
||||
|
||||
/// EdgeInsets.symmetric(vertical: 4px)
|
||||
static const EdgeInsets paddingVerticalXs =
|
||||
EdgeInsets.symmetric(vertical: xs);
|
||||
|
||||
/// EdgeInsets.symmetric(vertical: 8px)
|
||||
static const EdgeInsets paddingVerticalSm =
|
||||
EdgeInsets.symmetric(vertical: sm);
|
||||
|
||||
/// EdgeInsets.symmetric(vertical: 16px)
|
||||
static const EdgeInsets paddingVerticalMd =
|
||||
EdgeInsets.symmetric(vertical: md);
|
||||
|
||||
/// EdgeInsets.symmetric(vertical: 24px)
|
||||
static const EdgeInsets paddingVerticalLg =
|
||||
EdgeInsets.symmetric(vertical: lg);
|
||||
|
||||
/// EdgeInsets.symmetric(vertical: 32px)
|
||||
static const EdgeInsets paddingVerticalXl =
|
||||
EdgeInsets.symmetric(vertical: xl);
|
||||
|
||||
// ============================================
|
||||
// PRE-BUILT EDGEINSETS - COMPONENT SPECIFIC
|
||||
// ============================================
|
||||
|
||||
/// Card padding (16px all sides)
|
||||
static const EdgeInsets paddingCard = paddingAllMd;
|
||||
|
||||
/// Button padding (horizontal: 24px, vertical: 12px)
|
||||
static const EdgeInsets paddingButton =
|
||||
EdgeInsets.symmetric(horizontal: lg, vertical: buttonPaddingY);
|
||||
|
||||
/// List item padding (horizontal: 16px, vertical: 8px)
|
||||
static const EdgeInsets paddingListItem =
|
||||
EdgeInsets.symmetric(horizontal: md, vertical: sm);
|
||||
|
||||
/// Dialog padding (24px all sides)
|
||||
static const EdgeInsets paddingDialog = paddingAllLg;
|
||||
|
||||
// ============================================
|
||||
// SPACER WIDGETS - UNIVERSAL (SQUARE)
|
||||
// ============================================
|
||||
|
||||
/// SizedBox(width: 4, height: 4)
|
||||
static const Widget spacerXs = SizedBox(width: xs, height: xs);
|
||||
|
||||
/// SizedBox(width: 8, height: 8)
|
||||
static const Widget spacerSm = SizedBox(width: sm, height: sm);
|
||||
|
||||
/// SizedBox(width: 16, height: 16)
|
||||
static const Widget spacerMd = SizedBox(width: md, height: md);
|
||||
|
||||
/// SizedBox(width: 24, height: 24)
|
||||
static const Widget spacerLg = SizedBox(width: lg, height: lg);
|
||||
|
||||
/// SizedBox(width: 32, height: 32)
|
||||
static const Widget spacerXl = SizedBox(width: xl, height: xl);
|
||||
|
||||
// ============================================
|
||||
// SPACER WIDGETS - VERTICAL
|
||||
// ============================================
|
||||
|
||||
/// SizedBox(height: 4)
|
||||
static const Widget vSpacerXs = SizedBox(height: xs);
|
||||
|
||||
/// SizedBox(height: 8)
|
||||
static const Widget vSpacerSm = SizedBox(height: sm);
|
||||
|
||||
/// SizedBox(height: 16)
|
||||
static const Widget vSpacerMd = SizedBox(height: md);
|
||||
|
||||
/// SizedBox(height: 24)
|
||||
static const Widget vSpacerLg = SizedBox(height: lg);
|
||||
|
||||
/// SizedBox(height: 32)
|
||||
static const Widget vSpacerXl = SizedBox(height: xl);
|
||||
|
||||
/// SizedBox(height: 48)
|
||||
static const Widget vSpacerXxl = SizedBox(height: xxl);
|
||||
|
||||
/// SizedBox(height: 64)
|
||||
static const Widget vSpacerXxxl = SizedBox(height: xxxl);
|
||||
|
||||
// ============================================
|
||||
// SPACER WIDGETS - HORIZONTAL
|
||||
// ============================================
|
||||
|
||||
/// SizedBox(width: 4)
|
||||
static const Widget hSpacerXs = SizedBox(width: xs);
|
||||
|
||||
/// SizedBox(width: 8)
|
||||
static const Widget hSpacerSm = SizedBox(width: sm);
|
||||
|
||||
/// SizedBox(width: 16)
|
||||
static const Widget hSpacerMd = SizedBox(width: md);
|
||||
|
||||
/// SizedBox(width: 24)
|
||||
static const Widget hSpacerLg = SizedBox(width: lg);
|
||||
|
||||
/// SizedBox(width: 32)
|
||||
static const Widget hSpacerXl = SizedBox(width: xl);
|
||||
|
||||
/// SizedBox(width: 48)
|
||||
static const Widget hSpacerXxl = SizedBox(width: xxl);
|
||||
|
||||
/// SizedBox(width: 64)
|
||||
static const Widget hSpacerXxxl = SizedBox(width: xxxl);
|
||||
|
||||
// ============================================
|
||||
// GAPS FOR ROW/COLUMN SPACING
|
||||
// ============================================
|
||||
|
||||
/// Gap for Row/Column (4px)
|
||||
static const double gapXs = xs;
|
||||
|
||||
/// Gap for Row/Column (8px)
|
||||
static const double gapSm = sm;
|
||||
|
||||
/// Gap for Row/Column (16px)
|
||||
static const double gapMd = md;
|
||||
|
||||
/// Gap for Row/Column (24px)
|
||||
static const double gapLg = lg;
|
||||
|
||||
/// Gap for Row/Column (32px)
|
||||
static const double gapXl = xl;
|
||||
|
||||
// ============================================
|
||||
// RESPONSIVE SCREEN MARGINS
|
||||
// ============================================
|
||||
|
||||
/// Screen margin for mobile devices (< 600px)
|
||||
static const double screenMarginMobile = md; // 16px
|
||||
|
||||
/// Screen margin for tablets (600-1024px)
|
||||
static const double screenMarginTablet = lg; // 24px
|
||||
|
||||
/// Screen margin for desktop (> 1024px)
|
||||
static const double screenMarginDesktop = xl; // 32px
|
||||
|
||||
/// Max content width constraint
|
||||
static const double maxContentWidth = 1200.0;
|
||||
|
||||
/// Compact content width for forms/compact layouts
|
||||
static const double compactContentWidth = 600.0;
|
||||
|
||||
// ============================================
|
||||
// RESPONSIVE PADDING FOR SCREENS
|
||||
// ============================================
|
||||
|
||||
/// Screen padding for mobile
|
||||
static const EdgeInsets screenPaddingMobile =
|
||||
EdgeInsets.symmetric(horizontal: screenMarginMobile);
|
||||
|
||||
/// Screen padding for tablet
|
||||
static const EdgeInsets screenPaddingTablet =
|
||||
EdgeInsets.symmetric(horizontal: screenMarginTablet);
|
||||
|
||||
/// Screen padding for desktop
|
||||
static const EdgeInsets screenPaddingDesktop =
|
||||
EdgeInsets.symmetric(horizontal: screenMarginDesktop);
|
||||
|
||||
// ============================================
|
||||
// UTILITY METHODS
|
||||
// ============================================
|
||||
|
||||
/// Get responsive screen margin based on screen width
|
||||
static double getScreenMargin(double screenWidth) {
|
||||
if (screenWidth < 600) {
|
||||
return screenMarginMobile;
|
||||
} else if (screenWidth < 1024) {
|
||||
return screenMarginTablet;
|
||||
} else {
|
||||
return screenMarginDesktop;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get responsive screen padding based on screen width
|
||||
static EdgeInsets getScreenPadding(double screenWidth) {
|
||||
final margin = getScreenMargin(screenWidth);
|
||||
return EdgeInsets.symmetric(horizontal: margin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Svrnty Typography System
|
||||
/// Extended text styles and typography utilities beyond Material Design 3
|
||||
class AppTypography {
|
||||
// Prevent instantiation
|
||||
AppTypography._();
|
||||
|
||||
// ============================================
|
||||
// FONT FAMILIES
|
||||
// ============================================
|
||||
|
||||
/// Primary font family (Montserrat)
|
||||
static const String fontFamilyPrimary = 'Montserrat';
|
||||
|
||||
/// Monospace font family (IBM Plex Mono)
|
||||
static const String fontFamilyMono = 'IBMPlexMono';
|
||||
|
||||
// ============================================
|
||||
// FONT WEIGHTS
|
||||
// ============================================
|
||||
|
||||
/// Light font weight (300)
|
||||
static const FontWeight weightLight = FontWeight.w300;
|
||||
|
||||
/// Regular font weight (400)
|
||||
static const FontWeight weightRegular = FontWeight.w400;
|
||||
|
||||
/// Medium font weight (500)
|
||||
static const FontWeight weightMedium = FontWeight.w500;
|
||||
|
||||
/// Semi-bold font weight (600)
|
||||
static const FontWeight weightSemiBold = FontWeight.w600;
|
||||
|
||||
/// Bold font weight (700)
|
||||
static const FontWeight weightBold = FontWeight.w700;
|
||||
|
||||
// ============================================
|
||||
// FONT SIZES
|
||||
// ============================================
|
||||
|
||||
/// Display Large font size (57px)
|
||||
static const double sizeDisplayLarge = 57.0;
|
||||
|
||||
/// Display Medium font size (45px)
|
||||
static const double sizeDisplayMedium = 45.0;
|
||||
|
||||
/// Display Small font size (36px)
|
||||
static const double sizeDisplaySmall = 36.0;
|
||||
|
||||
/// Headline Large font size (32px)
|
||||
static const double sizeHeadlineLarge = 32.0;
|
||||
|
||||
/// Headline Medium font size (28px)
|
||||
static const double sizeHeadlineMedium = 28.0;
|
||||
|
||||
/// Headline Small font size (24px)
|
||||
static const double sizeHeadlineSmall = 24.0;
|
||||
|
||||
/// Title Large font size (22px)
|
||||
static const double sizeTitleLarge = 22.0;
|
||||
|
||||
/// Title Medium font size (16px)
|
||||
static const double sizeTitleMedium = 16.0;
|
||||
|
||||
/// Title Small font size (14px)
|
||||
static const double sizeTitleSmall = 14.0;
|
||||
|
||||
/// Body Large font size (16px)
|
||||
static const double sizeBodyLarge = 16.0;
|
||||
|
||||
/// Body Medium font size (14px)
|
||||
static const double sizeBodyMedium = 14.0;
|
||||
|
||||
/// Body Small font size (12px)
|
||||
static const double sizeBodySmall = 12.0;
|
||||
|
||||
/// Label Large font size (14px)
|
||||
static const double sizeLabelLarge = 14.0;
|
||||
|
||||
/// Label Medium font size (12px)
|
||||
static const double sizeLabelMedium = 12.0;
|
||||
|
||||
/// Label Small font size (11px)
|
||||
static const double sizeLabelSmall = 11.0;
|
||||
|
||||
// ============================================
|
||||
// LINE HEIGHTS
|
||||
// ============================================
|
||||
|
||||
/// Display Large line height (1.12 = 64px)
|
||||
static const double lineHeightDisplayLarge = 1.12;
|
||||
|
||||
/// Display Medium line height (1.16 = 52px)
|
||||
static const double lineHeightDisplayMedium = 1.16;
|
||||
|
||||
/// Display Small line height (1.22 = 44px)
|
||||
static const double lineHeightDisplaySmall = 1.22;
|
||||
|
||||
/// Headline Large line height (1.25 = 40px)
|
||||
static const double lineHeightHeadlineLarge = 1.25;
|
||||
|
||||
/// Headline Medium line height (1.29 = 36px)
|
||||
static const double lineHeightHeadlineMedium = 1.29;
|
||||
|
||||
/// Headline Small line height (1.33 = 32px)
|
||||
static const double lineHeightHeadlineSmall = 1.33;
|
||||
|
||||
/// Title Large line height (1.27 = 28px)
|
||||
static const double lineHeightTitleLarge = 1.27;
|
||||
|
||||
/// Title Medium line height (1.5 = 24px)
|
||||
static const double lineHeightTitleMedium = 1.5;
|
||||
|
||||
/// Title Small line height (1.43 = 20px)
|
||||
static const double lineHeightTitleSmall = 1.43;
|
||||
|
||||
/// Body Large line height (1.5 = 24px)
|
||||
static const double lineHeightBodyLarge = 1.5;
|
||||
|
||||
/// Body Medium line height (1.43 = 20px)
|
||||
static const double lineHeightBodyMedium = 1.43;
|
||||
|
||||
/// Body Small line height (1.33 = 16px)
|
||||
static const double lineHeightBodySmall = 1.33;
|
||||
|
||||
/// Label Large line height (1.43 = 20px)
|
||||
static const double lineHeightLabelLarge = 1.43;
|
||||
|
||||
/// Label Medium line height (1.33 = 16px)
|
||||
static const double lineHeightLabelMedium = 1.33;
|
||||
|
||||
/// Label Small line height (1.45 = 16px)
|
||||
static const double lineHeightLabelSmall = 1.45;
|
||||
|
||||
// ============================================
|
||||
// LETTER SPACING
|
||||
// ============================================
|
||||
|
||||
/// Display Large letter spacing (-0.5px)
|
||||
static const double letterSpacingDisplayLarge = -0.5;
|
||||
|
||||
/// Display Medium letter spacing (-0.5px)
|
||||
static const double letterSpacingDisplayMedium = -0.5;
|
||||
|
||||
/// Display Small letter spacing (-0.25px)
|
||||
static const double letterSpacingDisplaySmall = -0.25;
|
||||
|
||||
/// Headline Large letter spacing (-0.25px)
|
||||
static const double letterSpacingHeadlineLarge = -0.25;
|
||||
|
||||
/// Headline Medium letter spacing (0px)
|
||||
static const double letterSpacingHeadlineMedium = 0.0;
|
||||
|
||||
/// Headline Small letter spacing (0px)
|
||||
static const double letterSpacingHeadlineSmall = 0.0;
|
||||
|
||||
/// Title Large letter spacing (0px)
|
||||
static const double letterSpacingTitleLarge = 0.0;
|
||||
|
||||
/// Title Medium letter spacing (0.15px)
|
||||
static const double letterSpacingTitleMedium = 0.15;
|
||||
|
||||
/// Title Small letter spacing (0.1px)
|
||||
static const double letterSpacingTitleSmall = 0.1;
|
||||
|
||||
/// Body Large letter spacing (0.5px)
|
||||
static const double letterSpacingBodyLarge = 0.5;
|
||||
|
||||
/// Body Medium letter spacing (0.25px)
|
||||
static const double letterSpacingBodyMedium = 0.25;
|
||||
|
||||
/// Body Small letter spacing (0.4px)
|
||||
static const double letterSpacingBodySmall = 0.4;
|
||||
|
||||
/// Label Large letter spacing (0.1px)
|
||||
static const double letterSpacingLabelLarge = 0.1;
|
||||
|
||||
/// Label Medium letter spacing (0.5px)
|
||||
static const double letterSpacingLabelMedium = 0.5;
|
||||
|
||||
/// Label Small letter spacing (0.5px)
|
||||
static const double letterSpacingLabelSmall = 0.5;
|
||||
|
||||
// ============================================
|
||||
// CUSTOM TEXT STYLES
|
||||
// ============================================
|
||||
|
||||
/// Monospace small text style
|
||||
static const TextStyle monoSmall = TextStyle(
|
||||
fontFamily: fontFamilyMono,
|
||||
fontSize: sizeBodySmall,
|
||||
fontWeight: weightRegular,
|
||||
);
|
||||
|
||||
/// Monospace medium text style
|
||||
static const TextStyle monoMedium = TextStyle(
|
||||
fontFamily: fontFamilyMono,
|
||||
fontSize: sizeBodyMedium,
|
||||
fontWeight: weightRegular,
|
||||
);
|
||||
|
||||
/// Monospace large text style
|
||||
static const TextStyle monoLarge = TextStyle(
|
||||
fontFamily: fontFamilyMono,
|
||||
fontSize: sizeBodyLarge,
|
||||
fontWeight: weightRegular,
|
||||
);
|
||||
|
||||
/// Monospace bold text style
|
||||
static const TextStyle monoBold = TextStyle(
|
||||
fontFamily: fontFamilyMono,
|
||||
fontSize: sizeBodyMedium,
|
||||
fontWeight: weightBold,
|
||||
);
|
||||
|
||||
/// Code snippet text style
|
||||
static const TextStyle codeStyle = TextStyle(
|
||||
fontFamily: fontFamilyMono,
|
||||
fontSize: sizeBodySmall,
|
||||
fontWeight: weightRegular,
|
||||
backgroundColor: Color(0xFFF5F5F5),
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// TEXT STYLE EXTENSIONS
|
||||
// ============================================
|
||||
|
||||
/// Create a text style with color override
|
||||
static TextStyle withColor(
|
||||
TextStyle baseStyle,
|
||||
Color color,
|
||||
) {
|
||||
return baseStyle.copyWith(color: color);
|
||||
}
|
||||
|
||||
/// Create a text style with size override
|
||||
static TextStyle withSize(
|
||||
TextStyle baseStyle,
|
||||
double fontSize,
|
||||
) {
|
||||
return baseStyle.copyWith(fontSize: fontSize);
|
||||
}
|
||||
|
||||
/// Create a text style with weight override
|
||||
static TextStyle withWeight(
|
||||
TextStyle baseStyle,
|
||||
FontWeight fontWeight,
|
||||
) {
|
||||
return baseStyle.copyWith(fontWeight: fontWeight);
|
||||
}
|
||||
|
||||
/// Create a text style with opacity
|
||||
static TextStyle withOpacity(
|
||||
TextStyle baseStyle,
|
||||
double opacity,
|
||||
) {
|
||||
final color = baseStyle.color ?? Colors.black;
|
||||
return baseStyle.copyWith(
|
||||
color: color.withOpacity(opacity),
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a text style with letter spacing override
|
||||
static TextStyle withLetterSpacing(
|
||||
TextStyle baseStyle,
|
||||
double letterSpacing,
|
||||
) {
|
||||
return baseStyle.copyWith(letterSpacing: letterSpacing);
|
||||
}
|
||||
|
||||
/// Create a text style with line height override
|
||||
static TextStyle withLineHeight(
|
||||
TextStyle baseStyle,
|
||||
double height,
|
||||
) {
|
||||
return baseStyle.copyWith(height: height);
|
||||
}
|
||||
|
||||
/// Create a monospace version of a text style
|
||||
static TextStyle toMonospace(TextStyle baseStyle) {
|
||||
return baseStyle.copyWith(
|
||||
fontFamily: fontFamilyMono,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create an italic version of a text style
|
||||
static TextStyle toItalic(TextStyle baseStyle) {
|
||||
return baseStyle.copyWith(
|
||||
fontStyle: FontStyle.italic,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a strikethrough version of a text style
|
||||
static TextStyle withStrikethrough(TextStyle baseStyle) {
|
||||
return baseStyle.copyWith(
|
||||
decoration: TextDecoration.lineThrough,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create an underlined version of a text style
|
||||
static TextStyle withUnderline(TextStyle baseStyle) {
|
||||
return baseStyle.copyWith(
|
||||
decoration: TextDecoration.underline,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a text style with multiple modifications
|
||||
static TextStyle merge(
|
||||
TextStyle baseStyle, {
|
||||
Color? color,
|
||||
double? fontSize,
|
||||
FontWeight? fontWeight,
|
||||
double? letterSpacing,
|
||||
double? height,
|
||||
String? fontFamily,
|
||||
FontStyle? fontStyle,
|
||||
TextDecoration? decoration,
|
||||
}) {
|
||||
return baseStyle.copyWith(
|
||||
color: color,
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
letterSpacing: letterSpacing,
|
||||
height: height,
|
||||
fontFamily: fontFamily,
|
||||
fontStyle: fontStyle,
|
||||
decoration: decoration,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user