SPB Git

spb/zyquo-atlas Public License

The AI-native macOS web browser — every surface, intelligent.

Swift 75.2% JavaScript 22% Shell 2% Makefile 0.9%
4.6 KB · 135 lines swift
Raw Blame History
1//2//  AtlasTheme.swift3//  Zyquo Atlas4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//8//  The user-overridable theme value type (Phase 4.2). A theme is a named color9//  palette + background + appearance, Codable so it imports/exports as a small10//  JSON file. The base tokens in ZyquoTheme seed the flagship "Atlas Light"11//  theme (Phase 4.1); the ThemeEngine swaps the active AtlasTheme live. Layout12//  and typography preferences live in LayoutSettings (separate from color13//  themes) so changing colors never disturbs the user's layout.14//1516import SwiftUI1718extension Color {19    /// 0xRRGGBB → Color (sRGB).20    init(hex: UInt32) {21        self.init(.sRGB,22                  red: Double((hex >> 16) & 0xFF) / 255,23                  green: Double((hex >> 8) & 0xFF) / 255,24                  blue: Double(hex & 0xFF) / 255,25                  opacity: 1)26    }27}2829enum ThemeAppearance: String, Codable, Hashable {30    case light, dark31}3233/// The 13 semantic color slots (the flagship "Atlas Light" values are the34/// Phase 4.1 base spec).35struct AtlasPalette: Codable, Hashable {36    var background: UInt3237    var surface: UInt3238    var surfaceSecondary: UInt3239    var accent: UInt3240    var accentIndigo: UInt3241    var accentSubtle: UInt3242    var textPrimary: UInt3243    var textSecondary: UInt3244    var textTertiary: UInt3245    var border: UInt3246    var success: UInt3247    var warning: UInt3248    var danger: UInt3249}5051/// Background behind the chrome / new-tab page.52struct BackgroundStyle: Codable, Hashable {53    enum Kind: String, Codable { case solid, gradient, image }54    var kind: Kind = .solid55    var colorA: UInt32 = 0xFAFBFC56    var colorB: UInt32 = 0xE6F5F357    /// Absolute path to a wallpaper image (image kind only).58    var imagePath: String?59}6061struct AtlasTheme: Codable, Hashable, Identifiable {62    var id: String63    var name: String64    var appearance: ThemeAppearance65    var palette: AtlasPalette66    var background: BackgroundStyle6768    // MARK: - Resolved SwiftUI colors (views read these)6970    var backgroundColor: Color { Color(hex: palette.background) }71    var surface: Color { Color(hex: palette.surface) }72    var surfaceSecondary: Color { Color(hex: palette.surfaceSecondary) }73    var accent: Color { Color(hex: palette.accent) }74    var accentIndigo: Color { Color(hex: palette.accentIndigo) }75    var accentSubtle: Color { Color(hex: palette.accentSubtle) }76    var textPrimary: Color { Color(hex: palette.textPrimary) }77    var textSecondary: Color { Color(hex: palette.textSecondary) }78    var textTertiary: Color { Color(hex: palette.textTertiary) }79    var border: Color { Color(hex: palette.border) }80    var success: Color { Color(hex: palette.success) }81    var warning: Color { Color(hex: palette.warning) }82    var danger: Color { Color(hex: palette.danger) }8384    var colorScheme: ColorScheme { appearance == .dark ? .dark : .light }8586    /// The chrome/new-tab background as a SwiftUI view.87    @ViewBuilder88    var backgroundView: some View {89        switch background.kind {90        case .solid:91            backgroundColor92        case .gradient:93            LinearGradient(colors: [Color(hex: background.colorA), Color(hex: background.colorB)],94                           startPoint: .top, endPoint: .bottom)95        case .image:96            if let path = background.imagePath, let img = NSImage(contentsOfFile: path) {97                Image(nsImage: img).resizable().aspectRatio(contentMode: .fill)98            } else {99                backgroundColor100            }101        }102    }103}104105// MARK: - Layout & typography (separate from color themes)106107enum TabPosition: String, Codable, Hashable, CaseIterable {108    case top, left109}110111enum Density: String, Codable, Hashable, CaseIterable {112    case compact, comfortable113}114115/// User layout/typography preferences, persisted per profile and applied live.116struct LayoutSettings: Codable, Hashable {117    var tabPosition: TabPosition = .top118    var density: Density = .comfortable119    var uiScale: Double = 1.0          // 0.85 … 1.30120    var defaultPageZoom: Double = 1.0121    var showBookmarksBar: Bool = false122    var translucency: Bool = false123124    // Density-derived metrics.125    var toolbarHeight: CGFloat { density == .compact ? 38 : 44 }126    var tabBarHeight: CGFloat { density == .compact ? 30 : 36 }127    var verticalTabWidth: CGFloat { 220 }128    var rowSpacing: CGFloat { density == .compact ? ZyquoSpacing.xxs : ZyquoSpacing.xs }129130    /// UI font at a base size, scaled by the user's uiScale.131    func font(_ base: Double, weight: Font.Weight = .regular) -> Font {132        .system(size: base * uiScale, weight: weight)133    }134}135