add choice mechanic
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { Statement } from '@/lib/vn-parser';
|
||||
import { Sprite } from '@/lib/sprite-bank';
|
||||
|
||||
@@ -9,6 +9,7 @@ interface VNOutlineProps {
|
||||
isParsing: boolean;
|
||||
spriteBank: Record<string, Sprite[]>;
|
||||
onUpdateSpriteBank: (newBank: Record<string, Sprite[]>) => void;
|
||||
onAddSpriteToScript: (char: string, id: string, url: string) => void;
|
||||
}
|
||||
|
||||
export const VNOutline: React.FC<VNOutlineProps> = ({
|
||||
@@ -17,10 +18,13 @@ export const VNOutline: React.FC<VNOutlineProps> = ({
|
||||
onSelectLine,
|
||||
isParsing,
|
||||
spriteBank,
|
||||
onUpdateSpriteBank
|
||||
onUpdateSpriteBank,
|
||||
onAddSpriteToScript
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState<'outline' | 'sprites'>('outline');
|
||||
const [newCharName, setNewCharName] = useState('');
|
||||
const [uploadingFor, setUploadingFor] = useState<string | null>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const addCharacter = () => {
|
||||
if (!newCharName || spriteBank[newCharName]) return;
|
||||
@@ -33,14 +37,39 @@ export const VNOutline: React.FC<VNOutlineProps> = ({
|
||||
onUpdateSpriteBank(rest);
|
||||
};
|
||||
|
||||
const addSprite = (charName: string) => {
|
||||
const addSpriteUrl = (charName: string) => {
|
||||
const id = prompt('Sprite ID (e.g. happy):');
|
||||
if (!id) return;
|
||||
const url = prompt('Sprite Image URL:');
|
||||
if (!url) return;
|
||||
|
||||
const newSprites = [...spriteBank[charName], { id, name: id, url }];
|
||||
onUpdateSpriteBank({ ...spriteBank, [charName]: newSprites });
|
||||
onAddSpriteToScript(charName, id, url);
|
||||
};
|
||||
|
||||
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file || !uploadingFor) return;
|
||||
|
||||
const id = prompt('Sprite ID (e.g. happy):');
|
||||
if (!id) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const url = e.target?.result as string;
|
||||
if (url) {
|
||||
onAddSpriteToScript(uploadingFor, id, url);
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
// Reset file input
|
||||
if (fileInputRef.current) fileInputRef.current.value = '';
|
||||
setUploadingFor(null);
|
||||
};
|
||||
|
||||
const triggerFileUpload = (charName: string) => {
|
||||
setUploadingFor(charName);
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const removeSprite = (charName: string, spriteId: string) => {
|
||||
@@ -132,15 +161,16 @@ export const VNOutline: React.FC<VNOutlineProps> = ({
|
||||
{charName}
|
||||
</h3>
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => addSprite(charName)} className="text-[8px] text-gray-400 hover:text-cyan-400 uppercase font-bold tracking-tighter">Add Sprite</button>
|
||||
<button onClick={() => addSpriteUrl(charName)} className="text-[8px] text-gray-400 hover:text-cyan-400 uppercase font-bold tracking-tighter">URL</button>
|
||||
<button onClick={() => triggerFileUpload(charName)} className="text-[8px] text-gray-400 hover:text-cyan-400 uppercase font-bold tracking-tighter">Upload</button>
|
||||
<button onClick={() => removeCharacter(charName)} className="text-[8px] text-gray-400 hover:text-red-400 uppercase font-bold tracking-tighter">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{sprites.map(sprite => (
|
||||
<div key={sprite.id} className="group relative">
|
||||
<div className="aspect-[2/3] bg-gray-900 rounded border border-gray-800 overflow-hidden">
|
||||
<img src={sprite.url} alt={sprite.name} className="w-full h-full object-cover opacity-60 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="aspect-[2/3] bg-gray-900 rounded border border-gray-800 overflow-hidden p-1">
|
||||
<img src={sprite.url} alt={sprite.name} className="w-full h-full object-contain opacity-60 group-hover:opacity-100 transition-opacity" />
|
||||
</div>
|
||||
<div className="absolute bottom-0 inset-x-0 bg-black/80 p-1 text-[8px] font-bold flex justify-between items-center group-hover:bg-cyan-950/90">
|
||||
<span className="truncate flex-1">{sprite.id}</span>
|
||||
@@ -156,6 +186,13 @@ export const VNOutline: React.FC<VNOutlineProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
className="hidden"
|
||||
accept="image/*"
|
||||
onChange={handleFileUpload}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user