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