This commit is contained in:
2026-07-30 11:14:33 +02:00
parent 759bc1dc15
commit 1bb00e1edf
6 changed files with 116 additions and 11 deletions
+33
View File
@@ -0,0 +1,33 @@
<script lang="ts" setup>
import {computed} from 'vue'
import {useContextMenu} from '@/composables/useContextMenu'
const {isOpen, position, items, closeContextMenu} = useContextMenu()
// Cible virtuelle pour positionner Vuetify v-menu à la position X, Y exacte
const targetPosition = computed(() => [position.value.x, position.value.y])
</script>
<template>
<v-menu
v-model="isOpen"
:close-on-content-click="true"
:target="targetPosition as any"
location="bottom start"
>
<v-list class="py-1" density="compact" min-width="180">
<v-list-item
v-for="(item, index) in items"
:key="index"
:base-color="item.color"
:disabled="item.disabled"
@click="item.action"
>
<template v-if="item.icon" #prepend>
<v-icon :icon="item.icon" size="small"/>
</template>
<v-list-item-title>{{ item.label }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
@@ -0,0 +1,36 @@
import {ref} from 'vue'
export interface MenuItem {
label: string
icon?: string
color?: string
disabled?: boolean
action: () => void
}
const isOpen = ref(false)
const position = ref({x: 0, y: 0})
const items = ref<MenuItem[]>([])
export function useContextMenu() {
function openContextMenu(event: MouseEvent, menuItems: MenuItem[]) {
event.preventDefault()
event.stopPropagation()
position.value = {x: event.clientX, y: event.clientY}
items.value = menuItems
isOpen.value = true
}
function closeContextMenu() {
isOpen.value = false
}
return {
isOpen,
position,
items,
openContextMenu,
closeContextMenu,
}
}
+4 -2
View File
@@ -3,6 +3,7 @@ import {storeToRefs} from 'pinia'
import {useServerStore} from '@/stores/server'
import {ref} from 'vue'
import {useRouter} from 'vue-router'
import ContextMenu from "@/components/ContextMenu.vue";
const serverStore = useServerStore()
const router = useRouter()
@@ -74,7 +75,7 @@ const getServerColor = (str: string): string => {
</script>
<template>
<v-app>
<v-app @contextmenu.prevent>
<!--Top bar-->
<v-system-bar>
@@ -127,7 +128,8 @@ const getServerColor = (str: string): string => {
</v-navigation-drawer>
<router-view/>
<!-- Menu contextuel global -->
<ContextMenu/>
<v-dialog v-model="showDialog" width="400">
<v-card>
<v-card-title>Create Server</v-card-title>
+35
View File
@@ -5,6 +5,7 @@ import {useCategoryStore} from '@/stores/category'
import {ref, watch} from 'vue'
import {useRoute} from 'vue-router'
import CreateChannelDialog from '@/components/channel/CreateChannelDialog.vue'
import {type MenuItem, useContextMenu} from '@/composables/useContextMenu'
const props = defineProps<{
serverId: string
@@ -16,6 +17,8 @@ const channelStore = useChannelStore()
const categoryStore = useCategoryStore()
const {channels} = storeToRefs(channelStore)
const {categories} = storeToRefs(categoryStore)
const {openContextMenu} = useContextMenu()
const loadServerData = async (targetServerId: string) => {
if (!targetServerId) return
@@ -42,6 +45,37 @@ watch(
)
const showDialog = ref(false)
// Right click menu
async function openEditDialog(channel: any) {
console.log("edit dialog clicked")
}
async function deleteChannel(channelId: string) {
console.log("delete channel clicked")
}
function onChannelContextMenu(event: MouseEvent, channel: any) {
const menuItems: MenuItem[] = [
{
label: 'Marquer comme lu',
icon: 'mdi-check',
action: () => console.log('Marqué comme lu', channel.id),
},
{
label: 'Modifier le canal',
icon: 'mdi-pencil',
action: () => openEditDialog(channel),
},
{
label: 'Supprimer le canal',
icon: 'mdi-delete',
color: 'error',
action: () => deleteChannel(channel.id),
},
]
openContextMenu(event, menuItems);
}
</script>
<template>
@@ -69,6 +103,7 @@ const showDialog = ref(false)
:title="channel.name"
:to="`/server/${serverId}/channel/${channel.id}`"
link
@contextmenu="onChannelContextMenu($event, channel)"
></v-list-item>
</v-list>
</v-navigation-drawer>