From 1f9fc4d5bbcfd56da4f2c5a27a790656b92fcb56 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 1 Jan 2026 17:14:21 +0100 Subject: [PATCH] [FEAT] add grid metrics --- src/components/SpriteCanvas.vue | 63 ++++------ src/components/SpritePreview.vue | 64 +++++----- src/composables/useBackgroundStyles.ts | 113 +++++++++++++++++ src/composables/useDragSprite.ts | 75 ++++------- src/composables/useGridMetrics.ts | 165 +++++++++++++++++++++++++ 5 files changed, 352 insertions(+), 128 deletions(-) create mode 100644 src/composables/useBackgroundStyles.ts create mode 100644 src/composables/useGridMetrics.ts diff --git a/src/components/SpriteCanvas.vue b/src/components/SpriteCanvas.vue index 6c24b80..9cdd509 100644 --- a/src/components/SpriteCanvas.vue +++ b/src/components/SpriteCanvas.vue @@ -204,6 +204,8 @@ import type { Sprite } from '@/types/sprites'; import { useDragSprite } from '@/composables/useDragSprite'; import { useFileDrop } from '@/composables/useFileDrop'; + import { useGridMetrics } from '@/composables/useGridMetrics'; + import { useBackgroundStyles } from '@/composables/useBackgroundStyles'; import type { Layer } from '@/types/sprites'; @@ -315,8 +317,16 @@ } ); - // Grid metrics - const gridMetrics = computed(() => calculateMaxDimensions()); + // Use the new useGridMetrics composable for consistent calculations + const { gridMetrics: gridMetricsRef, getCellPosition: getCellPositionHelper } = useGridMetrics({ + layers: toRef(props, 'layers'), + negativeSpacingEnabled: toRef(settingsStore, 'negativeSpacingEnabled'), + manualCellSizeEnabled: toRef(settingsStore, 'manualCellSizeEnabled'), + manualCellWidth: toRef(settingsStore, 'manualCellWidth'), + manualCellHeight: toRef(settingsStore, 'manualCellHeight'), + }); + + const gridMetrics = gridMetricsRef; const totalCells = computed(() => { // Use all layers regardless of visibility to keep canvas size stable @@ -335,47 +345,20 @@ }); const getCellPosition = (index: number) => { - const col = index % props.columns; - const row = Math.floor(index / props.columns); - return { - x: Math.round(col * gridMetrics.value.maxWidth), - y: Math.round(row * gridMetrics.value.maxHeight), - }; + return getCellPositionHelper(index, props.columns, gridMetrics.value); }; - const getCellBackground = () => { - const bg = settingsStore.backgroundColor; - if (bg === 'transparent') { - return 'transparent'; - } - return bg; - }; + // Use the new useBackgroundStyles composable for consistent background styling + const { backgroundColor: cellBackgroundColor, backgroundImage: cellBackgroundImage, backgroundSize: cellBackgroundSize, backgroundPosition: cellBackgroundPosition } = useBackgroundStyles({ + backgroundColor: toRef(settingsStore, 'backgroundColor'), + checkerboardEnabled: toRef(settingsStore, 'checkerboardEnabled'), + darkMode: toRef(settingsStore, 'darkMode'), + }); - const getCellBackgroundImage = () => { - const bg = settingsStore.backgroundColor; - if (bg === 'transparent' && settingsStore.checkerboardEnabled) { - // Checkerboard pattern for transparent backgrounds (dark mode friendly) - const color = settingsStore.darkMode ? '#4b5563' : '#d1d5db'; - return `linear-gradient(45deg, ${color} 25%, transparent 25%), linear-gradient(-45deg, ${color} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${color} 75%), linear-gradient(-45deg, transparent 75%, ${color} 75%)`; - } - return 'none'; - }; - - const getCellBackgroundSize = () => { - const bg = settingsStore.backgroundColor; - if (bg === 'transparent') { - return '20px 20px'; - } - return 'auto'; - }; - - const getCellBackgroundPosition = () => { - const bg = settingsStore.backgroundColor; - if (bg === 'transparent') { - return '0 0, 0 10px, 10px -10px, -10px 0px'; - } - return '0 0'; - }; + const getCellBackground = () => cellBackgroundColor.value; + const getCellBackgroundImage = () => cellBackgroundImage.value; + const getCellBackgroundSize = () => cellBackgroundSize.value; + const getCellBackgroundPosition = () => cellBackgroundPosition.value; const startDrag = (event: MouseEvent) => { // If the click originated from an interactive element (button, link, input), ignore drag handling diff --git a/src/components/SpritePreview.vue b/src/components/SpritePreview.vue index 6497f24..240244d 100644 --- a/src/components/SpritePreview.vue +++ b/src/components/SpritePreview.vue @@ -73,9 +73,9 @@ width: `${cellDimensions.cellWidth}px`, height: `${cellDimensions.cellHeight}px`, backgroundColor: settingsStore.backgroundColor === 'transparent' ? '#f9fafb' : settingsStore.backgroundColor, - backgroundImage: getPreviewBackgroundImage(), - backgroundSize: settingsStore.backgroundColor === 'transparent' ? '20px 20px' : 'auto', - backgroundPosition: settingsStore.backgroundColor === 'transparent' ? '0 0, 0 10px, 10px -10px, -10px 0px' : '0 0', + backgroundImage: previewBackgroundImage, + backgroundSize: previewBackgroundSize, + backgroundPosition: previewBackgroundPosition, border: `1px solid ${settingsStore.darkMode ? '#4b5563' : '#e5e7eb'}`, }" @dragover.prevent="onDragOver" @@ -302,13 +302,13 @@