fix: add ContextMenu component, fix TS errors in ConnectionTree
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 5s
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 5s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c1f4875dfd
commit
b486679a49
61
src/components/common/ContextMenu.vue
Normal file
61
src/components/common/ContextMenu.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<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>
|
||||||
@ -101,7 +101,15 @@ import { invoke } from "@tauri-apps/api/core";
|
|||||||
import { useConnectionStore, type Connection, type Group } from "@/stores/connection.store";
|
import { useConnectionStore, type Connection, type Group } from "@/stores/connection.store";
|
||||||
import { useSessionStore } from "@/stores/session.store";
|
import { useSessionStore } from "@/stores/session.store";
|
||||||
import ContextMenu from "@/components/common/ContextMenu.vue";
|
import ContextMenu from "@/components/common/ContextMenu.vue";
|
||||||
import type { ContextMenuItem } from "@/components/common/ContextMenu.vue";
|
|
||||||
|
interface ContextMenuItem {
|
||||||
|
label?: string;
|
||||||
|
icon?: string;
|
||||||
|
action?: () => void;
|
||||||
|
separator?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
danger?: boolean;
|
||||||
|
}
|
||||||
import ConnectionEditDialog from "@/components/connections/ConnectionEditDialog.vue";
|
import ConnectionEditDialog from "@/components/connections/ConnectionEditDialog.vue";
|
||||||
|
|
||||||
const connectionStore = useConnectionStore();
|
const connectionStore = useConnectionStore();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user