diff --git a/apps/ios/Sources/Design/AgentProDreamingDestination.swift b/apps/ios/Sources/Design/AgentProDreamingDestination.swift index 55cf655fc36c..909121daf62f 100644 --- a/apps/ios/Sources/Design/AgentProDreamingDestination.swift +++ b/apps/ios/Sources/Design/AgentProDreamingDestination.swift @@ -49,6 +49,7 @@ struct AgentProDreamingDestination: View { self.dreamingPhasesCard } .padding(.vertical, 18) + .font(OpenClawType.body) } .refreshable { await self.refresh() @@ -194,6 +195,7 @@ struct AgentProDreamingDestination: View { Task { await self.runDreamAction(action) } } label: { Label(action.title, systemImage: self.dreamActionBusy == action ? "hourglass" : action.icon) + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) .controlSize(.small) diff --git a/apps/ios/Sources/Design/AgentProNodesDestination.swift b/apps/ios/Sources/Design/AgentProNodesDestination.swift index 7e0acae6d4a8..f1671c45eb84 100644 --- a/apps/ios/Sources/Design/AgentProNodesDestination.swift +++ b/apps/ios/Sources/Design/AgentProNodesDestination.swift @@ -23,6 +23,7 @@ struct AgentProNodesDestination: View { self.nodesList } .padding(.vertical, 18) + .font(OpenClawType.body) } .refreshable { await self.refresh() @@ -208,6 +209,7 @@ struct AgentProNodesDestination: View { self.nodeListCard(title: "Tags", values: entry.tags ?? []) } .padding(.vertical, 18) + .font(OpenClawType.body) } .safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset) } diff --git a/apps/ios/Sources/Design/AgentProTab+Cron.swift b/apps/ios/Sources/Design/AgentProTab+Cron.swift index 587f05cca7de..9e31bb66e8e5 100644 --- a/apps/ios/Sources/Design/AgentProTab+Cron.swift +++ b/apps/ios/Sources/Design/AgentProTab+Cron.swift @@ -98,6 +98,7 @@ extension AgentProTab { Task { await self.runCronJob(job) } } label: { Label("Run", systemImage: "play.fill") + .font(OpenClawType.captionSemiBold) } .disabled(busy || !self.liveGatewayConnected) @@ -105,6 +106,7 @@ extension AgentProTab { Task { await self.setCronJob(job, enabled: !job.enabled) } } label: { Label(job.enabled ? "Pause" : "Enable", systemImage: job.enabled ? "pause.fill" : "checkmark") + .font(OpenClawType.captionSemiBold) } .disabled(busy || !self.liveGatewayConnected) } diff --git a/apps/ios/Sources/Design/AgentProTab+Destinations.swift b/apps/ios/Sources/Design/AgentProTab+Destinations.swift index 8cda14d9a278..4126abbb8961 100644 --- a/apps/ios/Sources/Design/AgentProTab+Destinations.swift +++ b/apps/ios/Sources/Design/AgentProTab+Destinations.swift @@ -40,6 +40,7 @@ extension AgentProTab { .refreshable { await self.refreshOverview(force: true) } + .font(OpenClawType.body) .toolbar { if let headerLeadingAction { ToolbarItem(placement: .topBarLeading) { @@ -70,6 +71,7 @@ extension AgentProTab { self.skillsList } .padding(.vertical, 18) + .font(OpenClawType.body) } .refreshable { await self.refreshOverview(force: true) @@ -113,6 +115,7 @@ extension AgentProTab { self.cronJobsList(limit: nil) } .padding(.vertical, 18) + .font(OpenClawType.body) } .refreshable { await self.refreshOverview(force: true) @@ -142,6 +145,7 @@ extension AgentProTab { self.usageDailyList } .padding(.vertical, 18) + .font(OpenClawType.body) } .refreshable { await self.refreshOverview(force: true) diff --git a/apps/ios/Sources/Design/AgentProTab+Skills.swift b/apps/ios/Sources/Design/AgentProTab+Skills.swift index 7bbd3505db73..23ecf149d26d 100644 --- a/apps/ios/Sources/Design/AgentProTab+Skills.swift +++ b/apps/ios/Sources/Design/AgentProTab+Skills.swift @@ -21,18 +21,27 @@ extension AgentProTab { } HStack(spacing: 8) { - Button("Enable All") { + Button { Task { await self.enableAllSkills() } + } label: { + Text("Enable All") + .font(OpenClawType.captionSemiBold) } .disabled(self.skillMutationBusy) - Button("Disable All", role: .destructive) { + Button(role: .destructive) { Task { await self.disableAllSkills() } + } label: { + Text("Disable All") + .font(OpenClawType.captionSemiBold) } .disabled(self.skillMutationBusy) - Button("Reset") { + Button { Task { await self.resetSkillPolicy() } + } label: { + Text("Reset") + .font(OpenClawType.captionSemiBold) } .disabled(self.skillMutationBusy || self.agentSkillFilter == nil) } @@ -77,7 +86,9 @@ extension AgentProTab { } Picker("Status", selection: self.$skillStatusFilter) { ForEach(SkillStatusFilter.allCases) { filter in - Text(filter.title).tag(filter) + Text(filter.title) + .font(OpenClawType.captionSemiBold) + .tag(filter) } } .pickerStyle(.segmented) @@ -381,8 +392,11 @@ extension AgentProTab { .navigationTitle("Skill") .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Close") { + Button { self.skillEditorSelection = nil + } label: { + Text("Close") + .font(OpenClawType.subheadSemiBold) } } } @@ -407,8 +421,11 @@ extension AgentProTab { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Close") { + Button { self.skillEditorSelection = nil + } label: { + Text("Close") + .font(OpenClawType.subheadSemiBold) } } } @@ -459,6 +476,7 @@ extension AgentProTab { Task { await self.saveSkillAPIKey(skill) } } label: { Label("Save key", systemImage: "key") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.borderedProminent) .controlSize(.small) @@ -523,6 +541,7 @@ extension AgentProTab { Task { await self.installSkillRequirements(skill) } } label: { Label(install.label, systemImage: "wrench.and.screwdriver") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) .controlSize(.small) diff --git a/apps/ios/Sources/Design/IPadSidebarScreenChrome.swift b/apps/ios/Sources/Design/IPadSidebarScreenChrome.swift index 5e80c82b7eaa..28b460fcf707 100644 --- a/apps/ios/Sources/Design/IPadSidebarScreenChrome.swift +++ b/apps/ios/Sources/Design/IPadSidebarScreenChrome.swift @@ -48,6 +48,7 @@ struct IPadSidebarScreenChrome: View { self.content } .padding(.vertical, self.isCompactHeight ? 10 : 18) + .font(OpenClawType.body) } .safeAreaPadding(.bottom, self.bottomScrollInset) } diff --git a/apps/ios/Sources/Design/IPadSkillWorkshopScreen.swift b/apps/ios/Sources/Design/IPadSkillWorkshopScreen.swift index 3b0111b6a3d4..51ce33a2fcf6 100644 --- a/apps/ios/Sources/Design/IPadSkillWorkshopScreen.swift +++ b/apps/ios/Sources/Design/IPadSkillWorkshopScreen.swift @@ -71,8 +71,11 @@ struct IPadSkillWorkshopScreen: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .confirmationAction) { - Button("Done") { + Button { self.presentedProposalRoute = nil + } label: { + Text("Done") + .font(OpenClawType.subheadSemiBold) } } } @@ -118,6 +121,7 @@ struct IPadSkillWorkshopScreen: View { Task { await self.loadProposals(force: true) } } label: { Label("Refresh", systemImage: "arrow.clockwise") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) .controlSize(.small) @@ -177,6 +181,7 @@ struct IPadSkillWorkshopScreen: View { Task { await self.loadProposals(force: true) } } label: { Label("Refresh", systemImage: "arrow.clockwise") + .font(OpenClawType.captionSemiBold) .frame(maxWidth: .infinity) } .buttonStyle(.bordered) @@ -226,12 +231,18 @@ struct IPadSkillWorkshopScreen: View { .font(OpenClawType.captionSemiBold) .foregroundStyle(.secondary) Menu { - Button("Default agent") { + Button { self.selectedAgentScopeID = "" + } label: { + Text("Default agent") + .font(OpenClawType.subhead) } ForEach(self.agentScopeOptions, id: \.id) { option in - Button(option.title) { + Button { self.selectedAgentScopeID = option.id + } label: { + Text(option.title) + .font(OpenClawType.subhead) } } } label: { @@ -347,42 +358,60 @@ struct IPadSkillWorkshopScreen: View { } .buttonStyle(.plain) .contextMenu { - Button("Inspect") { + Button { self.selectProposal( proposal, opensSheet: true, forceInspect: true) + } label: { + Text("Inspect") + .font(OpenClawType.subhead) } if proposal.status == "pending" { - Button("Apply") { + Button { Task { await self.run(.apply, proposal: proposal) } + } label: { + Text("Apply") + .font(OpenClawType.subhead) } .disabled(!self.canApplyProposalMutations || self.busyAction != nil) - Button("Reject", role: .destructive) { + Button(role: .destructive) { Task { await self.run(.reject, proposal: proposal) } + } label: { + Text("Reject") + .font(OpenClawType.subhead) } .disabled(!self.canApplyProposalMutations || self.busyAction != nil) } } .swipeActions(edge: .trailing, allowsFullSwipe: false) { if proposal.status == "pending" { - Button("Apply") { + Button { Task { await self.run(.apply, proposal: proposal) } + } label: { + Text("Apply") + .font(OpenClawType.subhead) } .tint(OpenClawBrand.ok) .disabled(!self.canApplyProposalMutations || self.busyAction != nil) - Button("Reject", role: .destructive) { + Button(role: .destructive) { Task { await self.run(.reject, proposal: proposal) } + } label: { + Text("Reject") + .font(OpenClawType.subhead) } .disabled(!self.canApplyProposalMutations || self.busyAction != nil) } } .swipeActions(edge: .leading, allowsFullSwipe: true) { - Button("Inspect") { + Button { self.selectProposal( proposal, opensSheet: true, forceInspect: true) + } label: { + Text("Inspect") + .font(OpenClawType.subhead) } .tint(OpenClawBrand.accent) } @@ -482,6 +511,7 @@ struct IPadSkillWorkshopScreen: View { Task { await self.run(.apply, proposal: proposal) } } label: { Label("Apply", systemImage: "checkmark.circle") + .font(OpenClawType.captionSemiBold) .frame(maxWidth: self.isCompactWidth ? .infinity : nil) } .buttonStyle(.borderedProminent) @@ -494,6 +524,7 @@ struct IPadSkillWorkshopScreen: View { Task { await self.run(.reject, proposal: proposal) } } label: { Label("Reject", systemImage: "xmark.circle") + .font(OpenClawType.captionSemiBold) .frame(maxWidth: self.isCompactWidth ? .infinity : nil) } .buttonStyle(.bordered) @@ -506,6 +537,7 @@ struct IPadSkillWorkshopScreen: View { Task { await self.inspect(proposalID: proposal.id, force: true) } } label: { Label("Inspect", systemImage: "doc.text.magnifyingglass") + .font(OpenClawType.captionSemiBold) .frame(maxWidth: self.isCompactWidth ? .infinity : nil) } .buttonStyle(.bordered) @@ -976,6 +1008,7 @@ private struct IPadSkillProposalKanbanCard: View { if self.proposal.status == "pending" { Button(action: self.apply) { Image(systemName: "checkmark.circle") + .font(OpenClawType.captionSemiBold) } .accessibilityLabel("Apply Proposal") .buttonStyle(.bordered) @@ -984,6 +1017,7 @@ private struct IPadSkillProposalKanbanCard: View { Button(role: .destructive, action: self.reject) { Image(systemName: "xmark.circle") + .font(OpenClawType.captionSemiBold) } .accessibilityLabel("Reject Proposal") .buttonStyle(.bordered) @@ -993,6 +1027,7 @@ private struct IPadSkillProposalKanbanCard: View { Button(action: self.inspect) { Image(systemName: "doc.text.magnifyingglass") + .font(OpenClawType.captionSemiBold) } .accessibilityLabel("Inspect Proposal") .buttonStyle(.bordered) @@ -1006,12 +1041,21 @@ private struct IPadSkillProposalKanbanCard: View { in: RoundedRectangle(cornerRadius: OpenClawRadius.xs, style: .continuous)) .contentShape(Rectangle()) .contextMenu { - Button("Inspect", action: self.inspect) + Button(action: self.inspect) { + Text("Inspect") + .font(OpenClawType.subhead) + } if self.proposal.status == "pending" { - Button("Apply", action: self.apply) - .disabled(!self.canApplyProposalMutations || self.isBusy) - Button("Reject", role: .destructive, action: self.reject) - .disabled(!self.canApplyProposalMutations || self.isBusy) + Button(action: self.apply) { + Text("Apply") + .font(OpenClawType.subhead) + } + .disabled(!self.canApplyProposalMutations || self.isBusy) + Button(role: .destructive, action: self.reject) { + Text("Reject") + .font(OpenClawType.subhead) + } + .disabled(!self.canApplyProposalMutations || self.isBusy) } } } diff --git a/apps/ios/Sources/Design/OpenClawDocsScreen.swift b/apps/ios/Sources/Design/OpenClawDocsScreen.swift index b136794d4d43..405fddefe36f 100644 --- a/apps/ios/Sources/Design/OpenClawDocsScreen.swift +++ b/apps/ios/Sources/Design/OpenClawDocsScreen.swift @@ -29,6 +29,7 @@ struct OpenClawDocsScreen: View { self.linkCard } .padding(.vertical, 18) + .font(OpenClawType.body) } } .navigationTitle("Docs") @@ -39,6 +40,7 @@ struct OpenClawDocsScreen: View { ToolbarItem(placement: .topBarTrailing) { Button(action: gatewayAction) { Image(systemName: "antenna.radiowaves.left.and.right") + .font(OpenClawType.subheadSemiBold) } .accessibilityLabel("Gateway settings") } diff --git a/apps/ios/Sources/Design/OpenClawProComponents.swift b/apps/ios/Sources/Design/OpenClawProComponents.swift index 614e8f28e7ed..d76e6b149da0 100644 --- a/apps/ios/Sources/Design/OpenClawProComponents.swift +++ b/apps/ios/Sources/Design/OpenClawProComponents.swift @@ -47,9 +47,11 @@ struct ProSectionHeader: View { Spacer() if let actionTitle { if let action { - Button(actionTitle, action: action) - .font(OpenClawType.footnoteMedium) - .foregroundStyle(OpenClawBrand.accent) + Button(action: action) { + Text(actionTitle) + .font(OpenClawType.footnoteMedium) + } + .foregroundStyle(OpenClawBrand.accent) } else { Text(actionTitle) .font(OpenClawType.footnoteMedium) @@ -134,19 +136,23 @@ private struct OpenClawGlassButtonModifier: ViewModifier { if #available(iOS 26.0, *) { if self.prominent { content + .font(OpenClawType.subheadSemiBold) .buttonStyle(.glassProminent) .tint(self.tint ?? OpenClawBrand.accent) } else { content + .font(OpenClawType.subheadSemiBold) .buttonStyle(.glass) .tint(self.tint) } } else if self.prominent { content + .font(OpenClawType.subheadSemiBold) .buttonStyle(.borderedProminent) .tint(self.tint ?? OpenClawBrand.accent) } else { content + .font(OpenClawType.subheadSemiBold) .buttonStyle(.bordered) .tint(self.tint) } @@ -362,14 +368,20 @@ struct OpenClawNoticeBanner: View { OpenClawGlassControlGroup { HStack(spacing: 10) { if let primaryActionTitle, let onPrimaryAction { - Button(primaryActionTitle, action: onPrimaryAction) - .openClawGlassButton(prominent: true) - .controlSize(.small) + Button(action: onPrimaryAction) { + Text(primaryActionTitle) + .font(OpenClawType.captionSemiBold) + } + .openClawGlassButton(prominent: true) + .controlSize(.small) } if let secondaryActionTitle, let onSecondaryAction { - Button(secondaryActionTitle, action: onSecondaryAction) - .openClawGlassButton() - .controlSize(.small) + Button(action: onSecondaryAction) { + Text(secondaryActionTitle) + .font(OpenClawType.captionSemiBold) + } + .openClawGlassButton() + .controlSize(.small) } } } @@ -795,9 +807,11 @@ struct ProPanelHeader: View { .accessibilityLabel(self.actionAccessibilityLabel ?? actionTitle ?? self.title) .disabled(self.isActionDisabled) } else if let actionTitle { - Button(actionTitle, action: action) - .font(OpenClawType.captionSemiBold) - .disabled(self.isActionDisabled) + Button(action: action) { + Text(actionTitle) + .font(OpenClawType.captionSemiBold) + } + .disabled(self.isActionDisabled) } } } @@ -830,10 +844,12 @@ struct ProStatusRow: View { ProValuePill(value: value, color: self.color) } if let actionTitle, let action { - Button(actionTitle, action: action) - .font(OpenClawType.captionSemiBold) - .buttonStyle(.bordered) - .controlSize(.mini) + Button(action: action) { + Text(actionTitle) + .font(OpenClawType.captionSemiBold) + } + .buttonStyle(.bordered) + .controlSize(.mini) } } } diff --git a/apps/ios/Sources/Design/SettingsChannelsDestination.swift b/apps/ios/Sources/Design/SettingsChannelsDestination.swift index 8c1a0b813edd..66731207973a 100644 --- a/apps/ios/Sources/Design/SettingsChannelsDestination.swift +++ b/apps/ios/Sources/Design/SettingsChannelsDestination.swift @@ -22,6 +22,7 @@ struct SettingsChannelsDestination: View { } self.channelsCard } + .font(OpenClawType.body) .task(id: self.refreshID) { await self.loadChannels(force: false) } @@ -380,6 +381,7 @@ private struct SettingsChannelRow: View { private func accountRow(_ account: SettingsChannelAccount) -> some View { HStack(spacing: 10) { Image(systemName: account.running || account.connected ? "checkmark.circle.fill" : "circle") + .font(OpenClawType.captionSemiBold) .foregroundStyle(account.color) .frame(width: 28, height: 28) VStack(alignment: .leading, spacing: 2) { @@ -393,22 +395,32 @@ private struct SettingsChannelRow: View { Spacer(minLength: 8) Menu { if account.running { - Button("Stop") { + Button { self.stop(account.id) + } label: { + Text("Stop") + .font(OpenClawType.subhead) } } else { - Button("Start") { + Button { self.start(account.id) + } label: { + Text("Start") + .font(OpenClawType.subhead) } .disabled(!account.configured || !account.enabled) } if account.linked { - Button("Logout", role: .destructive) { + Button(role: .destructive) { self.logout(account.id) + } label: { + Text("Logout") + .font(OpenClawType.subhead) } } } label: { Image(systemName: self.actionMenuIcon(account)) + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) .controlSize(.mini) diff --git a/apps/ios/Sources/Design/SettingsProTab.swift b/apps/ios/Sources/Design/SettingsProTab.swift index 324880a23f2e..594d841eec30 100644 --- a/apps/ios/Sources/Design/SettingsProTab.swift +++ b/apps/ios/Sources/Design/SettingsProTab.swift @@ -119,6 +119,7 @@ struct SettingsProTab: View { self.gatewaySection self.settingsListSection } + .font(OpenClawType.body) .listStyle(.insetGrouped) .navigationTitle("Settings") .navigationBarTitleDisplayMode(.large) @@ -216,9 +217,15 @@ struct SettingsProTab: View { .ignoresSafeArea() .navigationTitle("Scan QR Code") .navigationBarTitleDisplayMode(.inline) + .font(OpenClawType.body) .toolbar { ToolbarItem(placement: .topBarLeading) { - Button("Cancel") { self.showQRScanner = false } + Button { + self.showQRScanner = false + } label: { + Text("Cancel") + .font(OpenClawType.subheadSemiBold) + } } } } @@ -294,17 +301,23 @@ struct HostedPushRelayDisclosureSheet: View { .foregroundStyle(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) + .font(OpenClawType.body) } VStack(spacing: 10) { Button { self.dismiss() self.onContinue() } label: { - Text("Continue").frame(maxWidth: .infinity) + Text("Continue") + .font(OpenClawType.subheadSemiBold) + .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) - Button("Not Now", role: .cancel) { + Button(role: .cancel) { self.dismiss() + } label: { + Text("Not Now") + .font(OpenClawType.subheadSemiBold) } .buttonStyle(.bordered) .frame(maxWidth: .infinity) diff --git a/apps/ios/Sources/Design/SettingsProTabSections.swift b/apps/ios/Sources/Design/SettingsProTabSections.swift index c3514cbeffa5..66e6b23cce18 100644 --- a/apps/ios/Sources/Design/SettingsProTabSections.swift +++ b/apps/ios/Sources/Design/SettingsProTabSections.swift @@ -241,6 +241,7 @@ extension SettingsProTab { } .padding(.top, 18) .padding(.bottom, OpenClawProMetric.bottomScrollInset) + .font(OpenClawType.body) } } .navigationTitle(self.title(for: route)) @@ -335,6 +336,7 @@ extension SettingsProTab { self.openNotificationsRouteFromApprovals() } label: { Label("Open Notifications", systemImage: "bell.badge") + .font(OpenClawType.captionSemiBold) .frame(maxWidth: .infinity) } .buttonStyle(.bordered) @@ -369,6 +371,7 @@ extension SettingsProTab { Task { await self.appModel.resolvePendingExecApprovalPrompt(decision: "allow-once") } } label: { Label("Allow", systemImage: "checkmark") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.borderedProminent) .disabled(self.appModel.pendingExecApprovalPromptResolving) @@ -380,6 +383,7 @@ extension SettingsProTab { } } label: { Label("Always", systemImage: "checkmark.shield") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) .disabled(self.appModel.pendingExecApprovalPromptResolving) @@ -389,6 +393,7 @@ extension SettingsProTab { Task { await self.appModel.resolvePendingExecApprovalPrompt(decision: "deny") } } label: { Label("Deny", systemImage: "xmark") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) .disabled(self.appModel.pendingExecApprovalPromptResolving) @@ -530,6 +535,7 @@ extension SettingsProTab { Label( self.notificationActionText, systemImage: self.notificationStatus.actionIcon) + .font(OpenClawType.captionSemiBold) .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) @@ -710,9 +716,15 @@ extension SettingsProTab { } Picker("Location", selection: self.$locationModeRaw) { - Text("Off").tag(OpenClawLocationMode.off.rawValue) - Text("While Using").tag(OpenClawLocationMode.whileUsing.rawValue) - Text("Always").tag(OpenClawLocationMode.always.rawValue) + Text("Off") + .font(OpenClawType.captionSemiBold) + .tag(OpenClawLocationMode.off.rawValue) + Text("While Using") + .font(OpenClawType.captionSemiBold) + .tag(OpenClawLocationMode.whileUsing.rawValue) + Text("Always") + .font(OpenClawType.captionSemiBold) + .tag(OpenClawLocationMode.always.rawValue) } .pickerStyle(.segmented) .disabled(self.isChangingLocationMode) @@ -793,12 +805,16 @@ extension SettingsProTab { Text("Default Agent") .font(OpenClawType.subheadSemiBold) Picker("Agent", selection: self.$selectedAgentPickerId) { - Text("Default").tag("") + Text("Default") + .font(OpenClawType.subhead) + .tag("") let defaultId = (self.appModel.gatewayDefaultAgentId ?? "") .trimmingCharacters(in: .whitespacesAndNewlines) ForEach(self.appModel.gatewayAgents.filter { $0.id != defaultId }, id: \.id) { agent in let name = (agent.name ?? "").trimmingCharacters(in: .whitespacesAndNewlines) - Text(name.isEmpty ? agent.id : name).tag(agent.id) + Text(name.isEmpty ? agent.id : name) + .font(OpenClawType.subhead) + .tag(agent.id) } } Text("Used for new Chat and Talk sessions.") @@ -817,6 +833,7 @@ extension SettingsProTab { TextField("Paste setup code", text: self.$setupCode) .textInputAutocapitalization(.never) .autocorrectionDisabled() + .font(OpenClawType.subhead) .textFieldStyle(.roundedBorder) HStack(spacing: 10) { self.gatewayActionButton( @@ -893,6 +910,7 @@ extension SettingsProTab { ProgressView().controlSize(.small) } else { Text("Connect") + .font(OpenClawType.captionSemiBold) } } .buttonStyle(.bordered) @@ -907,9 +925,11 @@ extension SettingsProTab { TextField("Host", text: self.$manualGatewayHost) .textInputAutocapitalization(.never) .autocorrectionDisabled() + .font(OpenClawType.subhead) .textFieldStyle(.roundedBorder) TextField("Port", text: self.manualPortBinding) .keyboardType(.numberPad) + .font(OpenClawType.subhead) .textFieldStyle(.roundedBorder) self.settingsButtonToggle("Use TLS", isOn: self.$manualGatewayTLS) self.gatewayActionButton( @@ -934,13 +954,16 @@ extension SettingsProTab { SecureField("Gateway Auth Token", text: self.$gatewayToken) .textInputAutocapitalization(.never) .autocorrectionDisabled() + .font(OpenClawType.subhead) .textFieldStyle(.roundedBorder) SecureField("Gateway Password", text: self.$gatewayPassword) + .font(OpenClawType.subhead) .textFieldStyle(.roundedBorder) Button(role: .destructive) { self.showResetOnboardingAlert = true } label: { Label("Reset Onboarding", systemImage: "arrow.counterclockwise") + .font(OpenClawType.captionSemiBold) .frame(maxWidth: .infinity) } .buttonStyle(.bordered) @@ -966,7 +989,9 @@ extension SettingsProTab { .disabled(self.appModel.isAppleReviewDemoModeEnabled) Picker("Speech Language", selection: self.$talkSpeechLocale) { ForEach(TalkSpeechLocale.supportedOptions()) { option in - Text(option.label).tag(option.id) + Text(option.label) + .font(OpenClawType.subhead) + .tag(option.id) } } self.settingsToggle("Background Listening", isOn: self.$talkBackgroundEnabled) @@ -999,14 +1024,20 @@ extension SettingsProTab { VStack(alignment: .leading, spacing: 12) { Picker("Provider", selection: self.talkProviderSelectionBinding) { ForEach(TalkModeProviderSelection.allCases) { option in - Text(option.label).tag(option.rawValue) + Text(option.label) + .font(OpenClawType.subhead) + .tag(option.rawValue) } } if self.shouldShowRealtimeVoicePicker { Picker("Realtime Voice", selection: self.talkRealtimeVoiceSelectionBinding) { - Text("Gateway Default").tag("") + Text("Gateway Default") + .font(OpenClawType.subhead) + .tag("") ForEach(TalkModeRealtimeVoiceSelection.voices, id: \.self) { voice in - Text(TalkModeRealtimeVoiceSelection.label(for: voice)).tag(voice) + Text(TalkModeRealtimeVoiceSelection.label(for: voice)) + .font(OpenClawType.subhead) + .tag(voice) } } } @@ -1030,15 +1061,20 @@ extension SettingsProTab { var shareSettingsCard: some View { ProCard(radius: SettingsLayout.cardRadius) { VStack(alignment: .leading, spacing: 12) { - Toggle("Show Talk Control", isOn: self.$talkButtonEnabled) + Toggle(isOn: self.$talkButtonEnabled) { + Text("Show Talk Control") + .font(OpenClawType.subhead) + } TextField("Default Share Instruction", text: self.$defaultShareInstruction, axis: .vertical) .lineLimit(2...5) .textInputAutocapitalization(.sentences) + .font(OpenClawType.subhead) .textFieldStyle(.roundedBorder) Button { Task { await self.appModel.runSharePipelineSelfTest() } } label: { Label("Run Share Self-Test", systemImage: "checkmark.seal") + .font(OpenClawType.captionSemiBold) } .buttonStyle(.bordered) Text(self.appModel.lastShareEventText) @@ -1089,10 +1125,13 @@ extension SettingsProTab { isOn: Binding, onChange: ((Bool) -> Void)? = nil) -> some View { - Toggle(title, isOn: isOn) - .onChange(of: isOn.wrappedValue) { _, enabled in - onChange?(enabled) - } + Toggle(isOn: isOn) { + Text(title) + .font(OpenClawType.subhead) + } + .onChange(of: isOn.wrappedValue) { _, enabled in + onChange?(enabled) + } } func settingsButtonToggle( diff --git a/apps/ios/Sources/Design/TalkProTab.swift b/apps/ios/Sources/Design/TalkProTab.swift index fb8c5f2235b5..c66ed5686dd5 100644 --- a/apps/ios/Sources/Design/TalkProTab.swift +++ b/apps/ios/Sources/Design/TalkProTab.swift @@ -60,8 +60,11 @@ struct TalkProTab: View { .navigationTitle("Enable Talk") .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Not Now") { + Button { self.showPermissionPrompt = false + } label: { + Text("Not Now") + .font(OpenClawType.subheadSemiBold) } } } diff --git a/apps/ios/Sources/Design/TalkRuntimeIssueBanner.swift b/apps/ios/Sources/Design/TalkRuntimeIssueBanner.swift index 1644dc37d384..20b63ad039ea 100644 --- a/apps/ios/Sources/Design/TalkRuntimeIssueBanner.swift +++ b/apps/ios/Sources/Design/TalkRuntimeIssueBanner.swift @@ -60,9 +60,12 @@ struct TalkRuntimeIssueDetailsSheet: View { .font(OpenClawType.monoFootnote) .foregroundStyle(.secondary) .textSelection(.enabled) - Button("Copy diagnostics") { + Button { UIPasteboard.general.string = self.issue.technicalDetails self.copyFeedback = "Copied diagnostics" + } label: { + Text("Copy diagnostics") + .font(OpenClawType.subheadSemiBold) } } @@ -79,15 +82,21 @@ struct TalkRuntimeIssueDetailsSheet: View { .toolbar { ToolbarItem(placement: .topBarLeading) { if let onOpenSettings { - Button("Open Settings") { + Button { self.dismiss() onOpenSettings() + } label: { + Text("Open Settings") + .font(OpenClawType.subheadSemiBold) } } } ToolbarItem(placement: .topBarTrailing) { - Button("Done") { + Button { self.dismiss() + } label: { + Text("Done") + .font(OpenClawType.subheadSemiBold) } } } diff --git a/apps/ios/Sources/Gateway/GatewayProblemView.swift b/apps/ios/Sources/Gateway/GatewayProblemView.swift index f9b157d12b59..520c5979a6fe 100644 --- a/apps/ios/Sources/Gateway/GatewayProblemView.swift +++ b/apps/ios/Sources/Gateway/GatewayProblemView.swift @@ -106,9 +106,12 @@ struct GatewayProblemDetailsSheet: View { Text(verbatim: requestId) .font(OpenClawType.mono) .textSelection(.enabled) - Button("Copy request ID") { + Button { UIPasteboard.general.string = requestId self.copyFeedback = "Copied request ID" + } label: { + Text("Copy request ID") + .font(OpenClawType.subheadSemiBold) } } } @@ -118,9 +121,12 @@ struct GatewayProblemDetailsSheet: View { Text(verbatim: actionCommand) .font(OpenClawType.mono) .textSelection(.enabled) - Button("Copy command") { + Button { UIPasteboard.general.string = actionCommand self.copyFeedback = "Copied command" + } label: { + Text("Copy command") + .font(OpenClawType.subheadSemiBold) } } } @@ -129,6 +135,7 @@ struct GatewayProblemDetailsSheet: View { Section("Help") { Link(destination: docsURL) { Label("Open docs", systemImage: "book") + .font(OpenClawType.subheadSemiBold) } Text(verbatim: docsURL.absoluteString) .font(OpenClawType.footnote) @@ -159,15 +166,21 @@ struct GatewayProblemDetailsSheet: View { .toolbar { ToolbarItem(placement: .topBarLeading) { if let primaryActionTitle, let onPrimaryAction { - Button(primaryActionTitle) { + Button { self.dismiss() onPrimaryAction() + } label: { + Text(primaryActionTitle) + .font(OpenClawType.subheadSemiBold) } } } ToolbarItem(placement: .topBarTrailing) { - Button("Done") { + Button { self.dismiss() + } label: { + Text("Done") + .font(OpenClawType.subheadSemiBold) } } } diff --git a/apps/ios/Sources/Gateway/GatewayQuickSetupSheet.swift b/apps/ios/Sources/Gateway/GatewayQuickSetupSheet.swift index f3df4bb6cddf..1c5051dff887 100644 --- a/apps/ios/Sources/Gateway/GatewayQuickSetupSheet.swift +++ b/apps/ios/Sources/Gateway/GatewayQuickSetupSheet.swift @@ -87,6 +87,7 @@ struct GatewayQuickSetupSheet: View { Spacer() } + .font(OpenClawType.body) .padding() .navigationTitle("Quick Setup") .navigationBarTitleDisplayMode(.inline) @@ -97,6 +98,7 @@ struct GatewayQuickSetupSheet: View { self.dismiss() } label: { Text("Close") + .font(OpenClawType.subheadSemiBold) } } } @@ -119,20 +121,23 @@ struct GatewayQuickSetupSheet: View { } private func fullRowToggle(_ title: LocalizedStringKey, isOn: Binding) -> some View { - Toggle(title, isOn: isOn) - .contentShape(Rectangle()) - .overlay { - // Keep Toggle semantics for accessibility while making the full visual row tappable. - Button { - isOn.wrappedValue.toggle() - } label: { - Rectangle() - .fill(.clear) - .contentShape(Rectangle()) - } - .buttonStyle(.plain) - .accessibilityHidden(true) + Toggle(isOn: isOn) { + Text(title) + .font(OpenClawType.subhead) + } + .contentShape(Rectangle()) + .overlay { + // Keep Toggle semantics for accessibility while making the full visual row tappable. + Button { + isOn.wrappedValue.toggle() + } label: { + Rectangle() + .fill(.clear) + .contentShape(Rectangle()) } + .buttonStyle(.plain) + .accessibilityHidden(true) + } } private func gatewayProblemPrimaryActionTitle(_ problem: GatewayConnectionProblem) -> String? { diff --git a/apps/ios/Sources/Settings/PrivacyAccessSectionView.swift b/apps/ios/Sources/Settings/PrivacyAccessSectionView.swift index 86f2640dcd65..1b4508213469 100644 --- a/apps/ios/Sources/Settings/PrivacyAccessSectionView.swift +++ b/apps/ios/Sources/Settings/PrivacyAccessSectionView.swift @@ -14,7 +14,7 @@ struct PrivacyAccessSectionView: View { @Environment(\.scenePhase) private var scenePhase var body: some View { - DisclosureGroup("Privacy & Access") { + DisclosureGroup { self.permissionRow( title: "Contacts", icon: "person.crop.circle", @@ -54,7 +54,11 @@ struct PrivacyAccessSectionView: View { detail: "List, add, and complete reminders.", actionTitle: self.remindersActionTitle, action: self.handleRemindersAction) + } label: { + Text("Privacy & Access") + .font(OpenClawType.subheadSemiBold) } + .font(OpenClawType.body) .onAppear { self.refreshAll() } .onChange(of: self.scenePhase) { _, phase in if phase == .active { @@ -74,6 +78,7 @@ struct PrivacyAccessSectionView: View { VStack(alignment: .leading, spacing: 6) { HStack { Label(title, systemImage: icon) + .font(OpenClawType.subheadSemiBold) Spacer() OpenClawStatusBadge(label: status, tone: self.statusTone(for: status)) .accessibilityIdentifier("privacy-access-\(title)-status") @@ -82,10 +87,12 @@ struct PrivacyAccessSectionView: View { .font(OpenClawType.footnote) .foregroundStyle(.secondary) if let actionTitle, let action { - Button(actionTitle, action: action) - .font(OpenClawType.footnote) - .buttonStyle(.bordered) - .accessibilityIdentifier("privacy-access-\(title)-action") + Button(action: action) { + Text(actionTitle) + .font(OpenClawType.footnoteSemiBold) + } + .buttonStyle(.bordered) + .accessibilityIdentifier("privacy-access-\(title)-action") } } .padding(.vertical, 2) diff --git a/apps/ios/Tests/OpenClawTypographyTests.swift b/apps/ios/Tests/OpenClawTypographyTests.swift index 78da512e84a7..37686e502520 100644 --- a/apps/ios/Tests/OpenClawTypographyTests.swift +++ b/apps/ios/Tests/OpenClawTypographyTests.swift @@ -89,6 +89,63 @@ struct OpenClawTypographyTests { #expect(!watchSource.contains(".font(.title")) } + @Test func `listed iOS app surfaces enforce branded control typography`() throws { + let proComponents = try String( + contentsOf: Self.sourceURL("Design/OpenClawProComponents.swift"), + encoding: .utf8) + let quickSetup = try String(contentsOf: Self.sourceURL("Gateway/GatewayQuickSetupSheet.swift"), encoding: .utf8) + let settingsSections = try String( + contentsOf: Self.sourceURL("Design/SettingsProTabSections.swift"), + encoding: .utf8) + let privacyAccess = try String( + contentsOf: Self.sourceURL("Settings/PrivacyAccessSectionView.swift"), + encoding: .utf8) + let skillWorkshop = try String( + contentsOf: Self.sourceURL("Design/IPadSkillWorkshopScreen.swift"), + encoding: .utf8) + let agentDestinations = try String( + contentsOf: Self.sourceURL("Design/AgentProTab+Destinations.swift"), + encoding: .utf8) + let dreaming = try String( + contentsOf: Self.sourceURL("Design/AgentProDreamingDestination.swift"), + encoding: .utf8) + let instances = try String(contentsOf: Self.sourceURL("Design/AgentProNodesDestination.swift"), encoding: .utf8) + let channels = try String( + contentsOf: Self.sourceURL("Design/SettingsChannelsDestination.swift"), + encoding: .utf8) + let docs = try String(contentsOf: Self.sourceURL("Design/OpenClawDocsScreen.swift"), encoding: .utf8) + + #expect(proComponents.contains(".font(OpenClawType.subheadSemiBold)")) + #expect(proComponents.contains("Text(primaryActionTitle)")) + #expect(proComponents.contains("Text(secondaryActionTitle)")) + + #expect(!quickSetup.contains("Button(\"Close\")")) + #expect(quickSetup.contains("Text(\"Close\")")) + #expect(quickSetup.contains(".font(OpenClawType.subheadSemiBold)")) + + #expect(settingsSections.contains(".font(OpenClawType.body)")) + #expect(settingsSections.contains("Toggle(isOn: self.$talkButtonEnabled)")) + #expect(settingsSections.contains("Text(\"Show Talk Control\")")) + #expect(settingsSections.contains("TextField(\"Default Share Instruction\"")) + #expect(settingsSections.contains(".font(OpenClawType.subhead)")) + + #expect(!privacyAccess.contains("DisclosureGroup(\"Privacy & Access\")")) + #expect(privacyAccess.contains("Text(\"Privacy & Access\")")) + #expect(privacyAccess.contains("Text(actionTitle)")) + #expect(privacyAccess.contains(".font(OpenClawType.footnoteSemiBold)")) + + #expect(!skillWorkshop.contains("Button(\"Done\")")) + #expect(skillWorkshop.contains("Label(\"Refresh\", systemImage: \"arrow.clockwise\")")) + #expect(skillWorkshop.contains("Text(\"Default agent\")")) + #expect(skillWorkshop.contains("Text(\"Inspect\")")) + #expect(skillWorkshop.contains("Text(\"Apply\")")) + #expect(skillWorkshop.contains("Text(\"Reject\")")) + + for source in [agentDestinations, dreaming, instances, channels, docs] { + #expect(source.contains(".font(OpenClawType.body)")) + } + } + private static let bundledFontFiles = [ "RedHatDisplay[wght].ttf", "Inter[opsz,wght].ttf", @@ -118,6 +175,10 @@ struct OpenClawTypographyTests { self.iosRootURL().appendingPathComponent("WatchApp/Sources/WatchInboxView.swift") } + private static func sourceURL(_ relativePath: String) -> URL { + self.iosRootURL().appendingPathComponent("Sources/\(relativePath)") + } + private static func iosRootURL() -> URL { URL(fileURLWithPath: #filePath) .deletingLastPathComponent()