Working on dialog editor, on dialogs, on phone
This commit is contained in:
1 parent
0e27521bea
commit
8f7797789d
63 files changed
+9502
-1459
No files matched your search
@@ -0,0 +1,114 @@
|
||||
import { useState } from 'react';
|
||||
import { LineNode } from '../../../types/dialogue';
|
||||
import { useDialogueStore } from '../../../store/dialogueStore';
|
||||
import { SpeakerField } from '../shared/SpeakerField';
|
||||
import { AutoSaveTextArea } from '../shared/TextArea';
|
||||
import { useValidation } from '../../../hooks/useValidation';
|
||||
import styles from '../RightPanel.module.css';
|
||||
|
||||
interface Props {
|
||||
node: LineNode;
|
||||
dialogueId: string;
|
||||
}
|
||||
|
||||
export function LineInspector({ node, dialogueId }: Props) {
|
||||
const { updateNode, deleteNode, file } = useDialogueStore();
|
||||
const { issuesByNodeId } = useValidation();
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
const issues = issuesByNodeId[node.id] ?? [];
|
||||
|
||||
const dialogue = file?.dialogues.find(d => d.id === dialogueId);
|
||||
const nodeIds = dialogue?.nodes.map(n => n.id) ?? [];
|
||||
|
||||
function update(patch: Partial<LineNode>) {
|
||||
updateNode(dialogueId, node.id, patch);
|
||||
}
|
||||
|
||||
function field(label: string, key: keyof LineNode, placeholder?: string) {
|
||||
const val = (node[key] as string) ?? '';
|
||||
return (
|
||||
<div>
|
||||
<label className={styles.label}>{label}</label>
|
||||
<input
|
||||
className={styles.input}
|
||||
value={val}
|
||||
placeholder={placeholder}
|
||||
onChange={e => update({ [key]: e.target.value } as Partial<LineNode>)}
|
||||
list={key === 'next' ? `nodelist-${node.id}` : undefined}
|
||||
/>
|
||||
{key === 'next' && (
|
||||
<datalist id={`nodelist-${node.id}`}>
|
||||
{nodeIds.map(id => <option key={id} value={id} />)}
|
||||
</datalist>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.inspector}>
|
||||
<div className={styles.inspectorHeader}>
|
||||
<span className={styles.nodeTypeBadge} style={{ background: '#1e66f5' }}>Line</span>
|
||||
<span className={styles.nodeIdLabel}>{node.id}</span>
|
||||
<button className={styles.deleteNodeBtn} onClick={() => deleteNode(dialogueId, node.id)} title="Delete node">🗑</button>
|
||||
</div>
|
||||
|
||||
{issues.length > 0 && (
|
||||
<div className={styles.issueList}>
|
||||
{issues.map((issue, i) => (
|
||||
<div key={i} className={issue.severity === 'error' ? styles.issueError : styles.issueWarning}>
|
||||
{issue.severity === 'error' ? '⚠' : '!'} {issue.message}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{field('Node ID', 'id')}
|
||||
<SpeakerField
|
||||
speaker={node.speaker}
|
||||
portrait={node.portrait}
|
||||
onSpeakerChange={(s, p) => update({ speaker: s, portrait: p })}
|
||||
/>
|
||||
<AutoSaveTextArea
|
||||
label="Text"
|
||||
value={node.text}
|
||||
placeholder="Dialogue line text..."
|
||||
onSave={v => update({ text: v })}
|
||||
/>
|
||||
{field('Next node', 'next', 'node_id')}
|
||||
|
||||
{dialogue?.mobileMode && (
|
||||
<div>
|
||||
<label className={styles.label}>Chat Bubble</label>
|
||||
<select
|
||||
className={styles.select}
|
||||
value={node.chatBubble ?? ''}
|
||||
onChange={e => update({ chatBubble: e.target.value as 'in' | 'out' | undefined || undefined })}
|
||||
>
|
||||
<option value="">(auto)</option>
|
||||
<option value="in">in</option>
|
||||
<option value="out">out</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
className={styles.advancedToggle}
|
||||
onClick={() => setShowAdvanced(v => !v)}
|
||||
>
|
||||
{showAdvanced ? '▼' : '▶'} Advanced triggers
|
||||
</button>
|
||||
|
||||
{showAdvanced && (
|
||||
<div className={styles.advancedSection}>
|
||||
{field('questUnlock', 'questUnlock', 'quest_id')}
|
||||
{field('objectiveComplete', 'objectiveComplete', 'group.objective')}
|
||||
{field('objectiveVisible', 'objectiveVisible', 'group.objective')}
|
||||
{field('questFail', 'questFail', 'quest_id')}
|
||||
{field('questComplete', 'questComplete', 'quest_id')}
|
||||
{field('luaCallback', 'luaCallback', 'on_event_name')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user