import { useEffect, useRef, useState } from "react"; import { Message } from "../api/games"; import { AwaitingRoll } from "../hooks/useGameSocket"; import MarkdownContent from "./MarkdownContent"; const DICE_FACES = ["⚀", "⚁", "⚂", "⚃", "⚄", "⚅"]; function senderLabel(message: Message): string { if (message.sender_type === "dm") return "Dungeon Master"; if (message.sender_type === "system") return "System"; if (message.character_name) return `${message.player_name} (${message.character_name})`; return message.player_name ?? "Spieler"; } function DiceRollAnimation({ notation }: { notation: string }) { const [faceIndex, setFaceIndex] = useState(0); useEffect(() => { const interval = setInterval(() => { setFaceIndex((i) => (i + 1) % DICE_FACES.length); }, 120); return () => clearInterval(interval); }, []); return (
Dungeon Master würfelt{" "} {" "} {notation && `(${notation})`}
); } export default function TranscriptPane({ messages, typing, rolling, awaitingRoll, }: { messages: Message[]; typing?: boolean; rolling?: string | null; awaitingRoll?: AwaitingRoll | null; }) { const bottomRef = useRef(null); useEffect(() => { bottomRef.current?.scrollIntoView({ block: "end" }); }, [messages, typing, rolling, awaitingRoll]); return (
{messages.map((m) => (
{senderLabel(m)}:
))} {awaitingRoll ? (
🎲 Du bist am Zug — würfle:{" "} {awaitingRoll.notation} {awaitingRoll.reason && ({awaitingRoll.reason})}

Wirf deinen Würfel und schreib das Ergebnis als Nachricht.

) : rolling != null ? ( ) : ( typing && (
Dungeon Master schreibt …
) )}
); }