Add design style system with 23 unique home screen aesthetics: - Classic (original SportsTime design, now default) - 12 experimental styles (Brutalist, Luxury Editorial, etc.) - 10 polished app-inspired styles (Flighty, SeatGeek, Apple Maps, Things 3, Airbnb, Spotify, Nike Run Club, Fantastical, Strava, Carrot Weather) Includes settings picker to switch between styles and persists selection via UserDefaults. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
191 lines
7.1 KiB
Swift
191 lines
7.1 KiB
Swift
//
|
|
// UIDesignStyle.swift
|
|
// SportsTime
|
|
//
|
|
// 22 distinctive aesthetic variants for the home screen.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
/// Available UI design aesthetics for the home screen
|
|
enum UIDesignStyle: String, CaseIterable, Identifiable, Codable {
|
|
// Default
|
|
case classic = "Classic"
|
|
|
|
// Original experimental aesthetics
|
|
case brutalist = "Brutalist"
|
|
case luxuryEditorial = "Luxury Editorial"
|
|
case retroFuturism = "Retro-Futurism"
|
|
case glassmorphism = "Glassmorphism"
|
|
case neoBrutalist = "Neo-Brutalist"
|
|
case organic = "Organic"
|
|
case maximalistChaos = "Maximalist"
|
|
case swissModernist = "Swiss Modern"
|
|
case playful = "Playful"
|
|
case artDeco = "Art Deco"
|
|
case darkIndustrial = "Industrial"
|
|
case softPastel = "Soft Pastel"
|
|
|
|
// Polished app-inspired aesthetics
|
|
case flighty = "Flighty"
|
|
case seatGeek = "SeatGeek"
|
|
case appleMaps = "Apple Maps"
|
|
case things3 = "Things 3"
|
|
case airbnb = "Airbnb"
|
|
case spotify = "Spotify"
|
|
case nikeRunClub = "Nike Run Club"
|
|
case fantastical = "Fantastical"
|
|
case strava = "Strava"
|
|
case carrotWeather = "Carrot Weather"
|
|
|
|
var id: String { rawValue }
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .classic:
|
|
return "The original SportsTime design"
|
|
case .brutalist:
|
|
return "Raw, unpolished anti-design rebellion"
|
|
case .luxuryEditorial:
|
|
return "Magazine-quality dramatic typography"
|
|
case .retroFuturism:
|
|
return "80s sci-fi meets modern sports tech"
|
|
case .glassmorphism:
|
|
return "Frosted glass, flowing ethereal shapes"
|
|
case .neoBrutalist:
|
|
return "Bold blocks, harsh shadows, high contrast"
|
|
case .organic:
|
|
return "Soft curves, earthy tones, breathing life"
|
|
case .maximalistChaos:
|
|
return "Dense, layered, gloriously overwhelming"
|
|
case .swissModernist:
|
|
return "Grid-obsessed clinical precision"
|
|
case .playful:
|
|
return "Bouncy, candy colors, pure delight"
|
|
case .artDeco:
|
|
return "1920s glamour with gold accents"
|
|
case .darkIndustrial:
|
|
return "Moody metallic dashboard aesthetic"
|
|
case .softPastel:
|
|
return "Light, airy, dreamy gradients"
|
|
case .flighty:
|
|
return "Aviation dashboard, data-rich elegance"
|
|
case .seatGeek:
|
|
return "Sports ticketing, vibrant modern cards"
|
|
case .appleMaps:
|
|
return "Native iOS, clean and familiar"
|
|
case .things3:
|
|
return "Ultra-clean, beautiful spacing"
|
|
case .airbnb:
|
|
return "Travel-focused, warm and inviting"
|
|
case .spotify:
|
|
return "Dark elegance, bold typography"
|
|
case .nikeRunClub:
|
|
return "Athletic stats, dynamic energy"
|
|
case .fantastical:
|
|
return "Calendar elegance, data-dense"
|
|
case .strava:
|
|
return "Athletic tracking, orange accent"
|
|
case .carrotWeather:
|
|
return "Bold personality, gradient skies"
|
|
}
|
|
}
|
|
|
|
var iconName: String {
|
|
switch self {
|
|
case .classic: return "star.fill"
|
|
case .brutalist: return "hammer.fill"
|
|
case .luxuryEditorial: return "book.fill"
|
|
case .retroFuturism: return "tv.fill"
|
|
case .glassmorphism: return "drop.fill"
|
|
case .neoBrutalist: return "square.fill"
|
|
case .organic: return "leaf.fill"
|
|
case .maximalistChaos: return "sparkles"
|
|
case .swissModernist: return "grid"
|
|
case .playful: return "face.smiling.fill"
|
|
case .artDeco: return "diamond.fill"
|
|
case .darkIndustrial: return "gearshape.fill"
|
|
case .softPastel: return "cloud.fill"
|
|
case .flighty: return "airplane"
|
|
case .seatGeek: return "ticket.fill"
|
|
case .appleMaps: return "map.fill"
|
|
case .things3: return "checkmark.circle.fill"
|
|
case .airbnb: return "house.fill"
|
|
case .spotify: return "waveform"
|
|
case .nikeRunClub: return "figure.run"
|
|
case .fantastical: return "calendar"
|
|
case .strava: return "location.fill"
|
|
case .carrotWeather: return "sun.max.fill"
|
|
}
|
|
}
|
|
|
|
var accentColor: Color {
|
|
switch self {
|
|
case .classic: return Color(red: 1.0, green: 0.45, blue: 0.2) // Warm Orange
|
|
case .brutalist: return .red
|
|
case .luxuryEditorial: return Color(red: 0.85, green: 0.65, blue: 0.13) // Gold
|
|
case .retroFuturism: return Color(red: 0.0, green: 1.0, blue: 0.8) // Cyan
|
|
case .glassmorphism: return Color(red: 0.6, green: 0.4, blue: 1.0) // Purple
|
|
case .neoBrutalist: return Color(red: 1.0, green: 0.8, blue: 0.0) // Yellow
|
|
case .organic: return Color(red: 0.4, green: 0.7, blue: 0.4) // Green
|
|
case .maximalistChaos: return Color(red: 1.0, green: 0.2, blue: 0.6) // Magenta
|
|
case .swissModernist: return .red
|
|
case .playful: return Color(red: 1.0, green: 0.4, blue: 0.6) // Pink
|
|
case .artDeco: return Color(red: 0.85, green: 0.65, blue: 0.13) // Gold
|
|
case .darkIndustrial: return Color(red: 1.0, green: 0.5, blue: 0.0) // Orange
|
|
case .softPastel: return Color(red: 0.7, green: 0.8, blue: 1.0) // Soft blue
|
|
case .flighty: return Color(red: 0.2, green: 0.5, blue: 1.0) // Blue
|
|
case .seatGeek: return Color(red: 0.85, green: 0.15, blue: 0.5) // Magenta
|
|
case .appleMaps: return Color(red: 0.0, green: 0.48, blue: 1.0) // Apple Blue
|
|
case .things3: return Color(red: 0.35, green: 0.6, blue: 0.95) // Things Blue
|
|
case .airbnb: return Color(red: 1.0, green: 0.22, blue: 0.4) // Airbnb Red
|
|
case .spotify: return Color(red: 0.12, green: 0.84, blue: 0.38) // Spotify Green
|
|
case .nikeRunClub: return Color(red: 0.77, green: 1.0, blue: 0.0) // Nike Volt
|
|
case .fantastical: return Color(red: 0.92, green: 0.26, blue: 0.26) // Fantastical Red
|
|
case .strava: return Color(red: 0.99, green: 0.32, blue: 0.15) // Strava Orange
|
|
case .carrotWeather: return Color(red: 1.0, green: 0.45, blue: 0.2) // Carrot Orange
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Design Style Manager
|
|
|
|
@Observable
|
|
final class DesignStyleManager {
|
|
static let shared = DesignStyleManager()
|
|
|
|
private let userDefaultsKey = "selectedUIDesignStyle"
|
|
|
|
private(set) var currentStyle: UIDesignStyle {
|
|
didSet {
|
|
UserDefaults.standard.set(currentStyle.rawValue, forKey: userDefaultsKey)
|
|
}
|
|
}
|
|
|
|
private init() {
|
|
if let savedValue = UserDefaults.standard.string(forKey: userDefaultsKey),
|
|
let style = UIDesignStyle(rawValue: savedValue) {
|
|
self.currentStyle = style
|
|
} else {
|
|
self.currentStyle = .classic // Default to original design
|
|
}
|
|
}
|
|
|
|
func setStyle(_ style: UIDesignStyle) {
|
|
currentStyle = style
|
|
}
|
|
}
|
|
|
|
// MARK: - Environment Key
|
|
|
|
private struct DesignStyleKey: EnvironmentKey {
|
|
static let defaultValue: UIDesignStyle = .classic
|
|
}
|
|
|
|
extension EnvironmentValues {
|
|
var designStyle: UIDesignStyle {
|
|
get { self[DesignStyleKey.self] }
|
|
set { self[DesignStyleKey.self] = newValue }
|
|
}
|
|
}
|