// // OmniboxView.swift // Zyquo Atlas // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // // The address/search field. Shows a security indicator, reflects the active // tab's URL when not being edited, and on submit resolves URL-vs-search via // OmniIntent. The Phase 3 "ask AI" route and answer overlay attach here. // import SwiftUI struct OmniboxView: View { @ObservedObject var tab: Tab let onSubmit: (String) -> Void var onAsk: (String) -> Void = { _ in } @EnvironmentObject private var themeEngine: ThemeEngine @EnvironmentObject private var windowState: WindowState private var theme: AtlasTheme { themeEngine.theme } @State private var text: String = "" @State private var isEditing: Bool = false @FocusState private var focused: Bool var body: some View { HStack(spacing: ZyquoSpacing.xs) { Image(systemName: securityGlyph) .font(.system(size: 11, weight: .semibold)) .foregroundStyle(securityColor) TextField("Search or enter website name", text: $text) .textFieldStyle(.plain) .font(ZyquoFont.control) .foregroundStyle(theme.textPrimary) .focused($focused) .onSubmit { onSubmit(text) focused = false } .onChange(of: focused) { now in isEditing = now if now { selectAll() } else { syncFromTab() } } if isEditing && !text.isEmpty { Button { onAsk(text) focused = false } label: { Label("Ask AI", systemImage: "sparkles") .font(.system(size: 10, weight: .semibold)) .padding(.horizontal, ZyquoSpacing.xs) .padding(.vertical, 2) .background(Capsule().fill(theme.accentSubtle)) .foregroundStyle(theme.accentIndigo) } .buttonStyle(.plain) .help("Ask AI about this (⌥Return)") Button { text = "" } label: { Image(systemName: "xmark.circle.fill") .font(.system(size: 12)) .foregroundStyle(theme.textTertiary) } .buttonStyle(.plain) } } .padding(.horizontal, ZyquoSpacing.sm) .frame(height: 30) .background( RoundedRectangle(cornerRadius: ZyquoRadius.small) .fill(theme.surfaceSecondary) ) .overlay( RoundedRectangle(cornerRadius: ZyquoRadius.small) .strokeBorder(focused ? theme.accent : theme.border, lineWidth: focused ? 1.5 : ZyquoMetrics.hairline) ) .onChange(of: tab.url) { _ in if !isEditing { syncFromTab() } } .onChange(of: windowState.omniboxFocusToken) { _ in focused = true } .onAppear { syncFromTab() } } // MARK: - Helpers private var securityGlyph: String { guard tab.url != nil else { return "magnifyingglass" } return tab.hasSecureConnection ? "lock.fill" : "exclamationmark.triangle.fill" } private var securityColor: Color { guard tab.url != nil else { return theme.textTertiary } return tab.hasSecureConnection ? theme.textSecondary : theme.warning } private func syncFromTab() { text = tab.url?.absoluteString ?? "" } private func selectAll() { // Reflect the raw URL for editing; SwiftUI selects on focus via the // field's default behavior when text is present. if text.isEmpty { syncFromTab() } } }