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

View File

@@ -327,17 +327,6 @@ enum Theme {
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
enum Spacing {

View File

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