This commit is contained in:
Dennis Postma 2025-04-05 13:26:33 +02:00
parent f738bbdd73
commit 3e849c0286
5 changed files with 101 additions and 65 deletions

View File

@ -1,4 +1,5 @@
import { spriteOffsets, notification } from '@/application/state';
import { type Sprite } from '@/application/types';
/**
* Logger utility with consistent error format
@ -60,3 +61,86 @@ export function isImageReady(img: HTMLImageElement): boolean {
export function getPixelPerfectCoordinate(value: number): number {
return Math.floor(value) + 0.5;
}
/**
* Create a sprite object from a file
*/
export function createSpriteFromFile(file: File, index: number): Promise<Sprite> {
return new Promise((resolve, reject) => {
// Create a URL for the file
const objectUrl = URL.createObjectURL(file);
const img = new Image();
// Set up event handlers
img.onload = () => {
// Verify the image has loaded properly
if (img.width === 0 || img.height === 0) {
logger.error('Image loaded with invalid dimensions:', { name: file.name, width: img.width, height: img.height });
URL.revokeObjectURL(objectUrl);
reject(new Error(`Image has invalid dimensions: ${file.name}`));
return;
}
// Create the sprite object
const sprite: Sprite = {
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,
};
// Keep the objectUrl reference and don't revoke it yet
// The image is still needed for rendering later
resolve(sprite);
};
img.onerror = error => {
logger.error('Error loading image:', { name: file.name, error });
URL.revokeObjectURL(objectUrl);
reject(new Error(`Failed to load image: ${file.name}`));
};
// Set the source to the object URL
img.src = objectUrl;
});
}
/**
* Process multiple files and create sprites
*/
export async function processImageFiles(files: FileList): Promise<{ newSprites: Sprite[], errorCount: number }> {
const imageFiles = Array.from(files).filter(file => file.type.startsWith('image/'));
if (imageFiles.length === 0) {
return { newSprites: [], errorCount: 0 };
}
const newSprites: Sprite[] = [];
let errorCount = 0;
for (let i = 0; i < imageFiles.length; i++) {
const file = imageFiles[i];
try {
const sprite = await createSpriteFromFile(file, i);
newSprites.push(sprite);
} catch (error) {
errorCount++;
logger.error('Error loading sprite:', error);
}
}
return { newSprites, errorCount };
}
/**
* Truncate text to a specific length and add ellipsis if needed
*/
export function truncateText(text: string, maxLength: number = 15): string {
return text.length > maxLength ? `${text.substring(0, maxLength)}...` : text;
}

View File

@ -54,20 +54,12 @@
return;
}
const newSprites: Sprite[] = [];
let errorCount = 0;
// Use the utility function to process image files
const { newSprites, errorCount } = await store.processImageFiles(files);
for (let i = 0; i < imageFiles.length; i++) {
const file = imageFiles[i];
try {
const sprite = await createSpriteFromFile(file, i);
newSprites.push(sprite);
} catch (error) {
errorCount++;
console.error('Error loading sprite:', error);
store.showNotification(`Failed to load ${file.name}`, 'error');
}
// Handle individual file errors
if (errorCount > 0) {
store.showNotification(`Failed to load ${errorCount} file(s)`, 'error');
}
if (newSprites.length > 0) {
@ -75,54 +67,7 @@
emit('files-uploaded', newSprites);
store.showNotification(`Added ${newSprites.length} sprites successfully`);
} else if (errorCount > 0) {
store.showNotification(`Failed to load all ${errorCount} sprites`, 'error');
store.showNotification(`Failed to load all sprites`, 'error');
}
};
const createSpriteFromFile = (file: File, index: number): Promise<Sprite> => {
return new Promise((resolve, reject) => {
// Create a URL for the file
const objectUrl = URL.createObjectURL(file);
const img = new Image();
// Set up event handlers
img.onload = () => {
// Verify the image has loaded properly
if (img.width === 0 || img.height === 0) {
console.error('Image loaded with invalid dimensions:', file.name, img.width, img.height);
URL.revokeObjectURL(objectUrl);
reject(new Error(`Image has invalid dimensions: ${file.name}`));
return;
}
// Create the sprite object
const sprite: Sprite = {
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,
};
// Keep the objectUrl reference and don't revoke it yet
// The image is still needed for rendering later
// URL.revokeObjectURL(objectUrl); - Don't do this anymore
resolve(sprite);
};
img.onerror = error => {
console.error('Error loading image:', file.name, error);
URL.revokeObjectURL(objectUrl);
reject(new Error(`Failed to load image: ${file.name}`));
};
// Set the source to the object URL
img.src = objectUrl;
});
};
</script>

View File

@ -10,7 +10,7 @@
</template>
<script setup lang="ts">
import type { Sprite } from '../composables/useSpritesheetStore';
import { useSpritesheetStore, type Sprite } from '../composables/useSpritesheetStore';
defineProps<{
sprites: Sprite[];
@ -20,7 +20,10 @@
spriteClicked: [id: string];
}>();
const store = useSpritesheetStore();
// Use the utility function for truncating text with a custom length
const truncateName = (name: string) => {
return name.length > 10 ? `${name.substring(0, 10)}...` : name;
return store.truncateText(name, 10);
};
</script>

View File

@ -69,7 +69,8 @@
}
};
// Use the utility function for truncating text
const truncateName = (name: string) => {
return name.length > 15 ? `${name.substring(0, 15)}...` : name;
return store.truncateText(name);
};
</script>

View File

@ -1,6 +1,6 @@
import { sprites, canvas, ctx, cellSize, columns, draggedSprite, dragOffset, isShiftPressed, isModalOpen, isSettingsModalOpen, isSpritesModalOpen, isHelpModalOpen, zoomLevel, previewBorder, animation, notification, currentSpriteOffset, spriteOffsets } from '@/application/state';
import { getSpriteOffset, showNotification } from '@/application/utilities';
import { getSpriteOffset, showNotification, createSpriteFromFile, processImageFiles, truncateText } from '@/application/utilities';
import { addSprites, updateCellSize, autoArrangeSprites, highlightSprite, clearAllSprites, applyOffsetsToMainView } from '@/application/spriteOperations';
@ -36,6 +36,9 @@ export function useSpritesheetStore() {
// Utils
getSpriteOffset,
showNotification,
createSpriteFromFile,
processImageFiles,
truncateText,
// Sprite operations
addSprites,