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
Generated
+6 -7
View File
@@ -3903,9 +3903,9 @@ dependencies = [
[[package]]
name = "toml"
version = "1.1.3+spec-1.1.0"
version = "1.1.4+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c"
checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
dependencies = [
"indexmap",
"serde_core",
@@ -3939,9 +3939,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
version = "1.1.3+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
dependencies = [
"winnow",
]
@@ -4228,12 +4228,11 @@ dependencies = [
[[package]]
name = "validator"
version = "0.20.0"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa"
checksum = "c3d68c6633c483df6780cc5277a417c7c2d1bceee2649d06c8ab6b0fd2dd3c81"
dependencies = [
"idna",
"once_cell",
"regex",
"serde",
"serde_derive",
+2 -2
View File
@@ -21,7 +21,7 @@ event_bus = { path = "event_bus" }
parking_lot = "0.12.5"
serde = "1.0.229"
serde_json = "1.0.151"
toml = "1.1.3"
toml = "1.1.4"
uuid = { version = "1.24.0", features = ["v4", "v7", "fast-rng", "serde"] }
tracing = "0.1.44"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "time"] }
@@ -35,7 +35,7 @@ jsonwebtoken = { version = "11.0.0", features = ["aws_lc_rs"] }
tower = { version = "0.5", features = ["util"] }
tower-http = { version = "0.7.0", features = ["catch-panic", "cors", "trace"] }
chrono = "0.4.45"
validator = { version = "0.20.0", features = ["derive"] }
validator = { version = "0.21.0", features = ["derive"] }
async-trait = "0.1.91"
anyhow = "1.0.104"
futures-util = "0.3"
+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>