67 lines
4.8 KiB
Markdown
67 lines
4.8 KiB
Markdown
# 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.
|