Files
shadow-over-bishkek001/dialogEditor/src/components/nodes/LineNode.tsx
T

67 lines
2.4 KiB
TypeScript

import { memo } from 'react';
import { Handle, Position, NodeProps } from '@xyflow/react';
import { LineNode as LineNodeData } from '../../types/dialogue';
import { useValidation } from '../../hooks/useValidation';
import { useDialogueStore } from '../../store/dialogueStore';
import { MAIN_CHARACTER } from '../../constants/characters';
import styles from './nodes.module.css';
export const LineNode = memo(({ data, selected }: NodeProps & { data: LineNodeData }) => {
const { hasError, hasWarning } = useValidation();
const startId = useDialogueStore(s => {
const id = s.selectedDialogueId;
return s.file?.dialogues.find(d => d.id === id)?.start;
});
const isMain = data.speaker === MAIN_CHARACTER;
const isStart = data.id === startId;
const error = hasError(data.id);
const warning = !error && hasWarning(data.id);
const triggers = [
data.chatBubble && `💬 ${data.chatBubble}`,
data.questUnlock && `🔓 quest`,
data.objectiveComplete && `✅ obj`,
data.objectiveVisible && `👁 obj`,
data.questFail && `❌ quest`,
data.questComplete && `🏁 quest`,
data.luaCallback && `⚡ lua`,
].filter(Boolean);
return (
<div
className={[
styles.node,
styles.lineNode,
isMain ? styles.mainChar : styles.otherChar,
selected ? styles.selected : '',
error ? styles.hasError : '',
warning ? styles.hasWarning : '',
].join(' ')}
>
{isStart && <div className={styles.startBadge}>▶ START</div>}
<Handle type="target" position={Position.Top} id="target" className={styles.handle} />
<div className={styles.nodeHeader}>
<span className={styles.speakerName}>{data.speaker || '(no speaker)'}</span>
<span className={styles.nodeType}>Line</span>
</div>
<div className={styles.nodeId}>{data.id}</div>
<div className={styles.nodeBody}>
{data.text ? (
<span className={styles.textSnippet}>{data.text}</span>
) : (
<span className={styles.emptyText}>(empty)</span>
)}
</div>
{triggers.length > 0 && (
<div className={styles.triggerRow}>
{triggers.map((t, i) => (
<span key={i} className={styles.triggerPill}>{t}</span>
))}
</div>
)}
<Handle type="source" position={Position.Bottom} id="source" className={styles.handle} />
</div>
);
});