From 2c608ed9cb11f3e835f577994b5627b9b7910f4f Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Mon, 20 Jul 2026 19:14:04 -0500 Subject: feat(a11y): unlock light mode and add appearance preference (#21 phase 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the 16 scattered .preferredColorScheme(.dark) calls and the one .toolbarColorScheme, and applies appearance in exactly one place — the WindowGroup in DomainDigApp. Re-applying per view is what let the lock spread across eight files unnoticed until light mode was unreachable. Adds AppAppearance (System / Light / Dark) in @AppStorage, exposed under Settings > Display next to Density. Honouring the system setting and offering an override is one key, and it keeps the deliberate dark aesthetic reachable for anyone who wants it. Also replaces .secondary with AppTextSecondary across 191 sites. iOS's own secondaryLabel is 3.29:1 on a light card — below AA — which never showed while the app was locked to dark, where the same colour reads 6.32:1. Unlocking light mode is precisely what exposed it, so it belongs here rather than in a later phase: without it, light mode would ship with body text under 4.5:1 app-wide. Dark mode reports 18 findings, unchanged from phase 1 — no regression from unlocking. Light mode reports 21. The three extra are iOS-rendered Section headers (TIER, PREFERENCES, SERVICES) using the system's grey; overriding system header styling across every section to gain ~0.3:1 on decorative labels is a poor trade and is left alone. Two long-standing Settings contrast findings are now explained. They are the last rows of a section sitting under the translucent tab bar, so the audit measures text against a blended background — confirmed by screenshot, present in dark mode since phase 0, and standard iOS scroll-under behaviour rather than a defect. --- DomainDig/WorkflowsView.swift | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'DomainDig/WorkflowsView.swift') diff --git a/DomainDig/WorkflowsView.swift b/DomainDig/WorkflowsView.swift index 2195af5..d628ba4 100644 --- a/DomainDig/WorkflowsView.swift +++ b/DomainDig/WorkflowsView.swift @@ -22,7 +22,7 @@ struct WorkflowsView: View { Section { Text(limitMessage) .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } .listRowBackground(Color(.appSurface)) } @@ -54,7 +54,6 @@ struct WorkflowsView: View { .sheet(item: workflowSummaryBinding) { summary in WorkflowRunSummaryView(viewModel: viewModel, summary: summary) } - .preferredColorScheme(.dark) } private var workflowSummaryBinding: Binding { @@ -78,7 +77,7 @@ struct WorkflowsView: View { HStack { Text(viewModel.batchProgressLabel) .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) Spacer() if viewModel.batchLookupRunning { Button("Cancel") { @@ -142,23 +141,23 @@ private struct WorkflowRowView: View { Spacer(minLength: 8) Text("\(workflow.domains.count) domains") .font(appDensity.font(.caption2)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } Text("Updated \(workflow.updatedAt.formatted(date: .abbreviated, time: .shortened))") .font(appDensity.font(.caption2)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) if let collaboration = workflow.collaboration, collaboration.isShared { Text("\(collaboration.ownership.title) • \(collaboration.permission.title)") .font(appDensity.font(.caption2)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } if let notes = workflow.notes, !notes.isEmpty { Text(notes) .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) .lineLimit(2) } } @@ -197,12 +196,12 @@ struct WorkflowDetailView: View { if let notes = workflow.notes, !notes.isEmpty { Text(notes) .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } if let collaboration = workflow.collaboration, collaboration.isShared { Text("\(collaboration.ownership.title) • \(collaboration.permission.title)") .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } } @@ -277,7 +276,7 @@ struct WorkflowDetailView: View { if !latestSummary.workflowInsights.isEmpty { Text(latestSummary.workflowInsights[0].description) .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } Button { @@ -306,7 +305,7 @@ struct WorkflowDetailView: View { if workflow.domains.isEmpty { Text("No domains in this workflow") .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } else { ForEach(workflow.domains, id: \.self) { domain in Button { @@ -318,7 +317,7 @@ struct WorkflowDetailView: View { .foregroundStyle(.primary) Spacer() Image(systemName: "arrow.up.right.circle") - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } } .buttonStyle(.plain) @@ -355,17 +354,16 @@ struct WorkflowDetailView: View { } else { Text("Workflow not found") .font(appDensity.font(.callout)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } } - .preferredColorScheme(.dark) } private func statRow(label: String, value: String) -> some View { HStack { Text(label) .font(appDensity.font(.caption)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) Spacer() Text(value) .font(appDensity.font(.callout)) @@ -449,7 +447,6 @@ struct WorkflowComposerView: View { } } } - .preferredColorScheme(.dark) } private var parsedDomains: [String] { @@ -507,7 +504,7 @@ struct WorkflowRunSummaryView: View { .foregroundStyle(.primary) Text(insight.domainsInvolved.joined(separator: ", ")) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } } } @@ -517,7 +514,7 @@ struct WorkflowRunSummaryView: View { if visibleResults.isEmpty { Text("No domains with meaningful changes or warnings") .font(.system(.caption, design: .monospaced)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) } else { ForEach(visibleResults) { result in if let entry = viewModel.historyEntry(for: result) { @@ -578,14 +575,13 @@ struct WorkflowRunSummaryView: View { } } } - .preferredColorScheme(.dark) } private func statRow(label: String, value: String) -> some View { HStack { Text(label) .font(.system(.caption, design: .monospaced)) - .foregroundStyle(.secondary) + .foregroundStyle(Color(.appTextSecondary)) Spacer() Text(value) .font(.system(.callout, design: .monospaced)) @@ -687,7 +683,6 @@ struct WorkflowBulkAddSheet: View { } } } - .preferredColorScheme(.dark) } private var selectedDomainList: [String] { -- cgit v1.2.3