mana-swift-ui/Sources/ManaComponentsUI/ManaScreenHeader.swift
Till JS fc8a8d4702 ManaComponentsUI: ManaSectionHeader + ManaPinnedGlyph, ManaScreenHeader fett
Geteilte Listen-Bausteine, drift-sicher als Pendant zur Compose-Lib:
- ManaSectionHeader: großer (.title2/SemiBold) Abschnitts-Header für
  scrollende Listen, optional einklappbar (Chevron).
- ManaPinnedGlyph: gezeichneter Fünfzack-Stern (geteilte Geometrie via
  ManaStarShape), kein SF-Symbol → pixelgleich zum Android-Pendant.
- ManaScreenHeader: Titel jetzt fett (.title.bold).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:08:02 +02:00

99 lines
3.7 KiB
Swift

import ManaTokens
import SwiftUI
/// Flotten-einheitlicher Seiten-Header — natives Pendant zur Android-
/// `ManaScreenHeader` (mana-kotlin-ui). **Der Stil ist hier zentral
/// festgelegt**, damit der Titel über alle nativen mana-Apps gleich aussieht:
///
/// - Titel: `.title`, Akzentfarbe (`primary`), **unterstrichen** — die
/// Marken-Signatur (Referenz: memoro „Deine Memos", pageta „Meine Artikel").
/// - Untertitel (optional): `.subheadline`, gedämpfte Vordergrundfarbe.
/// - **Links-bündig**; Titel-Spalte links, optionaler `trailing`-Slot rechts
/// oben (typisch der Konto-Avatar) — beide auf gleicher Höhe.
/// - Padding zentral: 20 horizontal, 12 vertikal.
///
/// Vor dieser Komponente malte jede App ihren Titel inline mit eigener Schrift,
/// Ausrichtung und Padding. Apps liefern jetzt nur noch Titel/Untertitel/Avatar.
///
/// Die Farben kommen aus der aktiven Theme-Variant über
/// `@Environment(\.manaTheme)`; die App injiziert sie an der Root via
/// `.manaTheme(_:)`.
///
/// ```swift
/// ManaScreenHeader("Deine Memos", subtitle: "local-first") {
/// ManaAccountAvatarButton(auth: auth) { showAccount = true }
/// }
/// ```
public struct ManaScreenHeader<Trailing: View>: View {
@Environment(\.manaTheme) private var theme
private let title: String
private let subtitle: String?
private let titleColor: Color?
private let horizontalPadding: CGFloat
private let verticalPadding: CGFloat
private let trailing: Trailing
/// - Parameters:
/// - title: Seitentitel (unterstrichen, Akzentfarbe).
/// - subtitle: optionaler erklärender Untertitel.
/// - titleColor: Titelfarbe-Override. `nil` → Theme-`primary`. Für Apps
/// mit eigenem Header-Hintergrund (z. B. weißer Titel auf dunkler Fläche).
/// - horizontalPadding: seitliches Padding (Default 20).
/// - verticalPadding: vertikales Padding (Default 12).
/// - trailing: rechts-oben angesetzter Slot, typisch der Konto-Avatar.
public init(
_ title: String,
subtitle: String? = nil,
titleColor: Color? = nil,
horizontalPadding: CGFloat = 20,
verticalPadding: CGFloat = 12,
@ViewBuilder trailing: () -> Trailing
) {
self.title = title
self.subtitle = subtitle
self.titleColor = titleColor
self.horizontalPadding = horizontalPadding
self.verticalPadding = verticalPadding
self.trailing = trailing()
}
public var body: some View {
HStack(alignment: .top, spacing: 12) {
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.title.weight(.bold))
.underline()
.foregroundStyle(titleColor ?? theme.colors.primary)
if let subtitle {
Text(subtitle)
.font(.subheadline)
.foregroundStyle(theme.colors.mutedForeground)
}
}
Spacer(minLength: 0)
trailing
}
.padding(.horizontal, horizontalPadding)
.padding(.vertical, verticalPadding)
}
}
public extension ManaScreenHeader where Trailing == EmptyView {
/// Header ohne `trailing`-Slot (kein Avatar/Aktion rechts).
init(
_ title: String,
subtitle: String? = nil,
titleColor: Color? = nil,
horizontalPadding: CGFloat = 20,
verticalPadding: CGFloat = 12
) {
self.init(
title,
subtitle: subtitle,
titleColor: titleColor,
horizontalPadding: horizontalPadding,
verticalPadding: verticalPadding
) { EmptyView() }
}
}