feat(dashboard): pin toggle on tiles + handleDashboardPin handler
Phase 5h slice 4 — adds the star button on each tile that flips Pinned on the projax item via POST /dashboard/pin. Backend: - store.SetPinned(ids, pinned bool) — minimal-write helper that mirrors SetPublic, only touching the pinned column. - web/dashboard_pin.go — handleDashboardPin parses id + pin from form, calls SetPinned, invalidates the entire dashboard cache (pin affects sort order across every view/scope/filter combo), then re-renders by delegating to handleDashboard so HTMX receives the updated #dashboard-section HTML. - Route: POST /dashboard/pin (sibling of /dashboard/task/*). Frontend: - Tile template now leads with a <form class="tile-pin-form"> that POSTs id + the inverted pin state. Button glyph is ☆ when unpinned, ★ when pinned; aria-label flips accordingly. - HTMX swaps the entire #dashboard-section so the tile moves to the pinned-first position (or back to alphabetical) without a full reload. - CSS: .tile-pin (transparent button, muted color, accent on hover); .tile-pin.pinned for the filled-star state. Test helper: server_test.go gains a post() helper paired with the existing get() — form-encoded POSTs for writeback tests. Tests (dashboard_pin_test.go): - TestDashboardPinTogglesItem — POST pin=true flips the row, and the re-render shows the .tile-pinned class on the tile <article>. - TestDashboardPinUnpinsItem — POST pin=false on a pinned row unpins. - TestDashboardPinRequiresID — missing id returns 400. - TestDashboardPinInvalidatesCache — primes with unpinned cache, POSTs pin, asserts the next GET reflects the pinned class (proving the prior cache entry was busted).
This commit is contained in:
@@ -355,7 +355,13 @@ table.bulk .chip-add-btn:hover { background: var(--accent); color: var(--accent-
|
||||
.dashboard .tile .tile-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
|
||||
.dashboard .tile .tile-title { font-weight: 600; color: var(--fg); text-decoration: none; }
|
||||
.dashboard .tile .tile-title:hover { text-decoration: underline; }
|
||||
.dashboard .tile .tile-star { color: var(--accent); margin-right: 2px; }
|
||||
.dashboard .tile .tile-pin-form { display: inline-flex; margin: 0 4px 0 0; }
|
||||
.dashboard .tile .tile-pin {
|
||||
background: transparent; border: none; cursor: pointer;
|
||||
color: var(--muted); padding: 0; font-size: 1.1em; line-height: 1;
|
||||
}
|
||||
.dashboard .tile .tile-pin.pinned { color: var(--accent); }
|
||||
.dashboard .tile .tile-pin:hover { color: var(--accent); }
|
||||
.dashboard .tile .tile-path {
|
||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
||||
font-size: 0.78em;
|
||||
|
||||
Reference in New Issue
Block a user