wraith/src/components/common/ContextMenu.vue
Vantz Stockwell b486679a49
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 5s
fix: add ContextMenu component, fix TS errors in ConnectionTree
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:19:52 -04:00

62 lines
1.7 KiB
Vue

<script setup lang="ts">
import { ref } from "vue";
export interface ContextMenuItem {
label?: string;
icon?: string;
action?: () => void;
separator?: boolean;
disabled?: boolean;
danger?: boolean;
}
const visible = ref(false);
const posX = ref(0);
const posY = ref(0);
const menuItems = ref<ContextMenuItem[]>([]);
function open(event: MouseEvent, items: ContextMenuItem[]) {
posX.value = event.clientX;
posY.value = event.clientY;
menuItems.value = items;
visible.value = true;
}
function close() {
visible.value = false;
}
function handleClick(item: ContextMenuItem) {
if (item.disabled || !item.action) return;
item.action();
close();
}
defineExpose({ open });
</script>
<template>
<Teleport to="body">
<div v-if="visible" class="fixed inset-0 z-50" @click="close" @contextmenu.prevent="close">
<div
class="absolute bg-zinc-800 border border-zinc-700 rounded-lg shadow-xl py-1 min-w-[160px] z-50"
:style="{ left: `${posX}px`, top: `${posY}px` }"
>
<template v-for="(item, i) in menuItems" :key="i">
<div v-if="item.separator" class="border-t border-zinc-700 my-1" />
<button
v-else
class="w-full text-left px-3 py-1.5 text-sm hover:bg-zinc-700 disabled:opacity-40 disabled:cursor-not-allowed flex items-center gap-2"
:class="item.danger ? 'text-red-400 hover:text-red-300' : 'text-zinc-200'"
:disabled="item.disabled"
@click="handleClick(item)"
>
<span v-if="item.icon" class="w-4 h-4 flex-shrink-0" v-html="item.icon" />
{{ item.label }}
</button>
</template>
</div>
</div>
</Teleport>
</template>