spb/prisme Public MIT
Navigateur iOS intelligent — chaque page comprise localement avant d'être affichée. SwiftUI · WebKit · Foundation Models, 100% on-device.
Swift 96.7%
JavaScript 3.3%
1//2// HistoryView.swift3// Prisme4//5// Author: Simon-Pierre Boucher <contact@spboucher.ai>6//78import SwiftUI910/// Semantic history browser: recent visits by day, natural language search11/// on top ("le site avec la recette de ramen vu au printemps").12struct HistoryView: View {13 let history: HistoryStore14 let containers: IdentityContainerStore15 let onOpen: (PageVisit) -> Void1617 @Environment(\.dismiss) private var dismiss18 @State private var query = ""1920 private var results: [PageVisit] {21 query.trimmingCharacters(in: .whitespaces).count >= 222 ? history.search(query)23 : history.recent24 }2526 var body: some View {27 NavigationStack {28 Group {29 if results.isEmpty {30 ContentUnavailableView {31 Label(32 query.isEmpty ? "Encore rien à retrouver" : "Rien trouvé",33 systemImage: "clock.arrow.circlepath"34 )35 } description: {36 Text(query.isEmpty37 ? "Les pages visitées seront retrouvables ici, en langage naturel. Tout reste sur l'appareil."38 : "Aucune page visitée ne correspond à « \(query) ».")39 }40 } else {41 visitList42 }43 }44 .navigationTitle("Historique")45 .navigationBarTitleDisplayMode(.inline)46 .searchable(47 text: $query,48 placement: .navigationBarDrawer(displayMode: .always),49 prompt: "Rechercher une page visitée…"50 )51 .toolbar {52 ToolbarItem(placement: .cancellationAction) {53 Button("Fermer") { dismiss() }54 }55 }56 }57 }5859 private var visitList: some View {60 List(results, id: \.urlString) { visit in61 Button {62 onOpen(visit)63 dismiss()64 } label: {65 HStack(alignment: .top, spacing: Spacing.m) {66 Circle()67 .fill(color(for: visit))68 .frame(width: 8, height: 8)69 .padding(.top, 6)70 VStack(alignment: .leading, spacing: 2) {71 Text(visit.title)72 .foregroundStyle(.primary)73 .lineLimit(2)74 HStack(spacing: Spacing.xs) {75 Text(visit.host)76 Text("·")77 Text(visit.visitedAt, style: .relative)78 }79 .font(.caption)80 .foregroundStyle(.secondary)81 if !visit.gist.isEmpty {82 Text(visit.gist)83 .font(.caption)84 .foregroundStyle(.tertiary)85 .lineLimit(2)86 }87 }88 }89 }90 .accessibilityIdentifier("history.row")91 }92 .listStyle(.plain)93 }9495 private func color(for visit: PageVisit) -> Color {96 containers.container(for: visit.containerID)?.color.color ?? .secondary97 }98}99