Files
initiative/specs/020-fix-zero-hp-opacity/tasks.md

102 lines
5.5 KiB
Markdown

# Tasks: Fix Zero-HP Opacity
**Input**: Design documents from `/specs/020-fix-zero-hp-opacity/`
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, quickstart.md
**Tests**: No test tasks included (not explicitly requested in spec). Existing tests must continue to pass via `pnpm check`.
**Organization**: Tasks are grouped by user story. US1 and US2 share the same root cause fix, so they are addressed together in Phase 2 (Foundational). US3 is verified as part of the same change.
## 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
**Purpose**: No setup required. This is a single-file bug fix in an existing codebase with all tooling already configured.
(No tasks — skip to Phase 2)
---
## Phase 2: Foundational (Core Fix)
**Purpose**: Remove the container-level `opacity-50` that cascades to popover/dropdown children and replace it with element-level dimming that preserves the unconscious visual indicator without affecting overlays.
- [x] T001 Remove `opacity-50` from the outer row container `<div>` (the `status === "unconscious" && "opacity-50"` expression on line 312) in `apps/web/src/components/combatant-row.tsx`
- [x] T002 Apply `opacity-50` to the inner grid `<div>` (line 316) when `status === "unconscious"` and restructure the JSX so that `HpAdjustPopover` (currently rendered inside `ClickableHp` within the grid) is moved to render as a sibling outside the grid container, not a child of it, in `apps/web/src/components/combatant-row.tsx`
- [x] T003 Apply `opacity-50` to the conditions container `<div>` (line 388) when `status === "unconscious"` and restructure the JSX so that `ConditionPicker` is rendered as a sibling outside the dimmed conditions wrapper, not a child of it, in `apps/web/src/components/combatant-row.tsx`
- [x] T004 Verify that the `HpAdjustPopover` component renders at full opacity (no inherited dimming) when opened on a 0-HP combatant, by running `pnpm --filter web dev` and manually testing
- [x] T005 Verify that the `ConditionPicker` component renders at full opacity (no inherited dimming) when opened on a 0-HP combatant, by running `pnpm --filter web dev` and manually testing
- [x] T005a Verify edge case transitions: (a) heal a 0-HP combatant while the HP popout is open — row should transition to normal styling, popout stays functional; (b) reduce a combatant to 0 HP while the HP popout is open — row should transition to dimmed styling, popout stays at full opacity. Manual test via `pnpm --filter web dev`.
**Checkpoint**: At this point, both US1 (HP popover) and US2 (condition picker) should render at full opacity for 0-HP combatants.
---
## Phase 3: User Story 3 - Row Visual Distinction (Priority: P2)
**Goal**: Unconscious combatants remain visually distinguishable from conscious combatants.
**Independent Test**: View encounter list with a mix of conscious and unconscious combatants; unconscious rows should look dimmed while their popouts are full opacity.
### Implementation for User Story 3
- [x] T006 [US3] Verify that unconscious combatant rows still appear visually dimmed (via the element-level `opacity-50` applied in T002/T003) compared to healthy combatants in `apps/web/src/components/combatant-row.tsx`
**Checkpoint**: All user stories verified — unconscious rows are dimmed, but popouts/dropdowns render at full opacity.
---
## Phase 4: Polish & Cross-Cutting Concerns
- [x] T007 Run `pnpm check` to verify all quality gates pass (knip, format, lint, typecheck, test)
- [x] T008 Run quickstart.md validation steps to confirm end-to-end fix
---
## Dependencies & Execution Order
### Phase Dependencies
- **Phase 2 (Foundational)**: No dependencies — start immediately. T001 must complete before T002/T003. T002 and T003 can run in parallel. T004/T005 are manual verification after T002/T003.
- **Phase 3 (US3)**: Depends on Phase 2 completion (visual distinction is a side effect of the fix approach).
- **Phase 4 (Polish)**: Depends on Phase 2 and Phase 3 completion.
### User Story Dependencies
- **US1 (HP popover)**: Addressed by T001 + T002. No dependency on other stories.
- **US2 (Condition picker)**: Addressed by T001 + T003. No dependency on other stories.
- **US3 (Visual distinction)**: Verified by T006. Depends on T002/T003 being correctly implemented.
### Parallel Opportunities
- T002 and T003 can be done in parallel (different sections of the same file, but non-overlapping regions)
- T004 and T005 can be verified in parallel
---
## Implementation Strategy
### MVP First (All Stories in One Pass)
1. Complete T001 (remove container opacity) — this is the root cause fix
2. Complete T002 + T003 (apply element-level dimming) — preserves visual distinction
3. Verify T004 + T005 + T006 (manual testing)
4. Run T007 (quality gate) + T008 (quickstart validation)
5. **Done** — single commit, single file change
This is a small, surgical bug fix. All three user stories are addressed by the same structural change in `combatant-row.tsx`. The entire fix can be completed in a single pass.
---
## Notes
- Single file change: `apps/web/src/components/combatant-row.tsx`
- No domain or application layer changes
- No new dependencies
- No new files
- The key insight: CSS `opacity` on a parent creates a stacking context that dims all children. The fix must ensure popovers are never DOM descendants of a dimmed element.