7.0 KiB
Implementation Plan: Combatant Row UI Polish
Branch: 027-ui-polish | Date: 2026-03-10 | Spec: spec.md
Input: Feature specification from /specs/027-ui-polish/spec.md
Summary
Six presentational improvements to the combatant row: move conditions inline after the creature name, make the row clickable for stat blocks (removing the BookOpen icon), hide the remove button until hover, display AC inside a shield shape, expand the concentration click target, and increase the d20 icon size. All changes are confined to the web adapter layer — no domain or application changes needed.
Technical Context
Language/Version: TypeScript 5.8 (strict mode, verbatimModuleSyntax)
Primary Dependencies: React 19, Tailwind CSS v4, Lucide React (icons), Vite 6
Storage: N/A (no storage changes — purely presentational)
Testing: Vitest (existing domain tests must continue passing; no new component tests)
Target Platform: Modern browsers (desktop primary, touch secondary)
Project Type: Web application (single-page, local-first)
Performance Goals: No perceptible layout shift on hover; smooth opacity transitions
Constraints: Must not break any existing interactions; all changes in apps/web/ only
Scale/Scope: ~1 main component file restructured, 1 new small component
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Notes |
|---|---|---|
| I. Deterministic Domain Core | PASS | No domain changes whatsoever |
| II. Layered Architecture | PASS | All changes in adapter layer (apps/web). No domain or application imports added. |
| III. Agent Boundary | N/A | No agent features involved |
| IV. Clarification-First | PASS | All six changes were discussed and confirmed with user before speccing |
| V. Escalation Gates | PASS | All changes are within spec scope |
| VI. MVP Baseline Language | PASS | No permanent bans introduced |
| VII. No Gameplay Rules | PASS | No gameplay mechanics in this feature |
Post-Phase 1 Re-check: All gates still pass. No domain or application layer changes introduced during design.
Project Structure
Documentation (this feature)
specs/027-ui-polish/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── checklists/
│ └── requirements.md # Spec quality checklist
└── tasks.md # Phase 2 output (via /speckit.tasks)
Source Code (repository root)
apps/web/src/components/
├── combatant-row.tsx # MODIFY — layout restructure, event handling, hover states
├── condition-tags.tsx # UNCHANGED — reused inline
├── condition-picker.tsx # MINOR MODIFY — positioning may need adjustment for inline context
├── d20-icon.tsx # UNCHANGED — sized via className prop
└── ac-shield.tsx # NEW — shield-shaped AC display component
Structure Decision: No new directories or architectural changes. One new presentational component (ac-shield.tsx). All modifications within existing apps/web/src/components/ directory.
Design Decisions
D1: Inline Conditions Layout
The name column (1fr) already uses flex items-center gap-1. Conditions move into this flex container after the name text. The name text gets min-w-0 truncate to shrink when conditions need space. The ConditionTags component is reused as-is. The "+" button uses opacity-0 group-hover:opacity-100 to appear only on hover.
The separate conditions row below the grid (with ml-[calc(3rem+0.75rem)]) is removed entirely.
D2: Row Click Stat Block via Event Delegation
The row container gets an onClick handler that calls onShowStatBlock (for bestiary combatants). All interactive child elements add event.stopPropagation() to their existing click handlers so clicks on initiative, HP, AC, conditions, "+", "×", and concentration don't bubble up to the row handler.
Bestiary rows get cursor-pointer on the row container. Custom combatant rows (no creatureId) don't get the handler or cursor.
The BookOpen icon button is deleted from the name area.
D3: Hover-Only Remove Button
The remove button gets opacity-0 group-hover:opacity-100 focus:opacity-100 classes. The button remains in the DOM (preserving the 2rem grid column) so no layout shift occurs. This matches the existing pattern used by the concentration button.
D4: AC Shield Shape Component
New AcShield component renders:
- An inline SVG shield outline (stroke-based,
currentColor) as background - The AC number centered inside via absolute positioning
- Click handler passed through for editing
- Sized approximately 28×32px to fit 1-3 digit values
Replaces the current Shield Lucide icon + number in AcDisplay. The edit mode input still appears on click, positioned over/replacing the shield.
D5: Concentration Click Target
Widen the first grid column from 1.25rem to 2rem and make the concentration button fill the full column with padding. The brain icon stays visually centered. The button's click area now spans from the row's left edge (after border) to the initiative column.
Grid changes from:
grid-cols-[1.25rem_3rem_1fr_auto_auto_2rem]
to:
grid-cols-[2rem_3rem_1fr_auto_auto_2rem]
D6: D20 Icon Size
Change className="h-5 w-5" to className="h-7 w-7" on the D20Icon in InitiativeDisplay. The icon grows from 20px to 28px. The initiative column (3rem = 48px) and the button (h-7 w-full) accommodate this without overflow.
D7: Dark Scrollbar Styling
Apply scrollbar-color: var(--color-border) transparent and scrollbar-width: thin on * in index.css. This gives all scrollbars (main page, stat block panel) a slim dark thumb (#334155) on a transparent track, matching the dark UI. Supported in Chrome 121+, Firefox 64+, Safari 18+.
D8: Top Bar Icon Redesign
Replace the Previous/Next text+chevron buttons with icon-only StepBack/StepForward buttons using the outline variant with border-foreground (white border matching the icon color). Utility actions (d20, trash) use ghost variant with text-muted-foreground — creating a two-tier visual hierarchy: primary navigation (outlined, white) vs secondary utilities (borderless, grey).
Layout: [StepBack] — center info — [d20][trash] [StepForward]. The d20 and trash are tightly grouped (gap-0) with gap-3 separating them from the Next button. Icon sizes: d20 h-6 w-6, trash h-5 w-5, step buttons h-5 w-5. All buttons h-8 w-8.
D9: Remove "Initiative Tracker" Heading
Remove the <header> block containing the <h1>Initiative Tracker</h1> from apps/web/src/App.tsx. The turn navigation bar already provides context (round number, active combatant name), making the heading redundant. Removing it reclaims ~60px of vertical space for the combatant list.
Complexity Tracking
No constitution violations to justify. All changes are straightforward adapter-layer modifications.