spb/zyquo-atlas Public License
The AI-native macOS web browser — every surface, intelligent.
Swift 75.2%
JavaScript 22%
Shell 2%
Makefile 0.9%
1//2// BrowserWindowView.swift3// Zyquo Atlas4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// The browser window root. Composes the chrome — tab strip (top-horizontal OR9// left-vertical per the live layout), optional bookmarks bar, toolbar, find10// bar, web content, and the AI sidebar — themed live by ThemeEngine and driven11// by a per-window WindowState that the app commands target. Hosts the history,12// bookmarks-manager, downloads, and customization panels.13//1415import SwiftUI1617struct BrowserWindowView: View {18 @EnvironmentObject private var env: AppEnvironment19 @EnvironmentObject private var themeEngine: ThemeEngine20 @StateObject private var tabManager: TabManager21 @StateObject private var windowState = WindowState()2223 private let profile: Profile2425 init(profile: Profile = .defaultProfile) {26 self.profile = profile27 _tabManager = StateObject(wrappedValue: TabManager(profile: profile))28 }2930 private var theme: AtlasTheme { themeEngine.theme }31 private var layout: LayoutSettings { themeEngine.layout }3233 var body: some View {34 Group {35 if layout.tabPosition == .left {36 HStack(spacing: 0) {37 VerticalTabBarView(tabManager: tabManager, onNewTab: { tabManager.newTab() })38 mainColumn39 }40 } else {41 VStack(spacing: 0) {42 TabBarView(tabManager: tabManager)43 mainColumn44 }45 }46 }47 .background(theme.backgroundColor)48 .frame(minWidth: 900, minHeight: 600)49 .animation(.easeInOut(duration: 0.15), value: windowState.showAISidebar)50 .animation(.easeInOut(duration: 0.18), value: layout.tabPosition)51 .environmentObject(windowState)52 .focusedSceneValue(\.windowState, windowState)53 .onAppear {54 windowState.tabManager = tabManager55 windowState.env = env56 if tabManager.history == nil {57 tabManager.history = profile.isPrivate ? nil : env.history58 tabManager.restoreSessionOrOpenHome()59 }60 }61 .sheet(isPresented: $windowState.showCustomize) {62 CustomizationView().environmentObject(themeEngine)63 }64 .sheet(isPresented: $windowState.showHistory) {65 HistoryView(onOpen: { tabManager.newTab(url: URL(string: $0)) })66 .environmentObject(env).environmentObject(themeEngine)67 }68 .sheet(isPresented: $windowState.showBookmarksManager) {69 BookmarksManagerView(onOpen: { tabManager.newTab(url: URL(string: $0)) })70 .environmentObject(env).environmentObject(themeEngine)71 }72 }7374 // MARK: - Main column (bookmarks bar + toolbar + content + AI sidebar)7576 @ViewBuilder77 private var mainColumn: some View {78 if let tab = tabManager.activeTab {79 VStack(spacing: 0) {80 ToolbarView(81 tab: tab,82 isAISidebarOpen: windowState.showAISidebar,83 onSubmit: { tabManager.loadInActiveTab($0) },84 onNewTab: { tabManager.newTab() },85 onToggleAI: { windowState.showAISidebar.toggle() },86 onCustomize: { windowState.showCustomize = true },87 downloadCount: tabManager.downloads.items.filter { $0.state == .inProgress }.count,88 onToggleDownloads: { windowState.showDownloads.toggle() }89 )90 if layout.showBookmarksBar && !profile.isPrivate {91 BookmarksBarView(onOpen: { tabManager.loadInActiveTab($0) })92 }93 if windowState.showFindBar {94 FindBarView(tab: tab, onClose: { windowState.showFindBar = false })95 }96 HStack(spacing: 0) {97 TabContentView(98 tab: tab,99 onNavigate: { tabManager.loadInActiveTab($0) },100 onAsk: { windowState.showAISidebar = true }101 )102 if windowState.showAISidebar {103 AISidebarView(tab: tab, ai: tab.ai, tabManager: tabManager)104 .transition(.move(edge: .trailing))105 }106 }107 }108 .overlay(alignment: .topTrailing) {109 if windowState.showDownloads {110 DownloadsPopover(downloads: tabManager.downloads,111 onClose: { windowState.showDownloads = false })112 .padding(.top, 4).padding(.trailing, 8)113 }114 }115 } else {116 Spacer()117 }118 }119120}121122/// The active tab's content region. Observes the tab so it switches reactively123/// between the start page (blank/home), reader mode, and live web content as the124/// URL changes — and overlays the selection toolbar on web pages.125private struct TabContentView: View {126 @ObservedObject var tab: Tab127 let onNavigate: (String) -> Void128 let onAsk: () -> Void129 @EnvironmentObject private var windowState: WindowState130131 var body: some View {132 if tab.url == nil || tab.url == TabManager.homeURL {133 StartPageView(onNavigate: onNavigate, onAsk: onAsk)134 } else if windowState.showReader {135 ReaderView(tab: tab)136 } else {137 WebContentArea(tab: tab)138 .overlay { SelectionToolbar(tab: tab) }139 }140 }141}142143/// Hosts the active tab's web view. Keyed by tab id so SwiftUI re-mounts the144/// correct WKWebView on a tab switch while background tabs keep theirs alive.145private struct WebContentArea: View {146 @ObservedObject var tab: Tab147148 var body: some View {149 WebView(tab: tab)150 .id(tab.id)151 }152}153