import SwiftUI import OnyxDesign /// Die Farbwahl. /// /// Drei Farben, nicht zehn: die Akzentfarbe, mit der Onyx sich selbst zeichnet, /// und das Paar für Herunter- und Hochladen. Die Signalfarben stehen bewusst /// nicht hier — Gelb heißt Warnung, Rot heißt kritisch, und wer das umstellen /// kann, kann die Bedeutung zerstören. struct ColorSettingsView: View { @Bindable var theme: OnyxTheme /// Ein paar Vorschläge, damit man nicht im Farbwähler anfangen muss. /// /// Alle gedämpft: Onyx ist eine dunkle Fläche, und eine volle Sättigung /// darauf sticht, statt zu leiten. private static let suggestions: [(name: LocalizedStringKey, hex: String)] = [ ("color.suggestion.onyx", "#7FA8FF"), ("color.suggestion.mint", "#6FCF97"), ("color.suggestion.amber", "#E8B44A"), ("color.suggestion.coral", "#E5675C"), ("color.suggestion.lilac", "#B79CFF"), ("color.suggestion.slate", "#9AA6B2"), ] var body: some View { Form { Section("color.section.accent") { ColorPicker(selection: $theme.accent, supportsOpacity: false) { Text("color.accent") } HStack(spacing: 8) { ForEach(Self.suggestions, id: \.hex) { suggestion in Swatch(hex: suggestion.hex, name: suggestion.name, isSelected: theme.accent.onyxHex == suggestion.hex) { theme.accent = Color(onyxHex: suggestion.hex) ?? theme.accent } } Spacer(minLength: 0) } Button { theme.adoptSystemAccent() } label: { Text("color.adoptSystem") } Text("color.accent.hint") .font(.caption).foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) } Section("color.section.network") { ColorPicker(selection: $theme.download, supportsOpacity: false) { Text("color.download") } ColorPicker(selection: $theme.upload, supportsOpacity: false) { Text("color.upload") } Button { let previous = theme.download theme.download = theme.upload theme.upload = previous } label: { Text("color.swap") } Text("color.network.hint") .font(.caption).foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) } Section("color.section.fixed") { // Sichtbar, aber nicht bedienbar: sonst sucht man die // Warnfarbe hier und findet sie nirgends. FixedRow(color: Onyx.Color.positive, label: "color.fixed.positive") FixedRow(color: Onyx.Color.warning, label: "color.fixed.warning") FixedRow(color: Onyx.Color.critical, label: "color.fixed.critical") Text("color.fixed.hint") .font(.caption).foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) } Section { Button { theme.reset() } label: { Text("color.reset") } .disabled(theme.isDefault) } } .formStyle(.grouped) // Der eigene Untergrund des Formulars weicht ein, zwei Prozent von dem // des Fensters ab. In Dunkelgrau sieht man genau das als Kante. .scrollContentBackground(.hidden) } } /// Ein Farbfeld zum Anklicken. private struct Swatch: View { let hex: String let name: LocalizedStringKey let isSelected: Bool let action: () -> Void var body: some View { Button(action: action) { Circle() .fill(Color(onyxHex: hex) ?? .gray) .frame(width: 20, height: 20) .overlay { // Der Ring statt eines Hakens: ein Haken auf einer dunklen // Farbe ist nicht zu sehen, auf einer hellen nicht auf // einer dunklen Fläche. Circle() .strokeBorder(.primary, lineWidth: isSelected ? 2 : 0) .padding(-3) } } .buttonStyle(.plain) .help(Text(name)) } } private struct FixedRow: View { let color: Color let label: LocalizedStringKey var body: some View { HStack { Text(label) Spacer(minLength: 12) Circle().fill(color).frame(width: 14, height: 14) } } }