feat: move vault UI config from localStorage to vault files

Add VaultConfig infrastructure (store, hook, migration) that persists
zoom, view mode, section visibility, tag/status colors, and property
display modes to config/ui.config.md in the vault instead of localStorage.

- New vaultConfigStore module with subscribe/notify pattern
- useVaultConfig hook loads config via Tauri, binds store, runs migration
- One-time silent migration from localStorage on first load
- Config type excluded from note search and unified search
- All hooks/utils updated to read/write through vault config store
- Tests updated to use vault config store instead of localStorage mocks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Test
2026-03-05 15:26:21 +01:00
parent 418ea8a7a8
commit 013cf0ffe1
22 changed files with 483 additions and 208 deletions

View File

@@ -24,25 +24,33 @@ function toResult(e: VaultEntry, typeEntryMap: Record<string, VaultEntry>): Note
}
}
/** Types excluded from note search results (internal infrastructure). */
const SEARCH_EXCLUDED_TYPES = new Set(['Config'])
export function useNoteSearch(entries: VaultEntry[], query: string, maxResults = DEFAULT_MAX_RESULTS) {
const [selectedIndex, setSelectedIndex] = useState(0)
const typeEntryMap = useMemo(() => buildTypeEntryMap(entries), [entries])
const searchableEntries = useMemo(
() => entries.filter((e) => !SEARCH_EXCLUDED_TYPES.has(e.isA ?? '')),
[entries],
)
const results: NoteSearchResult[] = useMemo(() => {
const mapResult = (e: VaultEntry) => toResult(e, typeEntryMap)
if (!query.trim()) {
return [...entries]
return [...searchableEntries]
.sort((a, b) => (b.modifiedAt ?? 0) - (a.modifiedAt ?? 0))
.slice(0, maxResults)
.map(mapResult)
}
return entries
return searchableEntries
.map((e) => ({ entry: e, ...fuzzyMatch(query, e.title) }))
.filter((r) => r.match)
.sort((a, b) => b.score - a.score)
.slice(0, maxResults)
.map((r) => mapResult(r.entry))
}, [entries, query, maxResults, typeEntryMap])
}, [searchableEntries, query, maxResults, typeEntryMap])
useEffect(() => {
setSelectedIndex(0) // eslint-disable-line react-hooks/set-state-in-effect -- reset on query change