diff --git a/docs/design.md b/docs/design.md index d54c7e2..88939ff 100644 --- a/docs/design.md +++ b/docs/design.md @@ -761,10 +761,67 @@ Top-nav `
` retired. Layout chrome now mirrors mBrian's surface so the tw - Quick-switcher / saved-searches / Today / Work / Quick-log slots from mBrian — none have analogues in projax. The 5-slot bottom-nav stays scoped to projax's actual surfaces. - Drawer slide-up gesture. `
` with a CSS `transform: translateY(8px) → 0` keyframe is enough for v1; a real bottom-sheet gesture is v2 polish. +## 19. Dashboard overhaul: Tiles + view switcher (Phase 5h) + +The Phase 3e task-centric stream (5 cards: Open tasks / Events / Open issues / Recent docs / Stale) ships unchanged on the new **Tasks tab**. The default landing surface at `/dashboard` flips to a project-centric **Tiles** view per m's request "easily show a helpful overview over my current projects". Design plan: `docs/plans/dashboard-overhaul.md` (Phase A: 3 candidates surveyed, Tiles greenlit). + +**URL contract** — defaults elide: + +| Param | Values | Default | Notes | +|---|---|---|---| +| `view` | `tiles` \| `tasks` \| `events` | `tiles` | Tab strip lives below the filter bar | +| `scope` | `current` \| `all` | `current` | Tiles-only chip; Tasks + Events ignore it | +| `tag` / `mgmt` / `has` / `q` / `status` / `public` | (unchanged) | — | Same `TreeFilter` vocabulary as `/`, `/timeline`, `/calendar`, `/graph` | +| `refresh` | `1` | — | Busts the current (filter, view, scope) cache slot | + +Unknown `view=` values fall back to `tiles`. + +**Per-project rollup (`dashboardProject`)** — one row per item.ID across every signal source. Built from the same aggregator rows the existing cards consume, so adding Tiles costs zero extra DAV/Gitea calls: + +- `OpenTasks` — open VTODOs across every linked calendar (uncapped, unlike the 30-row Tasks card). +- `Overdue` — subset of OpenTasks with `Due < startOfDay(now)`. +- `OpenIssues` — open Gitea issues across every linked repo (uncapped). +- `LastActivity` — `max(repo.updated_at, latest VTODO LastModified, latest event start, latest dated link, latest issue UpdatedAt)`. Zero when no signal is seen. +- `NextSignal` / `NextSignalKind` — soonest-due open VTODO summary (kind=`task`); falls back to the latest-updated issue title (kind=`issue`) when no task; empty otherwise. Task wins over issue. +- `IsLive` — derived from `Item.PublicLiveURL` being non-empty. +- `Stale` — fed by the existing `collectStale` set so the rollup doesn't re-probe Gitea. + +Sort: pinned first, then by primary path ascending. + +**`IsCurrent(now)` rule** — `Pinned OR OpenTasks > 0 OR OpenIssues > 0 OR LastActivity within 14d` (`dashboardActivityWindow`). Drives the Current/Quiet split when `scope=current`. + +**Tiles layout** — CSS grid `minmax(0, 1fr)` columns at 1/2/3 cols (≤600 / 600–900 / ≥900 px). Each tile: +- Star toggle (`POST /dashboard/pin` with `id` + `pin=true|false`) — flips `Item.Pinned`, invalidates the dashboard cache, re-renders the section. Star glyph is ☆ unpinned, ★ pinned. +- Title → `/i/`, primary path under (mono font), optional `live` badge for `IsLive`, optional `stale` badge for `Stale`. +- Counts row: `N open` / `M!` (overdue, red) / `K issues` / `quiet` fallback. +- NextSignal one-liner with `•` (task) or `◆` (issue) marker; ellipsis on overflow. +- LastActivity stamp in the footer: `now` / `Nm` / `Nh` / `Nd` (see `activityRel`). Distinct from `relativeTime` so the narrow tile column reads cleanly. + +`minmax(0, 1fr)` + `min-width: 0` on `.tile` + `overflow-wrap: anywhere` on `.tile-path` are the canonical CSS-grid containment recipe — without all three, a long unbreakable slug-path or task summary widens its column past the viewport and forces a horizontal scroll. The hotfix that introduced this triad landed mid-rollout after m flagged the scroll. + +**Quiet (N) ▾ fold** — `
` element below the primary grid containing every rollup with `IsCurrent=false`, including all stale candidates. Summary line: `Quiet (N) — older than 14d · M stale` (the stale count omits when zero). Tiles inside render with the same shape, slightly faded; stale tiles add a `tile-stale` class (dashed border) and a `stale` flag badge. The Quiet fold replaces the standalone Stale card from Phase 3e — m's pick: per-tile `LastActivity` stamp carries the staleness signal, "consider archiving?" framing migrates to the fold. + +**Scope chip** — renders on the Tiles tab only (`◇ current` ⇄ `○ all`). Tasks + Events tabs have no scope concept. The chip href flips between `?scope=all` and the default URL, preserving the active view + filter. + +**Tasks tab** — today's 5-card layout MINUS the Stale card. Inline VTODO writeback (`/dashboard/task/done|edit|delete`) stays exactly as Phase 3e wired it. + +**Events tab** — promoted from the Tasks-tab Events card to its own surface with: top summary header `N events · next 7 days`, three-column day headings (relative label / ISO date / right-aligned count), and an empty-state copy inviting the user to link a CalDAV calendar from a project detail page. Same `aggregate.Aggregator.Events` source as the cards-tab version. + +**Cache** — composes `(filter | view=X | scope=Y)` so each surface has its own 60s TTL slot. Pin flip calls `InvalidateAll` (Pinned affects sort order across every combination). + +**Mobile (≤768px)** — tab strip wraps; scope chip drops to its own row centered. Tile padding tightens; pin button has a 36 px touch target (intentionally less than the 44 px elsewhere to keep the header row balanced), live badge has 32 px, Quiet fold summary has 12 px vertical padding. Events tab day-heading wraps; count drops below the label + date. + +**What was deliberately parked for a later phase**: +- Activity tab (chronological feed of commits/issues/completions/docs) — m's pick was 3 tabs at launch, defer Activity to v2. +- Sortable Project Rows view (Candidate B from the design plan) — Tiles + Tasks tabs cover both daily-driver and detailed read-out shapes. +- Project filter dimension on `TreeFilter` and saved views — those are Phase 5i (parallel design with kahn). +- Anything that would need new MCP tools or schema columns — `Pinned` already existed and that was the only mutation needed. + ## 10. References - Project CLAUDE.md (this repo) — purpose, constraints, gated worker flow - `~/.claude/CLAUDE.md` — global conventions (memory, channel routing, git strategy) +- `docs/plans/dashboard-overhaul.md` — Phase 5h design plan (3 candidates + recommendation + m's chip picks) - `mai.projects` schema (msupabase) — current state being adapted - mBrian `nodes`/`edges` schema — terminology source - otto session 2026-05-15 — inventory motivating this project