63 lines
1.4 KiB
Vue
63 lines
1.4 KiB
Vue
<script setup>
|
|
import { inject, ref, onMounted, computed } from "vue";
|
|
|
|
defineOptions({ name: "ContextMenuContent" });
|
|
|
|
const { showMenu, position, closeMenu } = inject("context-menu");
|
|
const menuRef = ref(null);
|
|
|
|
const adjustedPosition = computed(() => {
|
|
if (!menuRef.value) return { top: position.value.y, left: position.value.x };
|
|
|
|
const menu = menuRef.value;
|
|
const menuRect = menu.getBoundingClientRect();
|
|
const windowHeight = window.innerHeight;
|
|
const windowWidth = window.innerWidth;
|
|
|
|
let top = position.value.y;
|
|
let left = position.value.x;
|
|
|
|
// Adjust vertical position
|
|
if (top + menuRect.height > windowHeight) {
|
|
top = Math.max(0, windowHeight - menuRect.height);
|
|
}
|
|
|
|
// Adjust horizontal position
|
|
if (left + menuRect.width > windowWidth) {
|
|
left = Math.max(0, windowWidth - menuRect.width);
|
|
}
|
|
|
|
return { top, left };
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Transition name="fade">
|
|
<div
|
|
v-if="showMenu"
|
|
ref="menuRef"
|
|
class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
|
|
:style="{
|
|
position: 'fixed',
|
|
top: `${adjustedPosition.top}px`,
|
|
left: `${adjustedPosition.left}px`,
|
|
}"
|
|
>
|
|
<slot />
|
|
</div>
|
|
</Transition>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.fade-enter-active,
|
|
.fade-leave-active {
|
|
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
}
|
|
|
|
.fade-enter-from,
|
|
.fade-leave-to {
|
|
opacity: 0;
|
|
transform: scale(0.95);
|
|
}
|
|
</style>
|