feat: [US-063] - Import characters/variables from another project
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
49698dd9a9
commit
a3e1d1cea2
@@ -3,10 +3,14 @@
|
||||
import { useState } from 'react'
|
||||
import { nanoid } from 'nanoid'
|
||||
import type { Character, Variable } from '@/types/flowchart'
|
||||
import ImportFromProjectModal from './ImportFromProjectModal'
|
||||
|
||||
type Tab = 'characters' | 'variables'
|
||||
|
||||
type ImportModalState = { open: boolean; mode: 'characters' | 'variables' }
|
||||
|
||||
type ProjectSettingsModalProps = {
|
||||
projectId: string
|
||||
characters: Character[]
|
||||
variables: Variable[]
|
||||
onCharactersChange: (characters: Character[]) => void
|
||||
@@ -26,6 +30,7 @@ function randomHexColor(): string {
|
||||
}
|
||||
|
||||
export default function ProjectSettingsModal({
|
||||
projectId,
|
||||
characters,
|
||||
variables,
|
||||
onCharactersChange,
|
||||
@@ -35,6 +40,15 @@ export default function ProjectSettingsModal({
|
||||
getVariableUsageCount,
|
||||
}: ProjectSettingsModalProps) {
|
||||
const [activeTab, setActiveTab] = useState<Tab>('characters')
|
||||
const [importModal, setImportModal] = useState<ImportModalState>({ open: false, mode: 'characters' })
|
||||
|
||||
const handleImportCharacters = (imported: Character[]) => {
|
||||
onCharactersChange([...characters, ...imported])
|
||||
}
|
||||
|
||||
const handleImportVariables = (imported: Variable[]) => {
|
||||
onVariablesChange([...variables, ...imported])
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
@@ -90,6 +104,7 @@ export default function ProjectSettingsModal({
|
||||
characters={characters}
|
||||
onChange={onCharactersChange}
|
||||
getUsageCount={getCharacterUsageCount}
|
||||
onImport={() => setImportModal({ open: true, mode: 'characters' })}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 'variables' && (
|
||||
@@ -97,10 +112,23 @@ export default function ProjectSettingsModal({
|
||||
variables={variables}
|
||||
onChange={onVariablesChange}
|
||||
getUsageCount={getVariableUsageCount}
|
||||
onImport={() => setImportModal({ open: true, mode: 'variables' })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{importModal.open && (
|
||||
<ImportFromProjectModal
|
||||
mode={importModal.mode}
|
||||
currentProjectId={projectId}
|
||||
existingCharacters={characters}
|
||||
existingVariables={variables}
|
||||
onImportCharacters={handleImportCharacters}
|
||||
onImportVariables={handleImportVariables}
|
||||
onClose={() => setImportModal({ open: false, mode: importModal.mode })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -110,6 +138,7 @@ type CharactersTabProps = {
|
||||
characters: Character[]
|
||||
onChange: (characters: Character[]) => void
|
||||
getUsageCount: (characterId: string) => number
|
||||
onImport: () => void
|
||||
}
|
||||
|
||||
type CharacterFormData = {
|
||||
@@ -118,7 +147,7 @@ type CharacterFormData = {
|
||||
description: string
|
||||
}
|
||||
|
||||
function CharactersTab({ characters, onChange, getUsageCount }: CharactersTabProps) {
|
||||
function CharactersTab({ characters, onChange, getUsageCount, onImport }: CharactersTabProps) {
|
||||
const [isAdding, setIsAdding] = useState(false)
|
||||
const [editingId, setEditingId] = useState<string | null>(null)
|
||||
const [formData, setFormData] = useState<CharacterFormData>({ name: '', color: randomHexColor(), description: '' })
|
||||
@@ -207,12 +236,20 @@ function CharactersTab({ characters, onChange, getUsageCount }: CharactersTabPro
|
||||
Define characters that can be referenced in dialogue nodes.
|
||||
</p>
|
||||
{!isAdding && !editingId && (
|
||||
<button
|
||||
onClick={() => { setIsAdding(true); resetForm(); setDeleteConfirm(null) }}
|
||||
className="rounded bg-blue-500 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-zinc-800"
|
||||
>
|
||||
Add Character
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={onImport}
|
||||
className="rounded border border-zinc-300 bg-white px-3 py-1.5 text-sm font-medium text-zinc-700 hover:bg-zinc-50 dark:border-zinc-600 dark:bg-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-600"
|
||||
>
|
||||
Import from project
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setIsAdding(true); resetForm(); setDeleteConfirm(null) }}
|
||||
className="rounded bg-blue-500 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-zinc-800"
|
||||
>
|
||||
Add Character
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -378,6 +415,7 @@ type VariablesTabProps = {
|
||||
variables: Variable[]
|
||||
onChange: (variables: Variable[]) => void
|
||||
getUsageCount: (variableId: string) => number
|
||||
onImport: () => void
|
||||
}
|
||||
|
||||
type VariableType = 'numeric' | 'string' | 'boolean'
|
||||
@@ -406,7 +444,7 @@ function parseInitialValue(type: VariableType, raw: string): number | string | b
|
||||
}
|
||||
}
|
||||
|
||||
function VariablesTab({ variables, onChange, getUsageCount }: VariablesTabProps) {
|
||||
function VariablesTab({ variables, onChange, getUsageCount, onImport }: VariablesTabProps) {
|
||||
const [isAdding, setIsAdding] = useState(false)
|
||||
const [editingId, setEditingId] = useState<string | null>(null)
|
||||
const [formData, setFormData] = useState<VariableFormData>({ name: '', type: 'numeric', initialValue: '0', description: '' })
|
||||
@@ -503,12 +541,20 @@ function VariablesTab({ variables, onChange, getUsageCount }: VariablesTabProps)
|
||||
Define variables that can be referenced in variable nodes and edge conditions.
|
||||
</p>
|
||||
{!isAdding && !editingId && (
|
||||
<button
|
||||
onClick={() => { setIsAdding(true); resetForm(); setDeleteConfirm(null) }}
|
||||
className="rounded bg-blue-500 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-zinc-800"
|
||||
>
|
||||
Add Variable
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={onImport}
|
||||
className="rounded border border-zinc-300 bg-white px-3 py-1.5 text-sm font-medium text-zinc-700 hover:bg-zinc-50 dark:border-zinc-600 dark:bg-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-600"
|
||||
>
|
||||
Import from project
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setIsAdding(true); resetForm(); setDeleteConfirm(null) }}
|
||||
className="rounded bg-blue-500 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-zinc-800"
|
||||
>
|
||||
Add Variable
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user