feat(frontend): add personal-notes menu item and modal#13134
Draft
sbpublic wants to merge 6 commits into
Draft
Conversation
… ids Add the display helpers PR-3 needs on top of the PR-2 store/service: `formatPersonalNoteTimestamp` (relative-then-absolute, local timezone, reusing the existing date utils), `neutralizePersonalNoteText` (strips bidi/control characters per spec Decision 15) and `personalNotePreview` (collapses whitespace for the 2-line list preview). Add the `personalNotesUndoStore` holding the whole decrypted note for the Undo window, and the notes test ids. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the `navigation.text.notes` menu label and the `notes.*` block (modal title, empty state, editor labels, privacy info box, timestamps, cap and too-long messages, delete/undo, decryption-failure copy) to `en.json`, then regenerate the i18n types and sync the locale structure via `npm run i18n`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the Notes modal and its parts under `components/notes/`: `NotesModal`
(list / empty / add-edit steps on a gix `Modal`, lazy load on first open,
cap gate, delete with Undo capture), `NoteListItem` (2-line plain-text
preview, Created/Updated timestamp, edit/delete, per-note decryption
failure + Retry), `InputPersonalNote` (auto-focused multi-line textarea,
code-point length, too-long error), `EmptyNotes`, `NotesPrivacyInfoBox`
and the pinned `NoteDeletedSnackbar`. Note text is always rendered as
escaped plain text (never `{@html}`); the editor step has no X and ignores
the backdrop. Add the `IconNotebook` lucide glyph.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a "Notes" `ButtonMenu` to the user menu immediately after Contacts (signed-in only), opening the modal via a new `openNotes`/`modalNotes` pair on the modal store. Mount `NotesModal` from the global modals host gated on `$modalNotes`, and mount the app-level `NoteDeletedSnackbar` next to the toasts so Undo survives list scroll. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Describe the standalone personal-notes feature: the Notes user-menu item, end-to-end vetKeys encryption, lazy load, the character/note caps, local timezone timestamps, safe plain-text rendering, and immediate-but-undoable delete. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover the new display utils (timestamp, bidi neutralization, preview), the modal states (empty / list / cap gate, save + delete through the service, Undo capture), the list-item plain-text/inert rendering and decryption failure, and the input's code-point length cap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Final wave of the personal-notes feature (PR-3 in
docs/ai/spec-driven-development/specs/2026-06-17-feat-personal-notes.md). PR-1 (#13130) landed the encrypted backend storage and API; PR-2 (#13131) landed the vetKeys crypto, API bindings, service and store. This PR adds the user-visible surface: a Notes user-menu item and the Notes modal (list / empty / add / edit / delete), wiring the existing service and store into the UI.Stacked on PR-2 — base branch is
feat/frontend/personal-notes-vetkeys-crypto; review/merge that first.Changes
ButtonMenuinMenu.svelteimmediately after Contacts (signed-in only), opening the modal via a newopenNotes/modalNotespair on the modal store; mounted from the globalModals.sveltehost gated on$modalNotes.components/notes/):NotesModal(list / empty / add-edit on a gixModal, lazy load on first open with cached re-opens, cap gate, delete with Undo),NoteListItem(2-line plain-text preview, Created/Updated timestamp, edit/delete, per-note decryption-failure + Retry),InputPersonalNote(auto-focused multi-line textarea, code-point length, too-long error),EmptyNotes,NotesPrivacyInfoBox, and the pinnedNoteDeletedSnackbar.{@html}), line breaks via CSS; bidi/control characters are neutralized on display.formatPersonalNoteTimestamp,neutralizePersonalNoteText,personalNotePreview, plus thepersonalNotesUndoStore. NewIconNotebooklucide glyph.navigation.text.notes+ thenotes.*block inen.json(regenerated types + synced locale structure).Tests
personal-note.utils.spec.ts: timestamp formatting (relative vs absolute), bidi neutralization, preview whitespace-collapse.NotesModal.spec.ts: empty / list states, cap gate disables Add note, save and delete go through the service, Undo capture.NoteListItem.spec.ts: Created vs Updated, HTML/script content renders inertly, bidi-override neutralized, edit/delete/retry callbacks, decryption-failure row.InputPersonalNote.spec.ts: too-long error past the cap, emoji counted by code points (not UTF-16).npm run format,npm run lint -- --max-warnings 0,npm run checkall pass.Divergence from the spec
The spec assumed the Undo affordance and the editor-step dismissal rules could ride on existing primitives; two adjustments were needed because the primitives don't support them:
ToastMsgis text-only (no action button) and no toast in the codebase renders actionable HTML, so the spec's "Undo via OISY's toast system" isn't achievable as-is. Implemented a small customNoteDeletedSnackbar, pinned at the standard toast position and auto-dismissing, reusing the existingrestorePersonalNoteservice to restore the note verbatim. (Confirmed with the requester before building.)WizardModalsetsvisible = falsebeforeonClose, so it can't refuse to close a step;Modalalways renders the header X. Used a plainModalwith internal list/editor step state, a guardedonClose, and a consumer-side CSS rule to hide the close button on the editor step.The Notes UI is gated behind sign-in and needs the vetKeys backend, so it isn't reachable in a headless preview; verification is via the unit/component tests plus type-check and lint. Live visual QA (dark mode, mobile full-page editor with the soft keyboard) is the remaining manual check.
🤖 Generated with Claude Code using Claude Opus 4.8 (claude-opus-4-8)