From eb8a0d30da0cc150e95d44bad998c13ee2defc25 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Mon, 20 Jul 2026 18:16:01 -0500 Subject: feat(a11y): semantic colour system (#21 phase 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces every hard-coded colour with semantic asset colours that adapt to light, dark, and Increase Contrast. Dark mode stays locked, so this is a pure refactor: the audit reports the same findings before and after. The accent is now blue rather than cyan, per the tech/DNS theme. Why custom values rather than the system palette: every system colour fails WCAG AA in light mode. Measured on white — systemYellow 1.51:1, systemOrange 2.20:1, systemGreen 2.22:1, systemCyan 2.54:1, systemRed 3.55:1. All of them pass in dark mode, which is why the dark-locked app looked fine, and why unlocking light mode was never a matter of deleting .preferredColorScheme(.dark). Every new value clears 4.5:1 as text on its page, its card, and its own 16% badge tint — the way AppStatusBadgeView actually draws it. The accent needed splitting in two. As text on a dark background it must be light; as a fill behind a white label it must be dark. #4DA3FF reads 8.00:1 as text on black but 2.63:1 behind white text, so StatusInfo / AccentColor cover the foreground role and AccentFill covers .borderedProminent. AppOnAccent is the label colour for a solid fill and flips by scheme. Colours live in Shared/Colors.xcassets rather than the app catalog: the Shared folder is already a synchronized group in all three targets, so the widget and share extension pick the palette up with no project-file surgery. AccentColor stays in the app catalog as the global tint — and is now actually defined, having been an empty colorset that silently left system controls rendering in stock blue while custom chrome used cyan. Two deliberate visual changes: orange folds into StatusWarning and pink into StatusCritical. They encoded the same severity as the colours they now share, and both sites also carry a text label. Audit findings drop 15 to 14, and one of the originals turned out to be a phantom: the Inspect contrast failure was the Run button in its disabled state, which WCAG 1.4.3 exempts. testInspectScreen now types a domain first so the audit measures an enabled control. Findings also carry the offending element now, so the remaining clipped-text items name themselves ("No Portfolio Yet", "Search domains") instead of being anonymous. --- .../AccentColor.colorset/Contents.json | 77 ++++++++++- DomainDig/BatchResultsView.swift | 20 +-- DomainDig/ContentView.swift | 150 +++++++++++---------- DomainDig/DashboardView.swift | 62 ++++----- DomainDig/DomainCompareView.swift | 4 +- DomainDig/DomainDig/AuditViews.swift | 48 +++---- DomainDig/DomainDigUI.swift | 42 +++--- DomainDig/HistoryView.swift | 18 +-- DomainDig/IntegrationsView.swift | 6 +- DomainDig/MonitoringView.swift | 28 ++-- DomainDig/PaywallView.swift | 2 +- DomainDig/SavedDomainsView.swift | 6 +- DomainDig/ScheduledReportsView.swift | 8 +- DomainDig/TimelineView.swift | 10 +- DomainDig/WatchlistView.swift | 46 +++---- DomainDig/WorkflowsView.swift | 18 +-- 16 files changed, 310 insertions(+), 235 deletions(-) (limited to 'DomainDig') diff --git a/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json b/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897..9d1e3b9 100644 --- a/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/DomainDig/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,11 +1,78 @@ { - "colors" : [ + "colors": [ { - "idiom" : "universal" + "idiom": "universal", + "color": { + "color-space": "srgb", + "components": { + "red": "0x00", + "green": "0x00", + "blue": "0xFF", + "alpha": "1.000" + } + } + }, + { + "idiom": "universal", + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0x4D", + "green": "0xA3", + "blue": "0xFF", + "alpha": "1.000" + } + } + }, + { + "idiom": "universal", + "appearances": [ + { + "appearance": "contrast", + "value": "high" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0x00", + "green": "0x00", + "blue": "0xCC", + "alpha": "1.000" + } + } + }, + { + "idiom": "universal", + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + }, + { + "appearance": "contrast", + "value": "high" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0x7F", + "green": "0xBF", + "blue": "0xFF", + "alpha": "1.000" + } + } } ], - "info" : { - "author" : "xcode", - "version" : 1 + "info": { + "author": "xcode", + "version": 1 } } diff --git a/DomainDig/BatchResultsView.swift b/DomainDig/BatchResultsView.swift index 027d074..afef5cb 100644 --- a/DomainDig/BatchResultsView.swift +++ b/DomainDig/BatchResultsView.swift @@ -13,7 +13,7 @@ struct BatchResultsView: View { if viewModel.batchLookupRunning { VStack(alignment: .trailing, spacing: 4) { ProgressView(value: Double(viewModel.batchCompletedCount), total: Double(max(viewModel.batchTotalCount, 1))) - .tint(.cyan) + .tint(Color(.statusInfo)) .frame(width: 120) Text(viewModel.batchProgressLabel) .font(appDensity.font(.caption2)) @@ -110,7 +110,7 @@ struct BatchResultRowView: View { if let errorMessage = result.errorMessage { Text(errorMessage) .font(appDensity.font(.caption2)) - .foregroundStyle(result.status == .failed ? .red : .secondary) + .foregroundStyle(result.status == .failed ? Color(.statusCritical) : .secondary) } } .frame(maxWidth: .infinity, alignment: .leading) @@ -138,29 +138,29 @@ struct BatchResultRowView: View { title: availabilityText, systemImage: "exclamationmark.circle", foregroundColor: .secondary, - backgroundColor: Color(.systemGray5).opacity(0.55) + backgroundColor: Color(.appSurfaceElevated) ) } private var quickStatusBadge: AppStatusBadgeModel { switch result.status { case .pending: - return .init(title: "Pending", systemImage: "clock", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: "Pending", systemImage: "clock", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) case .running: - return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16)) + return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16)) case .completed: if result.changeClassification == .critical || result.certificateWarningLevel == .critical || result.riskLevel == .high { - return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) } if result.changeClassification == .warning || result.changeSeverity == .medium || result.certificateWarningLevel == .warning { - return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) } if result.quickStatus == "Changed" { - return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16)) + return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16)) } - return .init(title: "Stable", systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Stable", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .failed: - return .init(title: "Failed", systemImage: "xmark.circle.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: "Failed", systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) } } } diff --git a/DomainDig/ContentView.swift b/DomainDig/ContentView.swift index 40c97d1..7eec8a0 100644 --- a/DomainDig/ContentView.swift +++ b/DomainDig/ContentView.swift @@ -167,7 +167,7 @@ struct ContentView: View { } .background( LinearGradient( - colors: [Color.black, Color(.systemGray6).opacity(0.12)], + colors: [Color(.appBackground), Color(.appSurface)], startPoint: .top, endPoint: .bottom ) @@ -302,7 +302,7 @@ struct ContentView: View { .keyboardType(.URL) .padding(.horizontal, 12) .padding(.vertical, appDensity.metrics.controlVerticalPadding) - .background(Color(.systemGray6)) + .background(Color(.appSurfaceElevated)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) .focused($focusedInputField, equals: .singleDomain) .onSubmit { @@ -320,6 +320,7 @@ struct ContentView: View { .frame(minHeight: appDensity.metrics.controlMinHeight) } .buttonStyle(.borderedProminent) + .tint(Color(.accentFill)) .disabled(viewModel.trimmedDomain.isEmpty) } else { if FeatureAccessService.hasAccess(to: .batchOperations) { @@ -346,7 +347,7 @@ struct ContentView: View { .lineLimit(4...10) .padding(.horizontal, 12) .padding(.vertical, appDensity.metrics.controlVerticalPadding) - .background(Color(.systemGray6)) + .background(Color(.appSurfaceElevated)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) .focused($focusedInputField, equals: .bulkDomains) @@ -360,6 +361,7 @@ struct ContentView: View { .frame(minHeight: appDensity.metrics.controlMinHeight) } .buttonStyle(.borderedProminent) + .tint(Color(.accentFill)) .disabled(viewModel.bulkInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || viewModel.batchLookupRunning) } } else { @@ -549,7 +551,7 @@ struct ContentView: View { } label: { Image(systemName: viewModel.isCurrentDomainSaved ? "bookmark.fill" : "bookmark") .font(appDensity.font(.body, design: .default)) - .foregroundStyle(viewModel.isCurrentDomainSaved ? .yellow : .secondary) + .foregroundStyle(viewModel.isCurrentDomainSaved ? Color(.statusWarning) : .secondary) } Menu { Button("Export TXT") { @@ -671,7 +673,7 @@ struct ContentView: View { .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 8) .padding(.horizontal, 10) - .background(Color(.systemGray6).opacity(0.5)) + .background(Color(.appSurface)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) } } @@ -696,7 +698,7 @@ struct ContentView: View { } .frame(maxWidth: .infinity, alignment: .leading) .padding(appDensity.metrics.cardPadding) - .background(Color(.systemGray6)) + .background(Color(.appSurfaceElevated)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) } @@ -792,7 +794,7 @@ struct SummaryView: View { .frame(minHeight: appDensity.metrics.rowMinHeight + 12, alignment: .topLeading) .frame(maxWidth: .infinity, alignment: .leading) .padding(appDensity.metrics.cardPadding) - .background(Color(.systemGray6).opacity(0.5)) + .background(Color(.appSurface)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) } } @@ -851,22 +853,22 @@ struct RiskSummaryCardView: View { private var levelColor: Color { switch report.riskAssessment.level { case .low: - return .green + return Color(.statusPositive) case .medium: - return .yellow + return Color(.statusWarning) case .high: - return .red + return Color(.statusCritical) } } private func factorColor(_ impact: RiskImpact) -> Color { switch impact { case .positive: - return .green + return Color(.statusPositive) case .neutral: return .secondary case .negative: - return .red + return Color(.statusCritical) } } } @@ -888,7 +890,7 @@ struct InsightsSummaryCardView: View { HStack(alignment: .top, spacing: 8) { Image(systemName: "chart.line.uptrend.xyaxis") .font(appDensity.font(.caption2)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) .padding(.top, 2) Text(insight) .font(appDensity.font(.caption)) @@ -995,13 +997,13 @@ struct LookupStatusBannerView: View { private var color: Color { switch resultSource { case .live: - return .green + return Color(.statusPositive) case .cached: return .secondary case .mixed: - return .yellow + return Color(.statusWarning) case .snapshot: - return .orange + return Color(.statusWarning) } } @@ -1029,7 +1031,7 @@ struct DomainChangeSummaryView: View { HStack { Label(summary.hasChanges ? "Changed" : "Stable", systemImage: summary.hasChanges ? "arrow.triangle.2.circlepath" : "checkmark.circle") .font(appDensity.font(.caption)) - .foregroundStyle(summary.hasChanges ? severityColor(summary.severity) : .green) + .foregroundStyle(summary.hasChanges ? severityColor(summary.severity) : Color(.statusPositive)) Spacer() Text(summary.severity.title.uppercased()) .font(appDensity.font(.caption2)) @@ -1079,13 +1081,13 @@ struct DomainChangeSummaryView: View { if let riskScoreDelta = summary.riskScoreDelta { Text("Risk delta: \(riskScoreDelta >= 0 ? "+" : "")\(riskScoreDelta)") .font(appDensity.font(.caption2)) - .foregroundStyle(riskScoreDelta > 0 ? .orange : .secondary) + .foregroundStyle(riskScoreDelta > 0 ? Color(.statusWarning) : .secondary) } if let contextNote = summary.contextNote { Text(contextNote) .font(appDensity.font(.caption2)) - .foregroundStyle(.orange) + .foregroundStyle(Color(.statusWarning)) } } .padding(.top, 4) @@ -1101,9 +1103,9 @@ struct DomainChangeSummaryView: View { case .low: return .secondary case .medium: - return .yellow + return Color(.statusWarning) case .high: - return .red + return Color(.statusCritical) } } @@ -1205,7 +1207,7 @@ struct DomainDiffView: View { } } .padding(10) - .background(item.hasChanges ? changeColor(for: item).opacity(0.08) : Color(.systemGray6).opacity(0.25)) + .background(item.hasChanges ? changeColor(for: item).opacity(0.08) : Color(.appSurface)) .cornerRadius(8) } } label: { @@ -1225,7 +1227,7 @@ struct DomainDiffView: View { .overlay { if highlightedSectionID == section.id { RoundedRectangle(cornerRadius: 12) - .stroke(Color.cyan.opacity(0.55), lineWidth: 1) + .stroke(Color(.statusInfo).opacity(0.55), lineWidth: 1) } } } @@ -1258,9 +1260,9 @@ struct DomainDiffView: View { case .low: return .blue case .medium: - return .yellow + return Color(.statusWarning) case .high: - return .red + return Color(.statusCritical) } } @@ -1269,9 +1271,9 @@ struct DomainDiffView: View { case .low: return .blue case .medium: - return .yellow + return Color(.statusWarning) case .high: - return .red + return Color(.statusCritical) } } @@ -1337,7 +1339,7 @@ struct DomainSectionView: View { CollapsibleSectionView(title: "Domain", isCollapsed: $isCollapsed) { if let trackedDomain { HStack(spacing: 8) { - AppStatusBadgeView(model: .init(title: "Tracked", systemImage: "eye.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16))) + AppStatusBadgeView(model: .init(title: "Tracked", systemImage: "eye.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16))) Button { onTogglePinned() } label: { @@ -1638,7 +1640,7 @@ struct IntelligenceSectionView: View { if item.isEphemeral { Text("Ephemeral") .font(appDensity.font(.caption2)) - .foregroundStyle(.yellow) + .foregroundStyle(Color(.statusWarning)) } } Text("First \(item.firstSeen.formatted(date: .abbreviated, time: .omitted)) • Last \(item.lastSeen.formatted(date: .abbreviated, time: .omitted)) • Seen \(item.recurrenceCount)x") @@ -1667,7 +1669,7 @@ struct IntelligenceSectionView: View { VStack(alignment: .leading, spacing: 8) { Text(title) .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) content() } } @@ -1758,7 +1760,7 @@ struct SubdomainsSectionView: View { HStack { Text("\(group.label).*") .font(appDensity.font(.caption)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) Spacer() Text("\(group.subdomains.count)") .font(appDensity.font(.caption2)) @@ -1776,10 +1778,10 @@ struct SubdomainsSectionView: View { if row.isInteresting { Text("Interesting") .font(.system(.caption2, design: .monospaced)) - .foregroundStyle(.yellow) + .foregroundStyle(Color(.statusWarning)) .padding(.horizontal, 8) .padding(.vertical, 4) - .background(Color.yellow.opacity(0.14)) + .background(Color(.statusWarning).opacity(0.14)) .clipShape(Capsule()) } } @@ -1883,7 +1885,7 @@ struct DNSSectionView: View { Text(section.title) .font(.system(.subheadline, design: .monospaced)) .fontWeight(.semibold) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) if let message = section.message { MessageRowView(text: message.text, isError: message.isError) @@ -1910,7 +1912,7 @@ struct DNSSectionView: View { Text("PTR") .font(.system(.subheadline, design: .monospaced)) .fontWeight(.semibold) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) SectionTrustMetadataView(provenance: ptrProvenance, confidence: nil) MessageRowView(text: ptrMessage.text, isError: ptrMessage.isError) } @@ -1920,7 +1922,7 @@ struct DNSSectionView: View { HStack { Text("History") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) Spacer() if let onLoadHistory, history.isEmpty, !historyLoading, !showsHistoryPlaceholder { Button("Load") { @@ -1990,7 +1992,7 @@ struct WebSectionView: View { HStack { Text("TLS") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) Spacer() if !sslLoading { AppStatusBadgeView(model: AppStatusFactory.tls(sslInfo: sslInfo, error: sslError)) @@ -2034,7 +2036,7 @@ struct WebSectionView: View { CardView { Text("Headers") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) SectionTrustMetadataView(provenance: httpProvenance, confidence: nil) if headersLoading { ProgressView("Fetching headers…") @@ -2052,7 +2054,7 @@ struct WebSectionView: View { HStack(alignment: .top, spacing: 4) { Text(header.name + ":") .font(appDensity.font(.caption)) - .foregroundStyle(header.isSecurityHeader ? .yellow : .cyan) + .foregroundStyle(header.isSecurityHeader ? Color(.statusWarning) : Color(.statusInfo)) Text(header.value) .font(appDensity.font(.caption)) .foregroundStyle(.primary) @@ -2067,7 +2069,7 @@ struct WebSectionView: View { HStack { Text("Redirects") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) Spacer() if let finalURL { AppCopyButton(value: finalURL, label: "Copy redirect URL") @@ -2093,7 +2095,7 @@ struct WebSectionView: View { .frame(width: 16, alignment: .trailing) Text(redirect.statusCode) .font(appDensity.font(.caption)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) .frame(width: 36, alignment: .leading) Text(redirect.url) .font(appDensity.font(.caption)) @@ -2163,7 +2165,7 @@ struct EmailSectionView: View { HStack(spacing: 8) { Text(row.label) .font(appDensity.font(.caption)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) .frame(width: 76, alignment: .leading) AppStatusBadgeView(model: emailRowBadge(row)) } @@ -2186,13 +2188,13 @@ struct EmailSectionView: View { private func emailRowBadge(_ row: EmailRowViewData) -> AppStatusBadgeModel { switch row.statusTone { case .success: - return .init(title: row.status, systemImage: "checkmark.shield.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: row.status, systemImage: "checkmark.shield.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .warning: - return .init(title: row.status, systemImage: "shield.lefthalf.filled", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: row.status, systemImage: "shield.lefthalf.filled", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .failure: - return .init(title: row.status, systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: row.status, systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) case .primary, .secondary: - return .init(title: row.status, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: row.status, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } } } @@ -2227,7 +2229,7 @@ struct NetworkSectionView: View { CardView { Text("Reachability") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) SectionTrustMetadataView(provenance: reachabilityProvenance, confidence: nil) if reachabilityLoading { ProgressView("Checking ports…") @@ -2252,7 +2254,7 @@ struct NetworkSectionView: View { CardView(allowsHorizontalScroll: false) { Text("Location") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) SectionTrustMetadataView(provenance: geolocationProvenance, confidence: geolocationConfidence) if geolocationLoading { ProgressView("Looking up location…") @@ -2284,13 +2286,13 @@ struct NetworkSectionView: View { CardView(allowsHorizontalScroll: false) { Text("Port Scan") .font(appDensity.font(.subheadline, weight: .semibold)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) SectionTrustMetadataView(provenance: portScanProvenance, confidence: nil) if isCloudflareProxied { Text("Domain is behind Cloudflare's proxy. Results reflect the edge, not the origin.") .font(appDensity.font(.caption2)) - .foregroundStyle(.orange) + .foregroundStyle(Color(.statusWarning)) .fixedSize(horizontal: false, vertical: true) } @@ -2314,7 +2316,7 @@ struct NetworkSectionView: View { .autocorrectionDisabled() .keyboardType(.numberPad) .padding(10) - .background(Color(.systemGray6).opacity(0.5)) + .background(Color(.appSurface)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) Button("Scan") { @@ -2322,6 +2324,7 @@ struct NetworkSectionView: View { onScanCustomPorts() } .buttonStyle(.borderedProminent) + .tint(Color(.accentFill)) .disabled(customPortScanLoading) if customPortScanLoading { @@ -2344,13 +2347,13 @@ struct NetworkSectionView: View { private func reachabilityBadge(_ row: ReachabilityRowViewData) -> AppStatusBadgeModel { switch row.statusTone { case .success: - return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .warning: - return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .failure: - return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) case .primary, .secondary: - return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } } } @@ -2395,13 +2398,13 @@ struct PortRowsView: View { private func portBadge(_ row: PortScanRowViewData) -> AppStatusBadgeModel { switch row.statusTone { case .success: - return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: row.statusLabel, systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .warning: - return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: row.statusLabel, systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .failure: - return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) case .primary, .secondary: - return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } } } @@ -2413,7 +2416,7 @@ struct SectionTitleView: View { var body: some View { Text(title) .font(appDensity.font(.headline, design: .default, weight: .semibold)) - .foregroundStyle(.white) + .foregroundStyle(.primary) } } @@ -2442,7 +2445,7 @@ struct CardView: View { } .frame(maxWidth: .infinity, alignment: .leading) .padding(appDensity.metrics.cardPadding) - .background(Color(.systemGray6).opacity(0.5)) + .background(Color(.appSurface)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) } @@ -2484,7 +2487,7 @@ struct MessageRowView: View { var body: some View { Label(text, systemImage: isError ? "exclamationmark.triangle.fill" : "info.circle") .font(appDensity.font(.caption)) - .foregroundStyle(isError ? .red : .secondary) + .foregroundStyle(isError ? Color(.statusCritical) : .secondary) .lineLimit(nil) .fixedSize(horizontal: false, vertical: true) } @@ -2576,6 +2579,11 @@ struct LabeledValueRow: View { } } +/// Maps a row's semantic tone onto the app palette. +/// +/// See `Docs/ACCESSIBILITY.md` for the measured contrast ratios behind these +/// colours. Never reach for a literal (`Color(.statusCritical)`, `Color(.statusWarning)`, …) — the system +/// palette fails WCAG AA badly in light mode (systemYellow is 1.28:1 on white). enum ResultColors { static func color(for tone: ResultTone) -> Color { switch tone { @@ -2584,11 +2592,11 @@ enum ResultColors { case .secondary: return .secondary case .success: - return .green + return Color(.statusPositive) case .warning: - return .yellow + return Color(.statusWarning) case .failure: - return .red + return Color(.statusCritical) } } } @@ -2654,7 +2662,7 @@ struct SettingsView: View { if let errorMessage = purchaseService.errorMessage { Text(errorMessage) .font(appDensity.font(.caption, design: .default)) - .foregroundStyle(.red) + .foregroundStyle(Color(.statusCritical)) } } @@ -2789,7 +2797,7 @@ private struct HistoryNetworkSettingsView: View { if let customResolverError { Text(customResolverError) .font(appDensity.font(.caption, design: .default)) - .foregroundStyle(.red) + .foregroundStyle(Color(.statusCritical)) } } } @@ -2871,7 +2879,7 @@ private struct CloudSyncSettingsView: View { if let lastErrorMessage = cloudSyncService.lastErrorMessage { Text(lastErrorMessage) .font(appDensity.font(.caption, design: .default)) - .foregroundStyle(.red) + .foregroundStyle(Color(.statusCritical)) } } } @@ -2964,7 +2972,7 @@ private struct LocalAPISettingsView: View { Spacer() Text("\(log.statusCode)") .font(appDensity.font(.caption, design: .default)) - .foregroundStyle(log.statusCode >= 400 ? .red : .secondary) + .foregroundStyle(log.statusCode >= 400 ? Color(.statusCritical) : .secondary) } Text(log.timestamp.formatted(date: .abbreviated, time: .standard)) @@ -3744,8 +3752,8 @@ extension ChangeImpactClassification { var color: Color { switch self { case .informational: return .secondary - case .warning: return .yellow - case .critical: return .red + case .warning: return Color(.statusWarning) + case .critical: return Color(.statusCritical) } } } diff --git a/DomainDig/DashboardView.swift b/DomainDig/DashboardView.swift index 398ff3e..da8d90a 100644 --- a/DomainDig/DashboardView.swift +++ b/DomainDig/DashboardView.swift @@ -22,20 +22,20 @@ struct DashboardView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { Section { LazyVGrid(columns: summaryColumns, spacing: 10) { - summaryCard(title: "Total Domains", value: viewModel.portfolioDashboardData.snapshot.totalDomains, filter: .all, tint: .cyan) - summaryCard(title: "Healthy", value: viewModel.portfolioDashboardData.snapshot.healthyCount, filter: .healthy, tint: .green) - summaryCard(title: "Warning", value: viewModel.portfolioDashboardData.snapshot.warningCount, filter: .warning, tint: .yellow) - summaryCard(title: "Critical", value: viewModel.portfolioDashboardData.snapshot.criticalCount, filter: .critical, tint: .red) - summaryCard(title: "Changes (24h)", value: viewModel.portfolioDashboardData.snapshot.changedLast24h, filter: .changed, tint: .orange) - summaryCard(title: "Unreachable", value: viewModel.portfolioDashboardData.snapshot.unreachableCount, filter: .unreachable, tint: .pink) + summaryCard(title: "Total Domains", value: viewModel.portfolioDashboardData.snapshot.totalDomains, filter: .all, tint: Color(.statusInfo)) + summaryCard(title: "Healthy", value: viewModel.portfolioDashboardData.snapshot.healthyCount, filter: .healthy, tint: Color(.statusPositive)) + summaryCard(title: "Warning", value: viewModel.portfolioDashboardData.snapshot.warningCount, filter: .warning, tint: Color(.statusWarning)) + summaryCard(title: "Critical", value: viewModel.portfolioDashboardData.snapshot.criticalCount, filter: .critical, tint: Color(.statusCritical)) + summaryCard(title: "Changes (24h)", value: viewModel.portfolioDashboardData.snapshot.changedLast24h, filter: .changed, tint: Color(.statusWarning)) + summaryCard(title: "Unreachable", value: viewModel.portfolioDashboardData.snapshot.unreachableCount, filter: .unreachable, tint: Color(.statusCritical)) } .padding(.vertical, 4) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Quick Filters") { ScrollView(.horizontal, showsIndicators: false) { @@ -46,10 +46,10 @@ struct DashboardView: View { } label: { Text(filter.title) .font(appDensity.font(.caption, weight: .semibold)) - .foregroundStyle(viewModel.dashboardFilter == filter ? Color.black : Color.white) + .foregroundStyle(viewModel.dashboardFilter == filter ? Color(.appOnAccent) : Color.primary) .padding(.horizontal, 12) .padding(.vertical, 8) - .background(viewModel.dashboardFilter == filter ? Color.cyan : Color(.systemGray5).opacity(0.6)) + .background(viewModel.dashboardFilter == filter ? Color(.statusInfo) : Color(.appSurfaceElevated)) .clipShape(Capsule()) } .buttonStyle(.plain) @@ -58,7 +58,7 @@ struct DashboardView: View { .padding(.vertical, 4) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Recent Activity") { if viewModel.filteredPortfolioRecentActivity.isEmpty { @@ -76,7 +76,7 @@ struct DashboardView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Attention Required") { if viewModel.filteredPortfolioAttentionRequired.isEmpty { @@ -94,7 +94,7 @@ struct DashboardView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Expiring Soon") { if viewModel.filteredPortfolioExpiringSoon.isEmpty { @@ -110,7 +110,7 @@ struct DashboardView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Portfolio List") { if viewModel.filteredPortfolioGroups.isEmpty { @@ -150,11 +150,11 @@ struct DashboardView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Dashboard") .searchable(text: $viewModel.dashboardSearchText, prompt: "Search portfolio") .toolbar { @@ -196,7 +196,7 @@ struct DashboardView: View { .foregroundStyle(.secondary) Text("\(value)") .font(.system(size: 28, weight: .bold, design: .rounded)) - .foregroundStyle(.white) + .foregroundStyle(.primary) HStack { Circle() .fill(tint) @@ -218,13 +218,13 @@ struct DashboardView: View { if viewModel.dashboardFilter == filter { return AnyShapeStyle( LinearGradient( - colors: [Color.cyan.opacity(0.28), Color.cyan.opacity(0.12)], + colors: [Color(.statusInfo).opacity(0.28), Color(.statusInfo).opacity(0.12)], startPoint: .topLeading, endPoint: .bottomTrailing ) ) } - return AnyShapeStyle(Color(.systemGray5).opacity(0.45)) + return AnyShapeStyle(Color(.appSurfaceElevated)) } private func dashboardEmptyRow(_ message: String) -> some View { @@ -243,15 +243,15 @@ struct DashboardView: View { if criticalCount > 0 { title = "\(criticalCount) critical" - color = .red + color = Color(.statusCritical) systemImage = "exclamationmark.octagon.fill" } else if warningCount > 0 { title = "\(warningCount) warning" - color = .yellow + color = Color(.statusWarning) systemImage = "exclamationmark.triangle.fill" } else { title = "Healthy" - color = .green + color = Color(.statusPositive) systemImage = "checkmark.circle.fill" } @@ -297,11 +297,11 @@ private struct PortfolioActivityRow: View { private var iconColor: Color { switch item.health { case .healthy: - return .cyan + return Color(.statusInfo) case .warning: - return .yellow + return Color(.statusWarning) case .critical: - return .red + return Color(.statusCritical) } } } @@ -332,11 +332,11 @@ private struct PortfolioAttentionRow: View { private var badgeModel: AppStatusBadgeModel { switch item.health { case .healthy: - return .init(title: "Healthy", systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Healthy", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .warning: - return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .critical: - return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: "Critical", systemImage: "exclamationmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) } } } @@ -371,11 +371,11 @@ private struct PortfolioExpiryRow: View { private var badgeModel: AppStatusBadgeModel { switch state.certificateExpiryState { case .none: - return .init(title: "Healthy", systemImage: "lock.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Healthy", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .warning: - return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Warning", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .critical: - return .init(title: "Critical", systemImage: "xmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: "Critical", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) } } } diff --git a/DomainDig/DomainCompareView.swift b/DomainDig/DomainCompareView.swift index 96341c2..90ee5b1 100644 --- a/DomainDig/DomainCompareView.swift +++ b/DomainDig/DomainCompareView.swift @@ -63,11 +63,11 @@ struct DomainCompareView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Compare Domains") } diff --git a/DomainDig/DomainDig/AuditViews.swift b/DomainDig/DomainDig/AuditViews.swift index 8602bb3..df5a9a9 100644 --- a/DomainDig/DomainDig/AuditViews.swift +++ b/DomainDig/DomainDig/AuditViews.swift @@ -27,7 +27,7 @@ struct AuditListView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { Section("Audit Domains") { ForEach(groupedSessions, id: \.domain) { group in @@ -65,11 +65,11 @@ struct AuditListView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Audit Mode") .toolbar { if !viewModel.searchedDomain.isEmpty { @@ -132,7 +132,7 @@ struct AuditDomainTimelineView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Trend") { ForEach(viewModel.auditTimeline(for: domain)) { point in @@ -152,10 +152,10 @@ struct AuditDomainTimelineView: View { .padding(.vertical, 2) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle(domain) .toolbar { ToolbarItem(placement: .topBarTrailing) { @@ -218,7 +218,7 @@ struct AuditSessionDetailView: View { .foregroundStyle(.secondary) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Audit Summary") { LabeledContent("Findings", value: "\(session.findings.count)") @@ -228,7 +228,7 @@ struct AuditSessionDetailView: View { LabeledContent("Highest Severity", value: severity.title) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Reviewer Notes") { TextEditor(text: $notesDraft) @@ -240,7 +240,7 @@ struct AuditSessionDetailView: View { viewModel.updateAuditNotes(notesDraft, sessionID: session.id) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Checklist") { ForEach(session.checklist) { item in @@ -249,7 +249,7 @@ struct AuditSessionDetailView: View { } label: { HStack(alignment: .top, spacing: 10) { Image(systemName: item.isComplete ? "checkmark.circle.fill" : "circle") - .foregroundStyle(item.isComplete ? Color.green : .secondary) + .foregroundStyle(item.isComplete ? Color(.statusPositive) : .secondary) VStack(alignment: .leading, spacing: 4) { Text(item.title) .font(appDensity.font(.callout)) @@ -264,7 +264,7 @@ struct AuditSessionDetailView: View { .buttonStyle(.plain) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Findings") { if session.findings.isEmpty { @@ -301,7 +301,7 @@ struct AuditSessionDetailView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Evidence Snapshot") { LabeledContent("Availability", value: availabilityTitle(session.evidence.report.availability)) @@ -311,7 +311,7 @@ struct AuditSessionDetailView: View { LabeledContent("Reachability", value: session.evidence.report.network.reachabilitySummary) LabeledContent("Registrar", value: session.evidence.report.ownership?.registrar ?? "Unavailable") } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) if !session.evidence.historicalContext.isEmpty { Section("Historical Context") { @@ -325,7 +325,7 @@ struct AuditSessionDetailView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } Section("Audit Timeline") { @@ -345,10 +345,10 @@ struct AuditSessionDetailView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Audit Session") .toolbar { ToolbarItemGroup(placement: .topBarTrailing) { @@ -398,7 +398,7 @@ struct AuditSessionDetailView: View { } } else { ContentUnavailableView("Audit Session Missing", systemImage: "exclamationmark.triangle") - .background(Color.black) + .background(Color(.appBackground)) } } .preferredColorScheme(.dark) @@ -477,7 +477,7 @@ private struct AuditFindingEditorView: View { Text(area.title) Spacer() Image(systemName: selectedAreas.contains(area) ? "checkmark.circle.fill" : "circle") - .foregroundStyle(selectedAreas.contains(area) ? Color.green : .secondary) + .foregroundStyle(selectedAreas.contains(area) ? Color(.statusPositive) : .secondary) } } .buttonStyle(.plain) @@ -528,11 +528,11 @@ private func auditStatusBadge(_ status: AuditStatus) -> some View { let model: AppStatusBadgeModel switch status { case .draft: - model = .init(title: "Draft", systemImage: "square.and.pencil", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + model = .init(title: "Draft", systemImage: "square.and.pencil", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .inReview: - model = .init(title: "In Review", systemImage: "doc.text.magnifyingglass", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16)) + model = .init(title: "In Review", systemImage: "doc.text.magnifyingglass", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16)) case .complete: - model = .init(title: "Complete", systemImage: "checkmark.seal.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + model = .init(title: "Complete", systemImage: "checkmark.seal.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) } return AppStatusBadgeView(model: model) } @@ -543,11 +543,11 @@ private func findingSeverityBadge(_ severity: AuditFindingSeverity) -> some View case .informational: color = .secondary case .low: - color = .green + color = Color(.statusPositive) case .medium: - color = .yellow + color = Color(.statusWarning) case .high: - color = .red + color = Color(.statusCritical) } return AppStatusBadgeView( model: .init( diff --git a/DomainDig/DomainDigUI.swift b/DomainDig/DomainDigUI.swift index 272c678..9c63e73 100644 --- a/DomainDig/DomainDigUI.swift +++ b/DomainDig/DomainDigUI.swift @@ -92,48 +92,48 @@ enum AppStatusFactory { static func availability(_ status: DomainAvailabilityStatus?) -> AppStatusBadgeModel { switch status { case .available: - return .init(title: "Available", systemImage: "checkmark.circle.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Available", systemImage: "checkmark.circle.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case .registered: - return .init(title: "Registered", systemImage: "circle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Registered", systemImage: "circle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .unknown, .none: - return .init(title: "Unknown", systemImage: "questionmark.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: "Unknown", systemImage: "questionmark.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } } static func tls(sslInfo: SSLCertificateInfo?, error: String?) -> AppStatusBadgeModel { if error != nil || sslInfo == nil { - return .init(title: "Invalid", systemImage: "xmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: "Invalid", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) } if let sslInfo, sslInfo.daysUntilExpiry <= 14 { - return .init(title: "Expiring", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Expiring", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) } - return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) } static func email(_ result: EmailSecurityResult?, error: String?) -> AppStatusBadgeModel { guard error == nil, let result else { - return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } let foundCount = [result.spf.found, result.dmarc.found, result.dkim.found].filter { $0 }.count switch foundCount { case 3: - return .init(title: "Secure", systemImage: "checkmark.shield.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Secure", systemImage: "checkmark.shield.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) case 1, 2: - return .init(title: "Partial", systemImage: "shield.lefthalf.filled", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Partial", systemImage: "shield.lefthalf.filled", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) default: - return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } } static func change(_ summary: DomainChangeSummary?) -> AppStatusBadgeModel { guard let summary else { - return .init(title: "Unchanged", systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: "Unchanged", systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } if summary.hasChanges { - return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: .cyan, backgroundColor: .cyan.opacity(0.16)) + return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16)) } - return .init(title: "Unchanged", systemImage: "checkmark.circle", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.55)) + return .init(title: "Unchanged", systemImage: "checkmark.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)) } } @@ -184,9 +184,9 @@ struct AppCopyButton: View { } label: { Image(systemName: didCopy ? "checkmark" : "doc.on.doc") .font(appDensity.font(.caption)) - .foregroundStyle(didCopy ? Color.green : .secondary) + .foregroundStyle(didCopy ? Color(.statusPositive) : .secondary) .frame(width: 30, height: 30) - .background(Color(.systemGray5).opacity(0.35)) + .background(Color(.appSurfaceElevated)) .clipShape(RoundedRectangle(cornerRadius: 8)) } .buttonStyle(.plain) @@ -264,11 +264,11 @@ struct EmptyStateCardView: View { Text(suggestion) .font(appDensity.font(.caption)) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) } .frame(maxWidth: .infinity, alignment: .leading) .padding(appDensity.metrics.cardPadding) - .background(showsCardBackground ? Color(.systemGray6).opacity(0.45) : Color.clear) + .background(showsCardBackground ? Color(.appSurface) : Color.clear) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) } } @@ -307,7 +307,7 @@ struct CollapsibleSectionView: View { VStack(alignment: .leading, spacing: 3) { Text(title) .font(appDensity.font(.headline, design: .default, weight: .semibold)) - .foregroundStyle(.white) + .foregroundStyle(.primary) if let subtitle { Text(subtitle) .font(appDensity.font(.caption)) @@ -346,7 +346,7 @@ struct TagChipRowView: View { .font(.caption) .padding(.horizontal, 10) .padding(.vertical, 5) - .background(Color(.systemGray5).opacity(0.6), in: Capsule()) + .background(Color(.appSurfaceElevated), in: Capsule()) } } } @@ -380,8 +380,8 @@ struct TagFilterChipRowView: View { .font(.caption) .padding(.horizontal, 10) .padding(.vertical, 5) - .background(isSelected ? Color.cyan.opacity(0.3) : Color(.systemGray5).opacity(0.6), in: Capsule()) - .foregroundStyle(isSelected ? Color.cyan : Color.primary) + .background(isSelected ? Color(.statusInfo).opacity(0.3) : Color(.appSurfaceElevated), in: Capsule()) + .foregroundStyle(isSelected ? Color(.statusInfo) : Color.primary) } .buttonStyle(.plain) } diff --git a/DomainDig/HistoryView.swift b/DomainDig/HistoryView.swift index 5350168..ffa7745 100644 --- a/DomainDig/HistoryView.swift +++ b/DomainDig/HistoryView.swift @@ -25,7 +25,7 @@ struct HistoryView: View { systemImage: "clock.arrow.trianglehead.counterclockwise.rotate.90", showsCardBackground: false ) - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { Section("Domains") { ForEach(domainSummaries, id: \.domain) { item in @@ -55,21 +55,21 @@ struct HistoryView: View { model: .init( title: severity.title, systemImage: "arrow.triangle.2.circlepath", - foregroundColor: severity == .high ? .red : .yellow, - backgroundColor: (severity == .high ? Color.red : .yellow).opacity(0.16) + foregroundColor: severity == .high ? Color(.statusCritical) : Color(.statusWarning), + backgroundColor: (severity == .high ? Color(.statusCritical) : Color(.statusWarning)).opacity(0.16) ) ) } } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("History") .searchable(text: $viewModel.timelineDomainFilter, prompt: "Search domains") .toolbar { @@ -321,7 +321,7 @@ struct HistoryDetailView: View { .padding(.horizontal) .padding(.bottom, 32) } - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle(entry.domain) .toolbar { ToolbarItemGroup(placement: .topBarTrailing) { @@ -390,12 +390,12 @@ struct HistoryDetailView: View { if let mismatchNote = viewModel.resolverMismatchNote(for: entry) { Text(mismatchNote) .font(appDensity.font(.caption2)) - .foregroundStyle(.orange) + .foregroundStyle(Color(.statusWarning)) } if entry.isPartialSnapshot { Text("Partial snapshot: \(entry.validationIssues.joined(separator: " | "))") .font(appDensity.font(.caption2)) - .foregroundStyle(.yellow) + .foregroundStyle(Color(.statusWarning)) } if let note = entry.note, !note.isEmpty { Text(note) @@ -406,7 +406,7 @@ struct HistoryDetailView: View { .foregroundStyle(.secondary) .padding(8) .frame(maxWidth: .infinity, alignment: .leading) - .background(Color(.systemGray6).opacity(0.3)) + .background(Color(.appSurface)) .clipShape(RoundedRectangle(cornerRadius: appDensity.metrics.cardCornerRadius)) .padding(.vertical, 12) } diff --git a/DomainDig/IntegrationsView.swift b/DomainDig/IntegrationsView.swift index 73f511a..163d4d1 100644 --- a/DomainDig/IntegrationsView.swift +++ b/DomainDig/IntegrationsView.swift @@ -52,7 +52,7 @@ struct IntegrationsSettingsView: View { if !target.isEnabled { Text("Disabled") .font(.caption2) - .foregroundStyle(.orange) + .foregroundStyle(Color(.statusWarning)) } } } @@ -158,7 +158,7 @@ private struct IntegrationDetailView: View { .foregroundStyle(.secondary) if let failureReason = record.failureReason { - let failureColor: Color = record.status == .skipped ? .secondary : .red + let failureColor: Color = record.status == .skipped ? .secondary : Color(.statusCritical) Text(failureReason) .font(.caption) .foregroundStyle(failureColor) @@ -324,7 +324,7 @@ private struct IntegrationEditorView: View { Section { Text(validationMessage) .font(.caption) - .foregroundStyle(.red) + .foregroundStyle(Color(.statusCritical)) } } } diff --git a/DomainDig/MonitoringView.swift b/DomainDig/MonitoringView.swift index fc0b8ab..decad35 100644 --- a/DomainDig/MonitoringView.swift +++ b/DomainDig/MonitoringView.swift @@ -41,7 +41,7 @@ struct MonitoringView: View { } .padding(.vertical, 4) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) if viewModel.monitoringLogs.isEmpty { Section { @@ -53,7 +53,7 @@ struct MonitoringView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { Section("Recent Runs") { ForEach(viewModel.monitoringLogs) { log in @@ -78,10 +78,10 @@ struct MonitoringView: View { HStack(spacing: 8) { metricBadge(title: "\(log.domainsChecked) checked") if log.changesFound > 0 { - metricBadge(title: "\(log.changesFound) changed", tint: .orange) + metricBadge(title: "\(log.changesFound) changed", tint: Color(.statusWarning)) } if log.alertsTriggered > 0 { - metricBadge(title: "\(log.alertsTriggered) alerts", tint: .red) + metricBadge(title: "\(log.alertsTriggered) alerts", tint: Color(.statusCritical)) } } } @@ -89,11 +89,11 @@ struct MonitoringView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Monitoring") .preferredColorScheme(.dark) .onAppear { @@ -101,7 +101,7 @@ struct MonitoringView: View { } } - private func metricBadge(title: String, tint: Color = .cyan) -> some View { + private func metricBadge(title: String, tint: Color = Color(.statusInfo)) -> some View { Text(title) .font(appDensity.font(.caption2)) .foregroundStyle(tint) @@ -133,7 +133,7 @@ struct MonitoringLogDetailView: View { LabeledContent("Alerts", value: "\(log.alertsTriggered)") LabeledContent("Timestamp", value: log.timestamp.formatted(date: .abbreviated, time: .shortened)) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section("Domains") { ForEach(log.checkedDomains) { result in @@ -167,7 +167,7 @@ struct MonitoringLogDetailView: View { if let errorMessage = result.errorMessage { Text(errorMessage) .font(appDensity.font(.caption2)) - .foregroundStyle(.yellow) + .foregroundStyle(Color(.statusWarning)) } if let historyEntryID = result.historyEntryID, @@ -181,7 +181,7 @@ struct MonitoringLogDetailView: View { .padding(.vertical, 4) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) if !log.errors.isEmpty { Section("Errors") { @@ -191,11 +191,11 @@ struct MonitoringLogDetailView: View { .foregroundStyle(.secondary) } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Run Details") .preferredColorScheme(.dark) } @@ -205,9 +205,9 @@ struct MonitoringLogDetailView: View { case .info: return .secondary case .warning: - return .yellow + return Color(.statusWarning) case .critical: - return .red + return Color(.statusCritical) } } } diff --git a/DomainDig/PaywallView.swift b/DomainDig/PaywallView.swift index cad8be4..27e80ee 100644 --- a/DomainDig/PaywallView.swift +++ b/DomainDig/PaywallView.swift @@ -75,7 +75,7 @@ struct PaywallView: View { if let errorMessage = purchaseService.errorMessage { Text(errorMessage) .font(appDensity.font(.caption, design: .default)) - .foregroundStyle(.red) + .foregroundStyle(Color(.statusCritical)) } } diff --git a/DomainDig/SavedDomainsView.swift b/DomainDig/SavedDomainsView.swift index f407d78..59dcb73 100644 --- a/DomainDig/SavedDomainsView.swift +++ b/DomainDig/SavedDomainsView.swift @@ -10,7 +10,7 @@ struct SavedDomainsView: View { Text("No saved domains") .font(.system(.callout, design: .monospaced)) .foregroundStyle(.secondary) - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { ForEach(viewModel.savedDomains, id: \.self) { domain in Button { @@ -22,7 +22,7 @@ struct SavedDomainsView: View { .font(.system(.callout, design: .monospaced)) .foregroundStyle(.primary) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } .onDelete { offsets in viewModel.removeSavedDomains(at: offsets) @@ -30,7 +30,7 @@ struct SavedDomainsView: View { } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Saved Domains") .toolbar { if !viewModel.savedDomains.isEmpty { diff --git a/DomainDig/ScheduledReportsView.swift b/DomainDig/ScheduledReportsView.swift index 170e02d..dffafe3 100644 --- a/DomainDig/ScheduledReportsView.swift +++ b/DomainDig/ScheduledReportsView.swift @@ -67,7 +67,7 @@ struct ScheduledReportsView: View { } .disabled(isGenerating || !FeatureAccessService.hasAccess(to: .automatedMonitoring)) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) if logs.isEmpty { Section { @@ -79,7 +79,7 @@ struct ScheduledReportsView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { Section("Recent Reports") { ForEach(logs) { log in @@ -96,11 +96,11 @@ struct ScheduledReportsView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Scheduled Reports") } diff --git a/DomainDig/TimelineView.swift b/DomainDig/TimelineView.swift index 8680d15..052b088 100644 --- a/DomainDig/TimelineView.swift +++ b/DomainDig/TimelineView.swift @@ -45,12 +45,12 @@ struct TimelineView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle(domain) .toolbar { ToolbarItemGroup(placement: .topBarTrailing) { @@ -116,8 +116,8 @@ private struct TimelineRow: View { model: .init( title: severity.title, systemImage: "arrow.triangle.2.circlepath", - foregroundColor: severity == .high ? .red : .yellow, - backgroundColor: (severity == .high ? Color.red : .yellow).opacity(0.16) + foregroundColor: severity == .high ? Color(.statusCritical) : Color(.statusWarning), + backgroundColor: (severity == .high ? Color(.statusCritical) : Color(.statusWarning)).opacity(0.16) ) ) } @@ -203,7 +203,7 @@ struct TimelineDiffView: View { } .padding() } - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Compare Snapshots") .navigationBarTitleDisplayMode(.inline) .onAppear { diff --git a/DomainDig/WatchlistView.swift b/DomainDig/WatchlistView.swift index 389ae91..5c5609e 100644 --- a/DomainDig/WatchlistView.swift +++ b/DomainDig/WatchlistView.swift @@ -38,7 +38,7 @@ struct WatchlistView: View { Section("Refresh Progress") { VStack(alignment: .leading, spacing: 8) { ProgressView(value: Double(viewModel.batchCompletedCount), total: Double(max(viewModel.batchTotalCount, 1))) - .tint(.cyan) + .tint(Color(.statusInfo)) HStack { Text(viewModel.batchProgressLabel) .font(appDensity.font(.caption)) @@ -59,7 +59,7 @@ struct WatchlistView: View { } .padding(.vertical, 4) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } if viewModel.filteredTrackedDomains.isEmpty { @@ -72,7 +72,7 @@ struct WatchlistView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { if let limitMessage = FeatureAccessService.trackedDomainLimitMessage(currentCount: viewModel.trackedDomains.count) { Section { @@ -80,7 +80,7 @@ struct WatchlistView: View { .font(appDensity.font(.caption)) .foregroundStyle(.secondary) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } if !pinnedDomains.isEmpty { @@ -94,7 +94,7 @@ struct WatchlistView: View { } .animation(.easeInOut(duration: 0.2), value: viewModel.filteredTrackedDomains.map(\.id)) .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle("Watchlist") .searchable(text: $viewModel.watchlistSearchText, prompt: "Search tracked domains") .toolbar { @@ -215,7 +215,7 @@ struct WatchlistView: View { Section { Text(addDomainError) .font(appDensity.font(.caption)) - .foregroundStyle(.red) + .foregroundStyle(Color(.statusCritical)) } } } @@ -317,14 +317,14 @@ struct WatchlistView: View { } label: { Label("Refresh", systemImage: "arrow.clockwise") } - .tint(.cyan) + .tint(Color(.statusInfo)) Button { viewModel.togglePinned(for: trackedDomain) } label: { Label(trackedDomain.isPinned ? "Unpin" : "Pin", systemImage: trackedDomain.isPinned ? "pin.slash" : "pin") } - .tint(.yellow) + .tint(Color(.statusWarning)) } .swipeActions(edge: .trailing, allowsFullSwipe: false) { Button { @@ -333,7 +333,7 @@ struct WatchlistView: View { } label: { Label("Refresh", systemImage: "arrow.clockwise") } - .tint(.cyan) + .tint(Color(.statusInfo)) if viewModel.canDelete(trackedDomain) { Button(role: .destructive) { @@ -380,7 +380,7 @@ struct WatchlistView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } private var batchSummaryBinding: Binding { @@ -437,7 +437,7 @@ struct WatchlistRowView: View { if trackedDomain.isPinned { Image(systemName: "pin.fill") .font(.caption2) - .foregroundStyle(.yellow) + .foregroundStyle(Color(.statusWarning)) } Text(trackedDomain.domain) .font(appDensity.font(.callout)) @@ -502,7 +502,7 @@ struct WatchlistRowView: View { @ViewBuilder private var statusBadge: some View { if isRefreshing { - AppStatusBadgeView(model: .init(title: "Refreshing", systemImage: "arrow.clockwise", foregroundColor: .secondary, backgroundColor: Color(.systemGray5).opacity(0.6))) + AppStatusBadgeView(model: .init(title: "Refreshing", systemImage: "arrow.clockwise", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))) } else { AppStatusBadgeView(model: AppStatusFactory.availability(trackedDomain.lastKnownAvailability)) } @@ -516,8 +516,8 @@ struct WatchlistRowView: View { model: .init( title: "Shared", systemImage: "person.2.fill", - foregroundColor: .cyan, - backgroundColor: .cyan.opacity(0.16) + foregroundColor: Color(.statusInfo), + backgroundColor: Color(.statusInfo).opacity(0.16) ) ) } @@ -534,11 +534,11 @@ struct WatchlistRowView: View { let days = trackedDomain.certificateDaysRemaining.map { "\($0)d" } ?? "Soon" switch trackedDomain.certificateWarningLevel { case .critical: - return .init(title: "Invalid \(days)", systemImage: "xmark.octagon.fill", foregroundColor: .red, backgroundColor: .red.opacity(0.16)) + return .init(title: "Invalid \(days)", systemImage: "xmark.octagon.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16)) case .warning: - return .init(title: "Expiring \(days)", systemImage: "exclamationmark.triangle.fill", foregroundColor: .yellow, backgroundColor: .yellow.opacity(0.16)) + return .init(title: "Expiring \(days)", systemImage: "exclamationmark.triangle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16)) case .none: - return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: .green, backgroundColor: .green.opacity(0.16)) + return .init(title: "Valid", systemImage: "lock.fill", foregroundColor: Color(.statusPositive), backgroundColor: Color(.statusPositive).opacity(0.16)) } } } @@ -577,7 +577,7 @@ struct TrackedDomainDetailView: View { isRefreshing: viewModel.refreshingTrackedDomainID == liveTrackedDomain.id ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) Section { Button { @@ -652,13 +652,13 @@ struct TrackedDomainDetailView: View { Label(liveTrackedDomain.collaboration?.isShared == true ? "Manage Share" : "Share Domain", systemImage: "person.2") } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) if !liveTrackedDomain.tags.isEmpty { Section("Tags") { TagChipRowView(tags: liveTrackedDomain.tags) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } Section("Monitoring Status") { @@ -672,7 +672,7 @@ struct TrackedDomainDetailView: View { LabeledContent("Queued Alerts", value: "\(liveTrackedDomain.pendingMonitoringAlerts.count)") } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) if let summary = viewModel.latestChangeSummary(for: liveTrackedDomain) { Section("Latest Change Summary") { @@ -718,10 +718,10 @@ struct TrackedDomainDetailView: View { } } } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle(liveTrackedDomain.domain) .preferredColorScheme(.dark) .onChange(of: viewModel.rerunNavigationToken) { _, _ in diff --git a/DomainDig/WorkflowsView.swift b/DomainDig/WorkflowsView.swift index ce889fb..2195af5 100644 --- a/DomainDig/WorkflowsView.swift +++ b/DomainDig/WorkflowsView.swift @@ -24,13 +24,13 @@ struct WorkflowsView: View { .font(appDensity.font(.caption)) .foregroundStyle(.secondary) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } workflowContent } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .refreshable { await viewModel.refreshWorkflowList() } @@ -73,7 +73,7 @@ struct WorkflowsView: View { value: Double(viewModel.batchCompletedCount), total: Double(max(viewModel.batchTotalCount, 1)) ) - .tint(.cyan) + .tint(Color(.statusInfo)) HStack { Text(viewModel.batchProgressLabel) @@ -91,7 +91,7 @@ struct WorkflowsView: View { } .padding(.vertical, 4) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } if viewModel.workflows.isEmpty { @@ -104,7 +104,7 @@ struct WorkflowsView: View { showsCardBackground: false ) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } else { ForEach(viewModel.workflows) { workflow in NavigationLink { @@ -112,7 +112,7 @@ struct WorkflowsView: View { } label: { WorkflowRowView(workflow: workflow) } - .listRowBackground(Color(.systemGray6).opacity(0.5)) + .listRowBackground(Color(.appSurface)) } .onDelete { offsets in let workflows = offsets.map { viewModel.workflows[$0] } @@ -133,7 +133,7 @@ private struct WorkflowRowView: View { if workflow.collaboration?.isShared == true { Image(systemName: "person.2.fill") .font(.caption2) - .foregroundStyle(.cyan) + .foregroundStyle(Color(.statusInfo)) } Text(workflow.name) .font(appDensity.font(.callout, design: .default, weight: .semibold)) @@ -335,7 +335,7 @@ struct WorkflowDetailView: View { } } .scrollContentBackground(.hidden) - .background(Color.black) + .background(Color(.appBackground)) .navigationTitle(workflow.name) .toolbar { if !workflow.domains.isEmpty { @@ -640,7 +640,7 @@ struct WorkflowBulkAddSheet: View { .foregroundStyle(.primary) Spacer() Image(systemName: selectedDomains.contains(domain) ? "checkmark.circle.fill" : "circle") - .foregroundStyle(selectedDomains.contains(domain) ? .cyan : .secondary) + .foregroundStyle(selectedDomains.contains(domain) ? Color(.statusInfo) : .secondary) } } .buttonStyle(.plain) -- cgit v1.2.3