The Search / Timeline / Reminders views each hand-rolled the same
items+loading+error scaffold, retry button, and editor-host glue.
- useNoteList(fetcher, fallbackError) (new): the load-a-note-list scaffold
(items/loading/error + a load() that never leaves a half-state). Views
supply just the fetcher; the refs drive <AsyncState>.
- SearchView / TimelineView / RemindersView: adopt useNoteList + useNoteEditor
+ <AsyncState>/<EmptyState>; drop the local list/loading/error refs, the
duplicated retry blocks, and the notes.items-shadowing navigate glue.
- GraphView: editor host now via useNoteEditor (openNode/closeEditor/onNavigate
collapse to navigate); loading/error via <AsyncState>. Its two empty states
keep inline markup/buttons, so they stay custom (not forced into EmptyState).
- reminders store: fetchReminders() is the single owner of /api/notes/reminders;
both the background poll (check) and RemindersView read through it.
Frontend-only; CI vue-tsc is the type gate (no local typecheck, rule 10).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm