diff options
| author | Christian Cleberg <[email protected]> | 2026-07-20 20:25:01 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-07-20 21:03:10 -0500 |
| commit | 9e58a36915bb1fe8cf88423c9519c0c12dbbf2e2 (patch) | |
| tree | a9397c168adcdb63deda80440511063ef57732f4 /DomainDig/DashboardView.swift | |
| parent | 2c608ed9cb11f3e835f577994b5627b9b7910f4f (diff) | |
| download | domain-dig-9e58a36915bb1fe8cf88423c9519c0c12dbbf2e2.tar.gz domain-dig-9e58a36915bb1fe8cf88423c9519c0c12dbbf2e2.tar.bz2 domain-dig-9e58a36915bb1fe8cf88423c9519c0c12dbbf2e2.zip | |
fix(a11y): rebalance the light palette so hues survive
Reported as "colors seem muted and hard to see on light mode", and
correct. The light palette optimised contrast and produced mud: #7A5600
reads olive rather than amber, #146C2E bottle-dark rather than green.
Contrast passed while the UI got harder to read, because hue identity is
what distinguishes warning from critical at a glance.
Two causes, both fixed.
Every foreground was required to clear 4.5:1 against its own 16% badge
tint — the harshest surface it ever sits on — which pushed each colour
about 20% darker than the common case needed. Most of what is actually on
screen is plain text on a card, with far more headroom. The fill is now
decoupled from the foreground: AppStatusTone carries a foreground and a
surface authored independently, with matching …Surface colorsets, so a
foreground no longer has to survive a wash of itself. Every status
foreground is now fully saturated.
And warning was yellow. Yellow cannot stay yellow at a lightness low
enough to pass 4.5:1 on white — it becomes olive. That is colorimetric,
not a tuning problem. Warning is now orange: #AD5100 light, #FF9F0A dark.
New light values: positive #008035, warning #AD5100, critical #CC0700.
Worst-case ratios 4.54–6.76 across page, card, and surface in both
schemes. Audit findings are unchanged — light 21, dark 18 — so the
vividness costs nothing.
Also picks up a literal .blue missed in phase 1: DomainDiffItem's
low-severity change colour, which the phase 1 sweep did not cover because
its pattern listed only cyan/yellow/green/red/orange/pink.
Diffstat (limited to 'DomainDig/DashboardView.swift')
| -rw-r--r-- | DomainDig/DashboardView.swift | 24 |
1 files changed, 12 insertions, 12 deletions
diff --git a/DomainDig/DashboardView.swift b/DomainDig/DashboardView.swift index 8d41ccb..16c4478 100644 --- a/DomainDig/DashboardView.swift +++ b/DomainDig/DashboardView.swift @@ -237,20 +237,20 @@ struct DashboardView: View { let criticalCount = states.filter { $0.health == .critical }.count let warningCount = states.filter { $0.health == .warning }.count let title: String - let color: Color + let tone: AppStatusTone let systemImage: String if criticalCount > 0 { title = "\(criticalCount) critical" - color = Color(.statusCritical) + tone = .critical systemImage = "exclamationmark.octagon.fill" } else if warningCount > 0 { title = "\(warningCount) warning" - color = Color(.statusWarning) + tone = .warning systemImage = "exclamationmark.triangle.fill" } else { title = "Healthy" - color = Color(.statusPositive) + tone = .positive systemImage = "checkmark.circle.fill" } @@ -258,8 +258,8 @@ struct DashboardView: View { model: .init( title: title, systemImage: systemImage, - foregroundColor: color, - backgroundColor: color.opacity(0.16) + foregroundColor: tone.foreground, + backgroundColor: tone.surface ) ) } @@ -331,11 +331,11 @@ private struct PortfolioAttentionRow: View { private var badgeModel: AppStatusBadgeModel { switch item.health { case .healthy: - return .init(title: "Healthy", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) + return .init(title: "Healthy", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositiveSurface)) case .warning: - return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) + return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarningSurface)) case .critical: - return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) + return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCriticalSurface)) } } } @@ -370,11 +370,11 @@ private struct PortfolioExpiryRow: View { private var badgeModel: AppStatusBadgeModel { switch state.certificateExpiryState { case .none: - return .init(title: "Healthy", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) + return .init(title: "Healthy", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositiveSurface)) case .warning: - return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) + return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarningSurface)) case .critical: - return .init(title: "Critical", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) + return .init(title: "Critical", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCriticalSurface)) } } } |
