Files
initiative/specs/010-ui-baseline/tasks.md

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 tailwindcss and @tailwindcss/vite as devDependencies and add the Tailwind Vite plugin to apps/web/vite.config.ts
  • T002 [P] Create apps/web/src/index.css with @import "tailwindcss" directive and @theme block defining CSS custom properties for the design system (colors, radii, fonts)
  • T003 [P] Install clsx and tailwind-merge as dependencies in apps/web and create the cn() utility in apps/web/src/lib/utils.ts
  • T004 Import ./index.css in apps/web/src/main.tsx
  • T005 [P] Install lucide-react as a dependency in apps/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-authority as a dependency in apps/web and create Button component in apps/web/src/components/ui/button.tsx following shadcn/ui pattern (variant props: default, outline, ghost, icon; size props: default, sm, icon) using cn() and class-variance-authority
  • T007 [P] Create Input component in apps/web/src/components/ui/input.tsx following shadcn/ui pattern (styled text/number input replacing browser defaults) using cn()

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 CombatantRow component to apps/web/src/components/combatant-row.tsx — accepts combatant, 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) when isActive is true. Move EditableName, MaxHpInput, and CurrentHpInput inline components into this file.
  • T010 [US1] Refactor apps/web/src/App.tsx to use CombatantRow — 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). Keep useEncounter hook 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 ActionBar component to apps/web/src/components/action-bar.tsx — accepts onAddCombatant and onAdvanceTurn callbacks. 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.tsx to use ActionBar component — 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 in apps/web/src/components/combatant-row.tsx to use the shadcn/ui-style Input component from components/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> in apps/web/src/components/combatant-row.tsx with a Button (ghost/icon variant) wrapping a Lucide X or Trash2 icon. Add title attribute 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.css theme defines a consistent type scale (heading, body, label sizes) and spacing tokens. Update apps/web/src/components/combatant-row.tsx, apps/web/src/components/action-bar.tsx, and apps/web/src/App.tsx to 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 — when encounter.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: ellipsis on the name column in apps/web/src/components/combatant-row.tsx and 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)

  1. Complete Phase 1: Setup (Tailwind + utilities)
  2. Complete Phase 2: Foundational (Button, Input primitives)
  3. Complete Phase 3: US1+US2 (structured layout + active highlight)
  4. STOP and VALIDATE: Combatants display in aligned columns, active turn highlighted
  5. This alone delivers the core visual upgrade

Incremental Delivery

  1. Setup + Foundational -> Build pipeline ready
  2. US1+US2 -> Structured layout with active highlight (MVP!)
  3. US3 -> Grouped action bar
  4. US4 -> Styled inline editing
  5. US5 -> Icon remove button
  6. US6 -> Typography/spacing audit
  7. Polish -> Edge cases, quality gate
  8. 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 format after each phase to keep Biome happy