Files
initiative/specs/027-ui-polish/research.md

67 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Research: Combatant Row UI Polish
**Feature**: 027-ui-polish | **Date**: 2026-03-10
## R1: CSS Shield Shape for AC
**Decision**: Use an inline SVG background with the AC number centered inside, rendered as a dedicated `AcShield` component.
**Rationale**: CSS `clip-path` clips the element itself (including borders and backgrounds) but makes it hard to get a clean outlined shield. An inline SVG shield path with the number as a `<text>` or overlaid HTML gives full control over stroke, fill, and sizing. This matches how D&D Beyond and character sheet PDFs render AC.
**Alternatives considered**:
- `clip-path: polygon(...)` — clips the element shape but can't produce a stroke outline easily. Would need a pseudo-element hack.
- Background image SVG — works but harder to make the stroke color respond to CSS custom properties (theme-aware).
- Lucide Shield icon with number overlaid via absolute positioning — fragile alignment, icon stroke competes with the number visually.
**Approach**: Create a small SVG shield outline (viewBox-based) as a React component. The AC number is rendered as a centered `<span>` overlaid on the SVG using relative/absolute positioning. The SVG uses `currentColor` for the stroke so it inherits theme colors. Size: approximately 28×32px to comfortably fit 1-3 digit numbers.
## R2: Row Click Stat Block — Event Delegation
**Decision**: Attach `onClick` handler to the row container, use `event.stopPropagation()` on all interactive child elements to prevent bubbling.
**Rationale**: This is the standard pattern for "click anywhere except interactive elements." Each interactive element (initiative, HP, AC, conditions, "+", "×", concentration) already has its own click handler — adding `stopPropagation()` to each ensures the row-level handler only fires for non-interactive areas.
**Alternatives considered**:
- Checking `event.target` against a list of interactive selectors — fragile and hard to maintain.
- Wrapping non-interactive areas in a separate clickable element — would complicate the grid layout.
## R3: Hover-Only Elements — Touch Device Accessibility
**Decision**: Use CSS `opacity-0 group-hover:opacity-100` for hide/show, combined with `focus-within:opacity-100` for keyboard accessibility. On touch devices, the elements are accessible via tap (the first tap reveals, second tap activates — standard mobile pattern with opacity transitions).
**Rationale**: The concentration button already uses this exact pattern (`opacity-0 group-hover:opacity-50`). Extending it to the remove button and "+" condition button is consistent.
**Alternatives considered**:
- `display: none` / `display: block` — causes layout shifts (violates FR-004).
- `visibility: hidden` / `visible` — works but doesn't allow opacity transitions.
## R4: Inline Conditions Layout
**Decision**: Move `ConditionTags` and the "+" button into the name column's flex container (the `1fr` column), after the name text. The conditions and "+" sit inline with the name, wrapping if needed.
**Rationale**: The name column is already a flex container (`flex items-center gap-1`). Adding condition icons here is natural. The `truncate` class on the name will need adjustment — the name should shrink (`min-w-0 truncate` on just the name text) while conditions fill remaining space.
**Alternatives considered**:
- Dedicated column for conditions — adds complexity to the grid and uses horizontal space poorly.
- Conditions as a second flex row within the name cell — still uses `flex-wrap` but explicitly creates a two-row layout when many conditions exist.
## R5: D20 Icon Sizing
**Decision**: Increase from `h-5 w-5` (20px) to `h-7 w-7` (28px). The initiative column is 3rem (48px) wide, so 28px fits comfortably with padding.
**Rationale**: At 20px the internal geometry lines of the d20 are too dense to read as a die shape. At 28px the icosahedron silhouette becomes recognizable. The column has room — the d20 button is already `h-7 w-full` so only the icon within needs to grow.
**Alternatives considered**:
- `h-6 w-6` (24px) — marginal improvement, still a bit small.
- `h-8 w-8` (32px) — might feel oversized relative to the initiative numbers in adjacent rows.
## R6: Concentration Click Target
**Decision**: Expand the concentration button from `1.25rem` width to fill the full gutter. Change the grid column from `1.25rem` to `2rem` (or use padding on the button to extend its hit area to the row edge). The brain icon stays centered visually.
**Rationale**: The left border of the row already has `px-3` padding. The concentration column at `1.25rem` (20px) with a 16px icon leaves very little extra hit area. Widening the column or extending the button's padding makes tapping much easier.
**Alternatives considered**:
- Negative margin on the button — hacky, could affect layout.
- Separate invisible overlay — unnecessary complexity.