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// StartPageView.swift3// Zyquo Atlas4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// The customizable new-tab / start page (Phase 4.2). Shows the theme9// background, a greeting, a prominent AI-or-search ask box, and a favorites10// quick grid. Bookmarks/history widgets and per-user layout of these sections11// fill in with the bookmark & history services in Phase 6.12//1314import SwiftUI1516struct StartPageView: View {17 let onNavigate: (String) -> Void18 let onAsk: () -> Void19 @EnvironmentObject private var themeEngine: ThemeEngine20 private var theme: AtlasTheme { themeEngine.theme }2122 @State private var query = ""2324 // Placeholder favorites until BookmarksService (Phase 6).25 private let quickLinks: [(String, String)] = [26 ("Wikipedia", "https://en.wikipedia.org"),27 ("DuckDuckGo", "https://duckduckgo.com"),28 ("GitHub", "https://github.com"),29 ("Hacker News", "https://news.ycombinator.com"),30 ("MDN", "https://developer.mozilla.org"),31 ("arXiv", "https://arxiv.org"),32 ]3334 var body: some View {35 ZStack {36 theme.backgroundView.ignoresSafeArea()3738 VStack(spacing: ZyquoSpacing.xl) {39 Spacer()4041 VStack(spacing: ZyquoSpacing.xs) {42 Text("Zyquo Atlas")43 .font(themeEngine.layout.font(34, weight: .bold))44 .foregroundStyle(theme.textPrimary)45 Text("Explore the web, with AI everywhere.")46 .font(themeEngine.layout.font(14))47 .foregroundStyle(theme.textSecondary)48 }4950 askBox51 .frame(maxWidth: 620)5253 favoritesGrid54 .frame(maxWidth: 620)5556 Spacer()57 Spacer()58 }59 .padding(ZyquoSpacing.xxl)60 }61 }6263 private var askBox: some View {64 HStack(spacing: ZyquoSpacing.sm) {65 Image(systemName: "magnifyingglass")66 .foregroundStyle(theme.textTertiary)67 TextField("Search, enter a URL, or ask AI…", text: $query)68 .textFieldStyle(.plain)69 .font(themeEngine.layout.font(15))70 .foregroundStyle(theme.textPrimary)71 .onSubmit {72 let q = query.trimmingCharacters(in: .whitespacesAndNewlines)73 guard !q.isEmpty else { return }74 onNavigate(q); query = ""75 }76 Button(action: onAsk) {77 Label("Ask AI", systemImage: "sparkles")78 .font(themeEngine.layout.font(12, weight: .medium))79 .padding(.horizontal, ZyquoSpacing.sm)80 .padding(.vertical, ZyquoSpacing.xxs)81 .background(RoundedRectangle(cornerRadius: ZyquoRadius.small).fill(theme.accentSubtle))82 .foregroundStyle(theme.accentIndigo)83 }84 .buttonStyle(.plain)85 }86 .padding(.horizontal, ZyquoSpacing.md)87 .frame(height: 52)88 .background(89 RoundedRectangle(cornerRadius: ZyquoRadius.large)90 .fill(theme.surface)91 .shadow(color: ZyquoShadow.soft.color, radius: ZyquoShadow.soft.radius,92 y: ZyquoShadow.soft.y)93 )94 .overlay(95 RoundedRectangle(cornerRadius: ZyquoRadius.large)96 .strokeBorder(theme.border, lineWidth: ZyquoMetrics.hairline)97 )98 }99100 private var favoritesGrid: some View {101 LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: ZyquoSpacing.sm), count: 3),102 spacing: ZyquoSpacing.sm) {103 ForEach(quickLinks, id: \.0) { name, url in104 Button { onNavigate(url) } label: {105 HStack(spacing: ZyquoSpacing.xs) {106 Image(systemName: "globe").foregroundStyle(theme.accent)107 Text(name)108 .font(themeEngine.layout.font(12.5, weight: .medium))109 .foregroundStyle(theme.textPrimary)110 .lineLimit(1)111 Spacer(minLength: 0)112 }113 .padding(.horizontal, ZyquoSpacing.sm)114 .frame(height: 40)115 .background(RoundedRectangle(cornerRadius: ZyquoRadius.medium).fill(theme.surface))116 .overlay(RoundedRectangle(cornerRadius: ZyquoRadius.medium)117 .strokeBorder(theme.border, lineWidth: ZyquoMetrics.hairline))118 }119 .buttonStyle(.plain)120 }121 }122 }123}124