11 KiB
Tasks: UI Baseline
Input: Design documents from /specs/010-ui-baseline/
Prerequisites: plan.md (required), spec.md (required), research.md, data-model.md, contracts/ui-components.md
Tests: No new tests requested in spec. Existing tests (layer boundary checks) must continue to pass.
Organization: Tasks grouped by user story. US1+US2 are combined (both P1, same component).
Format: [ID] [P?] [Story] Description
- [P]: Can run in parallel (different files, no dependencies)
- [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
Phase 1: Setup (Shared Infrastructure)
Purpose: Install Tailwind CSS v4, shadcn/ui utilities, and configure the build pipeline
- T001 Install
tailwindcssand@tailwindcss/viteas devDependencies and add the Tailwind Vite plugin toapps/web/vite.config.ts - T002 [P] Create
apps/web/src/index.csswith@import "tailwindcss"directive and@themeblock defining CSS custom properties for the design system (colors, radii, fonts) - T003 [P] Install
clsxandtailwind-mergeas dependencies inapps/weband create thecn()utility inapps/web/src/lib/utils.ts - T004 Import
./index.cssinapps/web/src/main.tsx - T005 [P] Install
lucide-reactas a dependency inapps/web
Phase 2: Foundational (Blocking Prerequisites)
Purpose: Create shadcn/ui-style primitive components that all user stories depend on
Warning: No user story work can begin until this phase is complete
- T006 [P] Install
class-variance-authorityas a dependency inapps/weband create Button component inapps/web/src/components/ui/button.tsxfollowing shadcn/ui pattern (variant props: default, outline, ghost, icon; size props: default, sm, icon) usingcn()andclass-variance-authority - T007 [P] Create Input component in
apps/web/src/components/ui/input.tsxfollowing shadcn/ui pattern (styled text/number input replacing browser defaults) usingcn()
Note: T008 merged into T006 (install CVA + create Button in one task).
Checkpoint: Foundation ready — shadcn/ui primitives available, Tailwind active
Phase 3: User Story 1 + 2 — Structured Layout + Active Highlight (Priority: P1) MVP
Goal: Replace the unstyled <ul>/<li> combatant list with a structured row layout (initiative | name | HP | actions columns) and visually highlight the active combatant's row
Independent Test: Add 3+ combatants, verify columns are aligned. Set initiative and HP on some. Advance turns and confirm the active row has a distinct highlight that moves correctly.
Implementation
- T009 [US1] Extract
CombatantRowcomponent toapps/web/src/components/combatant-row.tsx— acceptscombatant,isActive, and action callbacks per the UI contract. Render a grid/flex row with four columns: initiative (number input), name (click-to-edit text), HP (current/max with +/- buttons), actions (remove button placeholder). Apply active row highlight (accent left border + subtle background) whenisActiveis true. MoveEditableName,MaxHpInput, andCurrentHpInputinline components into this file. - T010 [US1] Refactor
apps/web/src/App.tsxto useCombatantRow— replace the<ul>list with a styled container. Add encounter header section showing title ("Initiative Tracker") and round/turn status. Remove domain events display section entirely (FR-011). KeepuseEncounterhook usage and all callbacks wired through.
Checkpoint: Combatants display in aligned columns with active highlight. All existing functionality preserved.
Phase 4: User Story 3 — Grouped Action Bar (Priority: P2)
Goal: Group the "Add Combatant" form and "Next Turn" button into a visually distinct action bar separated from the combatant list
Independent Test: Verify controls are grouped in a distinct bar area with visual separation (background, border, or spacing) from the combatant list.
Implementation
- T011 [US3] Extract
ActionBarcomponent toapps/web/src/components/action-bar.tsx— acceptsonAddCombatantandonAdvanceTurncallbacks. Render a styled bar with the add-combatant form (Input + Button) and Next Turn button (outline/secondary variant). Apply visual separation from the combatant list. - T012 [US3] Update
apps/web/src/App.tsxto useActionBarcomponent — replace inline form and button with the extracted component.
Checkpoint: Action bar is visually grouped and separated from combatant list.
Phase 5: User Story 4 — Inline Editing with Consistent Styling (Priority: P2)
Goal: Ensure all inline edit states (name, initiative, HP inputs) use the design system Input component instead of unstyled browser defaults
Independent Test: Click a combatant name to edit — the input should match the design system style. Verify initiative and HP number inputs are also styled consistently.
Implementation
- T013 [US4] Update
EditableName,MaxHpInput,CurrentHpInput, and initiative input inapps/web/src/components/combatant-row.tsxto use the shadcn/ui-styleInputcomponent fromcomponents/ui/input.tsx. Ensure edit-mode inputs match display-mode styling for seamless transitions.
Checkpoint: All form inputs across the encounter screen use consistent design system styling.
Phase 6: User Story 5 — Remove Action as Icon Button (Priority: P3)
Goal: Replace the text "Remove" button with a compact icon button using a Lucide icon
Independent Test: Each combatant row shows a small icon button (X or Trash2) instead of a text "Remove" button. Hovering shows tooltip feedback.
Implementation
- T014 [US5] Replace the remove
<button>inapps/web/src/components/combatant-row.tsxwith aButton(ghost/icon variant) wrapping a LucideXorTrash2icon. Addtitleattribute for hover tooltip ("Remove combatant").
Checkpoint: Remove action is a compact icon button with hover feedback.
Phase 7: User Story 6 — Consistent Typography and Spacing (Priority: P2)
Goal: Apply a consistent type scale and spacing scale across the entire encounter screen
Independent Test: Inspect the screen — headings, body text, labels, and inputs use a consistent font family, size scale, and spacing rhythm with no arbitrary values.
Implementation
- T015 [US6] Review and refine typography and spacing across all components — ensure
apps/web/src/index.csstheme defines a consistent type scale (heading, body, label sizes) and spacing tokens. Updateapps/web/src/components/combatant-row.tsx,apps/web/src/components/action-bar.tsx, andapps/web/src/App.tsxto use consistent Tailwind spacing/typography utilities (no arbitrary pixel values).
Checkpoint: The entire encounter screen has cohesive typography and spacing.
Phase 8: Polish & Cross-Cutting Concerns
Purpose: Edge cases, cleanup, and quality gate validation
- T016 Add empty state message in
apps/web/src/App.tsx— whenencounter.combatants.length === 0, display a centered muted message ("No combatants yet — add one to get started") instead of an empty list area - T017 Add long name truncation with CSS
text-overflow: ellipsison the name column inapps/web/src/components/combatant-row.tsxand make the combatant list area scrollable when it overflows (sticky header + action bar) - T018 Run
pnpm check(knip + format + lint + typecheck + test) and fix all issues — ensure no unused imports from shadcn/ui, Biome formatting passes, TypeScript compiles, and layer boundary tests pass
Dependencies & Execution Order
Phase Dependencies
- Setup (Phase 1): No dependencies — start immediately
- Foundational (Phase 2): Depends on T001 (Tailwind installed) and T003 (cn() available)
- US1+US2 (Phase 3): Depends on Phase 2 (Button, Input primitives available)
- US3 (Phase 4): Depends on Phase 3 (App.tsx refactored with layout shell)
- US4 (Phase 5): Depends on Phase 3 (CombatantRow exists with inline edit components)
- US5 (Phase 6): Depends on Phase 3 (CombatantRow exists) + T005 (lucide-react installed)
- US6 (Phase 7): Depends on Phases 3-6 (all components exist to audit typography)
- Polish (Phase 8): Depends on all user stories complete
User Story Dependencies
- US1+US2 (P1): Can start after Phase 2 — no other story dependencies
- US3 (P2): Depends on US1+US2 (App.tsx layout shell must exist)
- US4 (P2): Depends on US1+US2 (CombatantRow must exist)
- US5 (P3): Depends on US1+US2 (CombatantRow must exist)
- US6 (P2): Depends on US3, US4, US5 (all components must exist to audit)
Within Each User Story
- Component extraction before integration with App.tsx
- Structural changes before styling refinements
Parallel Opportunities
- T002, T003, T005 can run in parallel (different files, no dependencies)
- T006, T007 can run in parallel (different files)
- US3 (T011-T012) and US4 (T013) and US5 (T014) can run in parallel after Phase 3 (different files)
Parallel Example: Phase 1 Setup
# These three tasks touch different files and can run simultaneously:
Task T002: "Create index.css with Tailwind directives in apps/web/src/index.css"
Task T003: "Create cn() utility in apps/web/src/lib/utils.ts"
Task T005: "Install lucide-react in apps/web"
Parallel Example: Phase 2 Foundational
# These tasks create independent component files:
Task T006: "Install CVA + create Button in apps/web/src/components/ui/button.tsx"
Task T007: "Create Input in apps/web/src/components/ui/input.tsx"
Implementation Strategy
MVP First (US1+US2 Only)
- Complete Phase 1: Setup (Tailwind + utilities)
- Complete Phase 2: Foundational (Button, Input primitives)
- Complete Phase 3: US1+US2 (structured layout + active highlight)
- STOP and VALIDATE: Combatants display in aligned columns, active turn highlighted
- This alone delivers the core visual upgrade
Incremental Delivery
- Setup + Foundational -> Build pipeline ready
- US1+US2 -> Structured layout with active highlight (MVP!)
- US3 -> Grouped action bar
- US4 -> Styled inline editing
- US5 -> Icon remove button
- US6 -> Typography/spacing audit
- Polish -> Edge cases, quality gate
- Each phase adds visual polish without breaking previous work
Notes
- All changes are in
apps/web/only — domain and application packages are untouched (FR-010) - Domain events display is removed in T010 (FR-011)
- No new test files created — existing Vitest layer boundary tests must pass (T018)
- shadcn/ui components are hand-written following the pattern (not CLI-generated) to ensure Biome/Knip compatibility
- Run
pnpm formatafter each phase to keep Biome happy