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>
This commit is contained in:
Till JS 2026-05-22 12:29:19 +02:00
parent 8f4d4b0c03
commit d621cb8372
3 changed files with 70 additions and 1 deletions

View file

@ -6,6 +6,53 @@ Alle Änderungen werden hier dokumentiert. Format orientiert an
## [Unreleased]
## [0.7.0] — 2026-05-22
Minor — **`logoAssetName`** in `ManaBrandConfig`. Apps können jetzt
ein eigenes Logo-Asset (Asset-Catalog-Name) statt eines SF-Symbols
für den Login-/Sign-Up-/Forgot-Password-Header liefern.
### Hintergrund
Pageta hat ein eigenes Apple-Icon-Composer-SVG; das SF-Symbol
`book.pages` (vorher) sah neben dem polierten App-Icon unecht aus.
Andere Apps mit echten Logo-Assets (kommt) werden den gleichen
Migrationspfad gehen können.
### Neu
- `ManaBrandConfig.logoAssetName: String?` — Name eines Image-Assets
im Bundle der konsumierenden App. Hat Vorrang vor `logoSymbol`.
- `ManaAuthScaffold` rendert `logoAssetName` 64×64pt, `aspectRatio(.fit)`,
ohne Tint (Asset behält Originalfarben — typisch Apple-Icon-
Composer-Output mit Gradient). Fallback bleibt SF-Symbol mit Tint.
### Geändert
- `ManaBrandConfig.init` hat einen zusätzlichen optionalen Parameter
`logoAssetName: String? = nil`. Quellkompatibel — bestehende Apps
brauchen nichts ändern.
- `systemDefault`-Config setzt `logoAssetName: nil` explizit (kein
Verhaltenswechsel).
### Tests
- 50/50 grün (keine neuen Tests — die `ManaBrandConfig`-Änderung ist
rein additiv, gerendertes Asset hängt am Bundle der App).
### Adoption
Apps mit eigenem Logo:
```swift
ManaBrandConfig(
appName: "Pageta",
logoSymbol: "book.pages", // SF-Fallback bleibt
logoAssetName: "PagetaLogo", // Asset-Catalog-Name, hat Vorrang
...
)
```
## [0.6.0] — 2026-05-17
Minor — **neues Library-Product `ManaWebShell`**. WKWebView-Hülle für

View file

@ -23,8 +23,18 @@ public struct ManaBrandConfig: Sendable {
/// 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.
@ -58,6 +68,7 @@ public struct ManaBrandConfig: Sendable {
appName: String,
tagline: String? = nil,
logoSymbol: String? = nil,
logoAssetName: String? = nil,
background: Color,
foreground: Color,
surface: Color,
@ -71,6 +82,7 @@ public struct ManaBrandConfig: Sendable {
self.appName = appName
self.tagline = tagline
self.logoSymbol = logoSymbol
self.logoAssetName = logoAssetName
self.background = background
self.foreground = foreground
self.surface = surface
@ -91,6 +103,7 @@ public extension ManaBrandConfig {
appName: "mana",
tagline: nil,
logoSymbol: nil,
logoAssetName: nil,
background: PlatformPalette.background,
foreground: .primary,
surface: PlatformPalette.surface,

View file

@ -47,7 +47,16 @@ public struct ManaAuthScaffold<Content: View>: View {
@ViewBuilder
private var header: some View {
VStack(spacing: 12) {
if let symbol = brand.logoSymbol {
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)