Skip to content

Commit a0e437c

Browse files
committed
fix(ios): centralize app accent colors
Move iOS accent and status colors through design tokens so raw SwiftUI color literals are blocked outside token definitions. Set the app-wide tint in SwiftUI and UIKit from code, without relying on Assets.xcassets AccentColor.
1 parent e84b719 commit a0e437c

19 files changed

Lines changed: 74 additions & 34 deletions

apps/ios/.swiftlint.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,24 @@ parent_config: ../../config/swiftlint.yml
22

33
included:
44
- Sources
5-
- ../shared/ClawdisNodeKit/Sources
5+
- ShareExtension
6+
- ActivityWidget
7+
- WatchApp
8+
- ../shared/OpenClawKit/Sources/OpenClawChatUI
9+
10+
excluded:
11+
- ../macos
612

713
type_body_length:
814
warning: 900
915
error: 1300
16+
17+
custom_rules:
18+
openclaw_design_colors:
19+
name: "OpenClaw design colors"
20+
excluded:
21+
- Sources/Design/OpenClawBrand.swift
22+
- ../shared/OpenClawKit/Sources/OpenClawChatUI/ChatTheme.swift
23+
regex: '(Color\.accentColor|(^|[^A-Za-z0-9_])\.accentColor\b|Color\.(red|green|orange|cyan|blue|yellow|purple|pink)\b|\.(foregroundStyle|tint|fill|stroke|strokeBorder|background)\(\s*\.(red|green|orange|cyan|blue|yellow|purple|pink)\b|Color\(red:\s*0\s*/\s*255\.0,\s*green:\s*122\s*/\s*255\.0,\s*blue:\s*255\s*/\s*255\.0\))'
24+
message: "Use OpenClawBrand or OpenClawChatTheme design tokens instead of raw accent/status colors."
25+
severity: error

apps/ios/ActivityWidget/OpenClawLiveActivity.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,23 +74,30 @@ struct OpenClawLiveActivity: Widget {
7474
private func statusIcon(state: OpenClawActivityAttributes.ContentState) -> some View {
7575
if state.isConnecting {
7676
Image(systemName: "arrow.triangle.2.circlepath")
77-
.foregroundStyle(.cyan)
77+
.foregroundStyle(OpenClawActivityStyle.info)
7878
} else if state.isDisconnected {
7979
Image(systemName: "wifi.slash")
80-
.foregroundStyle(.red)
80+
.foregroundStyle(OpenClawActivityStyle.danger)
8181
} else if state.isIdle {
8282
Image(systemName: "checkmark")
83-
.foregroundStyle(.green)
83+
.foregroundStyle(OpenClawActivityStyle.ok)
8484
} else {
8585
Image(systemName: "exclamationmark.triangle.fill")
86-
.foregroundStyle(.orange)
86+
.foregroundStyle(OpenClawActivityStyle.warn)
8787
}
8888
}
8989

9090
private func dotColor(state: OpenClawActivityAttributes.ContentState) -> Color {
91-
if state.isDisconnected { return .red }
92-
if state.isConnecting { return .cyan }
93-
if state.isIdle { return .green }
94-
return .orange
91+
if state.isDisconnected { return OpenClawActivityStyle.danger }
92+
if state.isConnecting { return OpenClawActivityStyle.info }
93+
if state.isIdle { return OpenClawActivityStyle.ok }
94+
return OpenClawActivityStyle.warn
9595
}
9696
}
97+
98+
private enum OpenClawActivityStyle {
99+
static let info = Color(red: 0, green: 122 / 255.0, blue: 1)
100+
static let danger = Color(red: 185 / 255.0, green: 28 / 255.0, blue: 28 / 255.0)
101+
static let ok = Color(red: 34 / 255.0, green: 197 / 255.0, blue: 94 / 255.0)
102+
static let warn = Color(red: 245 / 255.0, green: 158 / 255.0, blue: 11 / 255.0)
103+
}

apps/ios/Sources/Design/AgentProTab+Skills.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ extension AgentProTab {
506506

507507
func skillEditorSwitchIndicator(isOn: Bool) -> some View {
508508
Capsule()
509-
.fill(isOn ? Color.accentColor : Color.secondary.opacity(0.35))
509+
.fill(isOn ? OpenClawBrand.accent : Color.secondary.opacity(0.35))
510510
.frame(width: 52, height: 32)
511511
.overlay(alignment: isOn ? .trailing : .leading) {
512512
Circle()

apps/ios/Sources/Design/AgentProTab.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ struct AgentProTab: View {
105105
var color: Color {
106106
switch self {
107107
case .online: OpenClawBrand.ok
108-
case .ready: Color(red: 0 / 255.0, green: 122 / 255.0, blue: 255 / 255.0)
108+
case .ready: OpenClawBrand.info
109109
}
110110
}
111111
}

apps/ios/Sources/Design/ChatProTab.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ struct ChatProTab: View {
277277
}
278278

279279
private var chatUserAccent: Color {
280-
self.colorScheme == .light ? Color(red: 0 / 255.0, green: 122 / 255.0, blue: 255 / 255.0) : OpenClawBrand.accent
280+
self.colorScheme == .light ? OpenClawBrand.info : OpenClawBrand.accent
281281
}
282282

283283
private var activeAgent: AgentSummary? {

apps/ios/Sources/Design/IPadSkillWorkshopScreen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,7 @@ struct IPadSkillProposalRow: View {
10361036
.padding(.horizontal, 14)
10371037
.padding(.vertical, 10)
10381038
.background(
1039-
self.isSelected ? Color.red.opacity(0.08) : Color.clear,
1039+
self.isSelected ? OpenClawBrand.danger.opacity(0.08) : Color.clear,
10401040
in: RoundedRectangle(cornerRadius: 8, style: .continuous))
10411041
}
10421042
}

apps/ios/Sources/Design/OpenClawBrand.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,13 @@ enum AppAppearancePreference: String, CaseIterable, Identifiable {
4747
}
4848

4949
enum OpenClawBrand {
50-
static let accent = Color(uiColor: UIColor { traits in
50+
static let uiAccent = UIColor { traits in
5151
traits.userInterfaceStyle == .dark
5252
? UIColor(red: 198 / 255.0, green: 62 / 255.0, blue: 56 / 255.0, alpha: 1)
5353
: UIColor(red: 183 / 255.0, green: 56 / 255.0, blue: 51 / 255.0, alpha: 1)
54-
})
54+
}
55+
56+
static let accent = Color(uiColor: Self.uiAccent)
5557
static let accentHot = Color(uiColor: UIColor { traits in
5658
traits.userInterfaceStyle == .dark
5759
? UIColor(red: 232 / 255.0, green: 92 / 255.0, blue: 86 / 255.0, alpha: 1)
@@ -64,6 +66,7 @@ enum OpenClawBrand {
6466
})
6567
static let ok = Color(red: 34 / 255.0, green: 197 / 255.0, blue: 94 / 255.0)
6668
static let warn = Color(red: 245 / 255.0, green: 158 / 255.0, blue: 11 / 255.0)
69+
static let info = Color(red: 0 / 255.0, green: 122 / 255.0, blue: 255 / 255.0)
6770
static let graphite = Color(uiColor: UIColor { traits in
6871
traits.userInterfaceStyle == .dark
6972
? UIColor(red: 20 / 255.0, green: 22 / 255.0, blue: 24 / 255.0, alpha: 1)

apps/ios/Sources/Design/SettingsProTabSections.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ extension SettingsProTab {
119119
self.gatewayActionButton(
120120
title: "Diagnose",
121121
icon: "cross.case",
122-
color: Color(red: 0 / 255.0, green: 122 / 255.0, blue: 255 / 255.0),
122+
color: OpenClawBrand.info,
123123
isBusy: self.isRefreshingGateway)
124124
{
125125
Task { await self.runDiagnostics() }
@@ -434,7 +434,7 @@ extension SettingsProTab {
434434
self.gatewayActionButton(
435435
title: "Run Diagnostics",
436436
icon: "cross.case",
437-
color: Color(red: 0 / 255.0, green: 122 / 255.0, blue: 255 / 255.0),
437+
color: OpenClawBrand.info,
438438
isBusy: self.isRefreshingGateway)
439439
{
440440
Task { await self.runDiagnostics() }
@@ -983,7 +983,7 @@ extension SettingsProTab {
983983

984984
func settingsSwitchIndicator(isOn: Bool) -> some View {
985985
Capsule()
986-
.fill(isOn ? Color.accentColor : Color.secondary.opacity(0.35))
986+
.fill(isOn ? OpenClawBrand.accent : Color.secondary.opacity(0.35))
987987
.frame(width: 52, height: 32)
988988
.overlay(alignment: isOn ? .trailing : .leading) {
989989
Circle()

apps/ios/Sources/Gateway/ExecApprovalPromptDialog.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private struct ExecApprovalPromptCard: View {
8787
if let errorText = self.normalized(self.errorText) {
8888
Text(errorText)
8989
.font(.footnote)
90-
.foregroundStyle(.red)
90+
.foregroundStyle(OpenClawBrand.danger)
9191
}
9292

9393
if self.isResolving {

apps/ios/Sources/Onboarding/OnboardingWizardSteps.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct OnboardingIntroStep: View {
4040
HStack(alignment: .top, spacing: 12) {
4141
Image(systemName: "exclamationmark.triangle.fill")
4242
.font(.title3.weight(.semibold))
43-
.foregroundStyle(.orange)
43+
.foregroundStyle(OpenClawBrand.warn)
4444
.frame(width: 24)
4545
.padding(.top, 2)
4646

@@ -177,7 +177,7 @@ struct OnboardingModeRow: View {
177177
}
178178
Spacer()
179179
Image(systemName: self.selected ? "checkmark.circle.fill" : "circle")
180-
.foregroundStyle(self.selected ? Color.accentColor : Color.secondary)
180+
.foregroundStyle(self.selected ? OpenClawBrand.accent : Color.secondary)
181181
}
182182
.contentShape(Rectangle())
183183
}

0 commit comments

Comments
 (0)