133 lines
3.4 KiB
Vue
133 lines
3.4 KiB
Vue
<template>
|
|
<div
|
|
@click="openFileDialog"
|
|
@dragover.prevent="onDragOver"
|
|
@dragleave="onDragLeave"
|
|
@drop.prevent="onDrop"
|
|
class="border-2 border-dashed border-gray-600 rounded-lg p-8 text-center cursor-pointer transition-all"
|
|
:class="{'border-blue-500 bg-blue-500 bg-opacity-5': isDragOver}"
|
|
>
|
|
<i class="fas fa-cloud-upload-alt text-blue-500 text-3xl mb-4"></i>
|
|
<p class="text-gray-400">
|
|
Drag & drop sprite images here<br>or click to select files
|
|
</p>
|
|
<input
|
|
type="file"
|
|
ref="fileInput"
|
|
multiple
|
|
accept="image/*"
|
|
class="hidden"
|
|
@change="onFileChange"
|
|
>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent, ref } from 'vue';
|
|
import { Sprite } from '../composables/useSpritesheetStore';
|
|
import { useSpritesheetStore } from '../composables/useSpritesheetStore';
|
|
|
|
export default defineComponent({
|
|
name: 'DropZone',
|
|
emits: ['files-uploaded'],
|
|
setup(props, { emit }) {
|
|
const store = useSpritesheetStore();
|
|
const fileInput = ref<HTMLInputElement | null>(null);
|
|
const isDragOver = ref(false);
|
|
|
|
const openFileDialog = () => {
|
|
if (fileInput.value) {
|
|
fileInput.value.click();
|
|
}
|
|
};
|
|
|
|
const onDragOver = () => {
|
|
isDragOver.value = true;
|
|
};
|
|
|
|
const onDragLeave = () => {
|
|
isDragOver.value = false;
|
|
};
|
|
|
|
const onDrop = (e: DragEvent) => {
|
|
isDragOver.value = false;
|
|
if (e.dataTransfer?.files.length) {
|
|
handleFiles(e.dataTransfer.files);
|
|
}
|
|
};
|
|
|
|
const onFileChange = (e: Event) => {
|
|
const input = e.target as HTMLInputElement;
|
|
if (input.files?.length) {
|
|
handleFiles(input.files);
|
|
}
|
|
};
|
|
|
|
const handleFiles = async (files: FileList) => {
|
|
const imageFiles = Array.from(files).filter(file => file.type.startsWith('image/'));
|
|
|
|
if (imageFiles.length === 0) {
|
|
store.showNotification('Please upload image files only', 'error');
|
|
return;
|
|
}
|
|
|
|
const newSprites: Sprite[] = [];
|
|
|
|
for (let i = 0; i < imageFiles.length; i++) {
|
|
const file = imageFiles[i];
|
|
try {
|
|
const sprite = await createSpriteFromFile(file, i);
|
|
newSprites.push(sprite);
|
|
} catch (error) {
|
|
console.error('Error loading sprite:', error);
|
|
}
|
|
}
|
|
|
|
if (newSprites.length > 0) {
|
|
store.addSprites(newSprites);
|
|
emit('files-uploaded', newSprites);
|
|
store.showNotification(`Added ${newSprites.length} sprites successfully`);
|
|
}
|
|
};
|
|
|
|
const createSpriteFromFile = (file: File, index: number): Promise<Sprite> => {
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
|
|
reader.onload = (e) => {
|
|
const img = new Image();
|
|
|
|
img.onload = () => {
|
|
resolve({
|
|
img,
|
|
width: img.width,
|
|
height: img.height,
|
|
x: 0,
|
|
y: 0,
|
|
name: file.name,
|
|
id: `sprite-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
uploadOrder: index
|
|
});
|
|
};
|
|
|
|
img.onerror = reject;
|
|
img.src = e.target?.result as string;
|
|
};
|
|
|
|
reader.onerror = reject;
|
|
reader.readAsDataURL(file);
|
|
});
|
|
};
|
|
|
|
return {
|
|
fileInput,
|
|
isDragOver,
|
|
openFileDialog,
|
|
onDragOver,
|
|
onDragLeave,
|
|
onDrop,
|
|
onFileChange
|
|
};
|
|
}
|
|
});
|
|
</script> |