import { type ReactNode,useMemo, useState } from 'react'; import { normalizeCustomWorldLandmarks } from '../data/customWorldSceneGraph'; import { Character, CustomWorldProfile } from '../types'; import { getNineSliceStyle, UI_CHROME } from '../uiAssets'; import { CustomWorldEntityCatalog, type ResultTab } from './CustomWorldEntityCatalog'; import { type CustomWorldEditorTarget,CustomWorldEntityEditorModal } from './CustomWorldEntityEditorModal'; interface CustomWorldResultViewProps { profile: CustomWorldProfile; previewCharacters: Character[]; isGenerating: boolean; progress: number; progressLabel: string; error: string | null; onBack: () => void; onEditSetting: () => void; onRegenerate: () => void; onContinueExpand?: () => void; onSave: () => void; onProfileChange: (profile: CustomWorldProfile) => void; } function SmallButton({ onClick, children, tone = 'default', disabled = false, }: { onClick: () => void; children: ReactNode; tone?: 'default' | 'sky'; disabled?: boolean; }) { return ( ); } function getCreateTargetByTab(activeTab: ResultTab): CustomWorldEditorTarget | null { if (activeTab === 'playable') return { kind: 'playable', mode: 'create' }; if (activeTab === 'story') return { kind: 'story', mode: 'create' }; if (activeTab === 'landmarks') return { kind: 'landmark', mode: 'create' }; return null; } function getCreateLabelByTab(activeTab: ResultTab) { if (activeTab === 'playable') return '新增可扮演角色'; if (activeTab === 'story') return '新增场景角色'; if (activeTab === 'landmarks') return '新增场景'; return ''; } function removeStoryNpcsFromProfile( profile: CustomWorldProfile, ids: string[], ) { const idSet = new Set(ids); const nextStoryNpcs = profile.storyNpcs.filter((npc) => !idSet.has(npc.id)); return { ...profile, storyNpcs: nextStoryNpcs, landmarks: normalizeCustomWorldLandmarks({ landmarks: profile.landmarks.map((landmark) => ({ ...landmark, sceneNpcIds: landmark.sceneNpcIds.filter((npcId) => !idSet.has(npcId)), })), storyNpcs: nextStoryNpcs, }), } satisfies CustomWorldProfile; } function removeLandmarksFromProfile(profile: CustomWorldProfile, ids: string[]) { const idSet = new Set(ids); const nextLandmarks = profile.landmarks.filter( (landmark) => !idSet.has(landmark.id), ); return { ...profile, landmarks: normalizeCustomWorldLandmarks({ landmarks: nextLandmarks.map((landmark) => ({ ...landmark, connections: landmark.connections.filter( (connection) => !idSet.has(connection.targetLandmarkId), ), })), storyNpcs: profile.storyNpcs, }), } satisfies CustomWorldProfile; } export function CustomWorldResultView({ profile, previewCharacters, isGenerating, progress, progressLabel, error, onBack, onEditSetting, onRegenerate: triggerRegenerate, onContinueExpand, onSave, onProfileChange, }: CustomWorldResultViewProps) { const [editorTarget, setEditorTarget] = useState(null); const [activeTab, setActiveTab] = useState('world'); const createTarget = useMemo(() => getCreateTargetByTab(activeTab), [activeTab]); const createLabel = useMemo(() => getCreateLabelByTab(activeTab), [activeTab]); const onRegenerate = () => { if (isGenerating) return; const confirmed = window.confirm( `确认重新生成“${profile.name}”吗?\n\n重新生成会重新生成当前世界中的所有信息,包括你修改和新增的所有内容。`, ); if (!confirmed) return; triggerRegenerate(); }; const handleDeleteStoryNpcs = (ids: string[]) => { if (ids.length === 0) return; onProfileChange(removeStoryNpcsFromProfile(profile, ids)); }; const handleDeleteLandmarks = (ids: string[]) => { if (ids.length === 0) return; onProfileChange(removeLandmarksFromProfile(profile, ids)); }; return (
setEditorTarget(createTarget) : undefined} />
{isGenerating && (
{progressLabel}
{Math.round(progress)}%
)} {error ? (
{error}
) : null}
{profile.generationStatus === 'key_only' ? (
当前世界处于快速预览模式,只生成了关键对象。继续补全后,系统会生成长尾场景角色与完整场景网络。
) : null}
修改设定 重新生成 {profile.generationStatus === 'key_only' && onContinueExpand ? ( 继续补全世界 ) : null}
setEditorTarget(null)} onProfileChange={onProfileChange} />
); }