Replace custom AppTypography with native iOS font sizes
Removed the custom AppTypography system and migrated all font references to use native SwiftUI Dynamic Type sizes. This enables automatic text scaling based on user preferences and ensures consistency with iOS design standards. Changes: - Removed AppTypography struct from DesignSystem.swift - Updated PrimaryButtonStyle and SecondaryButtonStyle to use .headline - Replaced all typography references throughout the app with native fonts: - displayLarge → .largeTitle.weight(.bold) - headlineSmall → .title3.weight(.semibold) - titleMedium → .title3.weight(.semibold) - bodyMedium → .body - labelMedium → .footnote.weight(.medium) - And many more across 18 files Benefits: - Supports Dynamic Type for accessibility - Reduces custom code maintenance - Aligns with iOS design guidelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,7 @@ struct ContractorCard: View {
|
||||
// Name with favorite star
|
||||
HStack(spacing: AppSpacing.xxs) {
|
||||
Text(contractor.name)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -37,7 +37,7 @@ struct ContractorCard: View {
|
||||
// Company
|
||||
if let company = contractor.company {
|
||||
Text(company)
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
@@ -47,21 +47,21 @@ struct ContractorCard: View {
|
||||
// Specialty
|
||||
if let specialty = contractor.specialty {
|
||||
Label(specialty, systemImage: "wrench.and.screwdriver")
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
// Rating
|
||||
if let rating = contractor.averageRating, rating.doubleValue > 0 {
|
||||
Label(String(format: "%.1f", rating.doubleValue), systemImage: "star.fill")
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.warning)
|
||||
}
|
||||
|
||||
// Task count
|
||||
if contractor.taskCount > 0 {
|
||||
Label("\(contractor.taskCount) tasks", systemImage: "checkmark.circle")
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.success)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,13 @@ struct ContractorDetailView: View {
|
||||
|
||||
// Name
|
||||
Text(contractor.name)
|
||||
.font(AppTypography.headlineSmall)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
|
||||
// Company
|
||||
if let company = contractor.company {
|
||||
Text(company)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ struct ContractorDetailView: View {
|
||||
Image(systemName: "wrench.and.screwdriver")
|
||||
.font(.caption)
|
||||
Text(specialty)
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
}
|
||||
.padding(.horizontal, AppSpacing.sm)
|
||||
.padding(.vertical, AppSpacing.xxs)
|
||||
@@ -73,13 +73,13 @@ struct ContractorDetailView: View {
|
||||
.font(.caption)
|
||||
}
|
||||
Text(String(format: "%.1f", rating.doubleValue))
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
|
||||
if contractor.taskCount > 0 {
|
||||
Text("\(contractor.taskCount) completed tasks")
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ struct ContractorDetailView: View {
|
||||
if let notes = contractor.notes, !notes.isEmpty {
|
||||
DetailSection(title: "Notes") {
|
||||
Text(notes)
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
.padding(AppSpacing.md)
|
||||
}
|
||||
@@ -153,7 +153,7 @@ struct ContractorDetailView: View {
|
||||
.foregroundColor(AppColors.success)
|
||||
Spacer()
|
||||
Text("\(contractor.taskCount) completed tasks")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
.padding(AppSpacing.md)
|
||||
@@ -235,7 +235,7 @@ struct DetailSection<Content: View>: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: AppSpacing.sm) {
|
||||
Text(title)
|
||||
.font(AppTypography.titleSmall)
|
||||
.font(.headline)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
.padding(.horizontal, AppSpacing.md)
|
||||
|
||||
@@ -264,11 +264,11 @@ struct DetailRow: View {
|
||||
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xxs) {
|
||||
Text(label)
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
Text(value)
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ struct ContractorFormSheet: View {
|
||||
.frame(width: 20)
|
||||
|
||||
Text("Private Notes")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ struct ContractorFormSheet: View {
|
||||
Image(systemName: "star.fill")
|
||||
.foregroundColor(isFavorite ? AppColors.warning : AppColors.textSecondary)
|
||||
Text("Mark as Favorite")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,7 @@ struct ContractorFormSheet: View {
|
||||
// Error Message
|
||||
if let error = viewModel.errorMessage {
|
||||
Text(error)
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.error)
|
||||
.padding(AppSpacing.sm)
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -360,7 +360,7 @@ struct SectionHeader: View {
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(title)
|
||||
.font(AppTypography.titleSmall)
|
||||
.font(.headline)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
Spacer()
|
||||
}
|
||||
@@ -385,12 +385,12 @@ struct FormTextField: View {
|
||||
.frame(width: 20)
|
||||
|
||||
Text(title)
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
} else {
|
||||
Text(title)
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ struct SearchBar: View {
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
TextField(placeholder, text: $text)
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
|
||||
if !text.isEmpty {
|
||||
Button(action: { text = "" }) {
|
||||
@@ -233,7 +233,7 @@ struct FilterChip: View {
|
||||
.font(.caption)
|
||||
}
|
||||
Text(title)
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
|
||||
Button(action: onRemove) {
|
||||
Image(systemName: "xmark")
|
||||
@@ -259,12 +259,12 @@ struct EmptyContractorsView: View {
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
|
||||
Text(hasFilters ? "No contractors found" : "No contractors yet")
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
if !hasFilters {
|
||||
Text("Add your first contractor to get started")
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,36 +52,6 @@ struct AppColors {
|
||||
)
|
||||
}
|
||||
|
||||
struct AppTypography {
|
||||
// Display - For hero sections
|
||||
static let displayLarge = Font.system(size: 57, weight: .bold, design: .rounded)
|
||||
static let displayMedium = Font.system(size: 45, weight: .bold, design: .rounded)
|
||||
static let displaySmall = Font.system(size: 36, weight: .bold, design: .rounded)
|
||||
|
||||
// Headline - For section headers
|
||||
static let headlineLarge = Font.system(size: 32, weight: .bold, design: .rounded)
|
||||
static let headlineMedium = Font.system(size: 28, weight: .semibold, design: .rounded)
|
||||
static let headlineSmall = Font.system(size: 24, weight: .semibold, design: .rounded)
|
||||
|
||||
// Title - For card titles
|
||||
static let titleLarge = Font.system(size: 22, weight: .semibold, design: .default)
|
||||
static let titleMedium = Font.system(size: 18, weight: .semibold, design: .default)
|
||||
static let titleSmall = Font.system(size: 16, weight: .semibold, design: .default)
|
||||
|
||||
// Body - For main content
|
||||
static let bodyLarge = Font.system(size: 17, weight: .regular, design: .default)
|
||||
static let bodyMedium = Font.system(size: 15, weight: .regular, design: .default)
|
||||
static let bodySmall = Font.system(size: 13, weight: .regular, design: .default)
|
||||
|
||||
// Label - For labels and captions
|
||||
static let labelLarge = Font.system(size: 14, weight: .medium, design: .default)
|
||||
static let labelMedium = Font.system(size: 12, weight: .medium, design: .default)
|
||||
static let labelSmall = Font.system(size: 11, weight: .medium, design: .default)
|
||||
|
||||
// Caption
|
||||
static let caption = Font.system(size: 12, weight: .regular, design: .default)
|
||||
}
|
||||
|
||||
struct AppSpacing {
|
||||
static let xxs: CGFloat = 4
|
||||
static let xs: CGFloat = 8
|
||||
@@ -143,7 +113,7 @@ struct PrimaryButtonStyle: ButtonStyle {
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.font(AppTypography.titleSmall)
|
||||
.font(.headline)
|
||||
.foregroundColor(.white)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 56)
|
||||
@@ -159,7 +129,7 @@ struct PrimaryButtonStyle: ButtonStyle {
|
||||
struct SecondaryButtonStyle: ButtonStyle {
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.font(AppTypography.titleSmall)
|
||||
.font(.headline)
|
||||
.foregroundColor(AppColors.primary)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 56)
|
||||
|
||||
@@ -39,21 +39,21 @@ struct DocumentCard: View {
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(document.title)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
if let description = document.description_, !description.isEmpty {
|
||||
Text(description)
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
.lineLimit(2)
|
||||
}
|
||||
|
||||
HStack(spacing: 8) {
|
||||
Text(getDocTypeDisplayName(document.documentType))
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(typeColor)
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.vertical, 2)
|
||||
@@ -62,7 +62,7 @@ struct DocumentCard: View {
|
||||
|
||||
if let fileSize = document.fileSize {
|
||||
Text(formatFileSize(Int(fileSize)))
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ struct EmptyStateView: View {
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
Text(title)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
Text(message)
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ struct WarrantyCard: View {
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(document.title)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
|
||||
Text(document.itemName ?? "")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ struct WarrantyCard: View {
|
||||
|
||||
// Status Badge
|
||||
Text(statusText)
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(statusColor)
|
||||
.padding(.horizontal, 8)
|
||||
@@ -57,10 +57,10 @@ struct WarrantyCard: View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Provider")
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
Text(document.provider ?? "N/A")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
@@ -69,10 +69,10 @@ struct WarrantyCard: View {
|
||||
|
||||
VStack(alignment: .trailing, spacing: 2) {
|
||||
Text("Expires")
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
Text(document.endDate ?? "N/A")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
@@ -80,14 +80,14 @@ struct WarrantyCard: View {
|
||||
|
||||
if document.isActive && daysUntilExpiration >= 0 {
|
||||
Text("\(daysUntilExpiration) days remaining")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(statusColor)
|
||||
}
|
||||
|
||||
// Category Badge
|
||||
if let category = document.category {
|
||||
Text(getCategoryDisplayName(category))
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(Color(hex: "374151"))
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 4)
|
||||
|
||||
@@ -16,7 +16,7 @@ struct HomeScreenView: View {
|
||||
ProgressView()
|
||||
.scaleEffect(1.2)
|
||||
Text("Loading...")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
} else {
|
||||
@@ -25,12 +25,12 @@ struct HomeScreenView: View {
|
||||
// Greeting Header
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xs) {
|
||||
Text("Hello!")
|
||||
.font(AppTypography.headlineLarge)
|
||||
.font(.title.weight(.bold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
|
||||
Text("Welcome to MyCrib")
|
||||
.font(AppTypography.bodyLarge)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
@@ -62,11 +62,11 @@ struct LoginView: View {
|
||||
|
||||
VStack(spacing: AppSpacing.xs) {
|
||||
Text("Welcome Back")
|
||||
.font(AppTypography.displaySmall)
|
||||
.font(.title2.weight(.bold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
|
||||
Text("Sign in to manage your properties")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ struct LoginView: View {
|
||||
// Username Field
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xs) {
|
||||
Text("Email or Username")
|
||||
.font(AppTypography.labelLarge)
|
||||
.font(.subheadline.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
HStack(spacing: AppSpacing.sm) {
|
||||
@@ -111,7 +111,7 @@ struct LoginView: View {
|
||||
// Password Field
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xs) {
|
||||
Text("Password")
|
||||
.font(AppTypography.labelLarge)
|
||||
.font(.subheadline.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
HStack(spacing: AppSpacing.sm) {
|
||||
@@ -167,7 +167,7 @@ struct LoginView: View {
|
||||
Button("Forgot Password?") {
|
||||
showPasswordReset = true
|
||||
}
|
||||
.font(AppTypography.labelLarge)
|
||||
.font(.subheadline.weight(.medium))
|
||||
.foregroundColor(AppColors.primary)
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ struct LoginView: View {
|
||||
Image(systemName: "exclamationmark.circle.fill")
|
||||
.foregroundColor(AppColors.error)
|
||||
Text(errorMessage)
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.error)
|
||||
Spacer()
|
||||
}
|
||||
@@ -195,13 +195,13 @@ struct LoginView: View {
|
||||
// Sign Up Link
|
||||
HStack(spacing: AppSpacing.xs) {
|
||||
Text("Don't have an account?")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
|
||||
Button("Sign Up") {
|
||||
showingRegister = true
|
||||
}
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(AppColors.primary)
|
||||
}
|
||||
@@ -276,7 +276,7 @@ struct LoginView: View {
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
||||
}
|
||||
Text(viewModel.isLoading ? "Signing In..." : "Sign In")
|
||||
.font(AppTypography.titleSmall)
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
@@ -16,7 +16,7 @@ struct ResidencesListView: View {
|
||||
ProgressView()
|
||||
.scaleEffect(1.2)
|
||||
Text("Loading properties...")
|
||||
.font(AppTypography.bodyMedium)
|
||||
.font(.body)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
} else if let error = viewModel.errorMessage {
|
||||
@@ -38,10 +38,10 @@ struct ResidencesListView: View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xxs) {
|
||||
Text("Your Properties")
|
||||
.font(AppTypography.headlineSmall)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
Text("\(response.residences.count) \(response.residences.count == 1 ? "property" : "properties")")
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -22,12 +22,12 @@ struct HomeNavigationCard: View {
|
||||
// Text Content
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xxs) {
|
||||
Text(title)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
|
||||
Text(subtitle)
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ struct OverviewCard: View {
|
||||
}
|
||||
|
||||
Text("Overview")
|
||||
.font(AppTypography.headlineSmall)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -19,12 +19,12 @@ struct StatView: View {
|
||||
}
|
||||
|
||||
Text(value)
|
||||
.font(AppTypography.headlineMedium)
|
||||
.font(.title2.weight(.semibold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
|
||||
Text(label)
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ struct ResidenceCard: View {
|
||||
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xxs) {
|
||||
Text(residence.name)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(residence.propertyType)
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
.textCase(.uppercase)
|
||||
.tracking(0.5)
|
||||
@@ -54,7 +54,7 @@ struct ResidenceCard: View {
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
Text(residence.streetAddress)
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ struct ResidenceCard: View {
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
Text("\(residence.city), \(residence.stateProvince)")
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ struct PriorityBadge: View {
|
||||
.font(.system(size: 10, weight: .bold))
|
||||
|
||||
Text(priority.capitalized)
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
.padding(.horizontal, AppSpacing.sm)
|
||||
|
||||
@@ -5,7 +5,7 @@ struct StatusBadge: View {
|
||||
|
||||
var body: some View {
|
||||
Text(formatStatus(status))
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.fontWeight(.semibold)
|
||||
.padding(.horizontal, AppSpacing.sm)
|
||||
.padding(.vertical, AppSpacing.xxs)
|
||||
|
||||
@@ -17,7 +17,7 @@ struct TaskCard: View {
|
||||
HStack(alignment: .top, spacing: AppSpacing.sm) {
|
||||
VStack(alignment: .leading, spacing: AppSpacing.xs) {
|
||||
Text(task.title)
|
||||
.font(AppTypography.titleMedium)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
.lineLimit(2)
|
||||
|
||||
@@ -34,7 +34,7 @@ struct TaskCard: View {
|
||||
// Description
|
||||
if let description = task.description_, !description.isEmpty {
|
||||
Text(description)
|
||||
.font(AppTypography.bodySmall)
|
||||
.font(.callout)
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
.lineLimit(3)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ struct TaskCard: View {
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
Text(task.frequency.displayName)
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
.padding(.horizontal, AppSpacing.sm)
|
||||
@@ -62,7 +62,7 @@ struct TaskCard: View {
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(AppColors.textTertiary)
|
||||
Text(formatDate(dueDate))
|
||||
.font(AppTypography.labelSmall)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundColor(AppColors.textSecondary)
|
||||
}
|
||||
.padding(.horizontal, AppSpacing.sm)
|
||||
@@ -88,7 +88,7 @@ struct TaskCard: View {
|
||||
.foregroundColor(AppColors.success)
|
||||
}
|
||||
Text("Completions (\(task.completions.count))")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(AppColors.textPrimary)
|
||||
}
|
||||
@@ -108,7 +108,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "play.circle.fill")
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
Text("In Progress")
|
||||
.font(AppTypography.labelLarge)
|
||||
.font(.subheadline.weight(.medium))
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -125,7 +125,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
Text("Complete")
|
||||
.font(AppTypography.labelLarge)
|
||||
.font(.subheadline.weight(.medium))
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -146,7 +146,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "pencil")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
Text("Edit")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 36)
|
||||
@@ -161,7 +161,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "xmark.circle")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
Text("Cancel")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 36)
|
||||
@@ -175,7 +175,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "arrow.uturn.backward")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
Text("Restore")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 36)
|
||||
@@ -193,7 +193,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "tray.and.arrow.up")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
Text("Unarchive")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 36)
|
||||
@@ -209,7 +209,7 @@ struct TaskCard: View {
|
||||
Image(systemName: "archivebox")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
Text("Archive")
|
||||
.font(AppTypography.labelMedium)
|
||||
.font(.footnote.weight(.medium))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 36)
|
||||
|
||||
Reference in New Issue
Block a user