[FEAT] negative spacing in JSON export logic, show cell size
This commit is contained in:
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
## [1.6.0] - 2025-11-18
|
## [1.6.0] - 2025-11-18
|
||||||
- Improved animation preview modal
|
- Improved animation preview modal
|
||||||
- Add toggle for negative spacing in cells
|
- Add toggle for negative spacing in cells
|
||||||
|
- Show cell size
|
||||||
|
|
||||||
## [1.5.0] - 2025-11-17
|
## [1.5.0] - 2025-11-17
|
||||||
- Show offset values in sprite cells and in preview modal
|
- Show offset values in sprite cells and in preview modal
|
||||||
|
|||||||
20
src/App.vue
20
src/App.vue
@@ -51,6 +51,11 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center space-x-1">
|
||||||
|
<span class="text-gray-700 dark:text-gray-200 font-medium">Cell size:</span>
|
||||||
|
<span class="text-gray-600 dark:text-gray-300">{{ cellSize.width }} × {{ cellSize.height }}px</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Add mass position buttons -->
|
<!-- Add mass position buttons -->
|
||||||
<div class="flex flex-wrap items-center justify-center gap-2">
|
<div class="flex flex-wrap items-center justify-center gap-2">
|
||||||
<button @click="alignSprites('left')" class="p-3 sm:p-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-100 rounded-lg transition-colors" title="Align Left" data-rybbit-event="align-left">
|
<button @click="alignSprites('left')" class="p-3 sm:p-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-100 rounded-lg transition-colors" title="Align Left" data-rybbit-event="align-left">
|
||||||
@@ -135,7 +140,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, toRef } from 'vue';
|
import { ref, onMounted, toRef, computed } from 'vue';
|
||||||
import FileUploader from './components/FileUploader.vue';
|
import FileUploader from './components/FileUploader.vue';
|
||||||
import SpriteCanvas from './components/SpriteCanvas.vue';
|
import SpriteCanvas from './components/SpriteCanvas.vue';
|
||||||
import Modal from './components/utilities/Modal.vue';
|
import Modal from './components/utilities/Modal.vue';
|
||||||
@@ -145,15 +150,26 @@
|
|||||||
import SpritesheetSplitter from './components/SpritesheetSplitter.vue';
|
import SpritesheetSplitter from './components/SpritesheetSplitter.vue';
|
||||||
import GifFpsModal from './components/GifFpsModal.vue';
|
import GifFpsModal from './components/GifFpsModal.vue';
|
||||||
import DarkModeToggle from './components/utilities/DarkModeToggle.vue';
|
import DarkModeToggle from './components/utilities/DarkModeToggle.vue';
|
||||||
import { useSprites } from './composables/useSprites';
|
import { useSprites, getMaxDimensions } from './composables/useSprites';
|
||||||
import { useExport } from './composables/useExport';
|
import { useExport } from './composables/useExport';
|
||||||
import { useSettingsStore } from './stores/useSettingsStore';
|
import { useSettingsStore } from './stores/useSettingsStore';
|
||||||
|
import { calculateNegativeSpacing } from './composables/useNegativeSpacing';
|
||||||
import type { SpriteFile } from './types/sprites';
|
import type { SpriteFile } from './types/sprites';
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const { sprites, columns, updateSpritePosition, updateSpriteCell, removeSprite, replaceSprite, addSprite, addSpriteWithResize, processImageFiles, alignSprites } = useSprites();
|
const { sprites, columns, updateSpritePosition, updateSpriteCell, removeSprite, replaceSprite, addSprite, addSpriteWithResize, processImageFiles, alignSprites } = useSprites();
|
||||||
|
|
||||||
const { downloadSpritesheet, exportSpritesheetJSON, importSpritesheetJSON, downloadAsGif, downloadAsZip } = useExport(sprites, columns, toRef(settingsStore, 'negativeSpacingEnabled'));
|
const { downloadSpritesheet, exportSpritesheetJSON, importSpritesheetJSON, downloadAsGif, downloadAsZip } = useExport(sprites, columns, toRef(settingsStore, 'negativeSpacingEnabled'));
|
||||||
|
|
||||||
|
const cellSize = computed(() => {
|
||||||
|
if (!sprites.value.length) return { width: 0, height: 0 };
|
||||||
|
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
||||||
|
const negativeSpacing = calculateNegativeSpacing(sprites.value, settingsStore.negativeSpacingEnabled);
|
||||||
|
return {
|
||||||
|
width: maxWidth + negativeSpacing,
|
||||||
|
height: maxHeight + negativeSpacing,
|
||||||
|
};
|
||||||
|
});
|
||||||
const isPreviewModalOpen = ref(false);
|
const isPreviewModalOpen = ref(false);
|
||||||
const isHelpModalOpen = ref(false);
|
const isHelpModalOpen = ref(false);
|
||||||
const isFeedbackModalOpen = ref(false);
|
const isFeedbackModalOpen = ref(false);
|
||||||
|
|||||||
@@ -68,7 +68,11 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>, negative
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const jsonData = { columns: columns.value, sprites: spritesData.filter(Boolean) };
|
const jsonData = {
|
||||||
|
columns: columns.value,
|
||||||
|
negativeSpacingEnabled: negativeSpacingEnabled.value,
|
||||||
|
sprites: spritesData.filter(Boolean),
|
||||||
|
};
|
||||||
const jsonString = JSON.stringify(jsonData, null, 2);
|
const jsonString = JSON.stringify(jsonData, null, 2);
|
||||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
@@ -86,6 +90,7 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>, negative
|
|||||||
if (!jsonData.sprites || !Array.isArray(jsonData.sprites)) throw new Error('Invalid JSON format: missing sprites array');
|
if (!jsonData.sprites || !Array.isArray(jsonData.sprites)) throw new Error('Invalid JSON format: missing sprites array');
|
||||||
|
|
||||||
if (jsonData.columns && typeof jsonData.columns === 'number') columns.value = jsonData.columns;
|
if (jsonData.columns && typeof jsonData.columns === 'number') columns.value = jsonData.columns;
|
||||||
|
if (typeof jsonData.negativeSpacingEnabled === 'boolean') negativeSpacingEnabled.value = jsonData.negativeSpacingEnabled;
|
||||||
|
|
||||||
// revoke existing blob urls
|
// revoke existing blob urls
|
||||||
if (sprites.value.length) {
|
if (sprites.value.length) {
|
||||||
|
|||||||
Reference in New Issue
Block a user