import { useEffect, useState, useMemo } from "react"; import { useVault } from "../App"; import { queryFrontmatter, type FrontmatterRow } from "../lib/commands"; type ViewMode = "table" | "gallery" | "list"; /** * DatabaseView — Notion-style table/gallery/list views from frontmatter. */ export function DatabaseView() { const { vaultPath, navigateToNote } = useVault(); const [rows, setRows] = useState([]); const [viewMode, setViewMode] = useState("table"); const [sortField, setSortField] = useState("title"); const [sortAsc, setSortAsc] = useState(true); const [filterField, setFilterField] = useState(""); const [filterValue, setFilterValue] = useState(""); useEffect(() => { if (!vaultPath) return; queryFrontmatter(vaultPath).then(setRows).catch(() => setRows([])); }, [vaultPath]); // All unique field keys const allFields = useMemo(() => { const keys = new Set(); rows.forEach(r => Object.keys(r.fields).forEach(k => keys.add(k))); return ["title", ...Array.from(keys)]; }, [rows]); // Sort + Filter const processed = useMemo(() => { let data = [...rows]; if (filterField && filterValue) { data = data.filter(r => { const val = filterField === "title" ? r.title : (r.fields[filterField] || ""); return val.toLowerCase().includes(filterValue.toLowerCase()); }); } data.sort((a, b) => { const va = sortField === "title" ? a.title : (a.fields[sortField] || ""); const vb = sortField === "title" ? b.title : (b.fields[sortField] || ""); return sortAsc ? va.localeCompare(vb) : vb.localeCompare(va); }); return data; }, [rows, sortField, sortAsc, filterField, filterValue]); const handleSort = (field: string) => { if (sortField === field) setSortAsc(!sortAsc); else { setSortField(field); setSortAsc(true); } }; return (

📊 Database

{filterField && ( setFilterValue(e.target.value)} placeholder="Contains…" /> )}
{(["table", "gallery", "list"] as ViewMode[]).map(m => ( ))}
{viewMode === "table" && (
{allFields.map(f => ( ))} {processed.map(row => ( navigateToNote(row.title)} > {allFields.map(f => ( ))} ))}
handleSort(f)} className="database-th"> {f} {sortField === f && {sortAsc ? " ↑" : " ↓"}}
{f === "title" ? row.title : (row.fields[f] || "—")}
)} {viewMode === "gallery" && (
{processed.map(row => (
navigateToNote(row.title)} >
{row.title}
{Object.entries(row.fields).slice(0, 3).map(([k, v]) => (
{k}: {v}
))}
))}
)} {viewMode === "list" && (
{processed.map(row => (
navigateToNote(row.title)} > {row.title} {Object.entries(row.fields).slice(0, 2).map(([k, v]) => `${k}: ${v}`).join(" • ")}
))}
)} {processed.length === 0 && (

No notes with frontmatter found.

Add YAML frontmatter between --- markers to your notes.

)}
); }