- ManaThemeUI: geteiltes Karten-Chrome `.manaCard(...)` (continuous Squircle + optionaler Border aus EINER gemeinsamen Form, saubere Ecken) und `RoundedRectangle.mana(Radius.*)` als geteilte Ecken-Sprache. - ManaSignInCTA (Login) + ManaFeedbackCard ziehen auf `.manaCard` — identisches Chrome, Login bekommt denselben Border, beide continuous. - Rest-Chrome (Eingabefelder, Primary-Button, Feedback-Buttons, 2FA-QR/Codes/ Kopier-Buttons) auf `RoundedRectangle.mana(Radius.*)`; keine cornerRadius- Literale mehr, Radien auf Token-Skala konvergiert. - ManaAboutSection: vereinheitlichte „Über"-Sektion (App/Version/Build + Links), opt-in via `ManaAccountView(about:)`. Kein API-Bruch (alles additiv/optisch). CHANGELOG aktualisiert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
90 lines
3.5 KiB
Swift
90 lines
3.5 KiB
Swift
import ManaCore
|
|
import ManaThemeUI
|
|
import ManaTokens
|
|
import SwiftUI
|
|
|
|
/// Prominenter Feedback-Block für den Konto-/Einstellungen-Tab — der
|
|
/// gewichtige Bruder der dezenten ``ManaFeedbackButton``-Listenzeile.
|
|
/// Icon + aktivierender Titel + ein Satz Einladung + gefüllter CTA in
|
|
/// Vereinsfarbe. Präsentiert dasselbe ``ManaFeedbackSheet``.
|
|
///
|
|
/// Wird typischerweise nicht von Hand platziert, sondern von
|
|
/// `ManaAccountView` an **fester Position** gerendert (direkt nach dem
|
|
/// Konto-/Anmelden-Block) — so steht Feedback in allen Verein-Apps gleich
|
|
/// weit oben und gleich auffällig, statt pro App handgebaut tief im
|
|
/// `extra`-Slot zu verschwinden.
|
|
///
|
|
/// Für Stand-alone-Einsatz (eigener Settings-Screen) in eine `Section`
|
|
/// mit geleertem Row-Background + Null-Insets legen, damit die Karte frei
|
|
/// in der `Form` schwebt:
|
|
///
|
|
/// ```swift
|
|
/// Section {
|
|
/// ManaFeedbackCard(client: client, isLoggedIn: session.isLoggedIn)
|
|
/// .listRowInsets(EdgeInsets())
|
|
/// .listRowBackground(Color.clear)
|
|
/// }
|
|
/// ```
|
|
public struct ManaFeedbackCard: View {
|
|
@Environment(\.manaTheme) private var theme
|
|
|
|
private let client: FeedbackClient
|
|
private let isLoggedIn: Bool
|
|
private let title: String
|
|
private let message: String
|
|
private let cta: String
|
|
|
|
@State private var isPresented = false
|
|
|
|
/// - Parameters:
|
|
/// - client: der App-`FeedbackClient` (trägt die `appId`).
|
|
/// - isLoggedIn: steuert das anonyme Kontakt-Mail-Feld im Sheet.
|
|
/// - title: aktivierende Überschrift. Default: Mitgestalten-Ton.
|
|
/// - message: ein Satz Einladung darunter.
|
|
/// - cta: Beschriftung des gefüllten Knopfs.
|
|
public init(
|
|
client: FeedbackClient,
|
|
isLoggedIn: Bool,
|
|
title: String = "Hilf mit, die App zu formen",
|
|
message: String = "Deine Wünsche steuern, was wir als Nächstes bauen — ein Mensch im Team liest mit.",
|
|
cta: String = "Vorschlag senden"
|
|
) {
|
|
self.client = client
|
|
self.isLoggedIn = isLoggedIn
|
|
self.title = title
|
|
self.message = message
|
|
self.cta = cta
|
|
}
|
|
|
|
public var body: some View {
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
HStack(spacing: 10) {
|
|
Image(systemName: "bubble.left.and.bubble.right.fill")
|
|
.font(.title3)
|
|
.foregroundStyle(theme.primary)
|
|
Text(title)
|
|
.font(.headline)
|
|
.foregroundStyle(theme.foreground)
|
|
}
|
|
Text(message)
|
|
.font(.subheadline)
|
|
.foregroundStyle(theme.mutedForeground)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
Button { isPresented = true } label: {
|
|
Text(cta)
|
|
.fontWeight(.semibold)
|
|
.frame(maxWidth: .infinity)
|
|
.padding(.vertical, 12)
|
|
.background(theme.primary, in: RoundedRectangle.mana(Radius.md))
|
|
.foregroundStyle(theme.primaryForeground)
|
|
}
|
|
.buttonStyle(.plain)
|
|
}
|
|
// Geteiltes Karten-Chrome: continuous Squircle-Ecken + Border aus einer
|
|
// gemeinsamen Form (vorher zwei getrennte circular RoundedRectangles,
|
|
// deren Border den Ecken nicht sauber folgte). Radius jetzt einheitlich
|
|
// mit dem Login-CTA (Radius.lg) statt eigener 16.
|
|
.manaCard(surface: theme.surface, border: theme.border)
|
|
.manaFeedbackSheet(isPresented: $isPresented, client: client, isLoggedIn: isLoggedIn)
|
|
}
|
|
}
|