Files
RolemasterDB/docs/tables_frontend_overhaul_implementation_plan.md

793 lines
48 KiB
Markdown

# Tables Frontend Overhaul Implementation Plan
## Purpose
This document turns the vision in [tables_ux_bible.md](./tables_ux_bible.md) into an execution plan for the current Blazor Web App frontend in `src/RolemasterDb.App`.
It is intentionally implementation-focused:
- clear task breakdown
- explicit acceptance criteria
- concrete definition of done
- reasonable implementation order
- minimal churn to the existing backend and API contracts
## Source Inputs
- [tables_ux_bible.md](./tables_ux_bible.md)
- current Blazor app shell and routes in `src/RolemasterDb.App/Components`
- current API and view models in `src/RolemasterDb.App/Features`
## Constraints
- keep the current tech stack
- keep the current backend and API contracts
- keep the current critical-table data model and curation workflow as the domain foundation
- treat route and UI changes as frontend/presentation refactors unless an additive backend endpoint is explicitly approved later
- keep changes incremental and shippable by phase
## Working Status
- Branch: `frontend/tables-overhaul`
- Last updated: `2026-03-21`
- Current focus: `Phase 3`
- Document mode: living plan and progress log
### Progress Log
| Date | Phase | Status | Notes |
| --- | --- | --- | --- |
| 2026-03-21 | Phase 0 | Completed | Created overhaul branch, audited the current frontend, and locked the route map, component boundaries, migration path, and shared-state ownership. |
| 2026-03-21 | P1.1 | Completed | Replaced the legacy token root with semantic background, surface, text, border, focus, shadow, and semantic accent ramps while keeping compatibility aliases for incremental migration. |
| 2026-03-21 | P1.2 | Completed | Switched the app to Fraunces, IBM Plex Sans, and IBM Plex Mono with distinct display, body, UI, and code font roles instead of one shared heading font. |
| 2026-03-21 | P1.3 | Completed | Added explicit light, dark, and system theme modes in the token layer and introduced a scoped `ThemeState` service for later shell controls. |
| 2026-03-21 | P1.4 | Completed | Added shared browser-storage wrappers, persisted theme mode in `localStorage`, and initialize/apply theme state from the layout on interactive render. |
| 2026-03-21 | P1.5 | Completed | Replaced the permanent sidebar layout with a sticky top app shell and mobile bottom navigation backed by dedicated shell components. |
| 2026-03-21 | P1.6 | Completed | Added explicit shell slots for nav, omnibox, shortcuts, and utilities; switched shell navigation to `Play`, `Tables`, `Curation`, and `Tools`; and wired the first live theme control into the shell. |
| 2026-03-21 | P1.7 | Completed | Added a shell-level skip link and tightened the top-level header, navigation, and main landmarks around the new shell structure. |
| 2026-03-21 | P1.8 | Completed | Introduced a cooler tooling emphasis for `Tools`, diagnostics, and API surfaces, and styled the `Tools` destination as distinct without splitting the shell. |
| 2026-03-21 | Post-P1 fix 1 | Completed | Closed the 768px-1023px navigation gap by adding a shell hamburger menu and drawer so primary navigation never disappears at tablet widths. |
| 2026-03-21 | Post-P1 fix 2 | Completed | Replaced the most visible light-only surface and control colors with theme-aware tokens so switching between `Light`, `Dark`, and `System` produces a clear visual change. |
| 2026-03-21 | Post-P1 fix 3 | Completed | Restored layout-level shell interactivity by rendering routed content in `InteractiveServer` mode, which re-enabled shell event handlers such as the hamburger menu and theme selector. |
| 2026-03-21 | Post-P1 fix 4 | Completed | Added early theme bootstrapping in `App.razor` and `theme.js` so the stored mode is applied before hydration and remains visible after refresh. |
| 2026-03-21 | P2.1 | Completed | Added canonical `/tools/diagnostics` and `/tools/api` routes with dedicated tooling page components, extracted the diagnostics and API content into shared tool components, and updated the `Tools` landing page to link to the new route structure. |
| 2026-03-21 | P2.2 | Completed | Replaced the old `/diagnostics` and `/api` pages with lightweight compatibility routes that reuse a shared redirect component, preserve query strings and fragments, and replace browser history while forwarding into the canonical `Tools` routes. |
| 2026-03-21 | P2.3 | Completed | Added a shared `RecentTablesState` service backed by browser storage, centralized the recents storage key, and started recording successful table visits from the `Tables` page so later omnibox and rail work has real shared data. |
| 2026-03-21 | P2.4 | Completed | Added a shared `PinnedTablesState` service with browser persistence, centralized the pin storage key, initialized pin state in the `Tables` page, and added a first live pin/unpin action plus pinned status chips so later omnibox and navigation work have real saved pins to consume. |
| 2026-03-21 | P2.5 | Completed | Added shared table-context URL types and a serializer, registered the serializer centrally, and started round-tripping table context through `/tables` and `/tools/diagnostics` so direct links restore the selected table and diagnostic cell context instead of relying only on local storage defaults. |
| 2026-03-21 | P2.6 | Completed | Replaced the dead shell omnibox trigger with a live drawer-backed omnibox foundation that loads critical tables on demand, filters table search results, surfaces pinned and recent table sections from shared state, and exposes slash-command navigation for the core destinations and tooling routes. |
| 2026-03-21 | P2.7 | Completed | Added shared frontend primitives for app-bar actions, chips, segmented tabs, drawers, inspector sections, and status indicators, wired the shell omnibox trigger onto the new app-bar action primitive, and switched the new pinned-table labels in `Tables` to the shared status-chip primitive so later page work can build on reusable building blocks instead of fresh ad hoc markup. |
| 2026-03-21 | P2.8 | Completed | Added a shared `TableContextState` service on top of browser storage and the URL serializer, moved the `Tables` page off page-local table selection persistence, and switched diagnostics to the same restore/persist/build-URI flow so table context logic now lives in shared frontend state instead of being reinvented per page. |
| 2026-03-21 | Post-P2 fix 1 | Completed | Fixed the shell omnibox drawer regression by adding explicit shell offset variables, constraining drawer/body scrolling, and giving the omnibox its own backdrop geometry so the flyout opens within the visible viewport instead of collapsing into invalid top/bottom positioning. |
| 2026-03-21 | Post-P2 fix 2 | Completed | Rebuilt the shell omnibox as a dedicated command palette instead of a repurposed drawer, with shell-owned overlay markup, explicit viewport-safe geometry, autofocus, Escape and navigation close behavior, and a stable scrollable result body. |
| 2026-03-21 | Post-P2 fix 3 | Completed | Moved omnibox overlay ownership from the header subtree into `AppShell` itself via a shared omnibox state service and a top-level palette host, which restored full-screen backdrop coverage and reliable outside-click close behavior. |
| 2026-03-21 | P3.1 | Completed | Split `Tables.razor` into focused table components for the selector header, context bar, canvas, and legend while leaving loading, deep-link synchronization, and dialog state in the page host. |
| 2026-03-21 | P3.2 | Completed | Replaced the floating table picker with a permanent left-rail layout, converted the old selector component into a real page header, and kept the current selection flow intact inside the new reference frame. |
| 2026-03-21 | P3.3 | Completed | Added rail search, family filters, pinned and recent sections, curated status chips, and keyboard up/down plus Enter handling on top of the new permanent table index rail. |
| 2026-03-21 | P3.4 | Completed | Added a sticky context bar with reference-mode tabs, variant and severity selectors, roll-jump state, and active filter chips, then wired those controls into page state and canvas filtering. |
| 2026-03-21 | P3.5 | Completed | Reworked the canvas with sticky headers, a sticky roll-band column, row and column emphasis driven by selection and roll-jump state, selected-cell treatment, and a comfortable/dense density toggle. |
| 2026-03-21 | P3.6 | Completed | Removed the always-visible cell button stack from resting cells, leaving status-only hints by default and limiting compact edit/curation buttons to the currently selected cell. |
| 2026-03-21 | P3.7 | Completed | Added a dedicated desktop inspector column that reads from the shared selected-cell state and keeps the selected result readable beside the grid. |
| 2026-03-21 | P3.8 | Completed | Reused the inspector body inside a mobile bottom sheet with its own backdrop and close affordance so touch users keep the same selection-driven inspector model as desktop. |
| 2026-03-21 | P3.9 | Completed | Pulled legend/help out of the always-on canvas component and turned it into an explicitly toggled secondary surface controlled from the context bar. |
| 2026-03-21 | P3.10 | Completed | Softened the default `Reference` mode by replacing repeated curation wording in resting cells with subtle status indicators and by simplifying the top-level guidance copy. |
| 2026-03-21 | P3.11 | Completed | Moved the live editor and curation entry points into the shared inspector content and removed the last remaining grid-owned action buttons. |
### Lessons Learned
- The current app shell is simple enough that the redesign can land incrementally in `MainLayout.razor` without changing the hosting model in `Program.cs`.
- The current `Tables.razor` page already contains three different concerns: reference browsing, curation queue work, and full editing. Splitting by workflow is the highest-value maintainability move.
- Existing contracts in `LookupContracts.cs` already contain the identifiers needed for deep links and cross-surface navigation: table slug, group key, column key, roll band, and result id.
- Diagnostics already behaves like a separate workflow and should be moved under `Tools` early, before the `Tables` page is rewritten further.
- `localStorage` access is currently page-local and ad hoc. Theme, recents, pins, and table context need one shared storage boundary before more UI work starts.
- The old typography setup coupled display and utility text under a single token. The new shell work needs separate display and UI font roles to avoid decorative type in controls.
- Theme mode selection can be prepared independently of persistence. Splitting those concerns keeps the theme CSS and the storage wiring reviewable.
- Shared UI state events in Blazor should stay synchronous unless the event contract is async-aware. Layout refresh can be triggered safely with `InvokeAsync(StateHasChanged)` from a synchronous handler.
- Extracting shell markup into dedicated components is lower-risk than continuing to evolve `MainLayout.razor` directly. It isolates responsive frame work from page content and keeps later nav changes localized.
- Once a Razor component exposes multiple named `RenderFragment` parameters, the page body must be passed explicitly through `<ChildContent>`. That pattern is now the baseline for shell composition here.
- Accessibility work is cheaper when the shell owns the landmarks. Adding skip links and nav/main structure at the shell layer avoids repeating that work page by page.
- Tooling can feel distinct through cooler surfaces and labeling alone. A separate app shell is unnecessary and would undermine the shared-product goal.
- Responsive shell design needs an explicit tablet state, not just desktop and phone states. The original breakpoints left a navigation dead zone between the top nav and bottom nav layouts.
- Theme infrastructure is not enough on its own. Any surface that keeps hardcoded light values will make the theme switch feel broken even when the selector logic is correct.
- In Blazor Web Apps, page-level render modes do not automatically make layout-level controls interactive in the way this shell expects. The routed shell itself needs an interactive render boundary.
- Persisted theme state should be applied before Blazor hydrates, not only after layout initialization. Otherwise refresh can look broken even when storage writes succeed.
- For route migration in Blazor, extracting the destination UI into shared components keeps canonical routes and temporary compatibility routes from drifting while the redirect phase is still pending.
- Compatibility routes should stay declarative and shared. A single redirect component is enough for route forwarding and avoids copy-pasted `NavigationManager` lifecycle logic in page files.
- Shared browser-backed state becomes more useful once one real page writes to it immediately. Recording recents from `Tables` now keeps later omnibox work from being blocked on synthetic placeholder data.
- Shared pinned-state services also need one live writer early. A minimal pin/unpin affordance in the current `Tables` page is enough to validate persistence before the larger navigation surfaces consume pins.
- URL serializers only pay off when wired into real pages. Using the shared serializer in both `Tables` and diagnostics now gives the project one verified round-trip path before the larger table-context service lands.
- The serializer alone is not the reusable boundary. The maintainable seam is a shared context-state helper that owns restore, persist, normalization, and URI-building conventions while pages keep only workflow-specific selection logic.
- Primitive extraction lands best when one or two live consumers adopt the new components immediately. That keeps the foundation honest without forcing a broad page rewrite just to validate the abstraction.
- The omnibox foundation does not need the full final interaction model to be useful. A drawer with real table search, real pinned/recent data, and a small slash-command set is enough to validate the shell surface before Phase 3 builds deeper index and inspector flows on top of it.
- Shared overlay primitives should not depend on undeclared layout variables. If a drawer needs shell offsets, the shell must define them explicitly and overlay-specific backdrops should be adjustable instead of assuming full-screen dimming is always correct.
- A command palette is not just a styled drawer. It needs shell-owned geometry, predictable focus behavior, and a bounded scroll region; treating it as a generic side panel led directly to the layout regressions found in Phase 2.
- Backdrop and outside-click behavior depend on overlay ownership as much as CSS. If the trigger owns the overlay inside a sticky header subtree, fixed-position assumptions can break; shell-level overlays should be rendered by the shell, not by individual header controls.
- The `Tables` rewrite is safer when orchestration and rendering are separated early. Keeping loading, persistence, and dialog state in the page host while extracting render-only components makes later layout and interaction changes much lower risk.
- The `Tables` navigation model needs its own persistent geometry before advanced behaviors land. Converting the selector to a real rail first keeps later search and keyboard work from being tangled up with another structural rewrite.
- Rail keyboard behavior is easiest to maintain when it works from one deduplicated option order, even if the UI shows multiple sections. Keeping one internal option list avoids separate arrow-key state per section.
- The context bar controls should own one shared view-state model before the canvas gets more visual treatment. Wiring the filters into the host page now avoids a second refactor when row, column, and cell emphasis land.
- Canvas emphasis becomes maintainable once selection, roll-jump, and density are all fed through one explicit state model. That lets the grid respond to context without hiding selection logic inside CSS-only heuristics.
- Resting-cell quietness should be enforced structurally, not only visually. Showing actions only for the selected cell prevents future CSS regressions from reintroducing button clutter across the whole grid.
- The inspector should be its own sibling surface in the page layout, not nested inside the table shell. That keeps the content reusable for both desktop and the later mobile sheet without coupling it to canvas markup.
- The inspector content itself should be shared independently of its container. Once the body is separated from the desktop column chrome, the mobile bottom sheet can reuse it with almost no behavioral drift.
- Help content should not stay embedded in the canvas component once the grid becomes the main task surface. Moving legend rendering back to the page host makes it easier to demote, reposition, or merge with future help surfaces.
- Hiding maintenance noise in default reference mode is mostly a copy and chrome problem, not a routing or data problem. Replacing repeated curation words with quieter indicators goes further than adding yet another toggle.
- Once the inspector owns the action entry points, the grid should stop carrying legacy button styles and callbacks. Removing dead grid-action code immediately keeps the browse-first model from drifting back toward edit-first behavior.
## Target Outcomes
The overhaul is complete when the app behaves as one coherent product with four clear destination families:
- `Play` for live lookup and fast resolution
- `Tables` for reference and inspection
- `Curation` for queue-based repair work
- `Tools` for diagnostics and API documentation
The new shell, navigation, spacing, theming, and interaction grammar must be reusable for future pages.
## Overall Definition Of Done
The frontend overhaul is done when all of the following are true:
- the app uses a shared design system with explicit light, dark, and system themes
- the primary navigation matches the UX bible and no longer reflects implementation buckets
- `/tables` is browse-first, selection-driven, and free of resting-state cell action clutter
- `Curation` is a dedicated queue-first workflow rather than ambient clutter inside `Tables`
- diagnostics and API docs are grouped under `Tools`
- `Play` and `Tables` share the same shell and interaction model
- deep links preserve object context for key user journeys
- keyboard, focus, contrast, responsive behavior, and sticky layout behavior meet the UX bible rules
- the solution is maintainable, with the current monolithic `Tables` page split into reusable components and services
## Delivery Strategy
Implement in vertical slices, not by page-wide rewrites. Each phase should leave the app in a buildable, reviewable, and partially usable state.
Recommended order:
1. foundation and shell
2. shared state and deep-link infrastructure
3. `Tables` reference experience
4. `Curation` workflow
5. `Tools` consolidation
6. `Play` alignment
7. hardening, QA, and rollout cleanup
## Phase 0: Discovery And Technical Baseline
### Status
`Completed`
### Goal
Create the implementation foundation so the visual overhaul does not start with uncontrolled edits in page files.
### Tasks
- `P0.1` Audit current component ownership in `Components/Layout`, `Components/Pages`, and `Components/Shared`.
- `P0.2` Identify which behaviors already exist and should be preserved:
- selected table persistence
- cell editor and curation dialogs
- diagnostics selection model
- lookup forms and result cards
- `P0.3` Define the target frontend structure for the overhaul.
- `P0.4` Decide the new route map and compatibility redirects.
- `P0.5` Define a shared frontend state strategy for:
- theme
- recent tables
- pinned tables
- selected table context
- deep-link parsing and serialization
- `P0.6` Define component boundaries for shared primitives before major page work starts.
### Deliverables
- agreed route map
- agreed component and state boundaries
- agreed migration path from current shell and pages
### Acceptance Criteria
- every planned frontend surface has an explicit owner component or service area
- route compatibility is defined before navigation work begins
- there is a clear plan for what stays in page components versus what moves to shared services/components
### Definition Of Done
- no unresolved structural ambiguity remains around shell, routes, state ownership, or shared primitives
### Current Repo Audit
| Area | Current owner | Current responsibility | Phase 0 decision |
| --- | --- | --- | --- |
| App host | `src/RolemasterDb.App/Components/App.razor` | document shell, fonts, global CSS/script includes | keep as the document root; only update fonts and global assets during Phase 1 |
| Router | `src/RolemasterDb.App/Components/Routes.razor` | route resolution and layout selection | keep single router; add compatibility route components instead of special middleware redirects |
| App shell | `src/RolemasterDb.App/Components/Layout/MainLayout.razor` | current sidebar layout and page body host | replace with the new top app bar shell and mobile bottom nav |
| Primary nav | `src/RolemasterDb.App/Components/Layout/NavMenu.razor` | implementation-bucket navigation | retire after the new shell lands; replace with destination navigation primitives |
| Home page | `src/RolemasterDb.App/Components/Pages/Home.razor` | live lookup flow | keep behavior, later restyle and reframe as `Play` |
| Tables page | `src/RolemasterDb.App/Components/Pages/Tables.razor` | table selection, table rendering, persisted selection, editor launch, curation queue work | split into page shell, selection state, index rail, context bar, table canvas, inspector, and action services |
| Diagnostics page | `src/RolemasterDb.App/Components/Pages/Diagnostics.razor` | engineering inspection of a selected cell | move under `Tools` and reuse shared table-selection state |
| API page | `src/RolemasterDb.App/Components/Pages/Api.razor` | static API docs page | move under `Tools` with updated framing |
| Shared editor and curation UI | `src/RolemasterDb.App/Components/Shared/CriticalCellEditorDialog.razor`, `src/RolemasterDb.App/Components/Shared/CriticalCellCurationDialog.razor` | full editing and quick curation interactions | preserve behavior; change launch points and page ownership |
| Lookup and table contracts | `src/RolemasterDb.App/Features/LookupContracts.cs` | frontend-facing DTOs for tables, lookups, editing, and diagnostics | preserve contracts; build frontend state and deep links around them |
### Behaviors To Preserve
| Behavior | Current source | Preserve as | Notes |
| --- | --- | --- | --- |
| Selected table persistence | `Tables.razor` local storage key `rolemaster.tables.selectedTable` | shared per-destination context persistence service | move out of page code during Phase 2 |
| Full cell editor flow | `Tables.razor` + `CriticalCellEditorDialog.razor` | stable editor entry from inspector, curation, and tools | editor remains modal for now |
| Quick curation flow and save-next behavior | `Tables.razor` + `CriticalCellCurationDialog.razor` | dedicated `Curation` workflow with reused quick-parse components | queue logic moves off the reference page |
| Diagnostics selection model | `Diagnostics.razor` | shared table-position selector model used by `Tools` | existing selection order is a good starting point |
| Attack and direct critical lookup flows | `Home.razor` | `Play` page behaviors | preserve contracts and calculation behavior |
| Result preview components | `CriticalLookupResultCard.razor`, `CompactCriticalCell.razor`, related shared components | reusable reference and inspector content | keep and adapt instead of rewriting presentation logic from scratch |
### Resolved Route Map
| Surface | Target route | Compatibility handling | Owner page/component |
| --- | --- | --- | --- |
| Play | `/` | none | `Pages/Home.razor` until renamed later |
| Tables | `/tables` | none | `Pages/Tables.razor`, later split into page components under `Components/Tables` |
| Curation | `/curation` | none | new page introduced in Phase 4 |
| Tools landing | `/tools` | none | new page introduced in Phase 5 |
| Diagnostics | `/tools/diagnostics` | keep `/diagnostics` as compatibility page that forwards to `/tools/diagnostics` | new page in `Pages/Tools/Diagnostics.razor` |
| API docs | `/tools/api` | keep `/api` as compatibility page that forwards to `/tools/api` | new page in `Pages/Tools/Api.razor` |
### Route Compatibility Strategy
- Use lightweight compatibility pages instead of server-side redirects so route behavior stays inside the Blazor app.
- Compatibility pages should preserve query string values and replace browser history when forwarding, so old bookmarks do not create noisy back-stack entries.
- New deep-link work should target the destination routes only. Compatibility pages are temporary migration aids and should not gain new UI.
### Target Frontend Structure
| Area | Planned location | Responsibility |
| --- | --- | --- |
| Shell components | `src/RolemasterDb.App/Components/Shell` | app frame, top app bar, bottom nav, destination nav, shell actions |
| Shared app state | `src/RolemasterDb.App/Frontend/AppState` | theme, recents, pins, selected context, URL serialization, storage access |
| Shared primitives | `src/RolemasterDb.App/Components/Primitives` | chips, tabs, buttons, drawers, inspector sections, empty states |
| Tables-specific components | `src/RolemasterDb.App/Components/Tables` | index rail, context bar, table canvas, inspector, state adapters |
| Curation-specific components | `src/RolemasterDb.App/Components/Curation` | queue layout, quick parse surface, save-and-advance actions |
| Tools-specific components | `src/RolemasterDb.App/Components/Tools` | diagnostics inspector, API docs framing, context links |
| Play-specific components | `src/RolemasterDb.App/Components/Play` | lookup forms, result rail, deep-link actions |
### Shared State Strategy
| Concern | Planned owner | Persistence | Consumers |
| --- | --- | --- | --- |
| Theme mode | `ThemeState` service | `localStorage` | shell, all pages |
| Recent tables | `RecentTablesState` service | `localStorage` | shell omnibox, tables rail, curation |
| Pinned tables | `PinnedTablesState` service | `localStorage` | shell shortcuts, tables rail, curation |
| Selected table context | `TableContextState` service | URL first, `localStorage` fallback per destination | tables, curation, tools |
| Table deep-link parsing and serialization | `TableContextUrlSerializer` helper | URL only | tables, curation, tools, play deep links |
| Local storage access | `BrowserStorageService` | wrapper around JS interop | all frontend state services |
### State Ownership Rules
- URL state is the source of truth for sharable context.
- Local storage is only for preferences and last-used convenience state.
- Page components should consume state services and emit intents. They should not own persistence logic directly.
- Editor and curation dialog transient state stays local to the workflow component that opened it.
### Shared Primitive Boundaries
| Primitive | First consumer | Notes |
| --- | --- | --- |
| App bar and destination nav | shell | replaces `NavMenu.razor` |
| Bottom nav | shell | mobile-only persistent destination nav |
| Omnibox trigger and panel | shell, tables | foundation in Phase 2; full search later |
| Chip and status pill primitives | shell, tables, curation, tools | replace ad hoc chip styling in `app.css` |
| Tabs and segmented controls | tables, tools | mode switching and filtered views |
| Drawer and bottom sheet primitives | tables, curation | inspector on small screens |
| Inspector section cards | tables, tools, curation | unify right-rail and sheet layout |
### Migration Path
1. Land the new shell and theme infrastructure in `MainLayout.razor` and `wwwroot/app.css` without changing page internals.
2. Add shared state and compatibility routes before splitting the largest pages.
3. Move diagnostics and API docs under `Tools` early to reduce noise in the main navigation.
4. Split `Tables.razor` into composable pieces while preserving existing editor and curation behaviors.
5. Extract the dedicated `Curation` workflow once the shared selector and table context code already exists.
6. Restyle and reconnect `Play` after shell, deep links, and shared primitives are stable.
### Phase 0 Exit Criteria
- the route map above is treated as implementation truth unless a later change is explicitly recorded here
- page, shell, and shared-state ownership are defined strongly enough to begin Phase 1 without structural rework
- compatibility handling for `/diagnostics` and `/api` is decided
- preserved behaviors are identified so later phases do not regress them accidentally
### Next Implementation Slice
- Start Phase 1 with the shell and design-token foundation in `MainLayout.razor`, `App.razor`, and `wwwroot/app.css`.
- Introduce the shared theme state and browser storage wrapper before rewriting destination pages.
- Replace the current sidebar navigation first so later page work lands inside the target shell instead of the legacy layout.
## Phase 1: Design System And Application Shell
### Status
`Completed`
### Task Progress
| Task | Status | Notes |
| --- | --- | --- |
| `P1.1` | Completed | Semantic token layer landed in `wwwroot/app.css` with compatibility aliases to keep existing pages stable. |
| `P1.2` | Completed | Font loading now uses Fraunces, IBM Plex Sans, and IBM Plex Mono with explicit role-based tokens. |
| `P1.3` | Completed | Explicit light, dark, and system modes now exist in CSS, backed by a scoped `ThemeState` service. |
| `P1.4` | Completed | Theme mode now persists through a shared storage service and is applied from the layout during interactive startup. |
| `P1.5` | Completed | The sidebar is gone; pages now render inside a sticky top-shell with a mobile bottom nav. |
| `P1.6` | Completed | The shell now has explicit nav, omnibox, shortcut, and utility slots, plus a live theme selector and destination-model navigation. |
| `P1.7` | Completed | The shell now exposes a skip link and explicit header/nav/main landmarks. |
| `P1.8` | Completed | Tooling surfaces and the `Tools` nav item now use a cooler emphasis without leaving the shared shell system. |
### Goal
Establish the shared shell, tokens, typography, and theme system that every destination will inherit.
### Tasks
- `P1.1` Replace the current token set in `wwwroot/app.css` with a semantic token system aligned to the UX bible:
- `--bg-*`
- `--surface-*`
- `--text-*`
- `--border-*`
- `--focus-*`
- `--shadow-*`
- accent ramp
- success ramp
- warning ramp
- danger ramp
- info ramp
- `P1.2` Update typography to:
- `Fraunces` for display and section titles
- `IBM Plex Sans` for body and UI labels
- `IBM Plex Mono` for diagnostics and code
- `P1.3` Implement theme modes:
- `Light`
- `Dark`
- `System`
- `P1.4` Persist theme preference in browser storage.
- `P1.5` Replace the current sidebar-first layout with a responsive shell:
- top app bar on desktop
- mobile top bar
- mobile bottom nav
- `P1.6` Add global shell slots for:
- app mark
- primary destination nav
- omnibox trigger or field
- recent/pinned shortcut slot
- theme/settings/help utilities
- `P1.7` Add a skip link and ensure main-content landmarks are valid.
- `P1.8` Keep tools visually separated from play-facing surfaces through styling and labeling, not a separate app.
### Deliverables
- global shell component(s)
- theme service or equivalent state holder
- revised design token layer
- updated app typography
### Acceptance Criteria
- the app no longer depends on the old permanent navigation rail for primary navigation
- theme selection survives reload
- light and dark themes are intentionally designed, not simple inversion
- sticky top navigation does not obscure page content
- the shell works at 375px, 768px, 1024px, and 1440px without horizontal overflow
### Definition Of Done
- all pages render inside the new shell
- primary navigation shows `Play`, `Tables`, `Curation`, and `Tools`
- the app has a stable theme system and global spacing/typography rules
### Phase 1 Exit Notes
- The app now has a semantic token system, explicit typography roles, theme modes with persistence, and a responsive shell.
- The shell already uses the destination model `Play`, `Tables`, `Curation`, and `Tools`, even though deeper route migration remains a Phase 2 concern.
- The next implementation focus is Phase 2: shared route compatibility, recents, pins, omnibox foundations, and deep-link infrastructure.
## Phase 2: Shared Navigation, Search, And State Infrastructure
### Status
`Completed`
### Task Progress
| Task | Status | Notes |
| --- | --- | --- |
| `P2.1` | Completed | Canonical `Tools` child routes now exist, backed by dedicated route pages and shared tooling content components. |
| `P2.2` | Completed | Old `/diagnostics` and `/api` routes now forward into the canonical `Tools` routes with shared redirect behavior. |
| `P2.3` | Completed | Recent critical-table visits now persist through a shared app-state service and are recorded from the `Tables` page. |
| `P2.4` | Completed | Pinned tables now persist through a shared app-state service and can already be toggled from the `Tables` page. |
| `P2.5` | Completed | Shared table-context URLs now parse and serialize through one helper and are consumed by `/tables` and `/tools/diagnostics`. |
| `P2.6` | Completed | The shell omnibox now opens a live drawer with table search, pinned tables, recent tables, and slash-command navigation. |
| `P2.7` | Completed | Shared primitives for chips, tabs, drawers, inspector sections, app-bar actions, and status indicators now exist in reusable components. |
| `P2.8` | Completed | Table-context restore, persistence, normalization, and URI building now flow through one shared state service used by `Tables` and diagnostics. |
### Goal
Build the shared interaction infrastructure needed by multiple destinations before page-specific UI work deepens.
### Tasks
- `P2.1` Implement the frontend route structure:
- keep `/`
- keep `/tables`
- add `/curation`
- add `/tools`
- move diagnostics and API docs under `/tools/...`
- `P2.2` Add compatibility redirects or navigation helpers for old `/diagnostics` and `/api` links.
- `P2.3` Implement a shared recent-items model for critical tables.
- `P2.4` Implement pinned tables state and persistence.
- `P2.5` Implement deep-link parsing and URL serialization for table context:
- table slug
- group key
- column key
- roll band or roll jump
- selected cell result id
- mode
- `P2.6` Build an omnibox foundation that can support:
- table search
- recent items
- pinned items
- slash commands
- `P2.7` Create shared primitives for:
- chips
- tabs
- app-bar actions
- drawers or sheets
- inspector sections
- status indicators
- `P2.8` Create a shared table-selection service or helper so `Tables`, `Curation`, and `Tools` do not each reinvent selection logic.
### Deliverables
- route updates
- local storage persistence helpers
- omnibox/search primitives
- shared state services/helpers
### Acceptance Criteria
- direct links into a selected table context can be opened and restored reliably
- recent and pinned tables are available to any page that needs them
- diagnostics and API docs remain reachable via new tools routes
- shared controls exist before page-specific implementations duplicate them
### Definition Of Done
- common navigation and state concerns are implemented once and consumed from shared code
## Phase 3: `Tables` Reference Experience
### Status
`In progress`
### Task Progress
| Task | Status | Notes |
| --- | --- | --- |
| `P3.1` | Completed | `Tables.razor` now acts as the stateful host while selector/header/canvas/legend rendering lives in dedicated `Components/Tables` components. |
| `P3.2` | Completed | The old dropdown picker is gone; `/tables` now uses a permanent left rail and a real page header while keeping the current selection flow intact. |
| `P3.3` | Completed | The rail now supports search-as-you-type, family filters, pinned and recent sections, curated status chips, and a deduplicated arrow/Enter keyboard path. |
| `P3.4` | Completed | The table surface now has a sticky context bar with mode tabs, variant/severity focus, roll-jump state, and active filter chips wired into host-page view state. |
| `P3.5` | Completed | The canvas now supports sticky headers and roll bands, row and column emphasis from selection and roll-jump state, selected-cell treatment, and a comfortable/dense density toggle. |
| `P3.6` | Completed | Resting cells now show only status hints; compact edit/curation buttons appear only for the selected cell. |
| `P3.7` | Completed | Desktop now has a dedicated inspector column driven by the shared selected-cell state instead of forcing result reading back into the grid alone. |
| `P3.8` | Completed | Mobile now uses a bottom-sheet inspector that reuses the same selected-cell content as the desktop inspector column. |
| `P3.9` | Completed | Legend/help is now on-demand and controlled from the context bar instead of always rendering below the canvas. |
| `P3.10` | Completed | Default `Reference` mode now uses quieter status indicators and calmer guidance copy so the page reads less like a maintenance surface. |
| `P3.11` | Completed | Full editor and curation entry points now live in the shared inspector content instead of the grid itself. |
| `P3.12` | Pending | Normalize click/tap/keyboard selection and close the phase with a hardening pass. |
### Goal
Turn `/tables` into the canonical reference surface for reading and inspecting critical tables quickly.
### Tasks
- `P3.1` Split the current `Tables.razor` into smaller components:
- page header
- table index rail
- sticky context bar
- table canvas
- inspector
- filter and mode controls
- `P3.2` Replace the current dropdown table picker with a searchable left rail.
- `P3.3` Add table index behavior:
- search-as-you-type
- keyboard arrow navigation
- enter to open
- pinned group
- recent group
- all tables list
- status chip showing curated percentage
- optional family filters
- `P3.4` Build the sticky context bar with:
- current table title
- variant selector when applicable
- roll jump input
- optional severity focus
- mode tabs
- filter chips
- `P3.5` Rework the table canvas for reference reading:
- sticky top headers
- sticky left roll-band column
- active row emphasis
- active column emphasis
- selected cell focus treatment
- optional roll-jump marker
- density toggle
- `P3.6` Remove resting-state button clutter from cells.
- `P3.7` Move cell actions to a selection-driven inspector and optional compact selected-cell affordances.
- `P3.8` Build the right inspector on desktop and bottom-sheet inspector on mobile.
- `P3.9` Rework legend/help so it is on-demand and secondary to the canvas.
- `P3.10` Hide maintenance and developer noise in default `Reference` mode.
- `P3.11` Preserve the current full editor and curation entry points, but expose them from the inspector instead of per-cell button stacks.
- `P3.12` Ensure one-tap or one-click selection works the same on desktop and touch.
### Deliverables
- new `Tables` page composition
- left rail selector
- sticky context bar
- selection-driven inspector
- deep-link-aware table state
### Acceptance Criteria
- a user can open a table in one search action from the index rail or omnibox
- a user can jump to a roll using a dedicated roll field
- the selected row, column, and cell are visually obvious
- a result can be read without opening a modal
- no action in `Tables` depends on hover-only discovery
- non-selected cells remain visually quiet
- mobile keeps the same task model using sheets instead of a persistent inspector
### Definition Of Done
- `/tables` is browse-first, not edit-first
- the grid is visually dominant and the inspector is secondary
- resting cells contain state hints, not visible action stacks
## Phase 4: `Curation` Workflow Surface
### Goal
Create a dedicated queue-first curation workflow so repair work is fast and does not pollute the reference experience.
### Tasks
- `P4.1` Create the new `/curation` page and route.
- `P4.2` Reuse shared table/context selection patterns from Phase 2 and Phase 3.
- `P4.3` Define queue scopes:
- all tables
- selected table
- pinned set
- `P4.4` Build a stable queue-first layout with:
- current queue item summary
- source image
- parsed preview
- quick parse area
- save-and-advance actions
- `P4.5` Move the current “next uncurated” logic into the dedicated workflow surface.
- `P4.6` Keep full editor access available, but make quick parse and mark curated the fast path.
- `P4.7` Ensure save-and-advance keeps the user in the same workflow lane without reopening context.
- `P4.8` Use warning styling only for disruptive repair actions, not for normal save flow.
- `P4.9` Hide developer-only diagnostics from the normal curation workflow.
### Deliverables
- `/curation` page
- queue-first layout
- integrated save-and-advance flow
- quick parse in-context workflow
### Acceptance Criteria
- a curator can move from one uncurated cell to the next with one primary action after save
- source and parsed result are visible side by side on wide screens
- quick parse can be completed without opening the full editor for common cases
- `Tables` no longer carries the primary queue-work burden
### Definition Of Done
- curation is a dedicated workflow page with a stable repeated interaction loop
## Phase 5: `Tools` Consolidation
### Goal
Separate diagnostic and developer tooling from player-facing flows without losing deep-link usefulness.
### Tasks
- `P5.1` Create a `Tools` landing page.
- `P5.2` Move diagnostics to `/tools/diagnostics`.
- `P5.3` Move API documentation to `/tools/api`.
- `P5.4` Reuse shared selection and table-context patterns so tooling feels related but distinct.
- `P5.5` Add cross-links back to `Tables` and `Curation` preserving object context where possible.
- `P5.6` Keep raw JSON, parser provenance, and deep inspection limited to tooling surfaces.
- `P5.7` Style tooling surfaces with the shared system but with the subdued “cool slate” tooling emphasis defined by the UX bible.
### Deliverables
- `Tools` hub
- migrated diagnostics page
- migrated API docs page
- context-preserving navigation back into reference and curation views
### Acceptance Criteria
- diagnostics and API docs remain bookmarkable
- player-facing pages no longer expose raw payload inspection
- a developer can inspect a cell in tools and jump back to its reference or curation context
### Definition Of Done
- developer-facing tools are clearly separated in both navigation and presentation
## Phase 6: `Play` Alignment
### Goal
Make the default landing experience feel like part of the same product and connect it to the new reference surfaces.
### Tasks
- `P6.1` Reframe the current home page as `Play`.
- `P6.2` Apply the new shell, typography, spacing, token, and action hierarchy to lookup forms and results.
- `P6.3` Reorganize the page to prioritize fast resolution over dashboard-like symmetry.
- `P6.4` Add deep links from lookup outcomes into `Tables` where the user wants to inspect the underlying critical result.
- `P6.5` Ensure player-facing copy avoids maintenance terminology.
- `P6.6` Preserve current lookup behavior and contracts while improving layout, clarity, and action priority.
### Deliverables
- updated `/` page within the new shell
- unified visual and interaction system
- result-to-table deep-link paths
### Acceptance Criteria
- a lookup result can lead directly into the relevant table context
- `Play` shares the same design language as `Tables` and `Curation`
- the primary action on the page is always obvious
### Definition Of Done
- `Play` and `Tables` feel connected, not like separate demos
## Phase 7: Hardening, Accessibility, Performance, And Rollout Cleanup
### Goal
Stabilize the overhaul and ensure the final UX matches the bible under real usage conditions.
### Tasks
- `P7.1` Review keyboard reachability for all app-bar actions, chips, tabs, table index items, table cells, inspector actions, and drawers.
- `P7.2` Verify visible focus states across light and dark themes.
- `P7.3` Verify contrast and accent-vs-semantic color distinction in both themes.
- `P7.4` Test sticky headers, sticky context bars, inspectors, and sheets across target breakpoints.
- `P7.5` Verify no page content is obscured by fixed or sticky shell elements.
- `P7.6` Verify deep links round-trip correctly across `Play`, `Tables`, `Curation`, and `Tools`.
- `P7.7` Verify last-used context persistence per destination.
- `P7.8` Measure table-switch and inspector-open performance and optimize obvious hotspots.
- `P7.9` Introduce virtualization only if profiling shows it is required and sticky behavior remains intact.
- `P7.10` Remove obsolete CSS and component paths left behind by the old shell or old `/tables` flow.
- `P7.11` Update documentation to reflect the final route map and shell model.
### Deliverables
- accessibility review pass
- responsive review pass
- performance review pass
- cleaned-up documentation and obsolete styles/components removed
### Acceptance Criteria
- keyboard-only usage is viable for the major reference and curation flows
- the app has no hover-only critical actions
- mobile hit targets are at least 44x44 px on primary controls
- there is no horizontal page overflow except intentional table-canvas panning
- table switching feels fast after initial load
### Definition Of Done
- the overhaul is stable, accessible, responsive, and cleaned up for future extension
## Cross-Cutting Technical Tasks
These tasks should be scheduled alongside the phases above rather than saved for the end.
### Component Architecture
- extract new classes and services into their own files
- keep page components thin and move reusable logic into helpers/services
- favor shared components over repeated markup in page files
### State Management
- centralize local storage keys
- avoid duplicating route parsing logic across pages
- keep selection state deterministic and serializable
### Visual Consistency
- use shared button hierarchy and chip patterns
- reserve warning and danger styles for true risk states
- ensure tools, curation, and reference surfaces differ through emphasis, not through unrelated styling systems
### Accessibility
- use semantic headings in order
- use true button and link elements for interactions
- only use grid semantics if keyboard behavior matches the semantics
### Documentation
- update related docs when route names, page responsibilities, or user flows materially change
## Proposed Task Sequencing Within The Repo
This is the recommended execution order at file and module level.
1. create shared theme, shell, and app-bar primitives
2. update root app layout and route structure
3. add shared state helpers for theme, recents, pins, and deep links
4. migrate diagnostics and API routes into the `Tools` shape with compatibility handling
5. split `Tables.razor` into focused components and land the new reference mode
6. add the dedicated `Curation` page reusing shared selectors and editor flows
7. align `Home.razor` into `Play`
8. remove obsolete shell and `/tables` implementation fragments
9. complete accessibility, responsive, and performance hardening
## Milestone-Based Acceptance Summary
### Milestone A
Foundation is accepted when the new shell, theme system, and route structure are in place without breaking basic navigation.
### Milestone B
`Tables` is accepted when a gamemaster can locate a table, jump to a result, and read it without modal friction or cell-level chrome clutter.
### Milestone C
`Curation` is accepted when a curator can save and advance through a stable queue flow without using `Tables` as the primary repair surface.
### Milestone D
`Tools` is accepted when diagnostics and API documentation are grouped under tooling routes and do not pollute player-facing flows.
### Milestone E
The overhaul is fully accepted when `Play`, `Tables`, `Curation`, and `Tools` all share the same shell, theme, navigation grammar, and deep-link model.
## Non-Goals For This Plan
- changing the backend data model
- redesigning API contracts
- adding speculative admin surfaces not described in the UX bible
- introducing a new frontend framework
- forcing virtualization before actual profiling justifies it
## Recommended First Implementation Slice
Start with a narrow but high-leverage slice:
1. semantic tokens and theme persistence
2. top app bar and mobile bottom nav
3. route restructuring for `Tools`
4. shared state helpers for recents, pins, and deep links
5. extraction of `/tables` shell pieces without yet rewriting every detail of the canvas
This sequence reduces risk because it establishes the shared infrastructure before the most complex page rewrite.