Files
onyx/Onyx/ColorSettingsView.swift
Scarriffle 2c3b3cdd55 Einstellungen: die Linie unter den Reitern ist weg, und eine Fläche für alles
Die Linie kam von `TabView` selbst: es zieht unter seiner Leiste einen Trenner
quer durchs Fenster, und der lässt sich nicht abschalten. Der Abstand nach
oben, den ich beim letzten Mal eingebaut habe, hat deshalb nichts geändert —
der Trenner ist mitgewandert. Jetzt ist die Reiterleiste selbst gebaut, ein
Auswahlfeld über dem Inhalt, dann gibt es die Linie gar nicht erst.

Der zweite Punkt hat dieselbe Wurzel: die Formulare bringen ihren eigenen
Untergrund mit, der Rest des Fensters hat den des Systems. In Dunkelgrau
liegen die beiden ein, zwei Prozent auseinander — sichtbar als Kante quer
durchs Fenster, genau dort, wo das Formular anfängt. Der Untergrund der
Formulare ist jetzt abgeschaltet, und das ganze Fenster hat einen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 23:34:47 +02:00

135 lines
4.8 KiB
Swift

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)
}
}
}