feat(npcs): drop binding; select NPCs on storyline export
Remove storyline/scene NPC binding and export chosen NPCs with relations/groups. Harden export modal so a missing npcs payload no longer blacks out the editor. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,9 +2,8 @@ import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { createPortal, flushSync } from 'react-dom';
|
||||
|
||||
import { ipcChannels } from '../../shared/ipc/contracts';
|
||||
import { noneBinding } from '../../shared/npcs/npcBinding';
|
||||
import { buildNpcGroupForest } from '../../shared/npcs/npcGroups';
|
||||
import type { NpcBinding, NpcGroupId, Project, ProjectNpc, ProjectNpcGroup } from '../../shared/types';
|
||||
import type { NpcGroupId, ProjectNpc, ProjectNpcGroup } from '../../shared/types';
|
||||
import editorStyles from '../editor/EditorApp.module.css';
|
||||
import {
|
||||
filterMaterialImagePaths,
|
||||
@@ -18,8 +17,6 @@ import { getDndApi } from '../shared/dndApi';
|
||||
import { Button, Input, Select } from '../shared/ui/controls';
|
||||
import { useAssetUrl } from '../shared/useAssetImageUrl';
|
||||
|
||||
import { NpcBindingFields } from './NpcBindingFields';
|
||||
|
||||
function normalizeName(input: string): string {
|
||||
return input.trim().toLowerCase();
|
||||
}
|
||||
@@ -41,7 +38,6 @@ type NpcEditModalProps = {
|
||||
open: boolean;
|
||||
initial: ProjectNpc | null;
|
||||
existingNames: string[];
|
||||
project: Project | null;
|
||||
npcGroups: ProjectNpcGroup[];
|
||||
onClose: () => void;
|
||||
onPickImage: () => Promise<{ filePath: string; previewDataUrl: string } | null>;
|
||||
@@ -49,7 +45,6 @@ type NpcEditModalProps = {
|
||||
name: string;
|
||||
filePath?: string;
|
||||
groupId?: NpcGroupId | null;
|
||||
binding?: NpcBinding;
|
||||
}) => Promise<void>;
|
||||
};
|
||||
|
||||
@@ -57,7 +52,6 @@ export function NpcEditModal({
|
||||
open,
|
||||
initial,
|
||||
existingNames,
|
||||
project,
|
||||
npcGroups,
|
||||
onClose,
|
||||
onPickImage,
|
||||
@@ -69,7 +63,6 @@ export function NpcEditModal({
|
||||
const [filePath, setFilePath] = useState<string | null>(null);
|
||||
const [localPreviewUrl, setLocalPreviewUrl] = useState<string | null>(null);
|
||||
const [groupId, setGroupId] = useState<NpcGroupId | ''>('');
|
||||
const [binding, setBinding] = useState<NpcBinding>(noneBinding());
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [saveProgress, setSaveProgress] = useState<{ percent: number; detail: string } | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -86,7 +79,6 @@ export function NpcEditModal({
|
||||
setFilePath(null);
|
||||
setLocalPreviewUrl(null);
|
||||
setGroupId(initial?.groupId ?? '');
|
||||
setBinding(initial?.binding ?? noneBinding());
|
||||
setSaving(false);
|
||||
setSaveProgress(null);
|
||||
setError(null);
|
||||
@@ -261,10 +253,6 @@ export function NpcEditModal({
|
||||
{!hasImage ? <div className={editorStyles.fieldError}>{t('npcs.avatarRequired')}</div> : null}
|
||||
</div>
|
||||
|
||||
{project && !initial ? (
|
||||
<NpcBindingFields project={project} binding={binding} onChange={setBinding} />
|
||||
) : null}
|
||||
|
||||
{error ? <div className={editorStyles.fieldError}>{error}</div> : null}
|
||||
|
||||
<div className={editorStyles.modalFooter}>
|
||||
@@ -286,7 +274,7 @@ export function NpcEditModal({
|
||||
await onSave({
|
||||
name: trimmed,
|
||||
...(filePath ? { filePath } : {}),
|
||||
...(!initial ? { groupId: groupId || null, binding } : {}),
|
||||
...(!initial ? { groupId: groupId || null } : {}),
|
||||
});
|
||||
onClose();
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user