// // HistoryView.swift // Prisme // // Author: Simon-Pierre Boucher // import SwiftUI /// Semantic history browser: recent visits by day, natural language search /// on top ("le site avec la recette de ramen vu au printemps"). struct HistoryView: View { let history: HistoryStore let containers: IdentityContainerStore let onOpen: (PageVisit) -> Void @Environment(\.dismiss) private var dismiss @State private var query = "" private var results: [PageVisit] { query.trimmingCharacters(in: .whitespaces).count >= 2 ? history.search(query) : history.recent } var body: some View { NavigationStack { Group { if results.isEmpty { ContentUnavailableView { Label( query.isEmpty ? "Encore rien à retrouver" : "Rien trouvé", systemImage: "clock.arrow.circlepath" ) } description: { Text(query.isEmpty ? "Les pages visitées seront retrouvables ici, en langage naturel. Tout reste sur l'appareil." : "Aucune page visitée ne correspond à « \(query) ».") } } else { visitList } } .navigationTitle("Historique") .navigationBarTitleDisplayMode(.inline) .searchable( text: $query, placement: .navigationBarDrawer(displayMode: .always), prompt: "Rechercher une page visitée…" ) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Fermer") { dismiss() } } } } } private var visitList: some View { List(results, id: \.urlString) { visit in Button { onOpen(visit) dismiss() } label: { HStack(alignment: .top, spacing: Spacing.m) { Circle() .fill(color(for: visit)) .frame(width: 8, height: 8) .padding(.top, 6) VStack(alignment: .leading, spacing: 2) { Text(visit.title) .foregroundStyle(.primary) .lineLimit(2) HStack(spacing: Spacing.xs) { Text(visit.host) Text("·") Text(visit.visitedAt, style: .relative) } .font(.caption) .foregroundStyle(.secondary) if !visit.gist.isEmpty { Text(visit.gist) .font(.caption) .foregroundStyle(.tertiary) .lineLimit(2) } } } } .accessibilityIdentifier("history.row") } .listStyle(.plain) } private func color(for visit: PageVisit) -> Color { containers.container(for: visit.containerID)?.color.color ?? .secondary } }