- NarrativeEvents collection redesigned with flowData JSON (React Flow format) - Custom admin field component: NarrativeFlowEditor with @xyflow/react - Three node types: NarrativeBeat (blue), Choice (amber), Outcome (emerald) - NodeEditDialog with type-specific forms replacing prompt() editing - Right-click context menu (Delete node/edge with Radix primitives) - Dynamic handles on Choice nodes (one per option) - Dark-themed canvas with MiniMap, Controls, and animated edges - All changes sync bidirectionally with Payload form state - AGENTS.md updated with architecture docs
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { Handle, Position, type NodeProps } from "@xyflow/react";
|
|
import { FlagIcon, PencilIcon } from "lucide-react";
|
|
|
|
export function OutcomeNode({ data }: NodeProps) {
|
|
const d = data as {
|
|
title?: string;
|
|
text?: string;
|
|
effects?: Array<{ type: string; value: string }>;
|
|
};
|
|
|
|
const effects = d.effects ?? [];
|
|
|
|
return (
|
|
<div className="bg-emerald-950/80 border border-emerald-500/50 rounded-lg shadow-md min-w-56">
|
|
<Handle type="target" position={Position.Top} className="!bg-emerald-400" />
|
|
<div className="flex items-center gap-2 px-3 py-2 border-b border-emerald-500/30">
|
|
<FlagIcon className="size-4 text-emerald-400 shrink-0" />
|
|
<span className="text-sm font-medium text-emerald-200 flex-1 truncate">
|
|
{d.title || "Untitled Outcome"}
|
|
</span>
|
|
<PencilIcon className="size-3 text-emerald-500/40 shrink-0" />
|
|
</div>
|
|
<div className="px-3 py-2 border-b border-emerald-500/20 text-xs text-emerald-300/80 line-clamp-2">
|
|
{d.text || "No description."}
|
|
</div>
|
|
<div className="px-3 py-2 space-y-1">
|
|
<span className="text-[10px] uppercase tracking-wider text-emerald-500/60 font-medium">
|
|
Effects
|
|
</span>
|
|
{effects.length === 0 ? (
|
|
<span className="text-xs text-emerald-400/40 italic block">None</span>
|
|
) : (
|
|
effects.map((eff, i) => (
|
|
<div
|
|
key={i}
|
|
className="flex items-center gap-1 text-xs text-emerald-300/70"
|
|
>
|
|
<span className="text-emerald-400/80 font-mono">{eff.type}</span>
|
|
<span className="text-emerald-500/40">:</span>
|
|
<span className="truncate">{eff.value}</span>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|