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

@@ -223,7 +223,7 @@ struct RoutePreviewStrip: View {
.frame(width: 8, height: 8) .frame(width: 8, height: 8)
Text(abbreviateCity(city)) Text(abbreviateCity(city))
.font(.system(size: 10, weight: .medium)) .font(.caption2)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.lineLimit(1) .lineLimit(1)
} }
@@ -256,7 +256,7 @@ struct PlanningProgressView: View {
// Current step text // Current step text
Text(steps[currentStep]) Text(steps[currentStep])
.font(.system(size: 16, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.animation(.easeInOut, value: currentStep) .animation(.easeInOut, value: currentStep)
} }
@@ -288,9 +288,9 @@ struct StatPill: View {
var body: some View { var body: some View {
HStack(spacing: 6) { HStack(spacing: 6) {
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 12)) .font(.caption)
Text(value) Text(value)
.font(.system(size: 13, weight: .medium)) .font(.footnote)
} }
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.padding(.horizontal, 12) .padding(.horizontal, 12)
@@ -313,16 +313,16 @@ struct EmptyStateView: View {
var body: some View { var body: some View {
VStack(spacing: 20) { VStack(spacing: 20) {
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 48)) .font(.largeTitle)
.foregroundStyle(Theme.warmOrange.opacity(0.7)) .foregroundStyle(Theme.warmOrange.opacity(0.7))
VStack(spacing: 8) { VStack(spacing: 8) {
Text(title) Text(title)
.font(.system(size: 20, weight: .semibold)) .font(.title3)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(message) Text(message)
.font(.system(size: 15)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
@@ -330,7 +330,7 @@ struct EmptyStateView: View {
if let actionTitle = actionTitle, let action = action { if let actionTitle = actionTitle, let action = action {
Button(action: action) { Button(action: action) {
Text(actionTitle) Text(actionTitle)
.font(.system(size: 16, weight: .semibold)) .font(.body)
.foregroundStyle(.white) .foregroundStyle(.white)
.padding(.horizontal, 24) .padding(.horizontal, 24)
.padding(.vertical, 12) .padding(.vertical, 12)
@@ -383,26 +383,26 @@ struct LoadingOverlay: View {
} }
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 24)) .font(.title2)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.opacity(progress != nil ? 1 : 0) .opacity(progress != nil ? 1 : 0)
} }
VStack(spacing: Theme.Spacing.xs) { VStack(spacing: Theme.Spacing.xs) {
Text(message) Text(message)
.font(.system(size: Theme.FontSize.cardTitle, weight: .semibold)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
if let detail = detail { if let detail = detail {
Text(detail) Text(detail)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
if let progress = progress { if let progress = progress {
Text("\(Int(progress * 100))%") Text("\(Int(progress * 100))%")
.font(.system(size: Theme.FontSize.micro, weight: .medium, design: .monospaced)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }

View File

@@ -327,17 +327,6 @@ enum Theme {
colorScheme == .dark ? Color.black.opacity(0.3) : Color.black.opacity(0.08) colorScheme == .dark ? Color.black.opacity(0.3) : Color.black.opacity(0.08)
} }
// MARK: - Typography
enum FontSize {
static let heroTitle: CGFloat = 34
static let sectionTitle: CGFloat = 24
static let cardTitle: CGFloat = 18
static let body: CGFloat = 16
static let caption: CGFloat = 14
static let micro: CGFloat = 12
}
// MARK: - Spacing // MARK: - Spacing
enum Spacing { enum Spacing {

View File

@@ -143,7 +143,7 @@ struct BadgeStyle: ViewModifier {
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.font(.system(size: Theme.FontSize.micro, weight: .semibold)) .font(.caption)
.padding(.horizontal, 10) .padding(.horizontal, 10)
.padding(.vertical, 5) .padding(.vertical, 5)
.background(filled ? color : color.opacity(0.2)) .background(filled ? color : color.opacity(0.2))
@@ -165,7 +165,7 @@ struct SectionHeaderStyle: ViewModifier {
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
} }

View File

@@ -410,7 +410,7 @@ struct ProgressShareView: View {
private var previewCard: some View { private var previewCard: some View {
VStack(spacing: Theme.Spacing.md) { VStack(spacing: Theme.Spacing.md) {
Text("Preview") Text("Preview")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
// Mini preview // Mini preview
@@ -486,7 +486,7 @@ struct ProgressShareView: View {
// Style selector // Style selector
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Style") Text("Style")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
@@ -499,7 +499,7 @@ struct ProgressShareView: View {
// Username toggle // Username toggle
Toggle(isOn: $includeUsername) { Toggle(isOn: $includeUsername) {
Text("Include Username") Text("Include Username")
.font(.system(size: Theme.FontSize.body)) .font(.body)
} }
.padding(.horizontal) .padding(.horizontal)
@@ -512,7 +512,7 @@ struct ProgressShareView: View {
// Map toggle // Map toggle
Toggle(isOn: $includeMap) { Toggle(isOn: $includeMap) {
Text("Include Map") Text("Include Map")
.font(.system(size: Theme.FontSize.body)) .font(.body)
} }
.padding(.horizontal) .padding(.horizontal)
} }
@@ -525,7 +525,7 @@ struct ProgressShareView: View {
withAnimation { cardStyle = style } withAnimation { cardStyle = style }
} label: { } label: {
Text(label) Text(label)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(cardStyle == style ? .white : Theme.textPrimary(colorScheme)) .foregroundStyle(cardStyle == style ? .white : Theme.textPrimary(colorScheme))
.padding(.horizontal, Theme.Spacing.md) .padding(.horizontal, Theme.Spacing.md)
.padding(.vertical, Theme.Spacing.sm) .padding(.vertical, Theme.Spacing.sm)

View File

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

View File

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

View File

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

View File

@@ -65,11 +65,11 @@ struct AchievementsListView: View {
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("\(earned) / \(total)") Text("\(earned) / \(total)")
.font(.system(size: Theme.FontSize.heroTitle, weight: .bold, design: .rounded)) .font(.largeTitle)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("Achievements Earned") Text("Achievements Earned")
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
if earned == total && total > 0 { if earned == total && total > 0 {
@@ -77,7 +77,7 @@ struct AchievementsListView: View {
Image(systemName: "star.fill") Image(systemName: "star.fill")
Text("All achievements unlocked!") Text("All achievements unlocked!")
} }
.font(.system(size: Theme.FontSize.caption, weight: .semibold)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
} }
@@ -190,9 +190,9 @@ struct CategoryFilterButton: View {
Button(action: action) { Button(action: action) {
HStack(spacing: Theme.Spacing.xs) { HStack(spacing: Theme.Spacing.xs) {
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 14)) .font(.subheadline)
Text(title) Text(title)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
} }
.padding(.horizontal, Theme.Spacing.md) .padding(.horizontal, Theme.Spacing.md)
.padding(.vertical, Theme.Spacing.sm) .padding(.vertical, Theme.Spacing.sm)
@@ -233,14 +233,14 @@ struct AchievementCard: View {
.frame(width: 60, height: 60) .frame(width: 60, height: 60)
Image(systemName: "lock.fill") Image(systemName: "lock.fill")
.font(.system(size: 14)) .font(.subheadline)
.foregroundStyle(.white) .foregroundStyle(.white)
} }
} }
// Title // Title
Text(achievement.definition.name) Text(achievement.definition.name)
.font(.system(size: Theme.FontSize.caption, weight: .semibold)) .font(.subheadline)
.foregroundStyle(achievement.isEarned ? Theme.textPrimary(colorScheme) : Theme.textMuted(colorScheme)) .foregroundStyle(achievement.isEarned ? Theme.textPrimary(colorScheme) : Theme.textMuted(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.lineLimit(2) .lineLimit(2)
@@ -250,7 +250,7 @@ struct AchievementCard: View {
if achievement.isEarned { if achievement.isEarned {
if let earnedAt = achievement.earnedAt { if let earnedAt = achievement.earnedAt {
Text(earnedAt.formatted(date: .abbreviated, time: .omitted)) Text(earnedAt.formatted(date: .abbreviated, time: .omitted))
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
} else { } else {
@@ -260,7 +260,7 @@ struct AchievementCard: View {
.progressViewStyle(AchievementProgressStyle()) .progressViewStyle(AchievementProgressStyle())
Text(achievement.progressText) Text(achievement.progressText)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -371,11 +371,11 @@ struct AchievementDetailSheet: View {
// Title and description // Title and description
VStack(spacing: Theme.Spacing.sm) { VStack(spacing: Theme.Spacing.sm) {
Text(achievement.definition.name) Text(achievement.definition.name)
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(achievement.definition.description) Text(achievement.definition.description)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
@@ -384,7 +384,7 @@ struct AchievementDetailSheet: View {
Image(systemName: achievement.definition.category.iconName) Image(systemName: achievement.definition.category.iconName)
Text(achievement.definition.category.displayName) Text(achievement.definition.category.displayName)
} }
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(categoryColor) .foregroundStyle(categoryColor)
.padding(.horizontal, Theme.Spacing.sm) .padding(.horizontal, Theme.Spacing.sm)
.padding(.vertical, Theme.Spacing.xs) .padding(.vertical, Theme.Spacing.xs)
@@ -401,7 +401,7 @@ struct AchievementDetailSheet: View {
.foregroundStyle(.green) .foregroundStyle(.green)
Text("Earned on \(earnedAt.formatted(date: .long, time: .omitted))") Text("Earned on \(earnedAt.formatted(date: .long, time: .omitted))")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
} }
@@ -409,7 +409,7 @@ struct AchievementDetailSheet: View {
// Progress section // Progress section
VStack(spacing: Theme.Spacing.sm) { VStack(spacing: Theme.Spacing.sm) {
Text("Progress") Text("Progress")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
ProgressView(value: achievement.progressPercentage) ProgressView(value: achievement.progressPercentage)
@@ -417,7 +417,7 @@ struct AchievementDetailSheet: View {
.frame(width: 200) .frame(width: 200)
Text("\(achievement.currentProgress) / \(achievement.totalRequired)") Text("\(achievement.currentProgress) / \(achievement.totalRequired)")
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
} }
@@ -428,7 +428,7 @@ struct AchievementDetailSheet: View {
Image(systemName: sport.iconName) Image(systemName: sport.iconName)
Text(sport.displayName) Text(sport.displayName)
} }
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(sport.themeColor) .foregroundStyle(sport.themeColor)
.padding(.horizontal, Theme.Spacing.md) .padding(.horizontal, Theme.Spacing.md)
.padding(.vertical, Theme.Spacing.sm) .padding(.vertical, Theme.Spacing.sm)

View File

@@ -72,24 +72,24 @@ struct GameMatchConfirmationView: View {
.frame(width: 80, height: 80) .frame(width: 80, height: 80)
Image(systemName: "photo.fill") Image(systemName: "photo.fill")
.font(.system(size: 36)) .font(.largeTitle)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
VStack(spacing: Theme.Spacing.xs) { VStack(spacing: Theme.Spacing.xs) {
if let date = candidate.metadata.captureDate { if let date = candidate.metadata.captureDate {
Label(formatDate(date), systemImage: "calendar") Label(formatDate(date), systemImage: "calendar")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
if candidate.metadata.hasValidLocation { if candidate.metadata.hasValidLocation {
Label("Location data available", systemImage: "location.fill") Label("Location data available", systemImage: "location.fill")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} else { } else {
Label("No location data", systemImage: "location.slash") Label("No location data", systemImage: "location.slash")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(.red) .foregroundStyle(.red)
} }
} }
@@ -108,7 +108,7 @@ struct GameMatchConfirmationView: View {
Image(systemName: "mappin.circle.fill") Image(systemName: "mappin.circle.fill")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("Nearest Stadium") Text("Nearest Stadium")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
} }
@@ -116,11 +116,11 @@ struct GameMatchConfirmationView: View {
HStack { HStack {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(match.stadium.name) Text(match.stadium.name)
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold, design: .rounded)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(match.stadium.fullAddress) Text(match.stadium.fullAddress)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -129,11 +129,11 @@ struct GameMatchConfirmationView: View {
// Distance badge // Distance badge
VStack(spacing: 2) { VStack(spacing: 2) {
Text(match.formattedDistance) Text(match.formattedDistance)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(confidenceColor(match.confidence)) .foregroundStyle(confidenceColor(match.confidence))
Text(match.confidence.description) Text(match.confidence.description)
.font(.system(size: 10)) .font(.caption2)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -155,7 +155,7 @@ struct GameMatchConfirmationView: View {
Image(systemName: "sportscourt.fill") Image(systemName: "sportscourt.fill")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text(matchOptionsTitle) Text(matchOptionsTitle)
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
} }
@@ -204,7 +204,7 @@ struct GameMatchConfirmationView: View {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundStyle(.red) .foregroundStyle(.red)
Text(reason.description) Text(reason.description)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
@@ -216,7 +216,7 @@ struct GameMatchConfirmationView: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
HStack { HStack {
Text(match.matchupDescription) Text(match.matchupDescription)
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Image(systemName: match.game.sport.iconName) Image(systemName: match.game.sport.iconName)
@@ -225,7 +225,7 @@ struct GameMatchConfirmationView: View {
} }
Text(match.gameDateTime) Text(match.gameDateTime)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
// Confidence // Confidence
@@ -234,7 +234,7 @@ struct GameMatchConfirmationView: View {
.fill(combinedConfidenceColor(match.confidence.combined)) .fill(combinedConfidenceColor(match.confidence.combined))
.frame(width: 8, height: 8) .frame(width: 8, height: 8)
Text(match.confidence.combined.description) Text(match.confidence.combined.description)
.font(.system(size: 10)) .font(.caption2)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -272,7 +272,7 @@ struct GameMatchConfirmationView: View {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
Text("Confirm & Import") Text("Confirm & Import")
} }
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(.white) .foregroundStyle(.white)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
@@ -287,7 +287,7 @@ struct GameMatchConfirmationView: View {
dismiss() dismiss()
} label: { } label: {
Text("Skip This Photo") Text("Skip This Photo")
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }

View File

@@ -96,11 +96,11 @@ struct PhotoImportView: View {
VStack(spacing: Theme.Spacing.sm) { VStack(spacing: Theme.Spacing.sm) {
Text("Import from Photos") Text("Import from Photos")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("Select photos taken at stadiums to automatically log your visits. We'll use GPS and date data to match them to games.") Text("Select photos taken at stadiums to automatically log your visits. We'll use GPS and date data to match them to games.")
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.padding(.horizontal, Theme.Spacing.xl) .padding(.horizontal, Theme.Spacing.xl)
@@ -114,7 +114,7 @@ struct PhotoImportView: View {
Image(systemName: "photo.stack") Image(systemName: "photo.stack")
Text("Select Photos") Text("Select Photos")
} }
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(.white) .foregroundStyle(.white)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
@@ -137,7 +137,7 @@ struct PhotoImportView: View {
Image(systemName: "info.circle.fill") Image(systemName: "info.circle.fill")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("How it works") Text("How it works")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
} }
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
@@ -147,7 +147,7 @@ struct PhotoImportView: View {
InfoRow(icon: "hand.tap", text: "You confirm or edit the rest") InfoRow(icon: "hand.tap", text: "You confirm or edit the rest")
} }
} }
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
.background(Theme.cardBackground(colorScheme)) .background(Theme.cardBackground(colorScheme))
@@ -164,11 +164,11 @@ struct PhotoImportView: View {
ThemedSpinner(size: 50, lineWidth: 4) ThemedSpinner(size: 50, lineWidth: 4)
Text("Processing photos...") Text("Processing photos...")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
Text("\(viewModel.processedCount) of \(viewModel.totalCount) photos") Text("\(viewModel.processedCount) of \(viewModel.totalCount) photos")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Spacer() Spacer()
@@ -222,7 +222,7 @@ struct PhotoImportView: View {
Image(systemName: "plus.circle") Image(systemName: "plus.circle")
Text("Add More Photos") Text("Add More Photos")
} }
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
.padding(.top, Theme.Spacing.md) .padding(.top, Theme.Spacing.md)
@@ -259,11 +259,11 @@ struct PhotoImportView: View {
private func summaryBadge(count: Int, label: String, color: Color) -> some View { private func summaryBadge(count: Int, label: String, color: Color) -> some View {
VStack(spacing: 4) { VStack(spacing: 4) {
Text("\(count)") Text("\(count)")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(color) .foregroundStyle(color)
Text(label) Text(label)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -283,10 +283,10 @@ struct PhotoImportView: View {
.foregroundStyle(color) .foregroundStyle(color)
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(title) Text(title)
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(subtitle) Text(subtitle)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
Spacer() Spacer()
@@ -372,7 +372,7 @@ struct PhotoImportCandidateCard: View {
.foregroundStyle(isConfirmed ? .green : Theme.textMuted(colorScheme)) .foregroundStyle(isConfirmed ? .green : Theme.textMuted(colorScheme))
} }
} }
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
// Match result // Match result
@@ -407,10 +407,10 @@ struct PhotoImportCandidateCard: View {
HStack { HStack {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text("\(matches.count) possible games") Text("\(matches.count) possible games")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("Tap to select the correct game") Text("Tap to select the correct game")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
Spacer() Spacer()
@@ -424,7 +424,7 @@ struct PhotoImportCandidateCard: View {
Image(systemName: "exclamationmark.triangle") Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.red) .foregroundStyle(.red)
Text(reason.description) Text(reason.description)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
@@ -434,7 +434,7 @@ struct PhotoImportCandidateCard: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
HStack { HStack {
Text(match.matchupDescription) Text(match.matchupDescription)
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Image(systemName: match.game.sport.iconName) Image(systemName: match.game.sport.iconName)
@@ -442,7 +442,7 @@ struct PhotoImportCandidateCard: View {
} }
Text("\(match.stadium.name)\(match.gameDateTime)") Text("\(match.stadium.name)\(match.gameDateTime)")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
// Confidence badge // Confidence badge
@@ -463,7 +463,7 @@ struct PhotoImportCandidateCard: View {
}() }()
return Text(text) return Text(text)
.font(.system(size: 10, weight: .medium)) .font(.caption2)
.foregroundStyle(color) .foregroundStyle(color)
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 2) .padding(.vertical, 2)
@@ -496,7 +496,7 @@ struct GameMatchPickerSheet: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
HStack { HStack {
Text(match.fullMatchupDescription) Text(match.fullMatchupDescription)
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
@@ -506,7 +506,7 @@ struct GameMatchPickerSheet: View {
} }
Text("\(match.stadium.name)\(match.gameDateTime)") Text("\(match.stadium.name)\(match.gameDateTime)")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.padding(.vertical, 4) .padding(.vertical, 4)

View File

@@ -178,21 +178,21 @@ struct ProgressTabView: View {
VStack(spacing: 0) { VStack(spacing: 0) {
Text("\(progress.visitedStadiums)") Text("\(progress.visitedStadiums)")
.font(.system(size: 24, weight: .bold, design: .rounded)) .font(.title3)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("/\(progress.totalStadiums)") Text("/\(progress.totalStadiums)")
.font(.system(size: 12, weight: .medium)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text(viewModel.selectedSport.displayName) Text(viewModel.selectedSport.displayName)
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold, design: .rounded)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("Stadium Quest") Text("Stadium Quest")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
if progress.isComplete { if progress.isComplete {
@@ -200,11 +200,11 @@ struct ProgressTabView: View {
Image(systemName: "checkmark.seal.fill") Image(systemName: "checkmark.seal.fill")
Text("Complete!") Text("Complete!")
} }
.font(.system(size: Theme.FontSize.caption, weight: .semibold)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} else { } else {
Text("\(progress.totalStadiums - progress.visitedStadiums) stadiums remaining") Text("\(progress.totalStadiums - progress.visitedStadiums) stadiums remaining")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -254,7 +254,7 @@ struct ProgressTabView: View {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green) .foregroundStyle(.green)
Text("Visited (\(viewModel.visitedStadiums.count))") Text("Visited (\(viewModel.visitedStadiums.count))")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -280,7 +280,7 @@ struct ProgressTabView: View {
Image(systemName: "circle.dotted") Image(systemName: "circle.dotted")
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text("Not Yet Visited (\(viewModel.unvisitedStadiums.count))") Text("Not Yet Visited (\(viewModel.unvisitedStadiums.count))")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -307,7 +307,7 @@ struct ProgressTabView: View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) { VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
HStack { HStack {
Text("Achievements") Text("Achievements")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
@@ -319,7 +319,7 @@ struct ProgressTabView: View {
Text("View All") Text("View All")
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
} }
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
} }
@@ -341,11 +341,11 @@ struct ProgressTabView: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text("Track Your Progress") Text("Track Your Progress")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("Earn badges for stadium visits") Text("Earn badges for stadium visits")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -371,7 +371,7 @@ struct ProgressTabView: View {
private var recentVisitsSection: some View { private var recentVisitsSection: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) { VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Recent Visits") Text("Recent Visits")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
ForEach(viewModel.recentVisits) { visitSummary in ForEach(viewModel.recentVisits) { visitSummary in
@@ -422,7 +422,7 @@ struct LeagueSelectorButton: View {
} }
Text(sport.rawValue) Text(sport.rawValue)
.font(.system(size: Theme.FontSize.micro, weight: isSelected ? .bold : .medium)) .font(.caption)
.foregroundStyle(isSelected ? Theme.textPrimary(colorScheme) : Theme.textMuted(colorScheme)) .foregroundStyle(isSelected ? Theme.textPrimary(colorScheme) : Theme.textMuted(colorScheme))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -451,14 +451,14 @@ struct ProgressStatPill: View {
VStack(spacing: 4) { VStack(spacing: 4) {
HStack(spacing: 4) { HStack(spacing: 4) {
Image(systemName: icon) Image(systemName: icon)
.font(.system(size: 12)) .font(.caption)
Text(value) Text(value)
.font(.system(size: Theme.FontSize.body, weight: .bold)) .font(.body)
} }
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(label) Text(label)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -483,12 +483,12 @@ struct StadiumChip: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(stadium.name) Text(stadium.name)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(1) .lineLimit(1)
Text(stadium.city) Text(stadium.city)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -524,7 +524,7 @@ struct RecentVisitRow: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(visit.stadium.name) Text(visit.stadium.name)
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
@@ -534,7 +534,7 @@ struct RecentVisitRow: View {
Text(matchup) Text(matchup)
} }
} }
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -545,7 +545,7 @@ struct RecentVisitRow: View {
Image(systemName: "photo") Image(systemName: "photo")
Text("\(visit.photoCount)") Text("\(visit.photoCount)")
} }
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
@@ -585,17 +585,17 @@ struct StadiumDetailSheet: View {
.frame(width: 80, height: 80) .frame(width: 80, height: 80)
Image(systemName: visitStatus.isVisited ? "checkmark.seal.fill" : sport.iconName) Image(systemName: visitStatus.isVisited ? "checkmark.seal.fill" : sport.iconName)
.font(.system(size: 36)) .font(.largeTitle)
.foregroundStyle(visitStatus.isVisited ? .green : sport.themeColor) .foregroundStyle(visitStatus.isVisited ? .green : sport.themeColor)
} }
Text(stadium.name) Text(stadium.name)
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold, design: .rounded)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Text(stadium.fullAddress) Text(stadium.fullAddress)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
if visitStatus.isVisited { if visitStatus.isVisited {
@@ -604,7 +604,7 @@ struct StadiumDetailSheet: View {
.foregroundStyle(.green) .foregroundStyle(.green)
Text("Visited \(visitStatus.visitCount) time\(visitStatus.visitCount == 1 ? "" : "s")") Text("Visited \(visitStatus.visitCount) time\(visitStatus.visitCount == 1 ? "" : "s")")
} }
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(.green) .foregroundStyle(.green)
} }
} }
@@ -613,23 +613,23 @@ struct StadiumDetailSheet: View {
if case .visited(let visits) = visitStatus { if case .visited(let visits) = visitStatus {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) { VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Visit History") Text("Visit History")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
ForEach(visits.sorted(by: { $0.visitDate > $1.visitDate })) { visit in ForEach(visits.sorted(by: { $0.visitDate > $1.visitDate })) { visit in
HStack { HStack {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(visit.shortDateDescription) Text(visit.shortDateDescription)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
if let matchup = visit.matchup { if let matchup = visit.matchup {
Text(matchup) Text(matchup)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
Spacer() Spacer()
Text(visit.visitType.displayName) Text(visit.visitType.displayName)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.padding(Theme.Spacing.sm) .padding(Theme.Spacing.sm)

View File

@@ -156,7 +156,7 @@ struct StadiumVisitSheet: View {
awayTeamFocused = false awayTeamFocused = false
} label: { } label: {
Text(team.name) Text(team.name)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.padding(.horizontal, 10) .padding(.horizontal, 10)
.padding(.vertical, 6) .padding(.vertical, 6)
@@ -192,7 +192,7 @@ struct StadiumVisitSheet: View {
homeTeamFocused = false homeTeamFocused = false
} label: { } label: {
Text(team.name) Text(team.name)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.padding(.horizontal, 10) .padding(.horizontal, 10)
.padding(.vertical, 6) .padding(.vertical, 6)
@@ -409,11 +409,11 @@ struct StadiumPickerSheet: View {
HStack { HStack {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(stadium.name) Text(stadium.name)
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(stadium.fullAddress) Text(stadium.fullAddress)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }

View File

@@ -147,23 +147,23 @@ struct VisitDetailView: View {
.frame(width: 80, height: 80) .frame(width: 80, height: 80)
Image(systemName: visit.sportEnum?.iconName ?? "sportscourt") Image(systemName: visit.sportEnum?.iconName ?? "sportscourt")
.font(.system(size: 36)) .font(.largeTitle)
.foregroundStyle(sportColor) .foregroundStyle(sportColor)
} }
VStack(spacing: Theme.Spacing.xs) { VStack(spacing: Theme.Spacing.xs) {
Text(stadium.name) Text(stadium.name)
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold, design: .rounded)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Text(stadium.fullAddress) Text(stadium.fullAddress)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
// Visit type badge // Visit type badge
Text(visit.visitType.displayName) Text(visit.visitType.displayName)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(.white) .foregroundStyle(.white)
.padding(.horizontal, Theme.Spacing.sm) .padding(.horizontal, Theme.Spacing.sm)
.padding(.vertical, 4) .padding(.vertical, 4)
@@ -189,7 +189,7 @@ struct VisitDetailView: View {
Image(systemName: "sportscourt.fill") Image(systemName: "sportscourt.fill")
.foregroundStyle(sportColor) .foregroundStyle(sportColor)
Text("Game Info") Text("Game Info")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -215,7 +215,7 @@ struct VisitDetailView: View {
} }
} }
} }
.font(.system(size: Theme.FontSize.body)) .font(.body)
.padding(Theme.Spacing.lg) .padding(Theme.Spacing.lg)
.background(Theme.cardBackground(colorScheme)) .background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.large)) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.large))
@@ -233,7 +233,7 @@ struct VisitDetailView: View {
Image(systemName: "info.circle.fill") Image(systemName: "info.circle.fill")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("Details") Text("Details")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -275,7 +275,7 @@ struct VisitDetailView: View {
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
.font(.system(size: Theme.FontSize.body)) .font(.body)
.padding(Theme.Spacing.lg) .padding(Theme.Spacing.lg)
.background(Theme.cardBackground(colorScheme)) .background(Theme.cardBackground(colorScheme))
.clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.large)) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.large))
@@ -293,12 +293,12 @@ struct VisitDetailView: View {
Image(systemName: "note.text") Image(systemName: "note.text")
.foregroundStyle(Theme.routeGold) .foregroundStyle(Theme.routeGold)
Text("Notes") Text("Notes")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
Text(visit.notes ?? "") Text(visit.notes ?? "")
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
@@ -318,7 +318,7 @@ struct VisitDetailView: View {
// Date // Date
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Date") Text("Date")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
DatePicker("", selection: $editVisitDate, displayedComponents: .date) DatePicker("", selection: $editVisitDate, displayedComponents: .date)
@@ -328,7 +328,7 @@ struct VisitDetailView: View {
// Visit Type // Visit Type
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Visit Type") Text("Visit Type")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
Picker("", selection: $editVisitType) { Picker("", selection: $editVisitType) {
@@ -343,7 +343,7 @@ struct VisitDetailView: View {
if editVisitType == .game { if editVisitType == .game {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) { VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text("Game Info") Text("Game Info")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
HStack { HStack {
@@ -374,7 +374,7 @@ struct VisitDetailView: View {
// Seat location // Seat location
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Seat Location") Text("Seat Location")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
TextField("e.g., Section 120, Row 5", text: $editSeatLocation) TextField("e.g., Section 120, Row 5", text: $editSeatLocation)
@@ -384,7 +384,7 @@ struct VisitDetailView: View {
// Notes // Notes
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Notes") Text("Notes")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
TextEditor(text: $editNotes) TextEditor(text: $editNotes)

View File

@@ -144,11 +144,11 @@ struct RegionMapSelector: View {
VStack(alignment: .leading, spacing: 1) { VStack(alignment: .leading, spacing: 1) {
Text(region.shortName) Text(region.shortName)
.font(.system(size: 11, weight: isSelected ? .bold : .medium)) .font(.caption2)
.foregroundStyle(isSelected ? regionColor(region) : Theme.textPrimary(colorScheme)) .foregroundStyle(isSelected ? regionColor(region) : Theme.textPrimary(colorScheme))
Text(states) Text(states)
.font(.system(size: 9)) .font(.caption2)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -159,7 +159,7 @@ struct RegionMapSelector: View {
HStack(spacing: Theme.Spacing.md) { HStack(spacing: Theme.Spacing.md) {
if selectedRegions.isEmpty { if selectedRegions.isEmpty {
Text("Tap map to select regions") Text("Tap map to select regions")
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} else { } else {
Spacer() Spacer()
@@ -168,7 +168,7 @@ struct RegionMapSelector: View {
selectedRegions.removeAll() selectedRegions.removeAll()
} label: { } label: {
Text("Clear") Text("Clear")
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
} }

View File

@@ -187,15 +187,15 @@ struct TripCreationView: View {
private var heroHeader: some View { private var heroHeader: some View {
VStack(spacing: Theme.Spacing.sm) { VStack(spacing: Theme.Spacing.sm) {
Image(systemName: "map.fill") Image(systemName: "map.fill")
.font(.system(size: 40)) .font(.largeTitle)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("Plan Your Adventure") Text("Plan Your Adventure")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("Select your games, set your route, and hit the road") Text("Select your games, set your route, and hit the road")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} }
@@ -214,7 +214,7 @@ struct TripCreationView: View {
.pickerStyle(.segmented) .pickerStyle(.segmented)
Text(viewModel.planningMode.description) Text(viewModel.planningMode.description)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.padding(.top, Theme.Spacing.xs) .padding(.top, Theme.Spacing.xs)
} }
@@ -248,7 +248,7 @@ struct TripCreationView: View {
HStack { HStack {
ThemedSpinnerCompact(size: 14) ThemedSpinnerCompact(size: 14)
Text("Searching...") Text("Searching...")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.padding(.top, Theme.Spacing.xs) .padding(.top, Theme.Spacing.xs)
@@ -281,7 +281,7 @@ struct TripCreationView: View {
HStack { HStack {
ThemedSpinnerCompact(size: 14) ThemedSpinnerCompact(size: 14)
Text("Searching...") Text("Searching...")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.padding(.top, Theme.Spacing.xs) .padding(.top, Theme.Spacing.xs)
@@ -363,16 +363,16 @@ struct TripCreationView: View {
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
Image(systemName: "mappin.circle.fill") Image(systemName: "mappin.circle.fill")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.font(.system(size: 14)) .font(.subheadline)
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(result.name) Text(result.name)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
if !result.address.isEmpty { if !result.address.isEmpty {
Text(result.address) Text(result.address)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -401,7 +401,7 @@ struct TripCreationView: View {
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
ThemedSpinnerCompact(size: 20) ThemedSpinnerCompact(size: 20)
Text("Loading games...") Text("Loading games...")
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.frame(maxWidth: .infinity, alignment: .center) .frame(maxWidth: .infinity, alignment: .center)
@@ -425,10 +425,10 @@ struct TripCreationView: View {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text("Browse Teams & Games") Text("Browse Teams & Games")
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("\(viewModel.availableGames.count) games available") Text("\(viewModel.availableGames.count) games available")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -451,7 +451,7 @@ struct TripCreationView: View {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green) .foregroundStyle(.green)
Text("\(viewModel.mustSeeGameIds.count) game(s) selected") Text("\(viewModel.mustSeeGameIds.count) game(s) selected")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
@@ -460,7 +460,7 @@ struct TripCreationView: View {
viewModel.deselectAllGames() viewModel.deselectAllGames()
} label: { } label: {
Text("Deselect All") Text("Deselect All")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(.red) .foregroundStyle(.red)
} }
} }
@@ -470,18 +470,18 @@ struct TripCreationView: View {
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
SportColorBar(sport: game.game.sport) SportColorBar(sport: game.game.sport)
Text("\(game.awayTeam.abbreviation) @ \(game.homeTeam.abbreviation)") Text("\(game.awayTeam.abbreviation) @ \(game.homeTeam.abbreviation)")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
Text(game.game.formattedDate) Text(game.game.formattedDate)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
if viewModel.selectedGames.count > 3 { if viewModel.selectedGames.count > 3 {
Text("+ \(viewModel.selectedGames.count - 3) more") Text("+ \(viewModel.selectedGames.count - 3) more")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
@@ -550,13 +550,13 @@ struct TripCreationView: View {
} }
Text("Select Games") Text("Select Games")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
Text("\(viewModel.selectedGamesCount) selected") Text("\(viewModel.selectedGamesCount) selected")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
@@ -576,7 +576,7 @@ struct TripCreationView: View {
// Region selector // Region selector
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Regions") Text("Regions")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
RegionMapSelector( RegionMapSelector(
@@ -588,12 +588,12 @@ struct TripCreationView: View {
if viewModel.selectedRegions.isEmpty { if viewModel.selectedRegions.isEmpty {
Text("Select at least one region") Text("Select at least one region")
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.padding(.top, Theme.Spacing.xxs) .padding(.top, Theme.Spacing.xxs)
} else { } else {
Text("Games will be found in selected regions") Text("Games will be found in selected regions")
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
.padding(.top, Theme.Spacing.xxs) .padding(.top, Theme.Spacing.xxs)
} }
@@ -602,7 +602,7 @@ struct TripCreationView: View {
// Route preference // Route preference
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text("Route Preference") Text("Route Preference")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
Picker("Route Preference", selection: $viewModel.routePreference) { Picker("Route Preference", selection: $viewModel.routePreference) {
@@ -622,7 +622,7 @@ struct TripCreationView: View {
if !viewModel.allowRepeatCities { if !viewModel.allowRepeatCities {
Text("Each city will only be visited on one day") Text("Each city will only be visited on one day")
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
.padding(.leading, 32) .padding(.leading, 32)
} }
@@ -640,11 +640,11 @@ struct TripCreationView: View {
Image(systemName: "mappin.circle") Image(systemName: "mappin.circle")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("Must-Stop Locations") Text("Must-Stop Locations")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
Text("\(viewModel.mustStopLocations.count)") Text("\(viewModel.mustStopLocations.count)")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -652,11 +652,11 @@ struct TripCreationView: View {
HStack { HStack {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(location.name) Text(location.name)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
if let address = location.address, !address.isEmpty { if let address = location.address, !address.isEmpty {
Text(address) Text(address)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -681,7 +681,7 @@ struct TripCreationView: View {
Image(systemName: "plus.circle.fill") Image(systemName: "plus.circle.fill")
Text("Add Location") Text("Add Location")
} }
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
} }
@@ -748,7 +748,7 @@ struct TripCreationView: View {
Image(systemName: "exclamationmark.triangle.fill") Image(systemName: "exclamationmark.triangle.fill")
.foregroundStyle(.orange) .foregroundStyle(.orange)
Text(message) Text(message)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
@@ -861,7 +861,7 @@ struct GamePickerSheet: View {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.green) .foregroundStyle(.green)
Text("\(selectedGamesCount) game(s) selected") Text("\(selectedGamesCount) game(s) selected")
.font(.system(size: 15, weight: .semibold)) .font(.subheadline)
Spacer() Spacer()
} }
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
@@ -934,23 +934,23 @@ struct SportSection: View {
} label: { } label: {
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
Image(systemName: sport.iconName) Image(systemName: sport.iconName)
.font(.system(size: 20)) .font(.title3)
.foregroundStyle(sport.themeColor) .foregroundStyle(sport.themeColor)
.frame(width: 32) .frame(width: 32)
Text(sport.rawValue) Text(sport.rawValue)
.font(.system(size: 17, weight: .bold)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("\(teams.flatMap { $0.games }.count) games") Text("\(teams.flatMap { $0.games }.count) games")
.font(.system(size: 13)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Spacer() Spacer()
if selectedCount > 0 { if selectedCount > 0 {
Text("\(selectedCount)") Text("\(selectedCount)")
.font(.system(size: 12, weight: .bold)) .font(.caption)
.foregroundStyle(.white) .foregroundStyle(.white)
.padding(.horizontal, 8) .padding(.horizontal, 8)
.padding(.vertical, 4) .padding(.vertical, 4)
@@ -1035,18 +1035,18 @@ struct TeamSection: View {
} }
Text("\(teamData.team.city) \(teamData.team.name)") Text("\(teamData.team.city) \(teamData.team.name)")
.font(.system(size: 15, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text("\(teamData.games.count)") Text("\(teamData.games.count)")
.font(.system(size: 12)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Spacer() Spacer()
if selectedCount > 0 { if selectedCount > 0 {
Text("\(selectedCount)") Text("\(selectedCount)")
.font(.system(size: 11, weight: .bold)) .font(.caption2)
.foregroundStyle(.white) .foregroundStyle(.white)
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 3) .padding(.vertical, 3)
@@ -1055,7 +1055,7 @@ struct TeamSection: View {
} }
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.system(size: 12, weight: .semibold)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
.rotationEffect(.degrees(isExpanded ? 90 : 0)) .rotationEffect(.degrees(isExpanded ? 90 : 0))
} }
@@ -1072,7 +1072,7 @@ struct TeamSection: View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
// Date header // Date header
Text(dateGroup.date) Text(dateGroup.date)
.font(.system(size: 12, weight: .semibold)) .font(.caption)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.padding(.horizontal, Theme.Spacing.md) .padding(.horizontal, Theme.Spacing.md)
.padding(.top, Theme.Spacing.sm) .padding(.top, Theme.Spacing.sm)
@@ -1116,24 +1116,24 @@ struct GameCalendarRow: View {
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
// Selection indicator // Selection indicator
Image(systemName: isSelected ? "checkmark.circle.fill" : "circle") Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
.font(.system(size: 22)) .font(.title3)
.foregroundStyle(isSelected ? Theme.warmOrange : Theme.textMuted(colorScheme)) .foregroundStyle(isSelected ? Theme.warmOrange : Theme.textMuted(colorScheme))
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text("vs \(game.awayTeam.name)") Text("vs \(game.awayTeam.name)")
.font(.system(size: 14, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
HStack(spacing: Theme.Spacing.xs) { HStack(spacing: Theme.Spacing.xs) {
Text(game.game.gameTime) Text(game.game.gameTime)
.font(.system(size: 12)) .font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
Text("") Text("")
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text(game.stadium.name) Text(game.stadium.name)
.font(.system(size: 12)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
.lineLimit(1) .lineLimit(1)
} }
@@ -1424,11 +1424,11 @@ struct TripOptionsView: View {
// Hero header // Hero header
VStack(spacing: 8) { VStack(spacing: 8) {
Image(systemName: "point.topright.arrow.triangle.backward.to.point.bottomleft.scurvepath.fill") Image(systemName: "point.topright.arrow.triangle.backward.to.point.bottomleft.scurvepath.fill")
.font(.system(size: 40)) .font(.largeTitle)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("\(filteredAndSortedOptions.count) of \(options.count) Routes") Text("\(filteredAndSortedOptions.count) of \(options.count) Routes")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
.padding(.top, Theme.Spacing.lg) .padding(.top, Theme.Spacing.lg)
@@ -1484,11 +1484,11 @@ struct TripOptionsView: View {
} label: { } label: {
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: sortOption.icon) Image(systemName: sortOption.icon)
.font(.system(size: 14)) .font(.subheadline)
Text(sortOption.rawValue) Text(sortOption.rawValue)
.font(.system(size: 14, weight: .medium)) .font(.subheadline)
Image(systemName: "chevron.down") Image(systemName: "chevron.down")
.font(.system(size: 12)) .font(.caption)
} }
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.padding(.horizontal, 16) .padding(.horizontal, 16)
@@ -1535,11 +1535,11 @@ struct TripOptionsView: View {
} label: { } label: {
HStack(spacing: 6) { HStack(spacing: 6) {
Image(systemName: paceFilter.icon) Image(systemName: paceFilter.icon)
.font(.system(size: 12)) .font(.caption)
Text(paceFilter.rawValue) Text(paceFilter.rawValue)
.font(.system(size: 13, weight: .medium)) .font(.subheadline)
Image(systemName: "chevron.down") Image(systemName: "chevron.down")
.font(.system(size: 10)) .font(.caption2)
} }
.foregroundStyle(paceFilter == .all ? Theme.textPrimary(colorScheme) : Theme.warmOrange) .foregroundStyle(paceFilter == .all ? Theme.textPrimary(colorScheme) : Theme.warmOrange)
.padding(.horizontal, 12) .padding(.horizontal, 12)
@@ -1556,7 +1556,7 @@ struct TripOptionsView: View {
private var citiesPicker: some View { private var citiesPicker: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Label("Max Cities", systemImage: "mappin.circle") Label("Max Cities", systemImage: "mappin.circle")
.font(.system(size: 13, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
ScrollView(.horizontal, showsIndicators: false) { ScrollView(.horizontal, showsIndicators: false) {
@@ -1593,7 +1593,7 @@ struct TripOptionsView: View {
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text("No routes match your filters") Text("No routes match your filters")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
Button { Button {
@@ -1603,7 +1603,7 @@ struct TripOptionsView: View {
} }
} label: { } label: {
Text("Reset Filters") Text("Reset Filters")
.font(.system(size: 14, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
} }
@@ -1657,19 +1657,19 @@ struct TripOptionCard: View {
// Vertical route display // Vertical route display
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
Text(uniqueCities.first ?? "") Text(uniqueCities.first ?? "")
.font(.system(size: 15, weight: .semibold)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
VStack(spacing: 0) { VStack(spacing: 0) {
Text("|") Text("|")
.font(.system(size: 10)) .font(.caption2)
Image(systemName: "chevron.down") Image(systemName: "chevron.down")
.font(.system(size: 8, weight: .bold)) .font(.caption2)
} }
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text(uniqueCities.last ?? "") Text(uniqueCities.last ?? "")
.font(.system(size: 15, weight: .semibold)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -1680,7 +1680,7 @@ struct TripOptionCard: View {
Label("\(Int(option.totalDistanceMiles)) mi", systemImage: "car") Label("\(Int(option.totalDistanceMiles)) mi", systemImage: "car")
} }
} }
.font(.system(size: 12)) .font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
// Bottom row: sports with game counts // Bottom row: sports with game counts
@@ -1688,9 +1688,9 @@ struct TripOptionCard: View {
ForEach(gamesPerSport, id: \.sport) { item in ForEach(gamesPerSport, id: \.sport) { item in
HStack(spacing: 3) { HStack(spacing: 3) {
Image(systemName: item.sport.iconName) Image(systemName: item.sport.iconName)
.font(.system(size: 9)) .font(.caption2)
Text("\(item.sport.rawValue.uppercased()) \(item.count)") Text("\(item.sport.rawValue.uppercased()) \(item.count)")
.font(.system(size: 9, weight: .semibold)) .font(.caption2)
} }
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 3) .padding(.vertical, 3)
@@ -1711,7 +1711,7 @@ struct TripOptionCard: View {
HStack(spacing: 4) { HStack(spacing: 4) {
ThemedSpinnerCompact(size: 12) ThemedSpinnerCompact(size: 12)
Text("Generating...") Text("Generating...")
.font(.system(size: 11)) .font(.caption2)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -1777,7 +1777,7 @@ struct ThemedSection<Content: View>: View {
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) { VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text(title) Text(title)
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
VStack(alignment: .leading, spacing: Theme.Spacing.md) { VStack(alignment: .leading, spacing: Theme.Spacing.md) {
@@ -1804,7 +1804,7 @@ struct ThemedTextField: View {
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.xs) { VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
Text(label) Text(label)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
@@ -1813,7 +1813,7 @@ struct ThemedTextField: View {
.frame(width: 24) .frame(width: 24)
TextField(placeholder, text: $text) TextField(placeholder, text: $text)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
.padding(Theme.Spacing.md) .padding(Theme.Spacing.md)
@@ -1836,7 +1836,7 @@ struct ThemedToggle: View {
.frame(width: 24) .frame(width: 24)
Text(label) Text(label)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
@@ -1859,7 +1859,7 @@ struct ThemedStepper: View {
var body: some View { var body: some View {
HStack { HStack {
Text(label) Text(label)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
@@ -1877,7 +1877,7 @@ struct ThemedStepper: View {
.disabled(value <= range.lowerBound) .disabled(value <= range.lowerBound)
Text("\(value)") Text("\(value)")
.font(.system(size: Theme.FontSize.body, weight: .bold)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.frame(minWidth: 30) .frame(minWidth: 30)
@@ -1907,7 +1907,7 @@ struct ThemedDatePicker: View {
Image(systemName: "calendar") Image(systemName: "calendar")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text(label) Text(label)
.font(.system(size: Theme.FontSize.body)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -2004,26 +2004,26 @@ struct DateRangePicker: View {
// Start date // Start date
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text("START") Text("START")
.font(.system(size: 10, weight: .semibold)) .font(.caption2)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text(startDate.formatted(.dateTime.month(.abbreviated).day().year())) Text(startDate.formatted(.dateTime.month(.abbreviated).day().year()))
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
// Arrow // Arrow
Image(systemName: "arrow.right") Image(systemName: "arrow.right")
.font(.system(size: 14, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
// End date // End date
VStack(alignment: .trailing, spacing: 4) { VStack(alignment: .trailing, spacing: 4) {
Text("END") Text("END")
.font(.system(size: 10, weight: .semibold)) .font(.caption2)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text(endDate.formatted(.dateTime.month(.abbreviated).day().year())) Text(endDate.formatted(.dateTime.month(.abbreviated).day().year()))
.font(.system(size: Theme.FontSize.body, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
.frame(maxWidth: .infinity, alignment: .trailing) .frame(maxWidth: .infinity, alignment: .trailing)
@@ -2041,7 +2041,7 @@ struct DateRangePicker: View {
} }
} label: { } label: {
Image(systemName: "chevron.left") Image(systemName: "chevron.left")
.font(.system(size: 16, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.frame(width: 36, height: 36) .frame(width: 36, height: 36)
.background(Theme.warmOrange.opacity(0.15)) .background(Theme.warmOrange.opacity(0.15))
@@ -2051,7 +2051,7 @@ struct DateRangePicker: View {
Spacer() Spacer()
Text(monthYearString) Text(monthYearString)
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold, design: .rounded)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
@@ -2062,7 +2062,7 @@ struct DateRangePicker: View {
} }
} label: { } label: {
Image(systemName: "chevron.right") Image(systemName: "chevron.right")
.font(.system(size: 16, weight: .semibold)) .font(.body)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.frame(width: 36, height: 36) .frame(width: 36, height: 36)
.background(Theme.warmOrange.opacity(0.15)) .background(Theme.warmOrange.opacity(0.15))
@@ -2075,7 +2075,7 @@ struct DateRangePicker: View {
HStack(spacing: 0) { HStack(spacing: 0) {
ForEach(Array(daysOfWeek.enumerated()), id: \.offset) { _, day in ForEach(Array(daysOfWeek.enumerated()), id: \.offset) { _, day in
Text(day) Text(day)
.font(.system(size: 12, weight: .semibold)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
@@ -2109,7 +2109,7 @@ struct DateRangePicker: View {
Image(systemName: "calendar.badge.clock") Image(systemName: "calendar.badge.clock")
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
Text("\(tripDuration) day\(tripDuration == 1 ? "" : "s")") Text("\(tripDuration) day\(tripDuration == 1 ? "" : "s")")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
.frame(maxWidth: .infinity, alignment: .center) .frame(maxWidth: .infinity, alignment: .center)
@@ -2247,7 +2247,7 @@ struct SportSelectionChip: View {
} }
Image(systemName: sport.iconName) Image(systemName: sport.iconName)
.font(.system(size: 20)) .font(.title3)
.foregroundStyle(isSelected ? .white : sport.themeColor) .foregroundStyle(isSelected ? .white : sport.themeColor)
} }

View File

@@ -124,23 +124,23 @@ struct TripDetailView: View {
.animation(.easeInOut(duration: 0.3), value: exportProgress?.percentComplete) .animation(.easeInOut(duration: 0.3), value: exportProgress?.percentComplete)
Image(systemName: "doc.fill") Image(systemName: "doc.fill")
.font(.system(size: 24)) .font(.title2)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
VStack(spacing: Theme.Spacing.xs) { VStack(spacing: Theme.Spacing.xs) {
Text("Creating PDF") Text("Creating PDF")
.font(.system(size: Theme.FontSize.cardTitle, weight: .semibold)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(exportProgress?.currentStep ?? "Preparing...") Text(exportProgress?.currentStep ?? "Preparing...")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
if let progress = exportProgress { if let progress = exportProgress {
Text("\(Int(progress.percentComplete * 100))%") Text("\(Int(progress.percentComplete * 100))%")
.font(.system(size: Theme.FontSize.micro, weight: .medium, design: .monospaced)) .font(.caption.monospaced())
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -177,7 +177,7 @@ struct TripDetailView: View {
toggleSaved() toggleSaved()
} label: { } label: {
Image(systemName: isSaved ? "heart.fill" : "heart") Image(systemName: isSaved ? "heart.fill" : "heart")
.font(.system(size: 22, weight: .medium)) .font(.title3)
.foregroundStyle(isSaved ? .red : .white) .foregroundStyle(isSaved ? .red : .white)
.padding(12) .padding(12)
.background(.ultraThinMaterial) .background(.ultraThinMaterial)
@@ -214,7 +214,7 @@ struct TripDetailView: View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) { VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
// Date range // Date range
Text(trip.formattedDateRange) Text(trip.formattedDateRange)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
// Route preview // Route preview
@@ -226,9 +226,9 @@ struct TripDetailView: View {
ForEach(Array(trip.uniqueSports), id: \.self) { sport in ForEach(Array(trip.uniqueSports), id: \.self) { sport in
HStack(spacing: 4) { HStack(spacing: 4) {
Image(systemName: sport.iconName) Image(systemName: sport.iconName)
.font(.system(size: 10)) .font(.caption2)
Text(sport.rawValue) Text(sport.rawValue)
.font(.system(size: 11, weight: .medium)) .font(.caption2)
} }
.padding(.horizontal, 10) .padding(.horizontal, 10)
.padding(.vertical, 5) .padding(.vertical, 5)
@@ -261,11 +261,11 @@ struct TripDetailView: View {
VStack(spacing: Theme.Spacing.md) { VStack(spacing: Theme.Spacing.md) {
HStack { HStack {
Text("Trip Score") Text("Trip Score")
.font(.system(size: Theme.FontSize.cardTitle, weight: .semibold)) .font(.headline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
Text(score.scoreGrade) Text(score.scoreGrade)
.font(.system(size: 32, weight: .bold, design: .rounded)) .font(.largeTitle)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
.glowEffect(color: Theme.warmOrange, radius: 8) .glowEffect(color: Theme.warmOrange, radius: 8)
} }
@@ -283,10 +283,10 @@ struct TripDetailView: View {
private func scoreItem(label: String, value: Double, color: Color) -> some View { private func scoreItem(label: String, value: Double, color: Color) -> some View {
VStack(spacing: 4) { VStack(spacing: 4) {
Text(String(format: "%.0f", value)) Text(String(format: "%.0f", value))
.font(.system(size: Theme.FontSize.cardTitle, weight: .bold)) .font(.headline)
.foregroundStyle(color) .foregroundStyle(color)
Text(label) Text(label)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
} }
@@ -296,7 +296,7 @@ struct TripDetailView: View {
private var itinerarySection: some View { private var itinerarySection: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.md) { VStack(alignment: .leading, spacing: Theme.Spacing.md) {
Text("Itinerary") Text("Itinerary")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
ForEach(Array(itinerarySections.enumerated()), id: \.offset) { index, section in ForEach(Array(itinerarySections.enumerated()), id: \.offset) { index, section in
@@ -604,11 +604,11 @@ struct DaySection: View {
HStack { HStack {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text("Day \(dayNumber)") Text("Day \(dayNumber)")
.font(.system(size: Theme.FontSize.sectionTitle, weight: .bold, design: .rounded)) .font(.title2)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(formattedDate) Text(formattedDate)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -626,7 +626,7 @@ struct DaySection: View {
// City label // City label
if let city = gameCity { if let city = gameCity {
Label(city, systemImage: "mappin") Label(city, systemImage: "mappin")
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -656,20 +656,20 @@ struct GameRow: View {
// Sport icon and name // Sport icon and name
HStack(spacing: 3) { HStack(spacing: 3) {
Image(systemName: game.game.sport.iconName) Image(systemName: game.game.sport.iconName)
.font(.system(size: 10)) .font(.caption2)
Text(game.game.sport.rawValue) Text(game.game.sport.rawValue)
.font(.system(size: 10, weight: .medium)) .font(.caption2)
} }
.foregroundStyle(game.game.sport.themeColor) .foregroundStyle(game.game.sport.themeColor)
// Matchup // Matchup
HStack(spacing: 4) { HStack(spacing: 4) {
Text(game.awayTeam.abbreviation) Text(game.awayTeam.abbreviation)
.font(.system(size: Theme.FontSize.body, weight: .bold)) .font(.body)
Text("@") Text("@")
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text(game.homeTeam.abbreviation) Text(game.homeTeam.abbreviation)
.font(.system(size: Theme.FontSize.body, weight: .bold)) .font(.body)
} }
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -677,9 +677,9 @@ struct GameRow: View {
// Stadium // Stadium
HStack(spacing: 4) { HStack(spacing: 4) {
Image(systemName: "building.2") Image(systemName: "building.2")
.font(.system(size: 10)) .font(.caption2)
Text(game.stadium.name) Text(game.stadium.name)
.font(.system(size: Theme.FontSize.caption)) .font(.subheadline)
} }
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -688,7 +688,7 @@ struct GameRow: View {
// Time // Time
Text(game.game.gameTime) Text(game.game.gameTime)
.font(.system(size: Theme.FontSize.caption, weight: .semibold)) .font(.subheadline)
.foregroundStyle(Theme.warmOrange) .foregroundStyle(Theme.warmOrange)
} }
.padding(Theme.Spacing.sm) .padding(Theme.Spacing.sm)
@@ -731,11 +731,11 @@ struct TravelSection: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text("Travel") Text("Travel")
.font(.system(size: Theme.FontSize.micro, weight: .semibold)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text("\(segment.fromLocation.name)\(segment.toLocation.name)") Text("\(segment.fromLocation.name)\(segment.toLocation.name)")
.font(.system(size: Theme.FontSize.body, weight: .medium)) .font(.body)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
} }
@@ -743,10 +743,10 @@ struct TravelSection: View {
VStack(alignment: .trailing, spacing: 2) { VStack(alignment: .trailing, spacing: 2) {
Text(segment.formattedDistance) Text(segment.formattedDistance)
.font(.system(size: Theme.FontSize.caption, weight: .semibold)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Text(segment.formattedDuration) Text(segment.formattedDuration)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
@@ -765,16 +765,16 @@ struct TravelSection: View {
HStack(spacing: Theme.Spacing.sm) { HStack(spacing: Theme.Spacing.sm) {
Image(systemName: "bolt.fill") Image(systemName: "bolt.fill")
.foregroundStyle(.green) .foregroundStyle(.green)
.font(.system(size: 12)) .font(.caption)
Text("\(segment.evChargingStops.count) EV Charger\(segment.evChargingStops.count > 1 ? "s" : "") Along Route") Text("\(segment.evChargingStops.count) EV Charger\(segment.evChargingStops.count > 1 ? "s" : "") Along Route")
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
Spacer() Spacer()
Image(systemName: showEVChargers ? "chevron.up" : "chevron.down") Image(systemName: showEVChargers ? "chevron.up" : "chevron.down")
.font(.system(size: 12, weight: .semibold)) .font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
} }
.padding(.horizontal, Theme.Spacing.md) .padding(.horizontal, Theme.Spacing.md)
@@ -834,7 +834,7 @@ struct EVChargerRow: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
HStack(spacing: Theme.Spacing.xs) { HStack(spacing: Theme.Spacing.xs) {
Text(charger.name) Text(charger.name)
.font(.system(size: Theme.FontSize.caption, weight: .medium)) .font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme)) .foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(1) .lineLimit(1)
@@ -844,7 +844,7 @@ struct EVChargerRow: View {
HStack(spacing: Theme.Spacing.xs) { HStack(spacing: Theme.Spacing.xs) {
if let address = charger.location.address { if let address = charger.location.address {
Text(address) Text(address)
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
@@ -852,7 +852,7 @@ struct EVChargerRow: View {
.foregroundStyle(Theme.textMuted(colorScheme)) .foregroundStyle(Theme.textMuted(colorScheme))
Text("~\(charger.formattedChargeTime) charge") Text("~\(charger.formattedChargeTime) charge")
.font(.system(size: Theme.FontSize.micro)) .font(.caption)
.foregroundStyle(Theme.textSecondary(colorScheme)) .foregroundStyle(Theme.textSecondary(colorScheme))
} }
} }
@@ -866,7 +866,7 @@ struct EVChargerRow: View {
private var chargerTypeBadge: some View { private var chargerTypeBadge: some View {
let (text, color) = chargerTypeInfo let (text, color) = chargerTypeInfo
Text(text) Text(text)
.font(.system(size: 9, weight: .semibold)) .font(.caption2)
.foregroundStyle(color) .foregroundStyle(color)
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 2) .padding(.vertical, 2)