From 8affa3ce0da5ad507764f8316b686f372350a88b Mon Sep 17 00:00:00 2001 From: Trey t Date: Sun, 11 Jan 2026 10:04:13 -0600 Subject: [PATCH] docs: add Dynamic Type implementation design Replace all custom font sizes with Apple's built-in text styles for accessibility compliance. Remove Theme.FontSize enum entirely. Export files keep fixed sizes for consistent PDF output. Co-Authored-By: Claude Opus 4.5 --- docs/plans/2026-01-11-dynamic-type-design.md | 206 +++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 docs/plans/2026-01-11-dynamic-type-design.md diff --git a/docs/plans/2026-01-11-dynamic-type-design.md b/docs/plans/2026-01-11-dynamic-type-design.md new file mode 100644 index 0000000..f96b357 --- /dev/null +++ b/docs/plans/2026-01-11-dynamic-type-design.md @@ -0,0 +1,206 @@ +# Dynamic Type Implementation Design + +## Overview + +Implement Dynamic Type app-wide by replacing all custom font sizes with Apple's built-in text styles. This ensures accessibility compliance and automatic scaling based on user preferences. + +## Scope + +**What changes:** +- Remove `Theme.FontSize` enum entirely +- Replace all `.font(.system(size:))` with Apple text styles +- Update 20 UI files + +**What stays fixed:** +- PDF export files (ProgressCardGenerator, PDFGenerator, MapSnapshotService) +- These need predictable dimensions for consistent output + +## Text Style Mapping + +### Apple Text Styles Reference + +| Style | Default Size | Use Case | +|-------|--------------|----------| +| `.largeTitle` | 34pt | Screen titles, hero text | +| `.title` | 28pt | Primary headings | +| `.title2` | 22pt | Section headers | +| `.title3` | 20pt | Subsection headers | +| `.headline` | 17pt semibold | Card titles, emphasis | +| `.body` | 17pt | Primary content | +| `.callout` | 16pt | Secondary content | +| `.subheadline` | 15pt | Supporting text | +| `.footnote` | 13pt | Tertiary info | +| `.caption` | 12pt | Labels, metadata | +| `.caption2` | 11pt | Fine print | + +### Current → Apple Mapping + +| Current Usage | Current Size | Apple Style | +|---------------|--------------|-------------| +| `Theme.FontSize.heroTitle` | 34 | `.largeTitle` | +| `Theme.FontSize.sectionTitle` | 24 | `.title2` | +| `Theme.FontSize.cardTitle` | 18 | `.headline` | +| `Theme.FontSize.body` | 16 | `.body` | +| `Theme.FontSize.caption` | 14 | `.subheadline` | +| `Theme.FontSize.micro` | 12 | `.caption` | + +## Files to Modify + +### UI Files (Dynamic Type) + +``` +SportsTime/Core/Theme/Theme.swift # Remove FontSize enum +SportsTime/Core/Theme/ViewModifiers.swift # Update BadgeStyle, SectionHeaderStyle +SportsTime/Core/Theme/AnimatedComponents.swift # Update component fonts +SportsTime/Features/Home/Views/HomeView.swift +SportsTime/Features/Home/Views/SuggestedTripCard.swift +SportsTime/Features/Home/Views/LoadingTripsView.swift +SportsTime/Features/Trip/Views/TripCreationView.swift +SportsTime/Features/Trip/Views/TripDetailView.swift +SportsTime/Features/Trip/Views/RegionMapSelector.swift +SportsTime/Features/Trip/Views/TimelineItemView.swift +SportsTime/Features/Schedule/Views/ScheduleListView.swift +SportsTime/Features/Settings/Views/SettingsView.swift +SportsTime/Features/Progress/Views/ProgressTabView.swift +SportsTime/Features/Progress/Views/ProgressMapView.swift +SportsTime/Features/Progress/Views/VisitDetailView.swift +SportsTime/Features/Progress/Views/StadiumVisitSheet.swift +SportsTime/Features/Progress/Views/AchievementsListView.swift +SportsTime/Features/Progress/Views/GameMatchConfirmationView.swift +SportsTime/Features/Progress/Views/PhotoImportView.swift +SportsTime/SportsTimeApp.swift +``` + +### Export Files (Keep Fixed) + +``` +SportsTime/Export/PDFGenerator.swift +SportsTime/Export/Services/ProgressCardGenerator.swift +SportsTime/Export/Services/MapSnapshotService.swift +``` + +## Replacement Patterns + +### Before → After Examples + +```swift +// Hero titles +// Before: +.font(.system(size: Theme.FontSize.heroTitle, weight: .bold)) +// After: +.font(.largeTitle) + +// Section headers +// Before: +.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) +// After: +.font(.title2) + +// Card titles +// Before: +.font(.system(size: Theme.FontSize.cardTitle, weight: .semibold)) +// After: +.font(.headline) + +// Body text +// Before: +.font(.system(size: Theme.FontSize.body)) +// After: +.font(.body) + +// Captions +// Before: +.font(.system(size: Theme.FontSize.caption)) +// After: +.font(.subheadline) + +// Micro/labels +// Before: +.font(.system(size: Theme.FontSize.micro, weight: .medium)) +// After: +.font(.caption) +``` + +### ViewModifiers.swift Updates + +```swift +// BadgeStyle +// Before: +.font(.system(size: Theme.FontSize.micro, weight: .semibold)) +// After: +.font(.caption) + +// SectionHeaderStyle +// Before: +.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) +// After: +.font(.title2) +``` + +### Decision Rule for Ambiguous Cases + +When a hardcoded size doesn't map cleanly: +- Primary content → `.body` +- Secondary/supporting → `.subheadline` +- Labels/metadata → `.caption` +- Emphasis within body → `.headline` + +## Implementation Plan + +### Order + +1. **Theme.swift** — Remove `FontSize` enum +2. **ViewModifiers.swift** — Update `BadgeStyle` and `SectionHeaderStyle` +3. **AnimatedComponents.swift** — Update component fonts +4. **Feature views** — Update all 16 view files +5. **SportsTimeApp.swift** — Update any root-level fonts +6. **Build & fix** — Compiler catches remaining `Theme.FontSize` references + +## Testing Strategy + +### Test Dynamic Type in Simulator + +Settings → Accessibility → Display & Text Size → Larger Text + +Or via Xcode scheme arguments: + +``` +-UIPreferredContentSizeCategoryName UICTContentSizeCategoryAccessibilityExtraExtraExtraLarge +``` + +### Test Cases + +| Size Category | What to Check | +|---------------|---------------| +| Default | App looks normal, similar to before | +| Large | Text scales up, layouts don't break | +| Accessibility XXL | Text very large, no truncation/overlap | +| Extra Small | Text scales down, still readable | + +### Key Screens to Test + +- Home (hero title, trip cards) +- Trip Creation (form labels, buttons) +- Trip Detail (timeline, game info) +- Schedule (list items, headers) +- Progress (stats, achievements) +- Settings (all rows) + +### Potential Layout Issues + +Watch for: +- Text truncation in fixed-width containers +- Overlapping elements at large sizes +- Buttons too small to tap at large sizes + +Fix with: +- `.lineLimit(nil)` for multi-line text +- `.minimumScaleFactor(0.8)` for tight spaces +- `ScrollView` for content that might overflow + +## Future Development Guidelines + +After this migration: +- **Always use Apple text styles** (`.body`, `.headline`, `.caption`, etc.) +- **Never use `.system(size:)`** in UI code (exception: Export files) +- **Test with Dynamic Type** enabled before merging UI changes