From 9a2bf6b2db6755b20481e9e1aa1836958f04a78a Mon Sep 17 00:00:00 2001 From: root Date: Sun, 23 Nov 2025 03:40:26 +0100 Subject: [PATCH] [FEAT] UX enhancements --- public/CHANGELOG.md | 4 ++ src/App.vue | 60 +++++++----------- src/components/SpriteCanvas.vue | 17 +++-- src/components/SpritePreview.vue | 104 ++++++++++++++++++++++++------- src/composables/useLayers.ts | 18 ++++-- 5 files changed, 135 insertions(+), 68 deletions(-) diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md index fdb245f..567cb0b 100644 --- a/public/CHANGELOG.md +++ b/public/CHANGELOG.md @@ -1,5 +1,9 @@ All notable changes to this project will be documented in this file. +## [1.8.0] - 2025-11-23 +- Fix context menu location +- You can now reposition all sprites in current frame + ## [1.7.0] - 2025-11-22 - Add layer support - Add background color picker diff --git a/src/App.vue b/src/App.vue index 2c2e40a..ddeadbe 100644 --- a/src/App.vue +++ b/src/App.vue @@ -57,7 +57,6 @@

Drag and drop images or import from JSON

-
@@ -250,24 +249,14 @@
- +
- + @@ -311,7 +300,7 @@ import type { SpriteFile } from './types/sprites'; const settingsStore = useSettingsStore(); - const { layers, visibleLayers, activeLayer, activeLayerId, columns, updateSpritePosition, updateSpriteCell, removeSprite, replaceSprite, addSprite, addSpriteWithResize, processImageFiles, alignSprites, addLayer, removeLayer, moveLayer } = useLayers(); + const { layers, visibleLayers, activeLayer, activeLayerId, columns, updateSpritePosition, updateSpriteInLayer, updateSpriteCell, removeSprite, replaceSprite, addSprite, processImageFiles, alignSprites, addLayer, removeLayer, moveLayer } = useLayers(); const { downloadSpritesheet, exportSpritesheetJSON, importSpritesheetJSON, downloadAsGif, downloadAsZip } = useExportLayers( layers, @@ -324,27 +313,27 @@ toRef(settingsStore, 'manualCellHeight') ); - const cellSize = computed(() => { - if (!layers.value.length) return { width: 0, height: 0 }; + const getCellSize = () => { + if (!visibleLayers.value.length) return { width: 0, height: 0 }; - // If manual cell size is enabled, use the manual values if (settingsStore.manualCellSizeEnabled) { return { width: settingsStore.manualCellWidth, height: settingsStore.manualCellHeight }; } - // Otherwise, calculate based on max dimensions const { maxWidth, maxHeight } = getMaxDimensionsAcrossLayers(visibleLayers.value); const allSprites = visibleLayers.value.flatMap(l => l.sprites); const negativeSpacing = calculateNegativeSpacing(allSprites, settingsStore.negativeSpacingEnabled); return { width: maxWidth + negativeSpacing, height: maxHeight + negativeSpacing }; - }); + }; + + const cellSize = computed(getCellSize); const isPreviewModalOpen = ref(false); const isHelpModalOpen = ref(false); const isFeedbackModalOpen = ref(false); const isSpritesheetSplitterOpen = ref(false); const isGifFpsModalOpen = ref(false); - const jsonFileInput = ref(null); const uploadInput = ref(null); + const jsonFileInput = ref(null); const spritesheetImageUrl = ref(''); const spritesheetImageFile = ref(null); const showFeedbackPopup = ref(false); @@ -356,12 +345,7 @@ const jsonFile = files.find(file => file.type === 'application/json' || file.name.endsWith('.json')); if (jsonFile) { - try { - await importSpritesheetJSON(jsonFile); - } catch (error) { - console.error('Error importing JSON:', error); - alert('Failed to import JSON file. Please check the file format.'); - } + await handleJSONImport(jsonFile); return; } @@ -387,6 +371,15 @@ processImageFiles(files); }; + const handleJSONImport = async (jsonFile: File) => { + try { + await importSpritesheetJSON(jsonFile); + } catch (error) { + console.error('Error importing JSON:', error); + alert('Failed to import JSON file. Please check the file format.'); + } + }; + const openPreviewModal = () => { if (!visibleLayers.value.some(l => l.sprites.length > 0)) { alert('Please upload or import sprites to preview an animation.'); @@ -447,14 +440,8 @@ const handleJSONFileChange = async (event: Event) => { const input = event.target as HTMLInputElement; if (input.files && input.files.length > 0) { - const jsonFile = input.files[0]; - try { - await importSpritesheetJSON(jsonFile); - } catch (error) { - console.error('Error importing JSON:', error); - alert('Failed to import JSON file. Please check the file format.'); - } - if (jsonFileInput.value) jsonFileInput.value.value = ''; + await handleJSONImport(input.files[0]); + input.value = ''; } }; @@ -483,9 +470,8 @@ const handleUploadChange = async (event: Event) => { const input = event.target as HTMLInputElement; if (input.files && input.files.length > 0) { - const files = Array.from(input.files); - await handleSpritesUpload(files); - if (uploadInput.value) uploadInput.value.value = ''; + await handleSpritesUpload(Array.from(input.files)); + input.value = ''; } }; diff --git a/src/components/SpriteCanvas.vue b/src/components/SpriteCanvas.vue index 9cc0503..e10d709 100644 --- a/src/components/SpriteCanvas.vue +++ b/src/components/SpriteCanvas.vue @@ -1,5 +1,5 @@