feat(web): permanent action key under the tabs

The card action strip is icon-only, so nothing on screen said what the
six glyphs do. Add a keyrow line under the tabs that names each one.

The key follows the tab, not the row: archived and finished swap Archive
for Restore, and finished drops Done — same conditions card.html already
uses for the buttons themselves. It therefore rides along in
writeChromeOOB, or a tab switch would leave the previous bucket's key.

Also from the Claude Design pass: per-action accent colours on hover and
press (slate archive, moss finished, clay chapter) so a press says which
lane it belongs to, a slightly larger cover and title, and the favourite
mark pinned to the right edge of the measure instead of trailing the
title, which drifted whenever a new-chapter title shrink-wrapped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 03:18:54 +07:00
parent f3b55fd883
commit 42b93dc155
4 changed files with 113 additions and 26 deletions
+6 -4
View File
@@ -248,12 +248,14 @@ func currentTab(r *http.Request) string {
return u.Query().Get("tab")
}
// writeChromeOOB appends the two regions that live outside #list — the recent
// strip and the Updated badge — as out-of-band swaps, so a mutation cannot
// leave them describing the library as it was before the tap.
// writeChromeOOB appends the regions that live outside #list — the recent
// strip, the Updated badge and the action key — as out-of-band swaps, so a
// mutation cannot leave them describing the library as it was before the tap.
// The key is in here because it is tab-shaped too: archived and finished swap
// Archive for Restore.
func (h *webHandler) writeChromeOOB(w http.ResponseWriter, view listView) {
view.OOB = true
for _, name := range []string{"recent", "newcount"} {
for _, name := range []string{"recent", "newcount", "keyrow"} {
if err := h.tmpl.ExecuteTemplate(w, name, view); err != nil {
// The card is already written; stale chrome beats a torn response.
log.Printf("render %s oob: %v", name, err)