mana-swift-ui/Sources/ManaAuthUI/Components/ManaAuthScaffold.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

76 lines
2.8 KiB
Swift

import SwiftUI
/// Gemeinsames Layout-Gerüst für alle Auth-Screens: brand-getöntes
/// Background, scrollbarer Content-Stack mit max-width, optional
/// ein zentriertes Logo + App-Name + Tagline-Block am Anfang.
///
/// Apps brauchen keine eigene NavigationStack-Wrapper das ist die
/// Aufgabe der konsumierenden View (Login/SignUp etc. sitzen ggf.
/// in einer Sheet oder einem NavigationStack der App).
public struct ManaAuthScaffold<Content: View>: View {
@Environment(\.manaBrand) private var brand
private let showsHeader: Bool
private let content: Content
/// - Parameters:
/// - showsHeader: Wenn `true`, wird oben Logo + AppName + Tagline
/// gerendert. Default `true`. Auf Account-Sub-Views (Change-
/// Password etc.) sinnvollerweise `false`.
public init(showsHeader: Bool = true, @ViewBuilder content: () -> Content) {
self.showsHeader = showsHeader
self.content = content()
}
public var body: some View {
ZStack {
brand.background.ignoresSafeArea()
ScrollView {
VStack(spacing: 24) {
if showsHeader {
header
}
content
}
.padding(.horizontal, 24)
.padding(.top, showsHeader ? 64 : 24)
.padding(.bottom, 32)
.frame(maxWidth: 480)
.frame(maxWidth: .infinity)
}
#if os(iOS)
.scrollDismissesKeyboard(.interactively)
#endif
}
}
@ViewBuilder
private var header: some View {
VStack(spacing: 12) {
if let assetName = brand.logoAssetName {
// App-spezifisches Logo aus dem Bundle der konsumierenden
// App. Größere 64pt-Variante, damit ein detailliertes
// Custom-Logo seinen Charakter zeigt (statt nur als
// SF-Symbol-Stand-In zu wirken).
Image(assetName)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 64, height: 64)
} else if let symbol = brand.logoSymbol {
Image(systemName: symbol)
.font(.system(size: 44, weight: .medium))
.foregroundStyle(brand.primary)
}
Text(brand.appName)
.font(.system(size: 40, weight: .bold))
.foregroundStyle(brand.primary)
.multilineTextAlignment(.center)
if let tagline = brand.tagline {
Text(tagline)
.font(.subheadline)
.foregroundStyle(brand.mutedForeground)
.multilineTextAlignment(.center)
}
}
}
}