mana-swift-ui/Sources/ManaAuthUI/Brand/ManaBrandConfig.swift
Till JS d621cb8372 feat(brand): logoAssetName für Custom-Logos (v0.7.0)
ManaBrandConfig.logoAssetName ergänzt — Apps liefern einen Asset-
Catalog-Namen, ManaAuthScaffold rendert das Bundle-Asset 64×64pt
ohne Tint statt eines getinteten SF-Symbols. logoSymbol bleibt
Fallback.

Hintergrund: Pageta hat ein eigenes Apple-Icon-Composer-SVG; SF-
Symbol "book.pages" sah neben dem polierten App-Icon unecht aus.

Additive Änderung, alle bestehenden Apps quellkompatibel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:29:19 +02:00

175 lines
5.6 KiB
Swift

import SwiftUI
/// App-injizierte Brand- und Theme-Werte für die Auth-Reise.
///
/// `ManaAuthUI` weiß nichts über Cards, Manaspur oder Memoro die
/// konsumierende App liefert ihren App-Namen, ihren Tagline und ihren
/// Farbsatz. Cards/Manaspur fahren heute den `forest`-Theme, Memoro
/// den `mana`-Default. Beide werden hier als Werte übergeben.
///
/// **Migration zu ManaTokens-Theme-Variants:** Sobald ManaTokens
/// (mana-swift-core) mehrere Variants liefert (`mana`, `forest`, ),
/// kann eine App einfach `.forest` statt eines manuellen
/// `ManaBrandConfig` schicken Convenience-Initializer folgen dann.
/// Heute (v0.1.0) ist alles explizit, bewusst.
public struct ManaBrandConfig: Sendable {
/// Anzeige-Name der App. Wird groß auf Login/SignUp gezeigt.
public let appName: String
/// Untertitel unter dem App-Namen. Optional wenn nil, wird kein
/// Tagline gerendert.
public let tagline: String?
/// Optionales SF-Symbol, das zentral über dem App-Namen erscheint.
/// Z.B. `"rectangle.stack.fill"` für Cardecky, `"map.fill"` für
/// Manaspur. Wenn nil, wird kein Icon gerendert.
///
/// Wenn ``logoAssetName`` gesetzt ist, hat das Vorrang das
/// SF-Symbol dient als Fallback.
public let logoSymbol: String?
/// Optionaler Asset-Catalog-Name eines App-spezifischen Logos
/// (z.B. SVG aus dem App Icon Composer). Hat Vorrang vor
/// ``logoSymbol``. Das Asset muss im Bundle der konsumierenden App
/// liegen und Template-fähig sein, wenn es brand.primary annehmen
/// soll sonst wird's in Originalfarben gerendert.
public let logoAssetName: String?
// MARK: - Theme-Farben
/// Seiten-Hintergrund.
public let background: Color
/// Standard-Text auf Background.
public let foreground: Color
/// Card, Panel, Modal, Eingabefeld.
public let surface: Color
/// Sekundär-Text, Placeholder.
public let mutedForeground: Color
/// Rahmen, Trennlinien.
public let border: Color
/// Brand-Akzent (Primary-Button, Logo-Tint).
public let primary: Color
/// Text auf Primary-Background.
public let primaryForeground: Color
/// Fehler-Text und Destruktiv-Buttons.
public let error: Color
/// Success-Text (z.B. "Email verschickt").
public let success: Color
public init(
appName: String,
tagline: String? = nil,
logoSymbol: String? = nil,
logoAssetName: String? = nil,
background: Color,
foreground: Color,
surface: Color,
mutedForeground: Color,
border: Color,
primary: Color,
primaryForeground: Color,
error: Color,
success: Color
) {
self.appName = appName
self.tagline = tagline
self.logoSymbol = logoSymbol
self.logoAssetName = logoAssetName
self.background = background
self.foreground = foreground
self.surface = surface
self.mutedForeground = mutedForeground
self.border = border
self.primary = primary
self.primaryForeground = primaryForeground
self.error = error
self.success = success
}
}
public extension ManaBrandConfig {
/// SwiftUI-System-Default Plattform-System-Colors, geeignet für
/// Previews und Apps ohne eigenes Brand-Theme (heute: Memoro).
/// Folgt automatisch dem Light/Dark-Mode des Systems.
static let systemDefault = ManaBrandConfig(
appName: "mana",
tagline: nil,
logoSymbol: nil,
logoAssetName: nil,
background: PlatformPalette.background,
foreground: .primary,
surface: PlatformPalette.surface,
mutedForeground: .secondary,
border: PlatformPalette.border,
primary: .accentColor,
primaryForeground: .white,
error: .red,
success: .green
)
}
/// Plattform-Brücke für die wenigen System-Colors, die zwischen iOS
/// und macOS unterschiedliche Namen haben. Bewusst privat Apps
/// arbeiten mit `Color`-Werten, nicht mit dieser Helper-Schicht.
private enum PlatformPalette {
static var background: Color {
#if canImport(UIKit)
Color(uiColor: .systemBackground)
#elseif canImport(AppKit)
Color(nsColor: .windowBackgroundColor)
#else
Color.white
#endif
}
static var surface: Color {
#if canImport(UIKit)
Color(uiColor: .secondarySystemBackground)
#elseif canImport(AppKit)
Color(nsColor: .underPageBackgroundColor)
#else
Color.gray.opacity(0.1)
#endif
}
static var border: Color {
#if canImport(UIKit)
Color(uiColor: .separator)
#elseif canImport(AppKit)
Color(nsColor: .separatorColor)
#else
Color.gray.opacity(0.3)
#endif
}
}
/// Environment-Key für die Brand-Config. Apps setzen den am Root-View
/// einmal; alle `ManaAuthUI`-Views lesen automatisch über
/// `@Environment(\.manaBrand)`.
public struct ManaBrandConfigKey: EnvironmentKey {
public static let defaultValue: ManaBrandConfig = .systemDefault
}
public extension EnvironmentValues {
/// Brand-/Theme-Werte für `ManaAuthUI`-Views. Vom App-Root via
/// `.environment(\.manaBrand, brandConfig)` gesetzt.
var manaBrand: ManaBrandConfig {
get { self[ManaBrandConfigKey.self] }
set { self[ManaBrandConfigKey.self] = newValue }
}
}
public extension View {
/// Convenience-Modifier semantisch `.environment(\.manaBrand, ...)`.
func manaBrand(_ config: ManaBrandConfig) -> some View {
environment(\.manaBrand, config)
}
}