spb/zyquo-agent Public MIT
The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.
Swift 94.7%
Shell 4.1%
Python 0.7%
Makefile 0.5%
1//2// AppearanceSettingsTab.swift3// Zyquo Agent4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// Settings › Appearance — theme mode (Light/Dark/System), the five accent9// choices with swatches (violet flagship + graphite, sky, emerald, amber),10// and the chat font size slider (12–18pt) with live preview.11//1213import SwiftUI1415struct AppearanceSettingsTab: View {16 @EnvironmentObject private var appearance: AppearanceStore1718 var body: some View {19 Form {20 Picker("Theme", selection: $appearance.themeMode) {21 ForEach(ThemeMode.allCases) { mode in22 Text(mode.displayName).tag(mode)23 }24 }25 .pickerStyle(.segmented)2627 VStack(alignment: .leading, spacing: ZyquoSpacing.xs) {28 Text("Accent")29 HStack(spacing: ZyquoSpacing.sm) {30 ForEach(AccentChoice.allCases) { choice in31 accentSwatch(choice)32 }33 Spacer(minLength: 0)34 }35 }3637 VStack(alignment: .leading, spacing: ZyquoSpacing.xs) {38 HStack {39 Text("Chat font size")40 Spacer()41 Text(String(format: "%.1f pt", appearance.chatFontSize))42 .font(ZyquoFont.caption)43 .foregroundStyle(ZyquoColor.textSecondary)44 .monospacedDigit()45 }46 Slider(value: $appearance.chatFontSize, in: 12...18, step: 0.5)47 VStack(alignment: .leading, spacing: ZyquoSpacing.xxs) {48 Text("Preview")49 .font(ZyquoFont.caption)50 .foregroundStyle(ZyquoColor.textTertiary)51 Text("The quick brown fox jumps over the lazy dog — Zyquo Agent renders task text at this size, with generous 1.45 line height for readability.")52 .font(ZyquoFont.body(size: appearance.chatFontSize))53 .lineSpacing(appearance.chatFontSize * ZyquoFont.bodyLineSpacingFactor)54 .foregroundStyle(ZyquoColor.textPrimary)55 .padding(ZyquoSpacing.sm)56 .frame(maxWidth: .infinity, alignment: .leading)57 .background(58 RoundedRectangle(cornerRadius: ZyquoRadius.medium, style: .continuous)59 .fill(ZyquoColor.surface)60 .overlay(61 RoundedRectangle(cornerRadius: ZyquoRadius.medium, style: .continuous)62 .strokeBorder(ZyquoColor.border, lineWidth: ZyquoMetrics.hairline)63 )64 )65 }66 }67 }68 .formStyle(.grouped)69 }7071 private func accentSwatch(_ choice: AccentChoice) -> some View {72 let isSelected = appearance.accent == choice73 return Button {74 withAnimation(ZyquoMotion.appear) { appearance.accent = choice }75 } label: {76 VStack(spacing: ZyquoSpacing.xxs) {77 Circle()78 .fill(swatchColor(choice))79 .frame(width: 26, height: 26)80 .overlay(81 Circle().strokeBorder(82 isSelected ? ZyquoColor.textPrimary : ZyquoColor.border,83 lineWidth: isSelected ? 2 : ZyquoMetrics.hairline84 )85 )86 .overlay {87 if isSelected {88 Image(systemName: "checkmark")89 .font(.system(size: 10, weight: .bold))90 .foregroundStyle(.white)91 }92 }93 Text(choice.displayName)94 .font(ZyquoFont.caption)95 .foregroundStyle(isSelected ? ZyquoColor.textPrimary : ZyquoColor.textSecondary)96 }97 }98 .buttonStyle(PressableButtonStyle())99 .help("\(choice.displayName) accent")100 }101102 /// Appearance-resolved swatch color for one accent choice.103 private func swatchColor(_ choice: AccentChoice) -> Color {104 let (light, dark) = choice.accentHex105 return Color(nsColor: NSColor(name: nil) { appearance in106 let hex = appearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua ? dark : light107 return NSColor(hex: hex)108 })109 }110}111