ionic-planb-logistic-app-fl.../lib/theme/README.md
Mathias Beaulieu-Duncan edb106a7fd Refactor theme system and remove unused platforms
- Overhaul theme system with Svrnty design and WCAG AAA compliance
- Remove android, macos, and web platform files (iOS-only focus)
- Update components with improved dark mode map and UI refinements
- Enhance settings page with additional configuration options
- Add theme system documentation in lib/theme/README.md
- Update CLAUDE.md with comprehensive theme guidelines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 14:47:51 -05:00

321 lines
9.2 KiB
Markdown

# Svrnty Theme System - Quick Reference
## Standard Color Access Pattern
**ALWAYS use:**
```dart
final colorScheme = Theme.of(context).colorScheme;
// Primary UI
colorScheme.primary // Primary brand color (Crimson Red)
colorScheme.onPrimary // Text on primary (white/black depending on theme)
// Secondary UI
colorScheme.secondary // Secondary brand color (Slate Blue)
colorScheme.onSecondary // Text on secondary
// Text
colorScheme.onSurface // Primary text
colorScheme.onSurfaceVariant // Secondary text
// Backgrounds
colorScheme.surface // Page background
colorScheme.surfaceContainer // Card background
// Status (specialized)
StatusColorScheme.getStatusColor(status)
StatusColorScheme.getStatusColorFromTheme(status, colorScheme) // Theme-aware (preferred)
```
**NEVER use:**
```dart
Colors.white // FORBIDDEN - use colorScheme.onPrimary or onSurface
Colors.black // FORBIDDEN - use colorScheme.onSurface or scrim
Color(0xFFXXXXXX) // FORBIDDEN in components (except in theme files)
SvrntyColors.crimsonRed // FORBIDDEN - use colorScheme.primary instead
```
## Theme Variants
The app provides **2 theme variants**:
### Light Theme
- **Background:** White (#FCFCFC)
- **Primary:** Crimson Red (#C91F37) - high contrast variant
- **Secondary:** Dark Slate (#2D3843) - high contrast variant
- **Text:** Very dark gray (#1A1C1E) - 16.5:1 contrast (WCAG AAA)
- **Secondary Text:** Dark gray (#3E4A56) - 7:1 contrast (WCAG AAA)
### Dark Theme (Forest Green)
- **Background:** Dark Forest Green (#0C1410) - unique branding
- **Primary:** Bright Crimson (#FF5A6D) - optimized for dark backgrounds
- **Secondary:** Light Slate Gray (#A5B6C8)
- **Text:** Pure white (#FFFFFF) - 18.2:1 contrast (WCAG AAA)
- **Secondary Text:** Light gray-green (#E0E8E4) - 14.1:1 contrast (WCAG AAA)
All text colors are WCAG AAA compliant (minimum 7:1 contrast for normal text, 4.5:1 for large text).
## Color Access Examples
### Good Examples
```dart
// Text on colored background (e.g., status badge, avatar)
Container(
color: Theme.of(context).colorScheme.primary,
child: Text(
'Label',
style: TextStyle(color: Theme.of(context).colorScheme.onPrimary),
),
)
// Primary text on page background
Text(
'Hello',
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
)
// Secondary/muted text
Text(
'Description',
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
)
// Shadow color
BoxShadow(
color: Theme.of(context).colorScheme.scrim.withValues(alpha: 0.2),
)
```
### Bad Examples (DON'T DO THIS)
```dart
// WRONG - hardcoded white
Text('Label', style: TextStyle(color: Colors.white))
// WRONG - hardcoded black
BoxShadow(color: Colors.black.withValues(alpha: 0.2))
// WRONG - hardcoded color value
Container(color: Color(0xFFFF9800))
// WRONG - using SvrntyColors directly for UI elements
Container(color: SvrntyColors.crimsonRed) // Use colorScheme.primary instead
```
## Status Colors
For delivery status indicators, use the `StatusColorScheme` utility:
```dart
import '../theme/status_colors.dart';
// Get status color (hardcoded, consistent across themes)
final color = StatusColorScheme.getStatusColor('completed');
// Get status color from theme (preferred - adapts to theme)
final themeColor = StatusColorScheme.getStatusColorFromTheme(
'completed',
Theme.of(context).colorScheme,
);
// Get background and text colors
final bgColor = StatusColorScheme.getStatusBackground('completed');
final textColor = StatusColorScheme.getStatusText('completed');
// Use pre-built widgets
StatusBadgeWidget(status: 'completed')
StatusAccentBar(status: 'in_transit')
```
**Supported Status Values:**
- `pending` - Amber (attention needed)
- `in_transit`, `in_progress`, `processing` - Slate blue (active)
- `completed`, `delivered`, `done` - Green (success)
- `failed`, `error` - Red (problem)
- `cancelled`, `skipped`, `rejected` - Gray (inactive)
- `on_hold`, `paused`, `waiting` - Slate (informational)
## Progress Gradient Colors
For progress indicators (e.g., route completion):
```dart
import '../theme/color_system.dart';
// Progress colors (0-100%)
SvrntyColors.progressLow // Orange - 0-40%
SvrntyColors.progressMedium // Amber - 40-70%
SvrntyColors.progressHigh // Green - 70-100%
// Example: color interpolation
Color progressColor = Color.lerp(
SvrntyColors.progressLow,
SvrntyColors.progressMedium,
progressPercent,
)!;
```
## Modifying Colors
### Changing Brand Colors
Edit the ColorScheme definitions in `/lib/theme.dart`:
```dart
// Light theme
static ColorScheme lightScheme() {
return const ColorScheme(
brightness: Brightness.light,
primary: Color(0xffC91F37), // Change this for new primary color
secondary: Color(0xff2D3843), // Change this for new secondary color
// ... rest of colors
);
}
// Dark theme
static ColorScheme darkScheme() {
return const ColorScheme(
brightness: Brightness.dark,
primary: Color(0xffFF5A6D), // Change this for new primary color
secondary: Color(0xffA5B6C8), // Change this for new secondary color
// ... rest of colors
);
}
```
### Adding New Semantic Colors
Add to `/lib/theme/color_system.dart`:
```dart
class SvrntyColors {
// ... existing colors
/// New semantic color
static const Color myNewColor = Color(0xFFXXXXXX);
}
```
Then use it in components:
```dart
Container(color: SvrntyColors.myNewColor)
```
### Changing Status Colors
Edit `/lib/theme/status_colors.dart`:
```dart
class StatusColorScheme {
static const Color completed = Color(0xFF22C55E); // Change this
static const Color completedBackground = Color(0xFFD1FAE5); // Change this
static const Color completedText = Color(0xFF065F46); // Change this
// ... rest of colors
}
```
## Text Theme
The app uses **Montserrat** font family for all text with explicit color assignments.
**Font Weights:**
- 300 (Light) - Unused in current design
- 400 (Regular) - Body text
- 500 (Medium) - Labels, buttons
- 600 (SemiBold) - Headings, titles
- 700 (Bold) - Display text, emphasis
**Text Styles:**
```dart
Theme.of(context).textTheme.displayLarge // 57px, bold, onSurface
Theme.of(context).textTheme.headlineMedium // 28px, semibold, onSurface
Theme.of(context).textTheme.titleLarge // 22px, semibold, onSurface
Theme.of(context).textTheme.bodyMedium // 14px, regular, onSurface
Theme.of(context).textTheme.labelSmall // 11px, medium, onSurfaceVariant
```
All text styles automatically adapt to light/dark themes with proper contrast.
## Accessibility
All color combinations meet **WCAG AAA** standards (7:1 contrast for normal text, 4.5:1 for large text):
**Light Theme:**
- Primary text on background: 16.5:1 (WCAG AAA)
- Secondary text on background: 7:1 (WCAG AAA)
- Text on primary color: 6.2:1 (WCAG AA Large)
**Dark Theme:**
- Primary text on background: 18.2:1 (WCAG AAA)
- Secondary text on background: 14.1:1 (WCAG AAA)
- Text on primary color: 11.8:1 (WCAG AAA)
## Component Themes
Component-specific theme configurations are in `/lib/theme/component_themes.dart`:
- CardTheme - Elevated cards with subtle shadows
- AppBarTheme - Navigation bars
- ButtonTheme - Filled, outlined, elevated buttons
- InputDecorationTheme - Text fields
- SnackBarTheme - Toast messages
- DialogTheme - Modal dialogs
- BottomNavigationBarTheme - Bottom navigation
- ChipTheme - Status chips
- ProgressIndicatorTheme - Loading indicators
- FloatingActionButtonTheme - FAB
- SliderTheme - Range inputs
All component themes use `ColorScheme` properties for consistency.
## Migration Guide
If you need to migrate old hardcoded colors to the new theme system:
### Step 1: Find Hardcoded Colors
```bash
# Search for hardcoded colors in your components
grep -r "Colors\.white\|Colors\.black\|Color(0x" lib/components/ lib/pages/
```
### Step 2: Replace with Theme Colors
| Old Pattern | New Pattern |
|------------|-------------|
| `Colors.white` on colored bg | `colorScheme.onPrimary` |
| `Colors.white` on page | `colorScheme.surface` |
| `Colors.black` for text | `colorScheme.onSurface` |
| `Colors.black` for shadow | `colorScheme.scrim` |
| `Color(0xFFXXXXXX)` | Use `colorScheme` or `SvrntyColors` |
### Step 3: Test Both Themes
- Run app in light mode, verify all text is visible
- Run app in dark mode, verify all text is visible
- Check color contrast with browser dev tools
## Troubleshooting
**Text not visible in dark mode:**
- Ensure you're using `colorScheme.onSurface` or `onSurfaceVariant` for text colors
- Don't use hardcoded `Colors.black` or dark colors for text
- Check that TextTheme is properly applied with `_buildTextTheme()`
**Colors not updating when switching themes:**
- Use `Theme.of(context).colorScheme` instead of `SvrntyColors` constants
- Ensure widget rebuilds when theme changes (use `ConsumerWidget` for Riverpod)
- Avoid caching ColorScheme outside of build method
**Wrong colors in components:**
- Verify component uses `colorScheme` parameter correctly
- Check that custom theme is applied in MaterialApp
- Use `theme()` method to generate ThemeData
## Resources
- **Material Design 3:** https://m3.material.io/
- **WCAG Contrast Checker:** https://webaim.org/resources/contrastchecker/
- **Flutter Theme Guide:** https://docs.flutter.dev/cookbook/design/themes
- **ColorScheme Docs:** https://api.flutter.dev/flutter/material/ColorScheme-class.html