studio/AssetManager.tsx

120 lines
4.9 KiB
TypeScript
Raw Permalink Normal View History

2025-12-10 09:43:39 +00:00
import React, { useState } from 'react';
import { CharacterData, LocationData, StyleOption, ModelSettings } from '../types';
import { User, MapPin, Info, Wand2, Plus } from 'lucide-react';
import InteractiveAssetEditor from './InteractiveAssetEditor';
interface AssetManagerProps {
characters: CharacterData[];
locations: LocationData[];
styleOption: StyleOption;
onUpdateCharacter: (char: CharacterData) => void;
onUpdateLocation: (loc: LocationData) => void;
onAddCharacter: () => void;
onAddLocation: () => void;
onComplete: () => void;
modelSettings: ModelSettings;
}
const AssetManager: React.FC<AssetManagerProps> = ({
characters,
locations,
styleOption,
onUpdateCharacter,
onUpdateLocation,
onAddCharacter,
onAddLocation,
onComplete,
modelSettings
}) => {
const [activeTab, setActiveTab] = useState<'characters' | 'locations'>('characters');
return (
<div className="animate-fade-in space-y-8 pb-32">
<div className="glass-card rounded-3xl p-8 flex flex-col md:flex-row justify-between items-end gap-6">
<div>
<h2 className="text-3xl font-bold text-white mb-2 text-glow"></h2>
<div className="flex items-center gap-3 text-sm text-zinc-400">
<span> DNA:</span>
<span className="px-3 py-1 bg-indigo-500/10 text-indigo-300 rounded-full border border-indigo-500/20 font-medium shadow-[0_0_10px_rgba(99,102,241,0.2)]">{styleOption.name}</span>
</div>
</div>
<div className="flex items-center gap-2">
<div className="glass-panel p-1 rounded-xl flex">
<button
onClick={() => setActiveTab('characters')}
className={`px-6 py-2.5 rounded-lg text-sm font-bold flex items-center gap-2 transition-all duration-300 ${
activeTab === 'characters' ? 'bg-white/10 text-white shadow-lg' : 'text-zinc-500 hover:text-zinc-300'
}`}
>
<User className="w-4 h-4" />
(Characters)
</button>
<button
onClick={() => setActiveTab('locations')}
className={`px-6 py-2.5 rounded-lg text-sm font-bold flex items-center gap-2 transition-all duration-300 ${
activeTab === 'locations' ? 'bg-white/10 text-white shadow-lg' : 'text-zinc-500 hover:text-zinc-300'
}`}
>
<MapPin className="w-4 h-4" />
(Locations)
</button>
</div>
<button
onClick={activeTab === 'characters' ? onAddCharacter : onAddLocation}
className="glass-btn w-10 h-10 rounded-xl flex items-center justify-center text-emerald-400 hover:bg-emerald-500/10 border-emerald-500/30"
title={activeTab === 'characters' ? "新增角色" : "新增場景"}
>
<Plus className="w-5 h-5" />
</button>
</div>
</div>
<div className="space-y-12">
{activeTab === 'characters' && characters.map(char => (
<InteractiveAssetEditor
key={char.id}
type="character"
data={char}
styleOption={styleOption}
onUpdate={(updated) => onUpdateCharacter(updated as CharacterData)}
modelSettings={modelSettings}
/>
))}
{activeTab === 'locations' && locations.map(loc => (
<InteractiveAssetEditor
key={loc.id}
type="location"
data={loc}
styleOption={styleOption}
onUpdate={(updated) => onUpdateLocation(updated as LocationData)}
modelSettings={modelSettings}
/>
))}
</div>
<div className="fixed bottom-8 left-1/2 -translate-x-1/2 z-40 w-[90%] max-w-4xl">
<div className="glass-card rounded-2xl p-4 flex justify-between items-center shadow-2xl backdrop-blur-xl">
<div className="flex items-center gap-3 px-4">
<div className="w-8 h-8 rounded-full bg-indigo-500/20 flex items-center justify-center text-indigo-400">
<Info className="w-4 h-4" />
</div>
<span className="text-zinc-300 text-sm hidden md:block"></span>
</div>
<button
onClick={onComplete}
className="glass-btn bg-emerald-500/20 border-emerald-500/50 text-white px-8 py-3 rounded-xl font-bold flex items-center gap-2 hover:bg-emerald-500/30 text-shadow-sm"
>
<Wand2 className="w-5 h-5 text-emerald-400" />
</button>
</div>
</div>
</div>
);
};
export default AssetManager;