Skip to content

Commit 3dd8bcb

Browse files
committed
style(macos): polish settings panes
1 parent 5e1fde7 commit 3dd8bcb

12 files changed

Lines changed: 962 additions & 396 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
66

77
### Changes
88

9+
- Mac app: redesign Settings pages with consistent card layouts, cached navigation, cleaner permissions/voice/skills/cron/exec/debug panes, and steadier spacing around the native sidebar.
910
- Skills: add a meme-maker skill for curated template search, local SVG/PNG rendering, Imgflip hosted rendering, and Know Your Meme provenance links.
1011
- Agents/tools: shorten built-in tool descriptions and schema hints across media, messaging, sessions, cron, Gateway, web, image/PDF, TTS, nodes, and plan tools while preserving routing guardrails.
1112
- Skills: add node inspector debugging, fused diagram generation, and throwaway spike workflow skills.

apps/macos/Sources/OpenClaw/CronSettings+Layout.swift

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ import SwiftUI
22

33
extension CronSettings {
44
var body: some View {
5-
VStack(alignment: .leading, spacing: 12) {
5+
VStack(alignment: .leading, spacing: 16) {
66
self.header
77
self.schedulerBanner
88
self.content
99
Spacer(minLength: 0)
1010
}
11+
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
12+
.padding(.leading, 18)
13+
.padding(.trailing, SettingsLayout.scrollbarGutter)
1114
.onAppear {
1215
self.updateActiveWork(active: self.isActive)
1316
}
@@ -101,16 +104,18 @@ extension CronSettings {
101104
}
102105

103106
var header: some View {
104-
HStack(alignment: .top) {
105-
VStack(alignment: .leading, spacing: 4) {
106-
Text("Cron")
107-
.font(.headline)
108-
Text("Manage Gateway cron jobs (main session vs isolated runs) and inspect run history.")
109-
.font(.footnote)
107+
HStack(alignment: .top, spacing: 16) {
108+
VStack(alignment: .leading, spacing: 5) {
109+
Text("Cron Jobs")
110+
.font(.title3.weight(.semibold))
111+
Text("Manage Gateway cron jobs and inspect run history.")
112+
.font(.callout)
110113
.foregroundStyle(.secondary)
111114
.fixedSize(horizontal: false, vertical: true)
112115
}
113-
Spacer()
116+
117+
Spacer(minLength: 16)
118+
114119
HStack(spacing: 8) {
115120
Button {
116121
Task { await self.store.refreshJobs() }

apps/macos/Sources/OpenClaw/CronSettings+Testing.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ extension CronSettings {
104104
store.runEntries = [run]
105105

106106
let view = CronSettings(store: store, channelsStore: ChannelsStore(isPreview: true))
107-
_ = view.body
108107
_ = view.jobRow(job)
109108
_ = view.jobContextMenu(job)
110109
_ = view.detailHeader(job)

apps/macos/Sources/OpenClaw/DebugSettings.swift

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct DebugSettings: View {
4949
VStack(alignment: .leading, spacing: 14) {
5050
self.header
5151

52+
self.overviewSection
5253
self.launchdSection
5354
self.appInfoSection
5455
self.gatewaySection
@@ -62,8 +63,8 @@ struct DebugSettings: View {
6263
Spacer(minLength: 0)
6364
}
6465
.frame(maxWidth: .infinity, alignment: .leading)
65-
.padding(.horizontal, 24)
66-
.padding(.vertical, 18)
66+
.padding(.vertical, 4)
67+
.padding(.trailing, SettingsLayout.scrollbarGutter)
6768
.groupBoxStyle(PlainSettingsGroupBoxStyle())
6869
}
6970
.task {
@@ -119,6 +120,31 @@ struct DebugSettings: View {
119120
}
120121
}
121122

123+
private var overviewSection: some View {
124+
HStack(spacing: 12) {
125+
DebugMetricCard(
126+
title: "App Health",
127+
value: self.healthStore.state.debugTitle,
128+
icon: "heart.text.square",
129+
tint: self.healthStore.state.tint,
130+
subtitle: self.healthStore.summaryLine)
131+
132+
DebugMetricCard(
133+
title: "Gateway",
134+
value: self.gatewayManager.status.label,
135+
icon: "antenna.radiowaves.left.and.right",
136+
tint: self.gatewayManager.status.debugTint,
137+
subtitle: self.canRestartGateway ? "Local process" : "Remote connection")
138+
139+
DebugMetricCard(
140+
title: "App PID",
141+
value: "\(ProcessInfo.processInfo.processIdentifier)",
142+
icon: "number.square",
143+
tint: .blue,
144+
subtitle: Bundle.main.bundleURL.lastPathComponent)
145+
}
146+
}
147+
122148
private func gridLabel(_ text: String) -> some View {
123149
Text(text)
124150
.foregroundStyle(.secondary)
@@ -216,8 +242,12 @@ struct DebugSettings: View {
216242
.frame(maxWidth: .infinity, alignment: .leading)
217243
.textSelection(.enabled)
218244
}
219-
.frame(height: 180)
220-
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Color.secondary.opacity(0.2)))
245+
.frame(height: 130)
246+
.background(.black.opacity(0.12), in: RoundedRectangle(cornerRadius: 8, style: .continuous))
247+
.overlay {
248+
RoundedRectangle(cornerRadius: 8, style: .continuous)
249+
.strokeBorder(.white.opacity(0.06))
250+
}
221251

222252
HStack(spacing: 8) {
223253
if self.canRestartGateway {
@@ -929,13 +959,81 @@ extension DebugSettings {
929959

930960
struct PlainSettingsGroupBoxStyle: GroupBoxStyle {
931961
func makeBody(configuration: Configuration) -> some View {
932-
VStack(alignment: .leading, spacing: 10) {
962+
VStack(alignment: .leading, spacing: 12) {
933963
configuration.label
934-
.font(.caption.weight(.semibold))
964+
.font(.subheadline.weight(.semibold))
935965
.foregroundStyle(.secondary)
936966
configuration.content
937967
}
968+
.padding(14)
938969
.frame(maxWidth: .infinity, alignment: .leading)
970+
.background(.quaternary.opacity(0.34), in: RoundedRectangle(cornerRadius: 12, style: .continuous))
971+
.overlay {
972+
RoundedRectangle(cornerRadius: 12, style: .continuous)
973+
.strokeBorder(.white.opacity(0.055))
974+
}
975+
}
976+
}
977+
978+
private struct DebugMetricCard: View {
979+
let title: String
980+
let value: String
981+
let icon: String
982+
let tint: Color
983+
let subtitle: String
984+
985+
var body: some View {
986+
HStack(alignment: .top, spacing: 12) {
987+
Image(systemName: self.icon)
988+
.font(.system(size: 18, weight: .semibold))
989+
.foregroundStyle(self.tint)
990+
.frame(width: 34, height: 34)
991+
.background(self.tint.opacity(0.18), in: Circle())
992+
993+
VStack(alignment: .leading, spacing: 3) {
994+
Text(self.title)
995+
.font(.caption.weight(.semibold))
996+
.foregroundStyle(.secondary)
997+
Text(self.value)
998+
.font(.callout.weight(.semibold))
999+
.lineLimit(1)
1000+
.truncationMode(.tail)
1001+
Text(self.subtitle)
1002+
.font(.caption2)
1003+
.foregroundStyle(.secondary)
1004+
.lineLimit(2)
1005+
.fixedSize(horizontal: false, vertical: true)
1006+
}
1007+
}
1008+
.padding(12)
1009+
.frame(maxWidth: .infinity, alignment: .topLeading)
1010+
.background(.quaternary.opacity(0.28), in: RoundedRectangle(cornerRadius: 12, style: .continuous))
1011+
.overlay {
1012+
RoundedRectangle(cornerRadius: 12, style: .continuous)
1013+
.strokeBorder(.white.opacity(0.055))
1014+
}
1015+
}
1016+
}
1017+
1018+
extension HealthState {
1019+
fileprivate var debugTitle: String {
1020+
switch self {
1021+
case .unknown: "Unknown"
1022+
case .ok: "Healthy"
1023+
case .linkingNeeded: "Needs Link"
1024+
case .degraded: "Degraded"
1025+
}
1026+
}
1027+
}
1028+
1029+
extension GatewayProcessManager.Status {
1030+
fileprivate var debugTint: Color {
1031+
switch self {
1032+
case .running, .attachedExisting: .green
1033+
case .starting: .orange
1034+
case .failed: .red
1035+
case .stopped: .secondary
1036+
}
9391037
}
9401038
}
9411039

@@ -984,6 +1082,7 @@ extension DebugSettings {
9841082

9851083
_ = view.body
9861084
_ = view.header
1085+
_ = view.overviewSection
9871086
_ = view.appInfoSection
9881087
_ = view.gatewaySection
9891088
_ = view.logsSection

apps/macos/Sources/OpenClaw/GeneralSettings.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct GeneralSettings: View {
4545
}
4646
.frame(maxWidth: 760, alignment: .leading)
4747
.padding(.bottom, 16)
48+
.padding(.leading, 18)
49+
.padding(.trailing, SettingsLayout.scrollbarGutter)
4850
}
4951
.onAppear {
5052
self.updateActiveWork(active: self.isActive)
@@ -538,7 +540,7 @@ struct GeneralSettings: View {
538540
{
539541
SecureField("remote gateway auth token (gateway.remote.token)", text: self.$state.remoteToken)
540542
.textFieldStyle(.roundedBorder)
541-
.frame(width: 520)
543+
.frame(width: 360)
542544
}
543545
if self.state.remoteTokenUnsupported {
544546
Text(

apps/macos/Sources/OpenClaw/InstancesSettings.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct InstancesSettings: View {
1111
}
1212

1313
var body: some View {
14-
VStack(alignment: .leading, spacing: 12) {
14+
VStack(alignment: .leading, spacing: 16) {
1515
self.header
1616
if let err = store.lastError {
1717
Text("Error: \(err)")
@@ -31,6 +31,9 @@ struct InstancesSettings: View {
3131
}
3232
Spacer()
3333
}
34+
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
35+
.padding(.leading, 18)
36+
.padding(.trailing, SettingsLayout.scrollbarGutter)
3437
.onAppear { self.updateActiveWork(active: self.isActive) }
3538
.onChange(of: self.isActive) { _, active in
3639
self.updateActiveWork(active: active)
@@ -47,15 +50,18 @@ struct InstancesSettings: View {
4750
}
4851

4952
private var header: some View {
50-
HStack {
51-
VStack(alignment: .leading, spacing: 4) {
53+
HStack(alignment: .top, spacing: 16) {
54+
VStack(alignment: .leading, spacing: 5) {
5255
Text("Connected Instances")
53-
.font(.headline)
56+
.font(.title3.weight(.semibold))
5457
Text("Latest presence beacons from OpenClaw nodes. Updated periodically.")
55-
.font(.footnote)
58+
.font(.callout)
5659
.foregroundStyle(.secondary)
60+
.fixedSize(horizontal: false, vertical: true)
5761
}
58-
Spacer()
62+
63+
Spacer(minLength: 16)
64+
5965
SettingsRefreshButton(isLoading: self.store.isLoading) {
6066
Task { await self.store.refresh() }
6167
}

0 commit comments

Comments
 (0)