Improve bestiary icon UX and auto-update stat block on turn change

- Use Book/BookOpen icons to indicate stat block open state
- Bump combatant icons (bestiary + PC) from 14px to 16px
- Use text-foreground for bestiary icon visibility
- Auto-update stat block panel to active combatant's creature on turn advance
- Update bestiary spec edge case to reflect new behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-17 12:48:38 +01:00
parent 7b3dbe2069
commit 43780772f6
3 changed files with 19 additions and 5 deletions

View File

@@ -203,6 +203,15 @@ export function App() {
const playerCharacterRef = useRef<PlayerCharacterSectionHandle>(null);
const actionBarAnim = useActionBarAnimation(encounter.combatants.length);
// Auto-update stat block panel when the active combatant changes
const activeCreatureId =
encounter.combatants[encounter.activeIndex]?.creatureId;
useEffect(() => {
if (activeCreatureId && sidePanel.panelView.mode === "creature") {
sidePanel.showCreature(activeCreatureId);
}
}, [activeCreatureId, sidePanel.panelView.mode, sidePanel.showCreature]);
// Auto-scroll to the active combatant when the turn changes
const activeRowRef = useRef<HTMLDivElement>(null);
useEffect(() => {
@@ -282,6 +291,9 @@ export function App() {
? () => handleCombatantStatBlock(c.creatureId as string)
: undefined
}
isStatBlockOpen={
c.creatureId === sidePanel.selectedCreatureId
}
onRollInitiative={
c.creatureId ? handleRollInitiative : undefined
}

View File

@@ -4,7 +4,7 @@ import {
deriveHpStatus,
type PlayerIcon,
} from "@initiative/domain";
import { BookOpen, Brain, X } from "lucide-react";
import { Book, BookOpen, Brain, X } from "lucide-react";
import { type Ref, useCallback, useEffect, useRef, useState } from "react";
import { cn } from "../lib/utils";
import { AcShield } from "./ac-shield";
@@ -41,6 +41,7 @@ interface CombatantRowProps {
onToggleCondition: (id: CombatantId, conditionId: ConditionId) => void;
onToggleConcentration: (id: CombatantId) => void;
onShowStatBlock?: () => void;
isStatBlockOpen?: boolean;
onRollInitiative?: (id: CombatantId) => void;
}
@@ -396,6 +397,7 @@ export function CombatantRow({
onToggleCondition,
onToggleConcentration,
onShowStatBlock,
isStatBlockOpen,
onRollInitiative,
}: CombatantRowProps & { ref?: Ref<HTMLDivElement> }) {
const { id, name, initiative, maxHp, currentHp } = combatant;
@@ -480,9 +482,9 @@ export function CombatantRow({
onClick={onShowStatBlock}
title="View stat block"
aria-label="View stat block"
className="shrink-0 text-muted-foreground transition-colors hover:text-hover-neutral"
className="shrink-0 text-foreground transition-colors hover:text-hover-neutral"
>
<BookOpen size={14} />
{isStatBlockOpen ? <BookOpen size={16} /> : <Book size={16} />}
</button>
)}
{!!combatant.icon &&
@@ -495,7 +497,7 @@ export function CombatantRow({
];
return PcIcon ? (
<PcIcon
size={14}
size={16}
style={{ color: iconColor }}
className="shrink-0"
/>