{title}
{meta.label}{sceneLine}
} {frame.voiceover && (“{frame.voiceover}”
)}import type { StoryboardFrameView } from "../../hooks/useStoryboard";
import { FramePoster, posterTime } from "./FramePoster";
import { FRAME_STATUS_META } from "./frameStatus";
export interface StoryboardFrameTileProps {
projectId: string;
frame: StoryboardFrameView;
/** Open this frame in the full-area focus view. */
onOpen: (index: number) => void;
}
function firstLine(text: string): string {
return (
text
.split("\n")
.find((line) => line.trim().length > 0)
?.trim() ?? ""
);
}
function placeholderMessage(frame: StoryboardFrameView): string {
if (frame.status === "outline") return "Not built yet";
if (frame.src && !frame.srcExists) return "Frame file not found";
return "No preview";
}
/** A single contact-sheet tile: poster preview + its metadata. Click to focus. */
// fallow-ignore-next-line complexity
export function StoryboardFrameTile({ projectId, frame, onOpen }: StoryboardFrameTileProps) {
const meta = FRAME_STATUS_META[frame.status];
const renderable = frame.srcExists && frame.status !== "outline";
const title = frame.title ?? `Frame ${frame.index}`;
const sceneLine = frame.scene ?? firstLine(frame.narrative);
return (
{sceneLine}
“{frame.voiceover}”
{title}
{meta.label}