Sources/OrgstarMobile/SearchScreen.swift
51 lines · 2173 bytes
1#if os(iOS)
2import OrgApp
3import OrgIndex
4import SwiftUI
5
6/// Files by name and headings by their words, as ⌘P and ⇧⌘F find them on the Mac.
7struct SearchScreen: View {
8 let workspace: WorkspaceModel
9 let session: DocumentSession
10 @State private var query = ""
11
12 var body: some View {
13 let trimmed = query.trimmingCharacters(in: .whitespaces)
14 List {
15 if !trimmed.isEmpty {
16 let files = FuzzyMatch.rank(trimmed, workspace.files.filter { $0.kind == .org }, limit: 8)
17 if !files.isEmpty {
18 Section("Files") {
19 ForEach(files) { file in
20 NavigationLink(value: ReaderRoute.file(file.path)) {
21 Label(file.relativePath, systemImage: "doc.text")
22 }
23 }
24 }
25 }
26 let headings = workspace.search(trimmed, overlay: workspace.overlay(session.openDocuments))
27 Section("Headings") {
28 if headings.isEmpty { Text("No headings match").foregroundStyle(.secondary) }
29 ForEach(headings, id: \.self) { location in
30 NavigationLink(value: ReaderRoute.heading(location)) {
31 VStack(alignment: .leading, spacing: 2) {
32 Text(location.title.isEmpty ? "(untitled)" : location.title).lineLimit(2)
33 Text((location.path as NSString).lastPathComponent).font(.caption).foregroundStyle(.secondary)
34 }
35 }
36 }
37 }
38 }
39 }
40 .overlay {
41 if trimmed.isEmpty {
42 ContentUnavailableView("Search notes", systemImage: "magnifyingglass", description: Text("File names and the words of headings and their text."))
43 }
44 }
45 .navigationTitle("Search")
46 .searchable(text: $query, placement: .navigationBarDrawer(displayMode: .always))
47 .autocorrectionDisabled()
48 .textInputAutocapitalization(.never)
49 }
50}
51#endif