More improvements
This commit is contained in:
parent
d6262903bf
commit
1a09a8cd1f
@ -2,8 +2,6 @@
|
||||
<header class="flex items-center justify-between bg-gray-800 p-3 shadow-md sticky top-0 z-40">
|
||||
<!-- Breadcrumb navigation -->
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- <span class="text-gray-400">Dashboard</span>-->
|
||||
<!-- <i class="fas fa-chevron-right text-xs text-gray-500"></i>-->
|
||||
<span class="text-gray-200">Spritesheet editor</span>
|
||||
</div>
|
||||
|
||||
@ -22,6 +20,13 @@
|
||||
<i class="fas fa-search-minus"></i>
|
||||
</button>
|
||||
|
||||
<!-- Download button -->
|
||||
<tooltip text="Download Spritesheet" position="bottom">
|
||||
<button @click="downloadSpritesheet" :disabled="sprites.length === 0" class="p-2 bg-gray-700 border border-gray-600 rounded hover:border-blue-500 transition-colors disabled:opacity-60 disabled:cursor-not-allowed">
|
||||
<i class="fas fa-download"></i>
|
||||
</button>
|
||||
</tooltip>
|
||||
|
||||
<!-- Help button -->
|
||||
<tooltip text="Keyboard Shortcuts" position="bottom">
|
||||
<button @click="openHelpModal" class="p-2 bg-gray-700 border border-gray-600 rounded hover:border-blue-500 transition-colors">
|
||||
@ -39,6 +44,7 @@
|
||||
|
||||
const store = useSpritesheetStore();
|
||||
const zoomLevel = computed(() => store.zoomLevel.value);
|
||||
const sprites = computed(() => store.sprites.value);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'toggleHelp'): void;
|
||||
@ -49,5 +55,5 @@
|
||||
};
|
||||
|
||||
// Expose store methods directly
|
||||
const { zoomIn, zoomOut } = store;
|
||||
const { zoomIn, zoomOut, downloadSpritesheet } = store;
|
||||
</script>
|
||||
|
@ -32,7 +32,7 @@
|
||||
</tooltip>
|
||||
|
||||
<!-- Settings -->
|
||||
<tooltip text="Settings" position="right">
|
||||
<tooltip text="Settings" position="bottom">
|
||||
<button class="w-10 h-10 rounded-lg flex items-center justify-center text-gray-200 hover:bg-gray-700 hover:text-blue-500 transition-colors" :class="{ 'bg-gray-700 text-blue-500': activeSection === 'settings' }" @click="openSettingsModal">
|
||||
<i class="fas fa-cog"></i>
|
||||
</button>
|
||||
@ -41,7 +41,7 @@
|
||||
|
||||
<!-- Help Button at Bottom -->
|
||||
<div class="mt-auto">
|
||||
<tooltip text="Help & Support" position="right">
|
||||
<tooltip text="Help & Support" position="bottom">
|
||||
<button class="w-10 h-10 rounded-lg flex items-center justify-center text-gray-200 hover:bg-gray-700 hover:text-blue-500 transition-colors" @click="showHelp">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
</button>
|
||||
|
@ -3,15 +3,15 @@
|
||||
<div @mouseenter="showTooltip" @mouseleave="hideTooltip">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div v-show="isVisible" class="tooltip absolute z-50 px-2 py-1 text-xs font-medium text-white bg-gray-800 rounded shadow-lg whitespace-nowrap" :class="[positionClass]" :style="customStyle">
|
||||
<div v-show="isVisible" ref="tooltipEl" class="tooltip fixed z-50 px-2 py-1 text-xs font-medium text-white bg-gray-800 rounded shadow-lg whitespace-nowrap" :style="tooltipStyle">
|
||||
{{ text }}
|
||||
<div class="absolute w-2 h-2 bg-gray-800 transform rotate-45" :class="[arrowPositionClass]"></div>
|
||||
<div class="absolute w-2 h-2 bg-gray-800 transform rotate-45" :style="arrowStyle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
text: string;
|
||||
@ -20,49 +20,122 @@
|
||||
}>();
|
||||
|
||||
const isVisible = ref(false);
|
||||
const customStyle = ref({});
|
||||
|
||||
// Default position is top if not specified
|
||||
const tooltipEl = ref<HTMLElement | null>(null);
|
||||
const position = computed(() => props.position || 'top');
|
||||
const offset = computed(() => props.offset || 8);
|
||||
|
||||
// Compute position classes based on the position prop
|
||||
const positionClass = computed(() => {
|
||||
switch (position.value) {
|
||||
case 'top':
|
||||
return 'bottom-full mb-2';
|
||||
case 'right':
|
||||
return 'left-full ml-2';
|
||||
case 'bottom':
|
||||
return 'top-full mt-2';
|
||||
case 'left':
|
||||
return 'right-full mr-2';
|
||||
default:
|
||||
return 'bottom-full mb-2';
|
||||
}
|
||||
// Dynamic styles for tooltip and arrow
|
||||
const tooltipStyle = ref({
|
||||
left: '0px',
|
||||
top: '0px',
|
||||
});
|
||||
|
||||
// Compute arrow position classes based on the position prop
|
||||
const arrowPositionClass = computed(() => {
|
||||
switch (position.value) {
|
||||
case 'top':
|
||||
return 'bottom-[-4px] left-1/2 -translate-x-1/2';
|
||||
case 'right':
|
||||
return 'left-[-4px] top-1/2 -translate-y-1/2';
|
||||
case 'bottom':
|
||||
return 'top-[-4px] left-1/2 -translate-x-1/2';
|
||||
case 'left':
|
||||
return 'right-[-4px] top-1/2 -translate-y-1/2';
|
||||
default:
|
||||
return 'bottom-[-4px] left-1/2 -translate-x-1/2';
|
||||
}
|
||||
const arrowStyle = ref({
|
||||
left: '50%',
|
||||
top: '100%',
|
||||
transform: 'translate(-50%, -50%) rotate(45deg)',
|
||||
});
|
||||
|
||||
const showTooltip = () => {
|
||||
const updatePosition = (event: MouseEvent) => {
|
||||
if (!isVisible.value || !tooltipEl.value) return;
|
||||
|
||||
const tooltip = tooltipEl.value;
|
||||
const tooltipRect = tooltip.getBoundingClientRect();
|
||||
const padding = 10; // Padding from screen edges
|
||||
|
||||
let left = event.clientX;
|
||||
let top = event.clientY;
|
||||
|
||||
// Calculate positions based on available space
|
||||
const spaceAbove = top;
|
||||
const spaceBelow = window.innerHeight - top;
|
||||
const spaceLeft = left;
|
||||
const spaceRight = window.innerWidth - left;
|
||||
|
||||
// Determine best position
|
||||
let finalPosition = position.value;
|
||||
if (finalPosition === 'top' && spaceAbove < tooltipRect.height + padding) {
|
||||
finalPosition = spaceBelow > tooltipRect.height + padding ? 'bottom' : 'right';
|
||||
} else if (finalPosition === 'bottom' && spaceBelow < tooltipRect.height + padding) {
|
||||
finalPosition = spaceAbove > tooltipRect.height + padding ? 'top' : 'right';
|
||||
} else if (finalPosition === 'left' && spaceLeft < tooltipRect.width + padding) {
|
||||
finalPosition = spaceRight > tooltipRect.width + padding ? 'right' : 'top';
|
||||
} else if (finalPosition === 'right' && spaceRight < tooltipRect.width + padding) {
|
||||
finalPosition = spaceLeft > tooltipRect.width + padding ? 'left' : 'top';
|
||||
}
|
||||
|
||||
// Position tooltip based on final position
|
||||
switch (finalPosition) {
|
||||
case 'top':
|
||||
left -= tooltipRect.width / 2;
|
||||
top -= tooltipRect.height + offset.value;
|
||||
arrowStyle.value = {
|
||||
left: '50%',
|
||||
top: '100%',
|
||||
transform: 'translate(-50%, -50%) rotate(45deg)',
|
||||
};
|
||||
break;
|
||||
case 'bottom':
|
||||
left -= tooltipRect.width / 2;
|
||||
top += offset.value;
|
||||
arrowStyle.value = {
|
||||
left: '50%',
|
||||
top: '0',
|
||||
transform: 'translate(-50%, -50%) rotate(45deg)',
|
||||
};
|
||||
break;
|
||||
case 'left':
|
||||
left -= tooltipRect.width + offset.value;
|
||||
top -= tooltipRect.height / 2;
|
||||
arrowStyle.value = {
|
||||
left: '100%',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -50%) rotate(45deg)',
|
||||
};
|
||||
break;
|
||||
case 'right':
|
||||
left += offset.value;
|
||||
top -= tooltipRect.height / 2;
|
||||
arrowStyle.value = {
|
||||
left: '0',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -50%) rotate(45deg)',
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure tooltip stays within screen bounds
|
||||
left = Math.max(padding, Math.min(left, window.innerWidth - tooltipRect.width - padding));
|
||||
top = Math.max(padding, Math.min(top, window.innerHeight - tooltipRect.height - padding));
|
||||
|
||||
tooltipStyle.value = {
|
||||
left: `${left}px`,
|
||||
top: `${top}px`,
|
||||
};
|
||||
};
|
||||
|
||||
const showTooltip = (event: MouseEvent) => {
|
||||
isVisible.value = true;
|
||||
// Wait for next tick to ensure tooltip is rendered
|
||||
setTimeout(() => updatePosition(event), 0);
|
||||
};
|
||||
|
||||
const hideTooltip = () => {
|
||||
isVisible.value = false;
|
||||
};
|
||||
|
||||
// Track mouse movement when tooltip is visible
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
if (isVisible.value) {
|
||||
updatePosition(event);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('mousemove', handleMouseMove);
|
||||
});
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user