From 76dda638ccfe13dfa8b1415d7abeb4473bf4f9db Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 27 Jan 2026 09:50:42 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- .../Views/Components/EmptyStateCardView.swift | 13 +++--- .../Views/Components/SectionHeaderView.swift | 8 +--- .../Insights/Components/InsightCardView.swift | 18 ++------ .../Components/InsightDetailSheet.swift | 8 ++-- .../Onboarding/FirstCheckInStepView.swift | 4 +- .../Onboarding/GoalSelectionStepView.swift | 13 +++--- .../Onboarding/TimeSelectionStepView.swift | 19 ++++----- .../Views/Onboarding/WelcomeStepView.swift | 11 ++--- .../Views/Onboarding/WhatsNextStepView.swift | 9 ++-- .../Rituals/Components/RitualCardView.swift | 11 +++-- .../App/Views/Rituals/RitualDetailView.swift | 11 ++--- Andromida/App/Views/Rituals/RitualsView.swift | 18 ++++---- .../Rituals/Sheets/ArcRenewalSheet.swift | 42 +++++++++---------- .../Rituals/Sheets/PresetLibrarySheet.swift | 8 ++-- .../Components/RitualFocusCardView.swift | 19 +++------ .../Components/TodayEmptyStateView.swift | 19 ++++----- .../Today/Components/TodayHabitRowView.swift | 18 ++++---- .../Today/Components/TodayHeaderView.swift | 9 +--- .../TodayNoRitualsForTimeView.swift | 22 ++++------ .../Components/TodayRitualSectionView.swift | 3 +- 20 files changed, 107 insertions(+), 176 deletions(-) diff --git a/Andromida/App/Views/Components/EmptyStateCardView.swift b/Andromida/App/Views/Components/EmptyStateCardView.swift index 3b7684a..899c42e 100644 --- a/Andromida/App/Views/Components/EmptyStateCardView.swift +++ b/Andromida/App/Views/Components/EmptyStateCardView.swift @@ -21,16 +21,17 @@ struct EmptyStateCardView: View { var body: some View { VStack(alignment: .leading, spacing: Design.Spacing.medium) { - Text(title) - .font(.title3) - .foregroundStyle(AppTextColors.primary) - .bold() + TitleLabel(title, style: .displaySmall, color: AppTextColors.primary) + + // Exception: Uses .bodyLarge which isn't a standard BodyLabel weight Text(message) - .font(.body) + .font(Design.Typography.bodyLarge) .foregroundStyle(AppTextColors.secondary) + Button(action: action) { + // Exception: Needs .frame() modifiers Text(actionTitle) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) .frame(maxWidth: .infinity) .frame(height: AppMetrics.Size.buttonHeight) diff --git a/Andromida/App/Views/Components/SectionHeaderView.swift b/Andromida/App/Views/Components/SectionHeaderView.swift index adf6aab..ce3dc2a 100644 --- a/Andromida/App/Views/Components/SectionHeaderView.swift +++ b/Andromida/App/Views/Components/SectionHeaderView.swift @@ -12,13 +12,9 @@ struct SectionHeaderView: View { var body: some View { VStack(alignment: .leading, spacing: Design.Spacing.xxxSmall) { - Text(title) - .font(.headline) - .foregroundStyle(AppTextColors.primary) + TitleLabel(title, style: .headline, color: AppTextColors.primary) if let subtitle { - Text(subtitle) - .font(.subheadline) - .foregroundStyle(AppTextColors.secondary) + BodyLabel(subtitle, emphasis: .secondary, color: AppTextColors.secondary) } } .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Andromida/App/Views/Insights/Components/InsightCardView.swift b/Andromida/App/Views/Insights/Components/InsightCardView.swift index a8823d4..771eb3d 100644 --- a/Andromida/App/Views/Insights/Components/InsightCardView.swift +++ b/Andromida/App/Views/Insights/Components/InsightCardView.swift @@ -22,31 +22,21 @@ struct InsightCardView: View { private var cardContent: some View { VStack(alignment: .leading, spacing: Design.Spacing.medium) { HStack { - Text(card.title) - .font(.subheadline) - .bold() - .foregroundStyle(AppTextColors.secondary) + BodyLabel(card.title, weight: .bold, color: AppTextColors.secondary) Spacer() // Subtle tap affordance - Image(systemName: "chevron.right") - .font(.caption2) - .foregroundStyle(AppTextColors.tertiary) + SymbolIcon.chevron(color: AppTextColors.tertiary) .accessibilityHidden(true) } // Show value prominently - Text(card.value) - .font(.title) - .foregroundStyle(AppTextColors.primary) - .bold() + TitleLabel(card.value, style: .displayMedium, color: AppTextColors.primary) // Show caption if present (non-chart cards) if !card.caption.isEmpty { - Text(card.caption) - .font(.caption) - .foregroundStyle(AppTextColors.secondary) + CaptionLabel(card.caption, color: AppTextColors.secondary) } // Show full-width mini bar chart at bottom (Athlytic style) diff --git a/Andromida/App/Views/Insights/Components/InsightDetailSheet.swift b/Andromida/App/Views/Insights/Components/InsightDetailSheet.swift index 5020116..8a28fdc 100644 --- a/Andromida/App/Views/Insights/Components/InsightDetailSheet.swift +++ b/Andromida/App/Views/Insights/Components/InsightDetailSheet.swift @@ -81,17 +81,15 @@ struct InsightDetailSheet: View { private var headerSection: some View { VStack(spacing: Design.Spacing.medium) { - Image(systemName: card.symbolName) - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppAccent.primary) + SymbolIcon(card.symbolName, size: .hero, color: AppAccent.primary) .accessibilityHidden(true) Text(card.value) - .font(.system(size: Design.IconSize.hero, weight: .bold)) + .font(.system(size: Design.SymbolSize.hero, weight: .bold)) .foregroundStyle(AppTextColors.primary) Text(card.caption) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) } .frame(maxWidth: .infinity) diff --git a/Andromida/App/Views/Onboarding/FirstCheckInStepView.swift b/Andromida/App/Views/Onboarding/FirstCheckInStepView.swift index 0b4f234..f4df4b0 100644 --- a/Andromida/App/Views/Onboarding/FirstCheckInStepView.swift +++ b/Andromida/App/Views/Onboarding/FirstCheckInStepView.swift @@ -146,9 +146,7 @@ struct FirstCheckInStepView: View { Spacer() // Success icon - Image(systemName: "checkmark.circle.fill") - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppStatus.success) + SymbolIcon("checkmark.circle.fill", size: .hero, color: AppStatus.success) .scaleEffect(showCelebration ? 1 : 0.5) .opacity(showCelebration ? 1 : 0) diff --git a/Andromida/App/Views/Onboarding/GoalSelectionStepView.swift b/Andromida/App/Views/Onboarding/GoalSelectionStepView.swift index f4418fa..1b1130e 100644 --- a/Andromida/App/Views/Onboarding/GoalSelectionStepView.swift +++ b/Andromida/App/Views/Onboarding/GoalSelectionStepView.swift @@ -21,8 +21,7 @@ struct GoalSelectionStepView: View { // Header VStack(spacing: Design.Spacing.small) { Text(String(localized: "What would you like to focus on?")) - .font(.title2) - .fontWeight(.bold) + .font(Design.Typography.displaySmall) .foregroundStyle(AppTextColors.primary) .multilineTextAlignment(.center) } @@ -56,7 +55,7 @@ struct GoalSelectionStepView: View { if !selectedGoals.isEmpty { Button(action: onContinue) { Text(String(localized: "Continue")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.inverse) .frame(maxWidth: .infinity) .frame(height: AppMetrics.Size.buttonHeight) @@ -95,18 +94,16 @@ private struct GoalCardView: View { Button(action: onTap) { VStack(spacing: Design.Spacing.medium) { // Icon - Image(systemName: goal.symbolName) - .font(.system(size: Design.IconSize.xxLarge)) - .foregroundStyle(isSelected ? AppAccent.primary : AppTextColors.secondary) + SymbolIcon(goal.symbolName, size: .card, color: isSelected ? AppAccent.primary : AppTextColors.secondary) // Text VStack(spacing: Design.Spacing.xSmall) { Text(goal.displayName) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) Text(goal.subtitle) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) .lineLimit(2) diff --git a/Andromida/App/Views/Onboarding/TimeSelectionStepView.swift b/Andromida/App/Views/Onboarding/TimeSelectionStepView.swift index e50cb55..6877745 100644 --- a/Andromida/App/Views/Onboarding/TimeSelectionStepView.swift +++ b/Andromida/App/Views/Onboarding/TimeSelectionStepView.swift @@ -16,8 +16,7 @@ struct TimeSelectionStepView: View { // Header VStack(spacing: Design.Spacing.small) { Text(String(localized: "When do you want to build habits?")) - .font(.title2) - .fontWeight(.bold) + .font(Design.Typography.displaySmall) .foregroundStyle(AppTextColors.primary) .multilineTextAlignment(.center) } @@ -51,7 +50,7 @@ struct TimeSelectionStepView: View { if selectedTime != nil { Button(action: onContinue) { Text(String(localized: "Continue")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.inverse) .frame(maxWidth: .infinity) .frame(height: AppMetrics.Size.buttonHeight) @@ -82,19 +81,17 @@ private struct TimeCardView: View { Button(action: onTap) { HStack(spacing: Design.Spacing.medium) { // Icon - Image(systemName: time.symbolName) - .font(.system(size: Design.IconSize.xLarge)) - .foregroundStyle(isSelected ? AppAccent.primary : AppTextColors.secondary) - .frame(width: 44) + SymbolIcon(time.symbolName, size: .rowContainer, color: isSelected ? AppAccent.primary : AppTextColors.secondary) + .frame(width: Design.Size.actionRowMinHeight) // Text VStack(alignment: .leading, spacing: Design.Spacing.xSmall) { Text(time.displayName) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) Text(time.subtitle) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) } @@ -102,9 +99,7 @@ private struct TimeCardView: View { // Selection indicator if isSelected { - Image(systemName: "checkmark.circle.fill") - .font(.title2) - .foregroundStyle(AppAccent.primary) + SymbolIcon("checkmark.circle.fill", size: .rowContainer, color: AppAccent.primary) } } .padding(Design.Spacing.large) diff --git a/Andromida/App/Views/Onboarding/WelcomeStepView.swift b/Andromida/App/Views/Onboarding/WelcomeStepView.swift index 2090581..4f07a09 100644 --- a/Andromida/App/Views/Onboarding/WelcomeStepView.swift +++ b/Andromida/App/Views/Onboarding/WelcomeStepView.swift @@ -21,13 +21,12 @@ struct WelcomeStepView: View { VStack(spacing: Design.Spacing.medium) { Text(String(localized: "Welcome to Rituals")) - .font(.largeTitle) - .fontWeight(.bold) + .font(Design.Typography.displayLarge) .foregroundStyle(AppTextColors.primary) .multilineTextAlignment(.center) Text(String(localized: "Build lasting habits through focused, time-bound journeys")) - .font(.title3) + .font(Design.Typography.bodyLarge) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) .padding(.horizontal, Design.Spacing.xxLarge) @@ -40,7 +39,7 @@ struct WelcomeStepView: View { // Get Started button Button(action: onContinue) { Text(String(localized: "Get Started")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.inverse) .frame(maxWidth: .infinity) .frame(height: AppMetrics.Size.buttonHeight) @@ -105,9 +104,7 @@ struct WelcomeStepView: View { ) // Center icon - Image(systemName: "sparkles") - .font(.system(size: Design.IconSize.xxLarge)) - .foregroundStyle(AppAccent.primary) + SymbolIcon("sparkles", size: .card, color: AppAccent.primary) .scaleEffect(animateRings ? 1.1 : 1.0) .animation( .easeInOut(duration: 1.5).repeatForever(autoreverses: true), diff --git a/Andromida/App/Views/Onboarding/WhatsNextStepView.swift b/Andromida/App/Views/Onboarding/WhatsNextStepView.swift index 4adcec8..4101774 100644 --- a/Andromida/App/Views/Onboarding/WhatsNextStepView.swift +++ b/Andromida/App/Views/Onboarding/WhatsNextStepView.swift @@ -13,17 +13,14 @@ struct WhatsNextStepView: View { // Header VStack(spacing: Design.Spacing.medium) { - Image(systemName: "checkmark.circle.fill") - .font(.system(size: Design.IconSize.display)) - .foregroundStyle(AppStatus.success) + SymbolIcon("checkmark.circle.fill", size: .section, color: AppStatus.success) Text(String(localized: "You're all set!")) - .font(.largeTitle) - .fontWeight(.bold) + .font(Design.Typography.displayLarge) .foregroundStyle(AppTextColors.primary) Text(String(localized: "Here's how to get the most from Rituals")) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) } diff --git a/Andromida/App/Views/Rituals/Components/RitualCardView.swift b/Andromida/App/Views/Rituals/Components/RitualCardView.swift index f347446..b8d44fe 100644 --- a/Andromida/App/Views/Rituals/Components/RitualCardView.swift +++ b/Andromida/App/Views/Rituals/Components/RitualCardView.swift @@ -32,20 +32,19 @@ struct RitualCardView: View { VStack(alignment: .leading, spacing: Design.Spacing.medium) { HStack(spacing: Design.Spacing.small) { // Icon - Image(systemName: iconName) - .foregroundStyle(hasActiveArc ? AppAccent.primary : AppTextColors.tertiary) + SymbolIcon(iconName, size: .row, color: hasActiveArc ? AppAccent.primary : AppTextColors.tertiary) .accessibilityHidden(true) // Title Text(title) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(hasActiveArc ? AppTextColors.primary : AppTextColors.tertiary) Spacer(minLength: Design.Spacing.medium) // Day label Text(dayLabel) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.secondary) .padding(.horizontal, Design.Spacing.small) .padding(.vertical, Design.Spacing.xxxSmall) @@ -55,11 +54,11 @@ struct RitualCardView: View { } Text(theme) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(hasActiveArc ? AppTextColors.secondary : AppTextColors.tertiary) Text(completionSummary) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.secondary) } .padding(Design.Spacing.large) diff --git a/Andromida/App/Views/Rituals/RitualDetailView.swift b/Andromida/App/Views/Rituals/RitualDetailView.swift index 084d54c..a740b32 100644 --- a/Andromida/App/Views/Rituals/RitualDetailView.swift +++ b/Andromida/App/Views/Rituals/RitualDetailView.swift @@ -199,20 +199,17 @@ struct RitualDetailView: View { private var headerSection: some View { HStack(spacing: Design.Spacing.medium) { - Image(systemName: ritual.iconName) - .font(.system(size: Design.IconSize.xLarge)) - .foregroundStyle(ritual.hasActiveArc ? AppAccent.primary : AppTextColors.secondary) - .frame(width: 56, height: 56) + SymbolIcon(ritual.iconName, size: .rowContainer, color: ritual.hasActiveArc ? AppAccent.primary : AppTextColors.secondary) + .frame(width: Design.Size.iconContainerLarge, height: Design.Size.iconContainerLarge) .background((ritual.hasActiveArc ? AppAccent.primary : AppTextColors.secondary).opacity(0.1)) .clipShape(.rect(cornerRadius: Design.CornerRadius.large)) VStack(alignment: .leading, spacing: Design.Spacing.xSmall) { Text(ritual.title) - .font(.title2) + .font(Design.Typography.displaySmall) .foregroundStyle(AppTextColors.primary) - .bold() Text(ritual.theme) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) } diff --git a/Andromida/App/Views/Rituals/RitualsView.swift b/Andromida/App/Views/Rituals/RitualsView.swift index 152a683..21e6e45 100644 --- a/Andromida/App/Views/Rituals/RitualsView.swift +++ b/Andromida/App/Views/Rituals/RitualsView.swift @@ -180,16 +180,14 @@ struct RitualsView: View { private var currentEmptyState: some View { VStack(spacing: Design.Spacing.large) { - Image(systemName: "sparkles") - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppAccent.primary) + SymbolIcon("sparkles", size: .hero, color: AppAccent.primary) Text(String(localized: "No Active Rituals")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) Text(String(localized: "Create a custom ritual or browse our preset library to get started.")) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) @@ -212,7 +210,7 @@ struct RitualsView: View { if !store.pastRituals.isEmpty { Text(String(localized: "Or restart a past ritual from the Past tab.")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) .padding(.top, Design.Spacing.small) } @@ -223,16 +221,14 @@ struct RitualsView: View { private var pastEmptyState: some View { VStack(spacing: Design.Spacing.large) { - Image(systemName: "clock.arrow.circlepath") - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppTextColors.tertiary) + SymbolIcon("clock.arrow.circlepath", size: .hero, color: AppTextColors.tertiary) Text(String(localized: "No Past Rituals")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) Text(String(localized: "Rituals that have ended will appear here. You can restart them anytime.")) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) } diff --git a/Andromida/App/Views/Rituals/Sheets/ArcRenewalSheet.swift b/Andromida/App/Views/Rituals/Sheets/ArcRenewalSheet.swift index 8c5890a..d15dbdd 100644 --- a/Andromida/App/Views/Rituals/Sheets/ArcRenewalSheet.swift +++ b/Andromida/App/Views/Rituals/Sheets/ArcRenewalSheet.swift @@ -63,17 +63,15 @@ struct ArcRenewalSheet: View { private var celebrationHeader: some View { VStack(spacing: Design.Spacing.medium) { - Image(systemName: "checkmark.seal.fill") - .font(.system(size: Design.IconSize.display)) - .foregroundStyle(AppStatus.success) + SymbolIcon("checkmark.seal.fill", size: .section, color: AppStatus.success) Text(ritual.title) - .font(.title2.bold()) + .font(Design.Typography.displaySmall) .foregroundStyle(AppTextColors.primary) if let arc = completedArc { Text(String(localized: "Arc \(arc.arcNumber) Complete")) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) } } @@ -84,26 +82,24 @@ struct ArcRenewalSheet: View { private var summaryCard: some View { VStack(alignment: .leading, spacing: Design.Spacing.medium) { Text(String(localized: "Your Journey")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) HStack { - Image(systemName: "chart.line.uptrend.xyaxis") - .foregroundStyle(AppAccent.primary) + SymbolIcon("chart.line.uptrend.xyaxis", size: .row, color: AppAccent.primary) Text(arcSummary) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) } - .font(.subheadline) if let arc = completedArc { let habitCount = (arc.habits ?? []).count HStack { - Image(systemName: "checkmark.circle.fill") - .foregroundStyle(AppAccent.primary) + SymbolIcon("checkmark.circle.fill", size: .row, color: AppAccent.primary) Text(String(localized: "\(habitCount) habits tracked")) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) } - .font(.subheadline) } } .padding(Design.Spacing.large) @@ -115,13 +111,13 @@ struct ArcRenewalSheet: View { private var durationSection: some View { VStack(alignment: .leading, spacing: Design.Spacing.medium) { Text(String(localized: "Next Arc Duration")) - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) VStack(spacing: Design.Spacing.small) { HStack { Text(String(localized: "\(Int(durationDays)) days")) - .font(.title3.bold()) + .font(Design.Typography.displaySmall) .foregroundStyle(AppAccent.primary) Spacer() } @@ -131,11 +127,11 @@ struct ArcRenewalSheet: View { HStack { Text(String(localized: "1 week")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) Spacer() Text(String(localized: "1 year")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) } } @@ -147,7 +143,7 @@ struct ArcRenewalSheet: View { durationDays = Double(days) } label: { Text("\(days)") - .font(.caption.bold()) + .font(Design.Typography.captionBold) .foregroundStyle(Int(durationDays) == days ? AppTextColors.primary : AppTextColors.secondary) .padding(.horizontal, Design.Spacing.small) .padding(.vertical, Design.Spacing.xSmall) @@ -171,10 +167,10 @@ struct ArcRenewalSheet: View { dismiss() } label: { HStack { - Image(systemName: "arrow.clockwise") + SymbolIcon("arrow.clockwise", size: .row, color: AppTextColors.primary) Text(String(localized: "Continue with Same Habits")) } - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppTextColors.primary) .frame(maxWidth: .infinity) .padding(Design.Spacing.medium) @@ -189,10 +185,10 @@ struct ArcRenewalSheet: View { showingEditSheet = true } label: { HStack { - Image(systemName: "pencil") + SymbolIcon("pencil", size: .row, color: AppAccent.primary) Text(String(localized: "Continue with Changes")) } - .font(.headline) + .font(Design.Typography.headline) .foregroundStyle(AppAccent.primary) .frame(maxWidth: .infinity) .padding(Design.Spacing.medium) @@ -211,10 +207,10 @@ struct ArcRenewalSheet: View { dismiss() } label: { HStack { - Image(systemName: "checkmark.circle") + SymbolIcon("checkmark.circle", size: .row, color: AppTextColors.secondary) Text(String(localized: "End This Ritual")) } - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) .frame(maxWidth: .infinity) .padding(Design.Spacing.medium) diff --git a/Andromida/App/Views/Rituals/Sheets/PresetLibrarySheet.swift b/Andromida/App/Views/Rituals/Sheets/PresetLibrarySheet.swift index 673d126..0f95fd7 100644 --- a/Andromida/App/Views/Rituals/Sheets/PresetLibrarySheet.swift +++ b/Andromida/App/Views/Rituals/Sheets/PresetLibrarySheet.swift @@ -200,19 +200,17 @@ struct PresetDetailSheet: View { private var headerSection: some View { VStack(spacing: Design.Spacing.medium) { - Image(systemName: preset.iconName) - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppAccent.primary) + SymbolIcon(preset.iconName, size: .hero, color: AppAccent.primary) Text(preset.theme) - .font(.title3) + .font(Design.Typography.bodyLarge) .foregroundStyle(AppTextColors.secondary) HStack(spacing: Design.Spacing.large) { Label(preset.timeOfDay.displayName, systemImage: preset.timeOfDay.symbolName) Label(String(localized: "\(preset.durationDays) days"), systemImage: "calendar") } - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) } .frame(maxWidth: .infinity) diff --git a/Andromida/App/Views/Today/Components/RitualFocusCardView.swift b/Andromida/App/Views/Today/Components/RitualFocusCardView.swift index 6dd329c..d298734 100644 --- a/Andromida/App/Views/Today/Components/RitualFocusCardView.swift +++ b/Andromida/App/Views/Today/Components/RitualFocusCardView.swift @@ -29,20 +29,17 @@ struct RitualFocusCardView: View { VStack(alignment: .leading, spacing: Design.Spacing.medium) { HStack(spacing: Design.Spacing.small) { // Icon - Image(systemName: iconName) - .foregroundStyle(AppAccent.primary) + SymbolIcon(iconName, size: .row, color: AppAccent.primary) .accessibilityHidden(true) // Title - Text(title) - .font(.headline) - .foregroundStyle(AppTextColors.primary) + TitleLabel(title, style: .headline, color: AppTextColors.primary) Spacer(minLength: Design.Spacing.medium) - // Day label + // Day label - needs additional modifiers (padding, background) Text(dayLabel) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.secondary) .padding(.horizontal, Design.Spacing.small) .padding(.vertical, Design.Spacing.xxxSmall) @@ -51,16 +48,12 @@ struct RitualFocusCardView: View { .accessibilityLabel(Text(dayLabel)) } - Text(theme) - .font(.subheadline) - .foregroundStyle(AppTextColors.secondary) + BodyLabel(theme, color: AppTextColors.secondary) VStack(alignment: .leading, spacing: Design.Spacing.xSmall) { ProgressView(value: progress) .tint(AppAccent.primary) - Text(completionSummary) - .font(.caption) - .foregroundStyle(AppTextColors.secondary) + CaptionLabel(completionSummary, color: AppTextColors.secondary) } } .padding(Design.Spacing.large) diff --git a/Andromida/App/Views/Today/Components/TodayEmptyStateView.swift b/Andromida/App/Views/Today/Components/TodayEmptyStateView.swift index f2b9034..4f82530 100644 --- a/Andromida/App/Views/Today/Components/TodayEmptyStateView.swift +++ b/Andromida/App/Views/Today/Components/TodayEmptyStateView.swift @@ -16,13 +16,11 @@ struct TodayEmptyStateView: View { VStack(spacing: Design.Spacing.large) { // Icon - Image(systemName: "sparkles") - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppAccent.primary) + SymbolIcon("sparkles", size: .hero, color: AppAccent.primary) .padding(.top, Design.Spacing.large) Text(String(localized: "Rituals help you build consistent habits through focused, time-bound journeys.")) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) .padding(.horizontal, Design.Spacing.large) @@ -36,7 +34,7 @@ struct TodayEmptyStateView: View { .fill(AppBorder.subtle) .frame(height: 1) Text(String(localized: "or")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) Rectangle() .fill(AppBorder.subtle) @@ -73,7 +71,7 @@ struct TodayEmptyStateView: View { // Past rituals hint if !store.pastRituals.isEmpty { Text(String(localized: "You can also restart a past ritual from the Rituals tab.")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) .multilineTextAlignment(.center) .padding(.top, Design.Spacing.small) @@ -97,8 +95,7 @@ struct TodayEmptyStateView: View { private var quickStartSection: some View { VStack(alignment: .leading, spacing: Design.Spacing.small) { Text(String(localized: "Quick Start")) - .font(.caption) - .fontWeight(.medium) + .font(Design.Typography.captionMedium) .foregroundStyle(AppTextColors.tertiary) .padding(.horizontal, Design.Spacing.medium) @@ -135,12 +132,10 @@ private struct QuickStartButton: View { var body: some View { Button(action: action) { HStack(spacing: Design.Spacing.small) { - Image(systemName: goal.symbolName) - .font(.body) - .foregroundStyle(AppAccent.primary) + SymbolIcon(goal.symbolName, size: .row, color: AppAccent.primary) Text(goal.displayName) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.primary) Spacer() diff --git a/Andromida/App/Views/Today/Components/TodayHabitRowView.swift b/Andromida/App/Views/Today/Components/TodayHabitRowView.swift index c47e72a..83ae040 100644 --- a/Andromida/App/Views/Today/Components/TodayHabitRowView.swift +++ b/Andromida/App/Views/Today/Components/TodayHabitRowView.swift @@ -25,22 +25,20 @@ struct TodayHabitRowView: View { var body: some View { Button(action: action) { HStack(spacing: Design.Spacing.medium) { - Image(systemName: symbolName) - .font(.body) - .foregroundStyle(isCompleted ? AppStatus.success : AppAccent.primary) + SymbolIcon(symbolName, size: .row, color: isCompleted ? AppStatus.success : AppAccent.primary) .frame(width: AppMetrics.Size.iconLarge) .accessibilityHidden(true) - Text(title) - .font(.subheadline) - .foregroundStyle(AppTextColors.primary) + BodyLabel(title, color: AppTextColors.primary) Spacer(minLength: Design.Spacing.medium) - Image(systemName: isCompleted ? "checkmark.circle.fill" : "circle") - .font(.body) - .foregroundStyle(isCompleted ? AppStatus.success : AppBorder.subtle) - .accessibilityHidden(true) + SymbolIcon( + isCompleted ? "checkmark.circle.fill" : "circle", + size: .row, + color: isCompleted ? AppStatus.success : AppBorder.subtle + ) + .accessibilityHidden(true) } .padding(.horizontal, horizontalPadding) .padding(.vertical, Design.Spacing.medium) diff --git a/Andromida/App/Views/Today/Components/TodayHeaderView.swift b/Andromida/App/Views/Today/Components/TodayHeaderView.swift index e2a8b64..a4a1c54 100644 --- a/Andromida/App/Views/Today/Components/TodayHeaderView.swift +++ b/Andromida/App/Views/Today/Components/TodayHeaderView.swift @@ -10,13 +10,8 @@ struct TodayHeaderView: View { var body: some View { VStack(alignment: .leading, spacing: Design.Spacing.xxxSmall) { - Text(String(localized: "Today")) - .font(.largeTitle) - .foregroundStyle(AppTextColors.primary) - .bold() - Text(dateText) - .font(.subheadline) - .foregroundStyle(AppTextColors.secondary) + TitleLabel(String(localized: "Today"), style: .displayLarge, color: AppTextColors.primary) + BodyLabel(dateText, color: AppTextColors.secondary) } .frame(maxWidth: .infinity, alignment: .leading) .accessibilityElement(children: .combine) diff --git a/Andromida/App/Views/Today/Components/TodayNoRitualsForTimeView.swift b/Andromida/App/Views/Today/Components/TodayNoRitualsForTimeView.swift index c03f1b5..a153d92 100644 --- a/Andromida/App/Views/Today/Components/TodayNoRitualsForTimeView.swift +++ b/Andromida/App/Views/Today/Components/TodayNoRitualsForTimeView.swift @@ -48,19 +48,17 @@ struct TodayNoRitualsForTimeView: View { VStack(spacing: Design.Spacing.large) { // Icon - Image(systemName: currentTimePeriod.symbolName) - .font(.system(size: Design.IconSize.hero)) - .foregroundStyle(AppAccent.primary.opacity(0.6)) + SymbolIcon(currentTimePeriod.symbolName, size: .hero, color: AppAccent.primary.opacity(0.6)) .padding(.top, Design.Spacing.large) VStack(spacing: Design.Spacing.xSmall) { Text(String(localized: "No rituals scheduled for \(currentTimePeriod.displayName.lowercased()).")) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.secondary) .multilineTextAlignment(.center) Text(currentTimePeriod.timeRange) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) } @@ -68,23 +66,21 @@ struct TodayNoRitualsForTimeView: View { if !nextRituals.isEmpty { VStack(alignment: .leading, spacing: Design.Spacing.medium) { Text(String(localized: "Coming up later:")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) ForEach(nextRituals) { ritual in HStack(spacing: Design.Spacing.small) { - Image(systemName: ritual.timeOfDay.symbolName) - .font(.caption) - .foregroundStyle(AppTextColors.secondary) + SymbolIcon(ritual.timeOfDay.symbolName, size: .chevron, color: AppTextColors.secondary) Text(ritual.title) - .font(.subheadline) + .font(Design.Typography.body) .foregroundStyle(AppTextColors.primary) Spacer() Text(ritual.timeOfDay.displayName) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) } .padding(Design.Spacing.small) @@ -100,7 +96,7 @@ struct TodayNoRitualsForTimeView: View { tomorrowRitual.timeOfDay.displayName, tomorrowRitual.timeOfDay.timeRange )) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) .multilineTextAlignment(.center) .padding(.top, Design.Spacing.small) @@ -108,7 +104,7 @@ struct TodayNoRitualsForTimeView: View { // Motivational message Text(String(localized: "Enjoy this moment. Your next ritual will appear when it's time.")) - .font(.caption) + .font(Design.Typography.caption) .foregroundStyle(AppTextColors.tertiary) .multilineTextAlignment(.center) .padding(.top, Design.Spacing.small) diff --git a/Andromida/App/Views/Today/Components/TodayRitualSectionView.swift b/Andromida/App/Views/Today/Components/TodayRitualSectionView.swift index 1c9e930..e755a25 100644 --- a/Andromida/App/Views/Today/Components/TodayRitualSectionView.swift +++ b/Andromida/App/Views/Today/Components/TodayRitualSectionView.swift @@ -33,8 +33,7 @@ struct TodayRitualSectionView: View { Spacer() // Time of day indicator - Image(systemName: timeOfDay.symbolName) - .foregroundStyle(AppTextColors.tertiary) + SymbolIcon(timeOfDay.symbolName, size: .row, color: AppTextColors.tertiary) .accessibilityLabel(timeOfDay.displayName) }