Skip to content

Commit 2da6a1d

Browse files
authored
Merge pull request #15 from Anmol1696/feat/ui-revamp
Feat/UI revamp
2 parents 0085f8f + 31f884b commit 2da6a1d

31 files changed

Lines changed: 5076 additions & 590 deletions

Makefile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.PHONY: build run test open log log-stream clean help
2+
3+
APP_DIR := app/macos
4+
DIST_DIR := dist
5+
BUNDLE_ID := ai.openclaw.launcher
6+
7+
help:
8+
@echo "OpenClaw Launcher - Development Commands"
9+
@echo ""
10+
@echo " make build - Build the .app and .dmg"
11+
@echo " make run - Build and run the app"
12+
@echo " make open - Open the app (without rebuilding)"
13+
@echo " make test - Run unit tests"
14+
@echo " make log - Show recent app logs (last 5 min)"
15+
@echo " make log-stream - Stream app logs in real-time"
16+
@echo " make clean - Clean build artifacts"
17+
@echo ""
18+
19+
build:
20+
@cd $(APP_DIR) && ./build
21+
22+
run: build open
23+
24+
open:
25+
@open $(DIST_DIR)/OpenClawLauncher.app
26+
27+
test:
28+
@cd $(APP_DIR) && swift test
29+
30+
log:
31+
@echo "Showing logs for OpenClawLauncher (last 5 minutes)..."
32+
@echo "---"
33+
@log show --predicate 'subsystem == "$(BUNDLE_ID)" OR process == "OpenClawLauncher"' \
34+
--style compact --last 5m
35+
36+
log-stream:
37+
@echo "Streaming logs for OpenClawLauncher... (Ctrl+C to stop)"
38+
@echo "---"
39+
@log stream --predicate 'subsystem == "$(BUNDLE_ID)" OR process == "OpenClawLauncher"' \
40+
--style compact
41+
42+
clean:
43+
@rm -rf $(DIST_DIR)/ $(APP_DIR)/.build
44+
@echo "Cleaned."

app/macos/Sources/OpenClawApp/OpenClawApp.swift

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,47 @@ import OpenClawLib
33

44
@main
55
struct OpenClawApp: App {
6-
@StateObject private var launcher = OpenClawLauncher()
6+
@StateObject private var launcher: OpenClawLauncher
7+
@StateObject private var settings: LauncherSettings
8+
9+
init() {
10+
// Proper StateObject initialization - load settings once at startup
11+
_launcher = StateObject(wrappedValue: OpenClawLauncher())
12+
_settings = StateObject(wrappedValue: LauncherSettings.load())
13+
}
714

815
var body: some Scene {
916
WindowGroup {
10-
LauncherView(launcher: launcher)
11-
.frame(width: 520, height: launcher.state == .running ? 580 : 520)
12-
.animation(.easeInOut(duration: 0.25), value: launcher.state)
13-
.onAppear { launcher.start() }
17+
if !settings.hasCompletedOnboarding {
18+
OnboardingView(settings: settings) {
19+
// Onboarding complete - launcher will auto-start if user clicked "Launch"
20+
configureLauncher()
21+
launcher.start()
22+
}
23+
.frame(width: 500, height: 400)
24+
} else {
25+
NewLauncherView(launcher: launcher, settings: settings)
26+
.frame(width: 700, height: launcher.state == .running ? 520 : 480)
27+
.animation(.easeInOut(duration: 0.3), value: launcher.state)
28+
.onAppear {
29+
// Auto-start for returning users (will recover running container or start fresh)
30+
if launcher.state == .idle {
31+
configureLauncher()
32+
launcher.start()
33+
}
34+
}
35+
}
36+
}
37+
.windowStyle(.hiddenTitleBar)
38+
.windowResizability(.contentSize)
39+
40+
// Settings Window
41+
Window("Settings", id: "settings") {
42+
SettingsView(
43+
settings: settings,
44+
onReAuthenticate: { launcher.reAuthenticate() },
45+
onResetAll: { launcher.resetEverything() }
46+
)
1447
}
1548
.windowStyle(.hiddenTitleBar)
1649
.windowResizability(.contentSize)
@@ -22,4 +55,10 @@ struct OpenClawApp: App {
2255
Text("🐙")
2356
}
2457
}
58+
59+
/// Configure launcher with current settings (port + resources)
60+
private func configureLauncher() {
61+
launcher.configurePort(useRandomPort: settings.useRandomPort, customPort: settings.customPort)
62+
launcher.configureResources(memoryLimit: settings.memoryLimit.rawValue, cpuLimit: settings.cpuLimit.rawValue)
63+
}
2564
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import SwiftUI
2+
3+
/// Small status badge with text
4+
public struct OceanBadge: View {
5+
public enum Style {
6+
case `default` // Accent dim
7+
case warning // Warning color
8+
case error // Error color
9+
case success // Success/accent
10+
11+
var backgroundColor: Color {
12+
switch self {
13+
case .default, .success: return Ocean.accentDim
14+
case .warning: return Ocean.warning.opacity(0.15)
15+
case .error: return Ocean.error.opacity(0.15)
16+
}
17+
}
18+
19+
var textColor: Color {
20+
switch self {
21+
case .default, .success: return Ocean.accent
22+
case .warning: return Ocean.warning
23+
case .error: return Ocean.error
24+
}
25+
}
26+
27+
var borderColor: Color {
28+
switch self {
29+
case .default, .success: return Ocean.border
30+
case .warning: return Ocean.borderWarning
31+
case .error: return Ocean.borderError
32+
}
33+
}
34+
}
35+
36+
let text: String
37+
let style: Style
38+
39+
public init(_ text: String, style: Style = .default) {
40+
self.text = text
41+
self.style = style
42+
}
43+
44+
public var body: some View {
45+
Text(text)
46+
.font(Ocean.mono(10, weight: .medium))
47+
.foregroundColor(style.textColor)
48+
.padding(.horizontal, 10)
49+
.padding(.vertical, 4)
50+
.background(style.backgroundColor)
51+
.cornerRadius(20)
52+
.overlay(
53+
RoundedRectangle(cornerRadius: 20)
54+
.stroke(style.borderColor, lineWidth: 1)
55+
)
56+
}
57+
}
58+
59+
// MARK: - Preview
60+
61+
#if DEBUG
62+
struct OceanBadge_Previews: PreviewProvider {
63+
static var previews: some View {
64+
HStack(spacing: 12) {
65+
OceanBadge("lockdown")
66+
OceanBadge("stopping", style: .warning)
67+
OceanBadge("error", style: .error)
68+
OceanBadge("active", style: .success)
69+
}
70+
.padding(40)
71+
.background(Ocean.bg)
72+
}
73+
}
74+
#endif
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import SwiftUI
2+
3+
/// Styled button variants for Ocean theme
4+
public struct OceanButton: View {
5+
public enum Variant {
6+
case primary // Accent background, dark text
7+
case secondary // Transparent, bordered
8+
case danger // Error color, bordered
9+
}
10+
11+
let title: String
12+
let icon: String?
13+
let variant: Variant
14+
let action: () -> Void
15+
16+
@Environment(\.isEnabled) private var isEnabled
17+
18+
public init(
19+
_ title: String,
20+
icon: String? = nil,
21+
variant: Variant = .primary,
22+
action: @escaping () -> Void
23+
) {
24+
self.title = title
25+
self.icon = icon
26+
self.variant = variant
27+
self.action = action
28+
}
29+
30+
public var body: some View {
31+
Button(action: action) {
32+
HStack(spacing: 6) {
33+
if let icon = icon {
34+
Text(icon)
35+
}
36+
Text(title)
37+
.font(Ocean.ui(13, weight: .medium))
38+
}
39+
.padding(.horizontal, 16)
40+
.padding(.vertical, 8)
41+
.background(background)
42+
.foregroundColor(foregroundColor)
43+
.cornerRadius(Ocean.buttonRadius)
44+
.overlay(
45+
RoundedRectangle(cornerRadius: Ocean.buttonRadius)
46+
.stroke(borderColor, lineWidth: variant == .primary ? 0 : 1)
47+
)
48+
}
49+
.buttonStyle(.plain)
50+
.opacity(isEnabled ? 1 : 0.5)
51+
}
52+
53+
private var background: Color {
54+
guard isEnabled else { return Ocean.surface }
55+
switch variant {
56+
case .primary: return Ocean.accent
57+
case .secondary, .danger: return .clear
58+
}
59+
}
60+
61+
private var foregroundColor: Color {
62+
guard isEnabled else { return Ocean.textDim }
63+
switch variant {
64+
case .primary: return Ocean.bg
65+
case .secondary: return Ocean.textDim
66+
case .danger: return Ocean.error
67+
}
68+
}
69+
70+
private var borderColor: Color {
71+
guard isEnabled else { return Ocean.border }
72+
switch variant {
73+
case .primary: return .clear
74+
case .secondary: return Ocean.border
75+
case .danger: return Ocean.borderError
76+
}
77+
}
78+
}
79+
80+
// MARK: - Preview
81+
82+
#if DEBUG
83+
struct OceanButton_Previews: PreviewProvider {
84+
static var previews: some View {
85+
VStack(spacing: 16) {
86+
OceanButton("Launch", icon: "", variant: .primary) {}
87+
OceanButton("Cancel", variant: .secondary) {}
88+
OceanButton("Stop", icon: "", variant: .danger) {}
89+
90+
Divider()
91+
92+
OceanButton("Disabled", variant: .primary) {}
93+
.disabled(true)
94+
OceanButton("Disabled", variant: .secondary) {}
95+
.disabled(true)
96+
}
97+
.padding(40)
98+
.background(Ocean.bg)
99+
}
100+
}
101+
#endif

0 commit comments

Comments
 (0)