import SwiftUI #if canImport(UIKit) import UIKit private typealias PlatformColorType = UIColor #elseif canImport(AppKit) import AppKit private typealias PlatformColorType = NSColor #endif /// Forest-Theme aus `mana/packages/themes/src/variants/forest.css`. /// Lokal in cards-native nachgebaut, weil ManaTokens v1.0.0 nur den /// Default-Theme (mana-Variant) liefert. /// /// Migration auf einen Theme-Switch in ManaTokens ist Phase ε aus /// `mana/docs/MANA_SWIFT.md` — bis dahin lebt forest hier. enum CardsTheme { /// Page-Hintergrund static let background = dynamic(light: HSL(0, 0, 100), dark: HSL(142, 30, 8)) /// Standard-Text static let foreground = dynamic(light: HSL(142, 30, 12), dark: HSL(142, 15, 95)) /// Card, Panel, Modal static let surface = dynamic(light: HSL(142, 25, 98), dark: HSL(142, 25, 12)) /// Hover-State auf Surface static let surfaceHover = dynamic(light: HSL(142, 20, 95), dark: HSL(142, 20, 16)) /// Disabled-Felder, Skeleton static let muted = dynamic(light: HSL(142, 15, 93), dark: HSL(142, 18, 18)) /// Sekundär-Text, Placeholder static let mutedForeground = dynamic(light: HSL(142, 10, 42), dark: HSL(142, 12, 65)) /// Rahmen, Trennlinien static let border = dynamic(light: HSL(142, 15, 88), dark: HSL(142, 18, 22)) /// Cards-Brand-Grün — Tiefgrün im Light, leuchtender im Dark static let primary = dynamic(light: HSL(142, 76, 28), dark: HSL(142, 71, 45)) /// Text auf Primary static let primaryForeground = dynamic(light: HSL(0, 0, 100), dark: HSL(142, 30, 8)) static let error = dynamic(light: HSL(0, 84, 60), dark: HSL(0, 63, 55)) static let success = dynamic(light: HSL(142, 71, 45), dark: HSL(142, 71, 45)) static let warning = dynamic(light: HSL(38, 92, 50), dark: HSL(48, 96, 53)) // MARK: - HSL Helper /// Hue/Saturation/Lightness als Wert-Typ. HSL ist konkreter als ein /// 3-Tupel und macht die Call-Sites lesbar. struct HSL { let hue: Double let saturation: Double let lightness: Double init(_ hue: Double, _ saturation: Double, _ lightness: Double) { self.hue = hue self.saturation = saturation self.lightness = lightness } } private static func dynamic(light: HSL, dark: HSL) -> Color { let lightColor = fromHSL(light.hue, light.saturation, light.lightness) let darkColor = fromHSL(dark.hue, dark.saturation, dark.lightness) #if canImport(UIKit) return Color(uiColor: UIColor { trait in trait.userInterfaceStyle == .dark ? darkColor : lightColor }) #elseif canImport(AppKit) return Color(nsColor: NSColor(name: nil) { appearance in let isDark = appearance.bestMatch(from: [.darkAqua, .vibrantDark]) != nil return isDark ? darkColor : lightColor }) #else return Color(red: 0, green: 0, blue: 0) #endif } private static func fromHSL(_ hue: Double, _ saturation: Double, _ lightness: Double) -> PlatformColorType { let h = hue / 360 let s = saturation / 100 let l = lightness / 100 if s == 0 { return PlatformColorType(red: l, green: l, blue: l, alpha: 1) } let q = l < 0.5 ? l * (1 + s) : l + s - l * s let p = 2 * l - q let r = hueToRGB(p, q, h + 1.0 / 3.0) let g = hueToRGB(p, q, h) let b = hueToRGB(p, q, h - 1.0 / 3.0) return PlatformColorType(red: r, green: g, blue: b, alpha: 1) } private static func hueToRGB(_ p: Double, _ q: Double, _ rawT: Double) -> Double { var t = rawT if t < 0 { t += 1 } if t > 1 { t -= 1 } if t < 1.0 / 6.0 { return p + (q - p) * 6 * t } if t < 1.0 / 2.0 { return q } if t < 2.0 / 3.0 { return p + (q - p) * (2.0 / 3.0 - t) * 6 } return p } }