From 82d58a57c61a5d50c12b63db0d086e0e9d6d117b Mon Sep 17 00:00:00 2001 From: sudacode Date: Thu, 9 Apr 2026 00:20:48 -0700 Subject: [PATCH] docs: add stats dashboard feedback pass design spec Design for a single PR covering seven stats dashboard items: collapsible library series groups, same-episode session rollups, 365d trend range, episode delete in library detail, tighter vocabulary word/reading column, filtering Anki-deleted cards, and a chart clarity pass with shared theming. --- ...09-stats-dashboard-feedback-pass-design.md | 347 ++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-09-stats-dashboard-feedback-pass-design.md diff --git a/docs/superpowers/specs/2026-04-09-stats-dashboard-feedback-pass-design.md b/docs/superpowers/specs/2026-04-09-stats-dashboard-feedback-pass-design.md new file mode 100644 index 00000000..0a8321ab --- /dev/null +++ b/docs/superpowers/specs/2026-04-09-stats-dashboard-feedback-pass-design.md @@ -0,0 +1,347 @@ +# Stats Dashboard Feedback Pass — Design + +Date: 2026-04-09 +Scope: Stats dashboard UX follow-ups from user feedback (items 1–7). +Delivery: **Single PR**, broken into logically scoped commits. + +## Goals + +Address seven concrete pieces of feedback against the Statistics menu: + +1. Library — collapse episodes behind a per-series dropdown. +2. Sessions — roll up multiple sessions of the same episode within a day. +3. Trends — add a 365d range option. +4. Library — delete an episode (video) from its detail view. +5. Vocabulary — tighten spacing between word and reading in the Top 50 table. +6. Episode detail — hide cards whose Anki notes have been deleted. +7. Trend/watch charts — add gridlines, fix tick legibility, unify theming. + +Out of scope for this pass: English-token ingestion cleanup and Overview stat-card drill-downs (feedback items 8 and 9). Those require a larger design decision and a migration respectively. + +## Files touched (inventory) + +Dashboard (`stats/src/`): +- `components/library/LibraryTab.tsx` — collapsible groups (item 1). +- `components/library/MediaDetailView.tsx`, `components/library/MediaHeader.tsx` — delete-episode action (item 4). +- `components/sessions/SessionsTab.tsx`, `components/library/MediaSessionList.tsx` — episode rollup (item 2). +- `components/trends/DateRangeSelector.tsx`, `hooks/useTrends.ts`, `lib/api-client.ts`, `lib/api-client.test.ts` — 365d (item 3). +- `components/vocabulary/FrequencyRankTable.tsx` — word/reading column collapse (item 5). +- `components/anime/EpisodeDetail.tsx` — filter deleted Anki cards (item 6). +- `components/trends/TrendChart.tsx`, `components/trends/StackedTrendChart.tsx`, `components/overview/WatchTimeChart.tsx`, `lib/chart-theme.ts` — chart clarity (item 7). +- New file: `stats/src/lib/session-grouping.ts` + `session-grouping.test.ts`. + +Backend (`src/core/services/`): +- `immersion-tracker/query-trends.ts` — extend `TrendRange` and `TREND_DAY_LIMITS` (item 3). +- `immersion-tracker/__tests__/query.test.ts` — 365d coverage (item 3). +- `stats-server.ts` — passthrough if range validation lives here (check before editing). +- `__tests__/stats-server.test.ts` — 365d coverage (item 3). + +## Commit plan + +One PR, one feature per commit. Order picks low-risk mechanical changes first so failures in later commits don't block merging of earlier ones. + +1. `feat(stats): add 365d range to trends dashboard` (item 3) +2. `fix(stats): tighten word/reading column in Top 50 table` (item 5) +3. `fix(stats): hide cards deleted from Anki in episode detail` (item 6) +4. `feat(stats): delete episode from library detail view` (item 4) +5. `feat(stats): collapsible series groups in library` (item 1) +6. `feat(stats): roll up same-episode sessions within a day` (item 2) +7. `feat(stats): gridlines and unified theme for trend charts` (item 7) + +Each commit must pass `bun run typecheck`, `bun run test:fast`, and any change-specific checks listed below. + +--- + +## Item 1 — Library collapsible series groups + +### Current behavior + +`LibraryTab.tsx` groups media via `groupMediaLibraryItems` and always renders the full grid of `MediaCard`s beneath each group header. + +### Target behavior + +Each group header becomes clickable. Groups with `items.length > 1` default to **collapsed**; single-video groups stay expanded (collapsing them would be visual noise). + +### Implementation + +- State: `const [collapsedGroups, setCollapsedGroups] = useState>(...)`. Initialize from `grouped` where `items.length > 1`. +- Toggle helper: `toggleGroup(key: string)` adds/removes from the set. +- Group header: wrap in a `