Commit Graph
6 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5 641999de58 frontend: reminders becomes a lens, and cards can clear a reminder (task 1913)
CI & Build / Python lint (push) Successful in 4s
CI & Build / TypeScript typecheck (push) Successful in 7s
CI & Build / Python tests (push) Successful in 11s
CI & Build / Build & push image (push) Successful in 46s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m50s
Android (Tauri) / Android APK (debug) (push) Successful in 3m41s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 5m2s
Desktop (Tauri) / Update manifest (push) Successful in 6s
Reminders was the last surface still reading as its own page — a bespoke row list
rather than the board's cards. It is now the same NoteGrid as every other lens.

The reason it wasn't already is that the list was a TRIAGE surface: one tap for
Done, 1h, 1d. Cards had none of that, so converting naively would have turned each
of those into open-act-close. Reminder upkeep is exactly the "maintenance must
stay dead simple or people stop coming back" case from the north star, so making
it three times more work to look tidier would have been a bad trade.

So the actions moved onto the card instead, shown wherever a note carries a
reminder — the board included. That turns out to be the better place for them
anyway: seeing something due while browsing and clearing it there is useful
outside the reminders lens. Always visible rather than hover-revealed, because a
finger cannot hover and these are the primary action on a due note; .chip-btn
takes the same coarse-pointer sizing rule as .icon-btn.

The card acts on the store directly, which the board picks up through reconcile.
The reminders lens fetches its own list, so it needs telling — hence the
reminder-changed event, which exists only for hosts that hold a list of their own.

Also carried recurrence (↻) onto the card. It was shown only in the reminders
list, so unifying would have silently dropped it; a repeating note now reads as
repeating on the board too. And the container went max-w-2xl → max-w-6xl, since a
narrower column would have reintroduced the different-page feeling the cards just
removed.

RemindersView is ~40 lines lighter for it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 14:48:28 -04:00
bvandeusenandClaude Opus 5 c8c8ec4b4e frontend: the shell names the active lens (task 1913)
CI & Build / TypeScript typecheck (push) Successful in 8s
CI & Build / Python tests (push) Successful in 15s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Build & push image (push) Successful in 44s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m57s
Desktop (Tauri) / Update manifest (push) Successful in 5s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m51s
Android (Tauri) / Android APK (debug) (push) Successful in 3m37s
Which lens you're looking at is a property of the space, not of a page you
navigated to — so the name now sits in the bar that never moves, beside the app
name, and stays put while everything beneath it re-filters.

It replaces three per-view <h1>s that each sat in a different place with slightly
different markup (timeline, reminders, graph) and, more to the point, were absent
entirely on the board and in search — the two lenses people spend the most time
in had no name at all. A label lens is named by the label itself, because
"Groceries" is what the user came looking for and "Label" tells them nothing.

Shown at every width rather than hidden on small screens, which was my first cut
and would have been a regression: deleting the per-view titles while hiding the
shell one leaves a phone with no lens name anywhere, and Android is a peer surface
now. Below `sm` the app name is already hidden, so the lens name simply takes the
space it vacates — you know which app you're in; what you need is which lens.

The h1s on Settings, Sync, Account, Login and Register are untouched: those routes
render outside the shell entirely, so they have no chrome to be named by.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 13:49:27 -04:00
bvandeusenandClaude Opus 4.8 590d3ff2f6 M9 S3 (frontend): recall views adopt useNoteList + AsyncState/EmptyState
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 6s
CI & Build / Python tests (push) Successful in 10s
CI & Build / Build & push image (push) Successful in 34s
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
2026-07-23 21:36:24 -04:00
bvandeusenandClaude Opus 4.8 d1bc91a54a M6 1908b: foreground reminder delivery + recurrence/snooze UI (frontend)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Python tests (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 14s
CI & Build / Build & push image (push) Successful in 29s
Completes 1908 without Web Push. While the app is open, due reminders now
actually surface; recurring reminders + snooze/done are manageable.

- reminders store (singleton): polls /api/notes/reminders every 45s while
  the app is open; each due reminder fires ONCE as a toast (with an "Open"
  action) and, if the user opts in, a page-context OS Notification — no
  service worker, no PWA. Silently primes a stale backlog on first load;
  only announces recently-due ones. AppShell starts/stops it.
- Editor reminder section: a Repeat picker (Does not repeat / Daily /
  Weekly / Monthly / Yearly) + Done (advances a recurring reminder / clears
  a one-off) + Snooze 1h/1d, shown when a reminder is set.
- RemindersView rebuilt as a chronological list: per row a due time +
  recurrence badge + Done / 1h / 1d, click to open; plus an "Enable
  notifications" opt-in and a note that background alerts come with native.
- Note type gains `recurrence`; notes store setRecurrence /
  completeReminder / snoozeReminder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
2026-07-23 11:58:44 -04:00
bvandeusenandClaude Opus 4.8 545f946754 m4: per-view error states (board / search / graph / reminders)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 5s
CI & Build / Python tests (push) Successful in 7s
CI & Build / Build & push image (push) Successful in 27s
Each data view now catches a failed load and shows an explicit error message
with a Retry button, instead of falling through to a misleading empty state.
Pairs with the global error toast: the toast says something failed, the view
says which and offers a retry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
2026-07-21 00:10:40 -04:00
bvandeusenandClaude Opus 4.8 c57982d910 M3 reminders: notes.remind_at + Reminders view
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 5s
CI & Build / Python tests (push) Successful in 7s
CI & Build / Build & push image (push) Successful in 32s
- Migration 0010: notes.remind_at (nullable tz). PATCH accepts remind_at
  (ISO set / null clear); GET /api/notes/reminders (soonest first, non-trashed);
  serialize includes remind_at.
- Frontend: datetime util (local<->ISO, format, overdue); notes store setReminder;
  editor datetime-local picker + clear; card reminder chip (overdue = red);
  sidebar Reminders entry + /reminders view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
2026-07-20 08:12:14 -04:00