spb/zyquo-router Public MIT
One local endpoint, every AI provider — a private OpenAI-compatible LLM gateway for your Mac (170 models, 12 providers).
Swift 95.7%
Python 2.3%
Shell 1.2%
Makefile 0.9%
1//2// AppearanceStore.swift3// Zyquo Router4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// User appearance preferences: theme mode, accent choice, font size.9// Persisted to appearance.json via PersistenceService. Family design with10// the Router's accent set: cyan (default) + graphite, sky, emerald, violet,11// copper.12//1314import SwiftUI1516/// Accent color choices in Settings → Appearance.17enum AccentChoice: String, Codable, CaseIterable, Identifiable {18 case cyan19 case graphite20 case sky21 case emerald22 case violet23 case copper2425 var id: String { rawValue }2627 var displayName: String {28 switch self {29 case .cyan: return "Signal Cyan"30 case .graphite: return "Graphite"31 case .sky: return "Sky"32 case .emerald: return "Emerald"33 case .violet: return "Violet"34 case .copper: return "Copper"35 }36 }3738 /// (light, dark) accent hex pair.39 var accentHex: (UInt32, UInt32) {40 switch self {41 case .cyan: return (0x0891B2, 0x22B8D4)42 case .graphite: return (0x374151, 0x9AA4B2)43 case .sky: return (0x2E7CD6, 0x5A9BE3)44 case .emerald: return (0x1E9E6A, 0x3CBA87)45 case .violet: return (0x7451D8, 0x9273E4)46 case .copper: return (0xB2622B, 0xC97F4B)47 }48 }4950 /// (light, dark) subtle-tint hex pair (selected rows, active tints).51 var subtleHex: (UInt32, UInt32) {52 switch self {53 case .cyan: return (0xE5F5F9, 0x143A44)54 case .graphite: return (0xEEF1F4, 0x2A2F36)55 case .sky: return (0xE8F1FC, 0x1B3350)56 case .emerald: return (0xE6F6EF, 0x173B2C)57 case .violet: return (0xF0EBFB, 0x2C2347)58 case .copper: return (0xF9EFE6, 0x3D2C1D)59 }60 }61}6263enum ThemeMode: String, Codable, CaseIterable, Identifiable {64 case system, light, dark65 var id: String { rawValue }6667 var displayName: String {68 switch self {69 case .system: return "System"70 case .light: return "Light"71 case .dark: return "Dark"72 }73 }7475 var colorScheme: ColorScheme? {76 switch self {77 case .system: return nil78 case .light: return .light79 case .dark: return .dark80 }81 }82}8384/// Observable appearance preferences, persisted with the app settings.85@MainActor86final class AppearanceStore: ObservableObject {87 struct Stored: Codable {88 var themeMode: ThemeMode = .system89 var accent: AccentChoice = .cyan90 var fontSize: Double = 1391 }9293 static let fileName = "appearance.json"9495 @Published var themeMode: ThemeMode { didSet { save() } }96 @Published var accent: AccentChoice { didSet { save() } }97 /// Base body font size, clamped to 12–16pt.98 @Published var fontSize: Double {99 didSet {100 let clamped = min(16, max(12, fontSize))101 if clamped != fontSize { fontSize = clamped }102 save()103 }104 }105106 private let persistence: PersistenceService107108 init(persistence: PersistenceService = .shared) {109 self.persistence = persistence110 let stored = persistence.load(Stored.self, from: Self.fileName) ?? Stored()111 themeMode = stored.themeMode112 accent = stored.accent113 fontSize = stored.fontSize114 }115116 /// Current accent color resolved for the active appearance.117 var accentColor: Color {118 let (light, dark) = accent.accentHex119 return ZyquoColor.dynamic(light: light, dark: dark)120 }121122 /// Current subtle accent tint resolved for the active appearance.123 var accentSubtleColor: Color {124 let (light, dark) = accent.subtleHex125 return ZyquoColor.dynamic(light: light, dark: dark)126 }127128 private func save() {129 persistence.save(130 Stored(themeMode: themeMode, accent: accent, fontSize: fontSize),131 to: Self.fileName132 )133 }134}135