1
0
Fork 0
polaris-task-force/src/components/admin/narrative-flow/OutcomeNode.tsx
Z8MB1E 103340271b feat: narrative events flowchart editor with React Flow
- 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
2026-07-28 16:26:57 -04:00

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>
);
}