From f7fda0adcab83638a4e33fff870d541524bdd4de Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 8 Apr 2026 13:08:01 -0400 Subject: [PATCH] docs: add specialized note type editors design spec --- .../specs/2026-04-08-note-type-editors.md | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-08-note-type-editors.md diff --git a/docs/superpowers/specs/2026-04-08-note-type-editors.md b/docs/superpowers/specs/2026-04-08-note-type-editors.md new file mode 100644 index 0000000..43d9799 --- /dev/null +++ b/docs/superpowers/specs/2026-04-08-note-type-editors.md @@ -0,0 +1,204 @@ +# Specialized Note Type Editors — Design Spec + +## Goal + +Replace the one-size-fits-all note editor with type-specialized views for Person, Place, and List. Each type gets a form-first layout where structured fields are the main content, with a secondary notes area for free text. Fix tab navigation across all note types so focus flows logically from title through fields to body, skipping the formatting toolbar. + +## Architecture + +The existing `NoteEditorView.vue` remains the single editor component but renders different layouts based on `noteType`. When `noteType` is `person`, `place`, or `list`, the main editor area switches from TipTap-first to form-first. The TipTap editor moves to a secondary "Notes" section below the form fields. The sidebar metadata fields for person/place move into the main content area. The `note_type` field, entity metadata storage, and API contract are unchanged. + +## Person Editor + +When `noteType === 'person'`, the main content area renders a contact card form instead of the TipTap editor. + +### Fields (in order, all in main content area) + +| Field | Type | Placeholder | Source | +|-------|------|-------------|--------| +| Name | text input (title) | "Name" | `title` | +| Relationship | text input | "e.g. Friend, Colleague, Family" | `entityMeta.relationship` | +| Birthday | date input | — | `entityMeta.birthday` (new field) | +| Email | email input | "email@example.com" | `entityMeta.email` | +| Phone | tel input | "+1 555 000 0000" | `entityMeta.phone` | +| Organization | text input | "Company or organization" | `entityMeta.organization` (new field) | +| Address | text input | "Street, City, State" | `entityMeta.address` (new field for person) | + +### Notes section + +Below the form fields, a collapsible "Notes" section with the TipTap editor for free-text content. This is where wikilinks, tags, and general context go. The section starts expanded if the note already has body content, collapsed if empty on a new note. + +### Layout + +``` +┌──────────────────────────────────────────┐ +│ [← Knowledge] [Save] [Delete] │ +│ │ +│ Name: [________________________________] │ +│ │ +│ Relationship: [________________________] │ +│ Birthday: [____date picker________] │ +│ Email: [________________________] │ +│ Phone: [________________________] │ +│ Organization: [________________________] │ +│ Address: [________________________] │ +│ │ +│ ▾ Notes │ +│ ┌──────────────────────────────────────┐ │ +│ │ TipTap editor (markdown body) │ │ +│ └──────────────────────────────────────┘ │ +│ │ +│ [sidebar: project/tags/etc] │ +└──────────────────────────────────────────┘ +``` + +### Data migration + +Existing person notes may have structured data written as plain text in the body (e.g. "Relationship: daughter Birthday: 2013-12-13"). No automatic migration — the body content stays as-is in the Notes section. Users can move data to the structured fields manually. + +## Place Editor + +When `noteType === 'place'`, same form-first pattern. + +### Fields + +| Field | Type | Placeholder | Source | +|-------|------|-------------|--------| +| Name | text input (title) | "Place name" | `title` | +| Address | text input | "Street, City, State" | `entityMeta.address` | +| Phone | tel input | "+1 555 000 0000" | `entityMeta.phone` | +| Hours | text input | "e.g. Mon–Fri 9am–5pm" | `entityMeta.hours` | +| Website | url input | "https://..." | `entityMeta.website` (new field) | +| Category | text input | "e.g. Restaurant, Office, Doctor" | `entityMeta.category` (new field) | + +### Notes section + +Same as Person — collapsible TipTap editor below the form. + +## List Editor + +When `noteType === 'list'`, the main content area renders a checklist builder instead of the TipTap editor. + +### List builder + +Each list item is a row with: +- Checkbox (toggle checked state) +- Text input (item text, fills available width) +- Delete button (× icon, right side) + +Below the items: an "Add item" button. + +### Behavior + +- **Enter** in any item input: creates a new item below and focuses it +- **Backspace** on an empty item: deletes the item and focuses the previous one +- **Checkbox toggle**: updates the item's checked state +- **Delete button**: removes the item + +### Serialization + +On save, list items are serialized to markdown checkbox format in the body: +```markdown +- [ ] Buy groceries +- [x] Call dentist +- [ ] Pick up prescription +``` + +On load, the body is parsed back into structured items (same parser already exists in `knowledge.py` and `KnowledgeView.vue`). + +### Notes section + +Same collapsible TipTap "Notes" section below the list builder, for additional context that isn't a list item. + +### Layout + +``` +┌──────────────────────────────────────────┐ +│ [← Knowledge] [Save] [Delete] │ +│ │ +│ List title: [____________________________│ +│ │ +│ [ ] Buy groceries [×] │ +│ [x] Call dentist [×] │ +│ [ ] Pick up prescription [×] │ +│ │ +│ [+ Add item] │ +│ │ +│ ▾ Notes │ +│ ┌──────────────────────────────────────┐ │ +│ │ TipTap editor (additional context) │ │ +│ └──────────────────────────────────────┘ │ +│ │ +│ [sidebar: project/tags/etc] │ +└──────────────────────────────────────────┘ +``` + +## Tab Navigation & Auto-Focus + +### All note types + +1. **On page load**: focus the title/name input automatically +2. **Tab from title**: skip the formatting toolbar entirely, go to the first content field: + - Note: TipTap editor body + - Person: Relationship field + - Place: Address field + - List: first list item (or "Add item" button if empty) +3. **Tab through fields**: natural order through all form fields +4. **Tab from last form field**: enter the Notes section (TipTap editor) + +### Implementation + +Set `tabindex="-1"` on all MarkdownToolbar buttons so they are clickable but not in the tab order. The toolbar remains fully functional via mouse/touch — it's just skipped when tabbing. + +### Title placeholder by type + +| Type | Placeholder | +|------|-------------| +| Note | "Title" | +| Person | "Name" | +| Place | "Place name" | +| List | "List title" | +| Task | "Title" (unchanged, task editor is separate) | + +## Sidebar changes + +When editing a Person or Place, the type-specific metadata fields (Relationship, Email, Phone, etc.) **move from the sidebar to the main content area**. The sidebar keeps: Project, Milestone, Tags, Suggest Tags, Type selector, Link Suggestions, Writing Assistant, Version History. + +The Type selector remains in the sidebar so users can change the type if needed. Changing type switches the layout. + +## Backend changes + +### New entity metadata fields + +The `entity_meta` JSON column on the Note model already stores arbitrary key-value pairs. No schema migration needed — just store the new keys: + +- Person: `birthday`, `organization`, `address` (new; `relationship`, `email`, `phone` existing) +- Place: `website`, `category` (new; `address`, `phone`, `hours` existing) + +### Knowledge service + +Update `_note_to_item` in `services/knowledge.py` to include the new fields in the response for person and place cards: + +- Person: add `birthday`, `organization`, `address` +- Place: add `website`, `category` + +### Knowledge card display + +Update `KnowledgeView.vue` card rendering to show the new fields where useful (e.g. organization on person cards, category on place cards). + +## Files changed + +| File | Change | +|------|--------| +| `frontend/src/views/NoteEditorView.vue` | Type-conditional layouts, form fields, list builder, tab navigation, auto-focus, title placeholders | +| `frontend/src/views/KnowledgeView.vue` | Card display for new person/place fields | +| `frontend/src/components/MarkdownToolbar.vue` | `tabindex="-1"` on all buttons | +| `src/fabledassistant/services/knowledge.py` | New fields in `_note_to_item` for person/place | + +## What does NOT change + +- Note model / database schema (entity_meta is already a JSON column) +- API endpoints (same CRUD) +- Task editor (`TaskEditorView.vue`) — separate component, unchanged +- Generic note editing — TipTap-first layout stays for `noteType === 'note'` +- Backend storage format — entity_meta key-value pairs