Implement the 019-combatant-row-declutter feature that replaces always-visible HP controls and AC/MaxHP inputs with compact click-to-edit and click-to-adjust patterns in the encounter tracker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-06 15:07:04 +01:00
parent e59fd83292
commit 0c0da9b90e
11 changed files with 723 additions and 207 deletions

View File

@@ -0,0 +1,154 @@
# Tasks: Combatant Row Declutter
**Input**: Design documents from `/specs/019-combatant-row-declutter/`
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, quickstart.md
**Tests**: Not explicitly requested in the feature specification. Test tasks are omitted.
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
## 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)
- Include exact file paths in descriptions
---
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: No new project setup needed — this feature modifies existing components only. Phase skipped.
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: No foundational/blocking work required. Both user stories modify independent components within the same file and can proceed directly.
---
## Phase 3: User Story 1 - HP Click-to-Adjust Popover (Priority: P1) MVP
**Goal**: Replace the always-visible QuickHpInput (delta input + Sword/Heart buttons) with a clickable current HP display that opens a popover for damage/healing.
**Independent Test**: Click a combatant's current HP number, enter a value, press Enter (damage) or Shift+Enter (heal), verify HP updates and popover dismisses. Verify bloodied/unconscious color coding on the static HP display.
### Implementation for User Story 1
- [x] T001 [US1] Create HpAdjustPopover component in `apps/web/src/components/hp-adjust-popover.tsx` — popover with auto-focused numeric input, Damage button (red/Sword icon), and Heal button (green/Heart icon). Input accepts positive integers only. Enter applies damage (negative delta), Shift+Enter applies healing (positive delta). Popover dismisses on action, Escape, or click-outside (use ref-based click-outside listener per research.md R1).
- [x] T002 [US1] Replace CurrentHpInput in `apps/web/src/components/combatant-row.tsx` with a clickable static HP display — render current HP as a `<button>` element with color-coded text (amber for bloodied, red for unconscious via `deriveHpStatus`). On click, open the HpAdjustPopover. Wire popover's onAdjustHp to existing `onAdjustHp` callback with unchanged signature.
- [x] T003 [US1] Remove QuickHpInput usage from `apps/web/src/components/combatant-row.tsx` — delete the `<QuickHpInput>` render and its import. The HP section should now show: clickable current HP / max HP input (always-visible).
- [x] T004 [US1] Delete `apps/web/src/components/quick-hp-input.tsx` — component is fully replaced by HpAdjustPopover.
- [x] T005 [US1] Run `pnpm check` to verify no lint, type, format, test, or unused-code errors after HP popover changes.
**Checkpoint**: HP adjustment works via click-to-adjust popover. No always-visible delta input or Sword/Heart buttons. Color-coded HP status preserved.
---
## Phase 4: User Story 2 - AC Click-to-Edit (Priority: P2)
**Goal**: Replace the always-visible AC input field with a static display (shield icon + number) that becomes an inline edit on click.
**Independent Test**: View a combatant row and verify AC shows as shield+number text (not an input). Click it, edit the value, press Enter — verify AC updates. Press Escape — verify edit cancels. Clear and commit — verify AC unsets.
### Implementation for User Story 2
- [x] T006 [US2] Refactor AcInput in `apps/web/src/components/combatant-row.tsx` to a click-to-edit pattern — default state renders shield icon + AC number as a `<button>` (or just shield icon if AC is unset). On click, switch to an inline `<Input>` with the current value pre-filled and selected. Commit on Enter/blur, cancel on Escape. Follow the same state pattern as the existing `EditableName` component (editing boolean, draft state, commit/cancel callbacks).
- [x] T007 [US2] Run `pnpm check` to verify no lint, type, format, test, or unused-code errors after AC click-to-edit changes.
**Checkpoint**: AC displays as compact static text. Click-to-edit works with Enter/blur commit and Escape cancel.
---
## Phase 4b: User Story 3 - Max HP Click-to-Edit (Priority: P2)
**Goal**: Replace the always-visible Max HP input field with a static display that becomes an inline edit on click, consistent with the AC click-to-edit pattern.
**Independent Test**: View a combatant row and verify Max HP shows as static text (not an input). Click it, edit the value, press Enter — verify Max HP updates. Press Escape — verify edit cancels. Clear and commit — verify Max HP unsets.
### Implementation for User Story 3
- [x] T010 [US3] Refactor MaxHpInput in `apps/web/src/components/combatant-row.tsx` to a click-to-edit pattern — default state renders max HP number as a `<button>` (or placeholder text "Max" if unset). On click, switch to an inline `<Input>` with the current value pre-filled and selected. Commit on Enter/blur, cancel on Escape. Follow the same state pattern as `AcDisplay` and `EditableName`.
- [x] T011 [US3] Run `pnpm check` to verify no lint, type, format, test, or unused-code errors after Max HP click-to-edit changes.
**Checkpoint**: Max HP displays as compact static text. Click-to-edit works with Enter/blur commit and Escape cancel.
---
## Phase 5: Polish & Cross-Cutting Concerns
**Purpose**: Final cleanup and grid layout adjustment after both stories are complete.
- [x] T008 Adjust combatant row grid layout in `apps/web/src/components/combatant-row.tsx` — update the `grid-cols-[...]` template to account for reduced HP section width (no more QuickHpInput) and compact AC display. Verify alignment on desktop and tablet-width viewports. Verify keyboard accessibility: HP display and AC display must be focusable via Tab, operable via Enter, and dismissable via Escape (FR-010).
- [x] T009 Run final `pnpm check` to verify the complete feature passes all quality gates.
---
## Dependencies & Execution Order
### Phase Dependencies
- **User Story 1 (Phase 3)**: No prerequisites — can start immediately
- **User Story 2 (Phase 4)**: No dependency on US1 — can start in parallel
- **Polish (Phase 5)**: Depends on both US1 and US2 being complete
### User Story Dependencies
- **User Story 1 (P1)**: Independent — modifies HP section of combatant row
- **User Story 2 (P2)**: Independent — modifies AC section of combatant row
### Within Each User Story
- HpAdjustPopover component (T001) must be created before integrating into combatant row (T002)
- QuickHpInput removal (T003, T004) must follow popover integration (T002)
- AC refactor (T006) is a single self-contained change
### Parallel Opportunities
- US1 (T001-T005) and US2 (T006-T007) can run in parallel since they modify different sections of the combatant row
- Within US1: T001 (new component) can be written before T002-T004 (integration + cleanup)
---
## Parallel Example: User Stories 1 & 2
```bash
# These two stories can run in parallel (different component sections):
# Developer A: User Story 1 — HP popover
Task: T001 "Create HpAdjustPopover component"
Task: T002 "Replace CurrentHpInput with clickable display + popover"
Task: T003 "Remove QuickHpInput usage from combatant row"
Task: T004 "Delete quick-hp-input.tsx"
Task: T005 "Run pnpm check"
# Developer B: User Story 2 — AC click-to-edit
Task: T006 "Refactor AcInput to click-to-edit pattern"
Task: T007 "Run pnpm check"
```
---
## Implementation Strategy
### MVP First (User Story 1 Only)
1. Complete Phase 3: User Story 1 (HP popover) — T001 through T005
2. **STOP and VALIDATE**: Test HP popover independently
3. This alone delivers the biggest declutter win (removes 3 always-visible controls per row)
### Incremental Delivery
1. Add User Story 1 → Test independently → Commit (MVP!)
2. Add User Story 2 → Test independently → Commit
3. Polish phase → Final grid adjustments → Commit
4. Each story adds declutter value without breaking previous work
---
## Notes
- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- Domain and application layers are untouched — all changes in `apps/web/src/components/`
- Callback signatures (`onAdjustHp`, `onSetAc`) remain unchanged
- Commit after each completed user story