diff --git a/docs/specs/2026-06-21-edit-book-actions-design.md b/docs/specs/2026-06-21-edit-book-actions-design.md new file mode 100644 index 0000000..3657b6b --- /dev/null +++ b/docs/specs/2026-06-21-edit-book-actions-design.md @@ -0,0 +1,127 @@ +# Edit Book Actions — design spec + +## Problem + +The index page shows books grouped by status but provides no way to change a book's +status, add reading notes, or record ratings. Users must edit the Org file manually. +We need lightweight, context-sensitive edit actions accessible from the agenda view. + +## Interaction model + +Click a book row on the index page → the footer (minibuffer) shows action links +tailored to that book's current status. Clicking an action either performs it +immediately (status transitions) or shows a lightweight prompt page (add note, +mark read with date). + +No JavaScript. All actions are plain `` links or simple HTML forms. + +## Actions per status + +### WANT +- **Mark reading** — immediate: sets TODO to READING +- **Add note** — prompt page: date + textarea, appends a note + +### READING +- **Mark read** — prompt page: date picker (default today) + Rating is deferred (see out of scope). +- **Abandon** — immediate: sets TODO to ABANDONED +- **Add note** — prompt page: date + textarea + +### READ +- **Read again** — immediate: sets TODO to READING +- **Add note** — prompt page: date + textarea +### ABANDONED +- **Try again** — immediate: sets TODO to READING + +## Implementation + +### New Org write functions (`spine.el`) + +**`spine-set-status (id status &optional date)`** + +Finds the book by `:ID:` property, changes its TODO keyword to `status`, and records +the state transition in the LOGBOOK drawer (using `org-todo`). If `date` is provided +(for READ status), sets a `:READ_DATE:` property. + +**`spine-add-note (id text &optional date)`** + +Finds the book by `:ID:`, appends `- [YYYY-MM-DD] text` to the headline body. Date +defaults to today if not provided. Follows the same pattern as `spine-add-book`: +`find-file-noselect`, modify, save, `kill-buffer`. + +**`spine-set-rating (id rating)`** + +Sets the `:RATING:` property on the book. + +### Handler: `httpd/edit` + +Single handler dispatching on `action` query param: + +- `action=status` — calls `spine-set-status` with `id` and `value` (the target TODO + state). Redirects to `/index?id=`. +- `action=note` — GET shows a prompt page with date + textarea for the book. POST + processes: calls `spine-add-note` with `id`, `text`, and optional `date`. Redirects + to `/index?id=`. +- `action=rating` — calls `spine-set-rating` with `id` and `value`. Redirects to + `/index?id=`. +- Unknown action or missing `id` — redirect to `/index` silently. + +The prompt page for notes is a minimal HTML page (no Mustache template needed — small +enough to inline): shows the book title as context, a date input (default today), a +textarea, and a submit button. POST data includes `id`, `action`, `date`, `text`. + +### Model: `spine-index-model` minibuffer extension + +When a book is selected (`selected-id` matches), the model gains a `minibuffer` field: + +```elisp +("minibuffer" . + (ht ("actions" + (list + (ht ("label" "Mark reading") ("href" "/edit?id=X&action=status&value=READING")) + (ht ("label" "Add note") ("href" "/edit?id=X&action=note")))))) +``` + +Actions are computed from the selected book's `:status` property. The exact set +follows the table in "Actions per status" above. + +### Template: `index.mustache` minibuffer section + +The existing minibuffer footer placeholder is replaced with a dynamic version: + +```mustache +{{#minibuffer}} + +{{/minibuffer}} +``` + +Styled as pill links consistent with the existing pill classes. `M-x` prefix keeps +the Emacs feel. + +### Testing + +New test file `test/spine-edit-test.el`: + +- `spine-set-status` changes TODO state correctly for each transition +- `spine-set-status` records LOGBOOK entry +- `spine-add-note` appends a note with the correct format +- `spine-add-note` defaults to today when no date provided +- `spine-set-rating` sets the rating property +- Model includes `minibuffer` field when book is selected +- Model has correct action set per status + +## Out of scope + +- Editing book properties (author, format, ISBN) — add-book covers creation; editing + those can come later if needed +- Deleting books — add-book is additive; no delete flow yet +- Rating prompt on the "Mark read" page — deferred; rating can be set separately +- Inline editing in the detail section — the minibuffer actions are the primary + surface for now