This commit is contained in:
Mariano Gabriel
2026-07-05 22:37:46 -03:00
parent b65d6075be
commit 8cfb4c2cbe
5 changed files with 289 additions and 186 deletions

View File

@@ -8,7 +8,8 @@
import { reactive, computed } from 'vue'
export interface FileNode {
path: string
path: string // composite: "<collectionId>/<relpath>"
collection?: string
name: string
ext: string
family: string
@@ -22,6 +23,13 @@ export interface FileNode {
warnings?: string[]
}
export interface CollectionInfo {
id: string
name: string
available: boolean
count: number
}
export interface Detail {
node: FileNode
content: string | null // extracted search text (heavy formats), markdown
@@ -53,7 +61,8 @@ export const TARGETS: Target[] = [
]
interface State {
root: string
collections: CollectionInfo[]
activeCollections: Set<string>
files: FileNode[]
tree: TreeItem[]
counts: Record<string, number>
@@ -74,7 +83,8 @@ interface State {
}
export const store = reactive<State>({
root: '',
collections: [],
activeCollections: new Set<string>(),
files: [],
tree: [],
counts: {},
@@ -110,7 +120,7 @@ export function runSearch(q: string): void {
store.searching = true
searchTimer = setTimeout(async () => {
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`)
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}&collections=${encodeURIComponent(activeCsv())}`)
if (!res.ok) return
const d = await res.json()
if (store.query !== q) return // a newer query superseded this one
@@ -163,14 +173,31 @@ function buildTree(files: FileNode[]): TreeItem[] {
return sort(root.children!)
}
function activeCsv(): string {
return [...store.activeCollections].join(',')
}
/** Load available collections; default every available one to active. */
export async function loadCollections(): Promise<void> {
try {
const res = await fetch('/api/collections')
const data = await res.json()
store.collections = data.collections ?? []
// Default: all available collections on.
store.activeCollections = new Set(store.collections.filter((c) => c.available).map((c) => c.id))
} catch (e) {
store.error = String(e)
}
}
export async function loadTree(): Promise<void> {
store.loading = true
store.error = ''
try {
const res = await fetch('/api/tree')
if (!store.collections.length) await loadCollections()
const res = await fetch(`/api/tree?collections=${encodeURIComponent(activeCsv())}`)
if (!res.ok) { store.error = (await res.json()).error ?? `HTTP ${res.status}`; return }
const index = await res.json()
store.root = index.root
store.files = index.files
store.counts = index.counts
store.tree = buildTree(index.files)
@@ -181,6 +208,14 @@ export async function loadTree(): Promise<void> {
}
}
/** Toggle a collection on/off and re-merge the tree (and re-run any search). */
export async function toggleCollection(id: string): Promise<void> {
if (store.activeCollections.has(id)) store.activeCollections.delete(id)
else store.activeCollections.add(id)
await loadTree()
if (store.query) runSearch(store.query)
}
export async function select(path: string): Promise<void> {
store.selectedPath = path
store.detailCollapsed = false // opening a file expands the viewer