Implement stat block panel fold/unfold and pin-to-second-panel

Replace the close button and heading with fold/unfold controls that
collapse the panel to a slim right-edge tab showing the creature name
vertically, and add a pin button (xl+ viewports with creature loaded)
that opens the creature in a second left-side panel for simultaneous
reference. Fold state is respected on turn change. 19 acceptance tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-11 14:18:15 +01:00
parent 95cb2edc23
commit 460c65bf49
12 changed files with 1165 additions and 57 deletions

View File

@@ -0,0 +1,62 @@
# Data Model: Stat Block Panel Fold/Unfold and Pin
**Feature**: 035-statblock-fold-pin
**Date**: 2026-03-11
## Entities
### Panel State
This feature introduces UI-only ephemeral state — no persistence changes, no domain model changes.
| Field | Type | Description |
|-------|------|-------------|
| `selectedCreatureId` | `CreatureId \| null` | Currently browsed creature (right panel). **Exists already.** |
| `pinnedCreatureId` | `CreatureId \| null` | Creature locked to left panel. **New.** |
| `isRightPanelFolded` | `boolean` | Whether the right (browse) panel is collapsed to a tab. **New.** |
### State Transitions
```
No panel → Open panel
Trigger: Click combatant row / auto-show on turn change
Effect: selectedCreatureId = creatureId, isRightPanelFolded = false
Open panel → Folded tab
Trigger: Click fold button
Effect: isRightPanelFolded = true (selectedCreatureId preserved)
Folded tab → Open panel
Trigger: Click folded tab
Effect: isRightPanelFolded = false
Open panel → Open panel + Pinned panel
Trigger: Click pin button (xl+ viewport only)
Effect: pinnedCreatureId = selectedCreatureId
Pinned panel → No pinned panel
Trigger: Click unpin button
Effect: pinnedCreatureId = null
Open panel (mobile) → Dismissed
Trigger: Click backdrop
Effect: selectedCreatureId = null
```
### Viewport Breakpoints
| Breakpoint | Panels Available | Pin Button |
|------------|-----------------|------------|
| < 1024px (mobile) | Mobile drawer only | Hidden |
| 1024px1279px (lg) | Right panel only | Hidden |
| >= 1280px (xl) | Right + optional left pinned | Visible |
## Existing Entities (Unchanged)
- **Creature** (`CreatureId`, `name`, stats…) — read-only, no changes
- **Encounter state** — no changes
- **Bestiary cache** — no changes
## Persistence
No persistence changes. All new state (pinnedCreatureId, isRightPanelFolded) is ephemeral React component state that resets on page reload. This aligns with the existing pattern where selectedCreatureId is also ephemeral.