feat: implement Dynamic Type with Apple text styles

Replace all custom Theme.FontSize values and hardcoded font sizes with
Apple's built-in text styles (.largeTitle, .title2, .headline, .body,
.subheadline, .caption, .caption2) to support accessibility scaling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-11 10:23:16 -06:00
parent 8affa3ce0d
commit 2d48f1411a
16 changed files with 273 additions and 284 deletions

View File

@@ -129,11 +129,11 @@ struct HomeView: View {
VStack(spacing: Theme.Spacing.lg) {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Adventure Awaits")
.font(.system(size: Theme.FontSize.heroTitle, weight: .bold, design: .rounded))
.font(.largeTitle)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text("Plan your ultimate sports road trip. Visit stadiums, catch games, and create unforgettable memories.")
.font(.system(size: Theme.FontSize.body))
.font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme))
.fixedSize(horizontal: false, vertical: true)
}
@@ -174,7 +174,7 @@ struct HomeView: View {
return VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Quick Start")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
VStack(spacing: Theme.Spacing.md) {
@@ -217,7 +217,7 @@ struct HomeView: View {
// Header with refresh button
HStack {
Text("Featured Trips")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer()
@@ -228,7 +228,7 @@ struct HomeView: View {
}
} label: {
Image(systemName: "arrow.clockwise")
.font(.system(size: 14, weight: .medium))
.font(.subheadline)
.foregroundStyle(Theme.warmOrange)
}
}
@@ -241,9 +241,9 @@ struct HomeView: View {
// Region header
HStack(spacing: Theme.Spacing.xs) {
Image(systemName: regionGroup.region.iconName)
.font(.system(size: 12))
.font(.caption)
Text(regionGroup.region.shortName)
.font(.system(size: Theme.FontSize.caption, weight: .semibold))
.font(.subheadline)
}
.foregroundStyle(Theme.textSecondary(colorScheme))
@@ -268,14 +268,14 @@ struct HomeView: View {
// Error state
VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Featured Trips")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
HStack {
Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.orange)
Text(error)
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
Spacer()
@@ -285,7 +285,7 @@ struct HomeView: View {
await suggestedTripsGenerator.generateTrips()
}
}
.font(.system(size: Theme.FontSize.caption, weight: .medium))
.font(.subheadline)
.foregroundStyle(Theme.warmOrange)
}
.padding(Theme.Spacing.md)
@@ -301,7 +301,7 @@ struct HomeView: View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
HStack {
Text("Recent Trips")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer()
Button {
@@ -312,7 +312,7 @@ struct HomeView: View {
Image(systemName: "chevron.right")
.font(.caption)
}
.font(.system(size: Theme.FontSize.caption, weight: .medium))
.font(.subheadline)
.foregroundStyle(Theme.warmOrange)
}
}
@@ -331,7 +331,7 @@ struct HomeView: View {
private var tipsSection: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Planning Tips")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
VStack(spacing: Theme.Spacing.xs) {
@@ -367,12 +367,12 @@ struct QuickSportButton: View {
.frame(width: 48, height: 48)
Image(systemName: sport.iconName)
.font(.system(size: 20))
.font(.title3)
.foregroundStyle(sport.themeColor)
}
Text(sport.rawValue)
.font(.system(size: 10, weight: .medium))
.font(.caption2)
.foregroundStyle(Theme.textSecondary(colorScheme))
}
.frame(maxWidth: .infinity)
@@ -413,11 +413,11 @@ struct SavedTripCard: View {
VStack(alignment: .leading, spacing: 4) {
Text(trip.name)
.font(.system(size: Theme.FontSize.body, weight: .semibold))
.font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text(trip.formattedDateRange)
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
HStack(spacing: Theme.Spacing.sm) {
@@ -432,7 +432,7 @@ struct SavedTripCard: View {
Text("\(trip.totalGames) games")
}
}
.font(.system(size: Theme.FontSize.micro))
.font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme))
}
@@ -468,16 +468,16 @@ struct TipRow: View {
.frame(width: 36, height: 36)
Image(systemName: icon)
.font(.system(size: 14))
.font(.subheadline)
.foregroundStyle(Theme.routeGold)
}
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.system(size: Theme.FontSize.caption, weight: .medium))
.font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text(subtitle)
.font(.system(size: Theme.FontSize.micro))
.font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme))
}
@@ -500,7 +500,7 @@ struct SavedTripsListView: View {
.frame(height: 100)
Image(systemName: "suitcase")
.font(.system(size: 60))
.font(.largeTitle)
.foregroundColor(.secondary)
Text("No Saved Trips")
@@ -558,11 +558,11 @@ struct SavedTripListRow: View {
VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text(trip.name)
.font(.system(size: Theme.FontSize.cardTitle, weight: .semibold))
.font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme))
Text(trip.formattedDateRange)
.font(.system(size: Theme.FontSize.caption))
.font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme))
// Route preview strip

View File

@@ -17,7 +17,7 @@ struct LoadingTripsView: View {
// Header
HStack {
Text("Featured Trips")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded))
.font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme))
Spacer()
}
@@ -27,7 +27,7 @@ struct LoadingTripsView: View {
LoadingDots()
Text(message)
.font(.system(size: Theme.FontSize.body))
.font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme))
.lineLimit(2)
.fixedSize(horizontal: false, vertical: true)

View File

@@ -17,7 +17,7 @@ struct SuggestedTripCard: View {
HStack {
// Region badge
Text(suggestedTrip.region.shortName)
.font(.system(size: Theme.FontSize.micro, weight: .semibold))
.font(.caption)
.foregroundStyle(.white)
.padding(.horizontal, Theme.Spacing.xs)
.padding(.vertical, 4)
@@ -30,7 +30,7 @@ struct SuggestedTripCard: View {
HStack(spacing: 4) {
ForEach(suggestedTrip.displaySports, id: \.self) { sport in
Image(systemName: sport.iconName)
.font(.system(size: 12))
.font(.caption)
.foregroundStyle(sport.themeColor)
}
}
@@ -58,12 +58,12 @@ struct SuggestedTripCard: View {
Image(systemName: "mappin")
}
}
.font(.system(size: 11))
.font(.caption2)
.foregroundStyle(Theme.textSecondary(colorScheme))
// Date range
Text(suggestedTrip.trip.formattedDateRange)
.font(.system(size: Theme.FontSize.micro))
.font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme))
}
.padding(Theme.Spacing.md)
@@ -86,16 +86,16 @@ struct SuggestedTripCard: View {
// Start End display
HStack(spacing: 6) {
Text(startCity)
.font(.system(size: Theme.FontSize.caption, weight: .semibold))
.font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(1)
Image(systemName: "arrow.right")
.font(.system(size: 10, weight: .semibold))
.font(.caption2)
.foregroundStyle(Theme.warmOrange)
Text(endCity)
.font(.system(size: Theme.FontSize.caption, weight: .semibold))
.font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(1)
}