UX enhancements
This commit is contained in:
@@ -78,7 +78,7 @@
|
|||||||
import Breadcrumbs from './components/Breadcrumbs.vue';
|
import Breadcrumbs from './components/Breadcrumbs.vue';
|
||||||
import { useLayers } from './composables/useLayers';
|
import { useLayers } from './composables/useLayers';
|
||||||
|
|
||||||
const { layers } = useLayers();
|
const { layers, hasSprites } = useLayers();
|
||||||
|
|
||||||
const isHelpModalOpen = ref(false);
|
const isHelpModalOpen = ref(false);
|
||||||
const isFeedbackModalOpen = ref(false);
|
const isFeedbackModalOpen = ref(false);
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
/* Dark mode transition */
|
/* Dark mode transition */
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
transition:
|
|
||||||
background-color 0.3s ease,
|
|
||||||
color 0.3s ease;
|
|
||||||
-webkit-tap-highlight-color: transparent; /* Remove tap highlight on mobile */
|
-webkit-tap-highlight-color: transparent; /* Remove tap highlight on mobile */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="showContextMenu" class="fixed bg-white dark:bg-gray-800 border-2 border-gray-300 dark:border-gray-600 rounded-xl shadow-2xl z-50 py-2 min-w-[200px] overflow-hidden" :style="{ left: contextMenuX + 'px', top: contextMenuY + 'px' }">
|
<div v-if="showContextMenu" @click.stop class="fixed bg-white dark:bg-gray-800 border-2 border-gray-300 dark:border-gray-600 rounded-xl shadow-2xl z-50 py-2 min-w-[200px] overflow-hidden" :style="{ left: contextMenuX + 'px', top: contextMenuY + 'px' }">
|
||||||
<button @click="addSprite" class="w-full px-5 py-3 text-left hover:bg-blue-50 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-3 transition-colors font-medium">
|
<button @click="addSprite" class="w-full px-5 py-3 text-left hover:bg-blue-50 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-3 transition-colors font-medium">
|
||||||
<i class="fas fa-plus text-blue-600 dark:text-blue-400"></i>
|
<i class="fas fa-plus text-blue-600 dark:text-blue-400"></i>
|
||||||
<span>Add Sprite</span>
|
<span>Add Sprite</span>
|
||||||
@@ -448,6 +448,11 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const startDrag = (event: MouseEvent) => {
|
const startDrag = (event: MouseEvent) => {
|
||||||
|
// If the click originated from an interactive element (button, link, input), ignore drag handling
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
if (target && target.closest('button, a, input, select, textarea')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!gridContainerRef.value) return;
|
if (!gridContainerRef.value) return;
|
||||||
|
|
||||||
// Hide context menu if open
|
// Hide context menu if open
|
||||||
@@ -476,8 +481,22 @@
|
|||||||
dragStart(event);
|
dragStart(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pendingDrag = ref(false);
|
||||||
|
const latestEvent = ref<MouseEvent | null>(null);
|
||||||
|
|
||||||
const drag = (event: MouseEvent) => {
|
const drag = (event: MouseEvent) => {
|
||||||
dragMove(event);
|
// Store the latest event and schedule a single animation frame update
|
||||||
|
latestEvent.value = event;
|
||||||
|
if (!pendingDrag.value) {
|
||||||
|
pendingDrag.value = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (latestEvent.value) {
|
||||||
|
dragMove(latestEvent.value);
|
||||||
|
}
|
||||||
|
pendingDrag.value = false;
|
||||||
|
latestEvent.value = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeSprite = () => {
|
const removeSprite = () => {
|
||||||
@@ -534,12 +553,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// Hide context menu when clicking elsewhere
|
document.addEventListener('mouseup', stopDrag);
|
||||||
document.addEventListener('click', hideContextMenu);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener('click', hideContextMenu);
|
document.removeEventListener('mouseup', stopDrag);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Watch for background color changes
|
// Watch for background color changes
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ export const useLayers = () => {
|
|||||||
|
|
||||||
const visibleLayers = computed(() => layers.value.filter(l => l.visible));
|
const visibleLayers = computed(() => layers.value.filter(l => l.visible));
|
||||||
|
|
||||||
|
const hasSprites = computed(() => layers.value.some(l => l.sprites.length > 0));
|
||||||
|
|
||||||
const updateSpritePosition = (id: string, x: number, y: number) => {
|
const updateSpritePosition = (id: string, x: number, y: number) => {
|
||||||
const l = activeLayer.value;
|
const l = activeLayer.value;
|
||||||
if (!l) return;
|
if (!l) return;
|
||||||
@@ -238,6 +240,7 @@ export const useLayers = () => {
|
|||||||
addLayer,
|
addLayer,
|
||||||
removeLayer,
|
removeLayer,
|
||||||
moveLayer,
|
moveLayer,
|
||||||
|
hasSprites,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user