{entry.actionText}
) : null} {visibleStepTexts.map((text, index) => ({text}
))} {canRegenerate ? ( ) : null}import { RotateCcw } from 'lucide-react';
import type {
VisualNovelHistoryEntry,
VisualNovelRunSnapshot,
VisualNovelRuntimeStep,
} from '../../../packages/shared/src/contracts/visualNovel';
type VisualNovelHistoryPanelProps = {
run: VisualNovelRunSnapshot;
allowRegeneration?: boolean;
isBusy?: boolean;
onRegenerateHistoryEntry?: (entryId: string) => void;
};
function renderStepText(step: VisualNovelRuntimeStep) {
if (step.type === 'narration') {
return step.text;
}
if (step.type === 'dialogue') {
return `${step.characterName}: ${step.text}`;
}
if (step.type === 'transition') {
return step.text ?? '';
}
if (step.type === 'choice') {
return step.choices.map((choice) => choice.text).join(' / ');
}
return '';
}
function VisualNovelHistoryEntryCard({
entry,
allowRegeneration,
isBusy,
onRegenerateHistoryEntry,
}: {
entry: VisualNovelHistoryEntry;
allowRegeneration: boolean;
isBusy: boolean;
onRegenerateHistoryEntry?: (entryId: string) => void;
}) {
const visibleStepTexts = entry.steps.map(renderStepText).filter(Boolean);
const canRegenerate =
allowRegeneration && entry.source === 'assistant' && onRegenerateHistoryEntry;
return (
{entry.actionText}
{text}