basic search
This commit is contained in:
@@ -66,6 +66,11 @@ interface State {
|
||||
detailCollapsed: boolean // bottom viewer collapsed to a bar
|
||||
targetKey: string
|
||||
error: string
|
||||
|
||||
query: string
|
||||
matches: Set<string> | null // null = not searching; else the matched paths
|
||||
searching: boolean
|
||||
searchStats: { count: number; bytes: number }
|
||||
}
|
||||
|
||||
export const store = reactive<State>({
|
||||
@@ -82,8 +87,50 @@ export const store = reactive<State>({
|
||||
detailCollapsed: false,
|
||||
targetKey: TARGETS[0].key,
|
||||
error: '',
|
||||
|
||||
query: '',
|
||||
matches: null,
|
||||
searching: false,
|
||||
searchStats: { count: 0, bytes: 0 },
|
||||
})
|
||||
|
||||
let searchTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
/** Search the cached text (transcripts, extracted docs, raw files) and prune the
|
||||
* tree to matches. Debounced; reliability over speed (server reads full text). */
|
||||
export function runSearch(q: string): void {
|
||||
store.query = q
|
||||
if (searchTimer) clearTimeout(searchTimer)
|
||||
if (!q.trim()) {
|
||||
store.matches = null
|
||||
store.searching = false
|
||||
store.searchStats = { count: 0, bytes: 0 }
|
||||
return
|
||||
}
|
||||
store.searching = true
|
||||
searchTimer = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`)
|
||||
if (!res.ok) return
|
||||
const d = await res.json()
|
||||
if (store.query !== q) return // a newer query superseded this one
|
||||
store.matches = new Set<string>(d.matches ?? [])
|
||||
store.searchStats = { count: d.count ?? 0, bytes: d.bytes ?? 0 }
|
||||
} finally {
|
||||
if (store.query === q) store.searching = false
|
||||
}
|
||||
}, 250)
|
||||
}
|
||||
|
||||
/** Tree pruned to search matches (folders auto-expand while searching). */
|
||||
export const visibleTree = computed(() =>
|
||||
store.matches ? buildTree(store.files.filter((f) => store.matches!.has(f.path))) : store.tree)
|
||||
|
||||
/** Put the current match set into the package selection (one package for now). */
|
||||
export function selectMatches(): void {
|
||||
if (store.matches) store.selected = new Set(store.matches)
|
||||
}
|
||||
|
||||
export function toggleFolder(path: string): void {
|
||||
if (store.collapsed.has(path)) store.collapsed.delete(path)
|
||||
else store.collapsed.add(path)
|
||||
|
||||
Reference in New Issue
Block a user