fix(web): actionable empty state for the summary list

Videos rows are created by `tapir run`, not when a YouTube account is
connected, so a freshly-connected account correctly shows an empty list —
but the old empty state ("No videos yet") gave no clue why or what to do.
Split it on whether the user has any connection:

- connected, no videos: a distinct accent callout telling them to run
  `tapir run` to discover subscriptions.
- not connected: a prompt with a Connect YouTube button.

handleList fetches connections only when the list is empty. Includes
web-shot captures of all three states under docs/ux-review/fixes/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 22:45:29 +02:00
co-authored by Claude Opus 4.8
parent 27aa319f1d
commit c63b2de66d
2 changed files with 173 additions and 153 deletions
+15 -2
View File
@@ -155,11 +155,24 @@ func (a *App) handleList(w http.ResponseWriter, r *http.Request) {
} }
rows = f.apply(rows) rows = f.apply(rows)
// hasConnected drives the empty state: a fresh account with a connection but
// no `tapir run` yet has zero rows, and we want it to read "connected, run
// tapir" rather than "nothing here". Only needed when the list is empty.
hasConnected := false
if len(rows) == 0 {
conns, err := a.Store.ConnectionsForUser(r.Context(), userID)
if err != nil {
a.serverError(w, r, "connections for user", err)
return
}
hasConnected = len(conns) > 0
}
if isHTMX(r) { if isHTMX(r) {
a.render(w, r, summaryList(rows)) a.render(w, r, summaryList(rows, hasConnected))
return return
} }
a.render(w, r, ListPage(rows, f, takeFlash(w, r))) a.render(w, r, ListPage(rows, f, takeFlash(w, r), hasConnected))
} }
// handleDetail renders one summary in full (highlights, takeaways, action group). // handleDetail renders one summary in full (highlights, takeaways, action group).
File diff suppressed because it is too large Load Diff