import 'package:flutter/material.dart'; /// Design System centralisé pour Afterwork /// /// Ce fichier contient toutes les constantes de design pour assurer /// une cohérence visuelle à travers toute l'application. /// /// **Sections:** /// - Spacing: Espacements standardisés /// - BorderRadius: Rayons de bordure /// - Shadows: Ombres et élévations /// - Durations: Durées d'animations /// - Curves: Courbes d'animations /// - Sizes: Tailles standardisées class DesignSystem { // ============================================================================ // SPACING // ============================================================================ /// Espacements standardisés /// /// Utiliser ces constantes pour tous les paddings, margins, gaps, etc. /// Cela garantit une cohérence visuelle et facilite les ajustements. static const double spacing2xs = 2.0; static const double spacingXs = 4.0; static const double spacingSm = 8.0; static const double spacingMd = 12.0; static const double spacingLg = 16.0; static const double spacingXl = 24.0; static const double spacing2xl = 32.0; static const double spacing3xl = 48.0; static const double spacing4xl = 64.0; /// Padding horizontal standard des écrans static const double screenPaddingHorizontal = spacingLg; /// Padding vertical standard des écrans static const double screenPaddingVertical = spacingLg; /// Gap entre éléments de liste static const double listItemGap = spacingMd; /// Gap entre sections static const double sectionGap = spacingXl; // ============================================================================ // BORDER RADIUS // ============================================================================ /// Rayons de bordure standardisés static const double radiusXs = 4.0; static const double radiusSm = 8.0; static const double radiusMd = 12.0; static const double radiusLg = 16.0; static const double radiusXl = 20.0; static const double radius2xl = 24.0; static const double radiusRound = 999.0; /// BorderRadius objets pour utilisation directe static final BorderRadius borderRadiusXs = BorderRadius.circular(radiusXs); static final BorderRadius borderRadiusSm = BorderRadius.circular(radiusSm); static final BorderRadius borderRadiusMd = BorderRadius.circular(radiusMd); static final BorderRadius borderRadiusLg = BorderRadius.circular(radiusLg); static final BorderRadius borderRadiusXl = BorderRadius.circular(radiusXl); static final BorderRadius borderRadius2xl = BorderRadius.circular(radius2xl); static final BorderRadius borderRadiusRound = BorderRadius.circular(radiusRound); // ============================================================================ // SHADOWS // ============================================================================ /// Ombres standardisées pour Material Design /// /// Niveaux d'élévation: /// - None: Pas d'ombre /// - Sm: Petite élévation (cartes au repos) /// - Md: Élévation moyenne (cartes survolées) /// - Lg: Grande élévation (dialogs, bottom sheets) /// - Xl: Très grande élévation (navigation drawer) static const List shadowNone = []; static const List shadowSm = [ BoxShadow( color: Color(0x0F000000), // 6% opacity blurRadius: 4, offset: Offset(0, 1), spreadRadius: 0, ), ]; static const List shadowMd = [ BoxShadow( color: Color(0x14000000), // 8% opacity blurRadius: 8, offset: Offset(0, 2), spreadRadius: 0, ), ]; static const List shadowLg = [ BoxShadow( color: Color(0x1F000000), // 12% opacity blurRadius: 16, offset: Offset(0, 4), spreadRadius: 0, ), ]; static const List shadowXl = [ BoxShadow( color: Color(0x29000000), // 16% opacity blurRadius: 24, offset: Offset(0, 8), spreadRadius: 0, ), ]; /// Ombres pour mode sombre (plus subtiles) static const List shadowSmDark = [ BoxShadow( color: Color(0x33000000), // 20% opacity blurRadius: 4, offset: Offset(0, 1), spreadRadius: 0, ), ]; static const List shadowMdDark = [ BoxShadow( color: Color(0x3D000000), // 24% opacity blurRadius: 8, offset: Offset(0, 2), spreadRadius: 0, ), ]; static const List shadowLgDark = [ BoxShadow( color: Color(0x47000000), // 28% opacity blurRadius: 16, offset: Offset(0, 4), spreadRadius: 0, ), ]; // ============================================================================ // DURATIONS (Durées d'animations) // ============================================================================ /// Durées d'animations standardisées /// /// Suivent les Material Design motion guidelines: /// - Fast: Micro-interactions rapides (100-200ms) /// - Medium: Transitions standard (200-300ms) /// - Slow: Animations complexes (300-500ms) static const Duration durationInstant = Duration(milliseconds: 100); static const Duration durationFast = Duration(milliseconds: 200); static const Duration durationMedium = Duration(milliseconds: 300); static const Duration durationSlow = Duration(milliseconds: 400); static const Duration durationSlower = Duration(milliseconds: 500); // ============================================================================ // CURVES (Courbes d'animations) // ============================================================================ /// Courbes d'animations standardisées /// /// Material Design recommande: /// - easeIn: Accélération au début (sortie d'écran) /// - easeOut: Décélération à la fin (entrée d'écran) /// - easeInOut: Accélération puis décélération (transitions) /// - bounce: Effet rebond (micro-interactions fun) static const Curve curveStandard = Curves.easeInOut; static const Curve curveDecelerate = Curves.easeOut; static const Curve curveAccelerate = Curves.easeIn; static const Curve curveSharp = Curves.easeInOutCubic; static const Curve curveBounce = Curves.elasticOut; // ============================================================================ // SIZES (Tailles standardisées) // ============================================================================ /// Tailles d'icônes static const double iconSizeXs = 16.0; static const double iconSizeSm = 20.0; static const double iconSizeMd = 24.0; static const double iconSizeLg = 32.0; static const double iconSizeXl = 48.0; static const double iconSize2xl = 64.0; /// Tailles d'avatars static const double avatarSizeXs = 24.0; static const double avatarSizeSm = 32.0; static const double avatarSizeMd = 40.0; static const double avatarSizeLg = 56.0; static const double avatarSizeXl = 72.0; static const double avatarSize2xl = 96.0; /// Hauteurs de boutons static const double buttonHeightSm = 36.0; static const double buttonHeightMd = 44.0; static const double buttonHeightLg = 52.0; /// Hauteurs de champs de saisie static const double inputHeightSm = 40.0; static const double inputHeightMd = 48.0; static const double inputHeightLg = 56.0; /// Tailles de FAB (Floating Action Button) static const double fabSizeSm = 48.0; static const double fabSizeMd = 56.0; static const double fabSizeLg = 64.0; // ============================================================================ // OPACITIES (Opacités standardisées) // ============================================================================ static const double opacityDisabled = 0.38; static const double opacityInactive = 0.54; static const double opacitySecondary = 0.7; static const double opacityPrimary = 0.87; static const double opacityFull = 1.0; // ============================================================================ // Z-INDEX / ELEVATION // ============================================================================ static const double elevationNone = 0.0; static const double elevationXs = 1.0; static const double elevationSm = 2.0; static const double elevationMd = 4.0; static const double elevationLg = 8.0; static const double elevationXl = 16.0; // ============================================================================ // BREAKPOINTS (pour responsive design) // ============================================================================ static const double breakpointMobile = 600.0; static const double breakpointTablet = 900.0; static const double breakpointDesktop = 1200.0; // ============================================================================ // HELPER METHODS // ============================================================================ /// Retourne les ombres appropriées selon le thème static List getShadow( BuildContext context, ShadowSize size, ) { final isDark = Theme.of(context).brightness == Brightness.dark; switch (size) { case ShadowSize.none: return shadowNone; case ShadowSize.sm: return isDark ? shadowSmDark : shadowSm; case ShadowSize.md: return isDark ? shadowMdDark : shadowMd; case ShadowSize.lg: return isDark ? shadowLgDark : shadowLg; case ShadowSize.xl: return shadowXl; } } /// Retourne un EdgeInsets avec padding uniforme static EdgeInsets paddingAll(double value) => EdgeInsets.all(value); /// Retourne un EdgeInsets avec padding horizontal static EdgeInsets paddingHorizontal(double value) => EdgeInsets.symmetric(horizontal: value); /// Retourne un EdgeInsets avec padding vertical static EdgeInsets paddingVertical(double value) => EdgeInsets.symmetric(vertical: value); /// Retourne un EdgeInsets avec padding screen standard static EdgeInsets get paddingScreen => const EdgeInsets.symmetric( horizontal: screenPaddingHorizontal, vertical: screenPaddingVertical, ); /// Retourne un SizedBox avec hauteur static SizedBox verticalSpace(double height) => SizedBox(height: height); /// Retourne un SizedBox avec largeur static SizedBox horizontalSpace(double width) => SizedBox(width: width); } /// Énumération pour les tailles d'ombres enum ShadowSize { none, sm, md, lg, xl, } /// Extensions pour faciliter l'utilisation du Design System extension DesignSystemExtensions on BuildContext { /// Retourne les ombres selon le thème List shadow(ShadowSize size) => DesignSystem.getShadow(this, size); /// Retourne true si on est en mode sombre bool get isDarkMode => Theme.of(this).brightness == Brightness.dark; /// Retourne la largeur de l'écran double get screenWidth => MediaQuery.of(this).size.width; /// Retourne la hauteur de l'écran double get screenHeight => MediaQuery.of(this).size.height; /// Retourne true si on est sur mobile bool get isMobile => screenWidth < DesignSystem.breakpointMobile; /// Retourne true si on est sur tablette bool get isTablet => screenWidth >= DesignSystem.breakpointMobile && screenWidth < DesignSystem.breakpointTablet; /// Retourne true si on est sur desktop bool get isDesktop => screenWidth >= DesignSystem.breakpointDesktop; }