wake-ios/wake/Theme.swift
2025-08-22 18:58:08 +08:00

186 lines
6.8 KiB
Swift

//
// Theme.swift
// wake
//
// Created by fairclip on 2025/8/19.
//
import SwiftUI
// MARK: -
struct Theme {
// MARK: -
struct Colors {
// MARK: -
static let primary = Color(hex: "FFB645") //
static let primaryLight = Color(hex: "FFF8DE") //
static let primaryDark = Color(hex: "E6A03D") //
// MARK: -
static let secondary = Color(hex: "6C7B7F") //
static let accent = Color(hex: "FF6B6B") //
// MARK: -
static let background = Color(hex: "F8F9FA") //
static let surface = Color.white //
static let surfaceSecondary = Color(hex: "F5F5F5") //
// MARK: -
static let textPrimary = Color.black //
static let textSecondary = Color(hex: "6B7280") //
static let textTertiary = Color(hex: "9CA3AF") //
static let textInverse = Color.white //
static let textMessage = Color(hex: "7B7B7B") //
static let textMessageMain = Color(hex: "000000") //
static let textWhite = Color(hex: "FFFFFF") //
static let textWhiteSecondary = Color(hex: "FAFAFA") //
// MARK: -
static let success = Color(hex: "10B981") //
static let warning = Color(hex: "F59E0B") //
static let error = Color(hex: "EF4444") //
static let info = Color(hex: "3B82F6") //
// MARK: -
static let border = Color(hex: "E5E7EB") //
static let borderLight = Color(hex: "F3F4F6") //
static let borderDark = Color(hex: "D1D5DB") //
// MARK: -
static let freeBackground = primaryLight // Free
static let pioneerBackground = primary // Pioneer
static let subscribeButton = primary //
}
// MARK: -
struct Gradients {
static let primaryGradient = LinearGradient(
colors: [Colors.primary, Colors.primaryDark],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
static let backgroundGradient = LinearGradient(
colors: [Colors.background, Colors.surface],
startPoint: .top,
endPoint: .bottom
)
static let accentGradient = LinearGradient(
colors: [Colors.accent, Color(hex: "FF8E8E")],
startPoint: .leading,
endPoint: .trailing
)
}
// MARK: -
struct Shadows {
static let small = Color.black.opacity(0.1)
static let medium = Color.black.opacity(0.15)
static let large = Color.black.opacity(0.2)
//
static let cardShadow = (color: small, radius: CGFloat(4), x: CGFloat(0), y: CGFloat(2))
static let buttonShadow = (color: medium, radius: CGFloat(6), x: CGFloat(0), y: CGFloat(3))
static let modalShadow = (color: large, radius: CGFloat(12), x: CGFloat(0), y: CGFloat(8))
}
// MARK: -
struct CornerRadius {
static let small: CGFloat = 8
static let medium: CGFloat = 12
static let large: CGFloat = 16
static let extraLarge: CGFloat = 20
static let round: CGFloat = 50
}
// MARK: -
struct Spacing {
static let xs: CGFloat = 4
static let sm: CGFloat = 8
static let md: CGFloat = 12
static let lg: CGFloat = 16
static let xl: CGFloat = 20
static let xxl: CGFloat = 24
static let xxxl: CGFloat = 32
}
}
// MARK: - 便
extension Color {
/// 访
static var themePrimary: Color { Theme.Colors.primary }
static var themePrimaryLight: Color { Theme.Colors.primaryLight }
static var themeSecondary: Color { Theme.Colors.secondary }
static var themeAccent: Color { Theme.Colors.accent }
static var themeBackground: Color { Theme.Colors.background }
static var themeSurface: Color { Theme.Colors.surface }
static var themeTextPrimary: Color { Theme.Colors.textPrimary }
static var themeTextSecondary: Color { Theme.Colors.textSecondary }
static var themeTextMessage: Color { Theme.Colors.textMessage }
static var themeTextMessageMain: Color { Theme.Colors.textMessageMain }
static var themeTextWhite: Color { Theme.Colors.textWhite }
static var themeTextWhiteSecondary: Color { Theme.Colors.textWhiteSecondary }
}
// MARK: -
#Preview("Theme Colors") {
ScrollView {
VStack(spacing: Theme.Spacing.lg) {
//
ColorPreviewSection(title: "品牌色", colors: [
("Primary", Theme.Colors.primary),
("Primary Light", Theme.Colors.primaryLight),
("Primary Dark", Theme.Colors.primaryDark)
])
//
ColorPreviewSection(title: "辅助色", colors: [
("Secondary", Theme.Colors.secondary),
("Accent", Theme.Colors.accent)
])
//
ColorPreviewSection(title: "状态色", colors: [
("Success", Theme.Colors.success),
("Warning", Theme.Colors.warning),
("Error", Theme.Colors.error),
("Info", Theme.Colors.info)
])
}
.padding()
}
.background(Theme.Colors.background)
}
// MARK: -
struct ColorPreviewSection: View {
let title: String
let colors: [(String, Color)]
var body: some View {
VStack(alignment: .leading, spacing: Theme.Spacing.sm) {
Text(title)
.font(.headline)
.foregroundColor(Theme.Colors.textPrimary)
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: Theme.Spacing.sm) {
ForEach(colors, id: \.0) { name, color in
VStack(spacing: Theme.Spacing.xs) {
Rectangle()
.fill(color)
.frame(height: 60)
.cornerRadius(Theme.CornerRadius.small)
Text(name)
.font(.caption)
.foregroundColor(Theme.Colors.textSecondary)
}
}
}
}
}
}