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 · 124 lines swift
Raw Blame History
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