Files
npc-config-app/src/components/nodes/OutputNode.tsx

125 lines
4.8 KiB
TypeScript

import { memo, useState } from 'react';
import { Handle, Position } from '@xyflow/react';
import type { NodeProps } from '@xyflow/react';
import { FileText, ChevronDown, ChevronUp, Download } from 'lucide-react';
import type { OutputNodeData } from '../../types/nodes';
export const OutputNode = memo(({ data }: NodeProps) => {
const [isExpanded, setIsExpanded] = useState(true);
const nodeData = data as OutputNodeData;
const downloadJSON = () => {
if (!nodeData.previewData) return;
const jsonString = JSON.stringify(nodeData.previewData, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${nodeData.previewData.id || 'npc'}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
return (
<div className="bg-white rounded-lg shadow-xl border-2 border-indigo-500 min-w-[400px] max-w-[500px]">
{/* Node Header */}
<div className="bg-indigo-500 text-white px-4 py-2 rounded-t-lg flex items-center justify-between">
<div className="flex items-center gap-2">
<FileText className="h-4 w-4" />
<span className="font-semibold text-sm">Output Preview</span>
</div>
<div className="flex items-center gap-2">
<button
onClick={downloadJSON}
className="text-white hover:bg-indigo-600 rounded p-1 transition-colors"
title="Download JSON"
>
<Download className="h-4 w-4" />
</button>
<button
onClick={() => setIsExpanded(!isExpanded)}
className="text-white hover:bg-indigo-600 rounded p-1 transition-colors"
>
{isExpanded ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
</button>
</div>
</div>
{/* Input Handle */}
<Handle
type="target"
position={Position.Left}
className="w-3 h-3 bg-indigo-500 border-2 border-white"
/>
{/* Node Content */}
{isExpanded && (
<div className="p-4 space-y-3">
<div className="bg-gray-50 rounded-lg p-3 border border-gray-200">
<h4 className="text-xs font-semibold text-gray-700 mb-2">NPC Summary</h4>
<dl className="space-y-1 text-xs">
<div className="flex justify-between">
<dt className="text-gray-600">Name:</dt>
<dd className="font-medium text-gray-900">
{nodeData.previewData?.names?.[0] || 'Unnamed'}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600">ID:</dt>
<dd className="font-medium text-gray-900">
{nodeData.previewData?.id || 'N/A'}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600">Battle:</dt>
<dd className="font-medium text-gray-900">
{nodeData.previewData?.battleConfiguration?.canChallenge
? 'Enabled'
: 'Disabled'}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600">Party:</dt>
<dd className="font-medium text-gray-900">
{nodeData.previewData?.party?.type || 'None'}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600">Variables:</dt>
<dd className="font-medium text-gray-900">
{nodeData.previewData?.config?.length || 0}
</dd>
</div>
</dl>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between">
<h4 className="text-xs font-semibold text-gray-700">JSON Preview</h4>
<span className="text-xs text-gray-500">
{JSON.stringify(nodeData.previewData).length} chars
</span>
</div>
<pre className="bg-gray-900 text-green-400 rounded-lg p-3 text-xs overflow-x-auto max-h-96 overflow-y-auto font-mono">
{JSON.stringify(nodeData.previewData, null, 2)}
</pre>
</div>
<button
onClick={downloadJSON}
className="w-full inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg text-white bg-indigo-600 hover:bg-indigo-700 transition-colors"
>
<Download className="h-4 w-4 mr-2" />
Download JSON
</button>
</div>
)}
</div>
);
});
OutputNode.displayName = 'OutputNode';