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>
67 lines
2.3 KiB
Swift
67 lines
2.3 KiB
Swift
import ManaTokens
|
|
import SwiftUI
|
|
|
|
/// Flotten-einheitlicher **Abschnitts-Header** für scrollende Listen (Datums-
|
|
/// gruppen, „Angepinnt" …) — natives Pendant zur Android-`ManaSectionHeader`
|
|
/// (mana-kotlin-ui). **Der Stil ist hier zentral festgelegt**, damit sticky
|
|
/// Section-Header über alle Apps gleich aussehen:
|
|
///
|
|
/// - Label: `.title2` + SemiBold, gedämpfte Vordergrundfarbe (foreground 80 %).
|
|
/// - Links-bündig, Padding 12 oben / 8 unten.
|
|
/// - Optional **einklappbar**: ganze Zeile tappbar, Chevron zeigt auf-/zugeklappt.
|
|
///
|
|
/// Bewusst groß (nicht das winzige `.footnote`/uppercase-Caption-Muster) — wie
|
|
/// die memoro-Android-Referenz. Farbe aus der aktiven Theme-Variant via
|
|
/// `@Environment(\.manaTheme)`.
|
|
///
|
|
/// ```swift
|
|
/// ManaSectionHeader("Gestern")
|
|
/// ManaSectionHeader("Angepinnt", isExpanded: pinnedExpanded) { pinnedExpanded.toggle() }
|
|
/// ```
|
|
public struct ManaSectionHeader: View {
|
|
@Environment(\.manaTheme) private var theme
|
|
|
|
private let label: String
|
|
private let isExpanded: Bool?
|
|
private let onToggle: (() -> Void)?
|
|
|
|
/// Nicht einklappbarer Header (reines Label).
|
|
public init(_ label: String) {
|
|
self.label = label
|
|
isExpanded = nil
|
|
onToggle = nil
|
|
}
|
|
|
|
/// Einklappbarer Header: ganze Zeile tappbar, Chevron spiegelt `isExpanded`.
|
|
public init(_ label: String, isExpanded: Bool, onToggle: @escaping () -> Void) {
|
|
self.label = label
|
|
self.isExpanded = isExpanded
|
|
self.onToggle = onToggle
|
|
}
|
|
|
|
public var body: some View {
|
|
let color = theme.colors.foreground.opacity(0.8)
|
|
let content = HStack(spacing: 4) {
|
|
Text(label)
|
|
.font(.title2.weight(.semibold))
|
|
.foregroundStyle(color)
|
|
if let isExpanded {
|
|
Image(systemName: isExpanded ? "chevron.down" : "chevron.up")
|
|
.font(.body.weight(.semibold))
|
|
.foregroundStyle(color)
|
|
}
|
|
Spacer(minLength: 0)
|
|
}
|
|
.padding(.top, 12)
|
|
.padding(.bottom, 8)
|
|
.contentShape(Rectangle())
|
|
|
|
if let onToggle {
|
|
Button(action: onToggle) { content }
|
|
.buttonStyle(.plain)
|
|
.accessibilityAddTraits(.isHeader)
|
|
} else {
|
|
content.accessibilityAddTraits(.isHeader)
|
|
}
|
|
}
|
|
}
|