128 lines
4.4 KiB
Markdown
128 lines
4.4 KiB
Markdown
# 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
|