feat: add edit/delete buttons to list views and inline privacy toggle

Fave cards in the list and profile views now show edit, delete, and
privacy toggle buttons directly — no need to open the detail page first.

- New POST /faves/{id}/privacy route with HTMX privacy toggle partial
- New UpdatePrivacy store method for single-column update
- fave_list.html: edit link, HTMX delete, privacy toggle on every card
- profile.html: edit/delete for owner's own cards
- privacy_toggle.html: new HTMX partial that swaps inline on toggle
- CSS: compact .fave-card-actions styles

The existing handleFaveDelete already returns empty 200 for HTMX
requests, so hx-target="closest article" hx-swap="outerHTML" removes
the card from DOM seamlessly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-04-07 10:17:46 +02:00
commit b186fb4bc5
9 changed files with 360 additions and 3 deletions

View file

@ -150,6 +150,37 @@ func TestFaveNotes(t *testing.T) {
}
}
func TestUpdatePrivacy(t *testing.T) {
db := testDB(t)
users := NewUserStore(db)
faves := NewFaveStore(db)
Argon2Memory = 1024
Argon2Time = 1
defer func() { Argon2Memory = 65536; Argon2Time = 3 }()
user, _ := users.Create("testuser", "password123", "user")
fave, _ := faves.Create(user.ID, "Toggle me", "", "", "", "public")
// Toggle to private.
err := faves.UpdatePrivacy(fave.ID, "private")
if err != nil {
t.Fatalf("update privacy: %v", err)
}
got, _ := faves.GetByID(fave.ID)
if got.Privacy != "private" {
t.Errorf("privacy = %q, want private", got.Privacy)
}
// Toggle back to public.
faves.UpdatePrivacy(fave.ID, "public")
got, _ = faves.GetByID(fave.ID)
if got.Privacy != "public" {
t.Errorf("privacy = %q, want public", got.Privacy)
}
}
func TestListByTag(t *testing.T) {
db := testDB(t)
users := NewUserStore(db)