docs: add edit book actions design spec

This commit is contained in:
2026-06-21 09:38:53 -04:00
parent 31833bf38e
commit 41a8ba24d1
@@ -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 `<a href>` 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=<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=<id>`.
- `action=rating` — calls `spine-set-rating` with `id` and `value`. Redirects to
`/index?id=<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}}
<footer class="minibuffer">
<span class="muted">M-x</span>
<span style="display:flex;gap:.5rem;flex-wrap:wrap">
{{#actions}}
<a href="{{href}}" class="pill {{command}}">{{label}}</a>
{{/actions}}
</span>
</footer>
{{/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