init
This commit is contained in:
Generated
+6
-7
@@ -3903,9 +3903,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c"
|
checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -3939,9 +3939,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
@@ -4228,12 +4228,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "validator"
|
name = "validator"
|
||||||
version = "0.20.0"
|
version = "0.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa"
|
checksum = "c3d68c6633c483df6780cc5277a417c7c2d1bceee2649d06c8ab6b0fd2dd3c81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"idna",
|
"idna",
|
||||||
"once_cell",
|
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
|||||||
+2
-2
@@ -21,7 +21,7 @@ event_bus = { path = "event_bus" }
|
|||||||
parking_lot = "0.12.5"
|
parking_lot = "0.12.5"
|
||||||
serde = "1.0.229"
|
serde = "1.0.229"
|
||||||
serde_json = "1.0.151"
|
serde_json = "1.0.151"
|
||||||
toml = "1.1.3"
|
toml = "1.1.4"
|
||||||
uuid = { version = "1.24.0", features = ["v4", "v7", "fast-rng", "serde"] }
|
uuid = { version = "1.24.0", features = ["v4", "v7", "fast-rng", "serde"] }
|
||||||
tracing = "0.1.44"
|
tracing = "0.1.44"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "time"] }
|
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 = { version = "0.5", features = ["util"] }
|
||||||
tower-http = { version = "0.7.0", features = ["catch-panic", "cors", "trace"] }
|
tower-http = { version = "0.7.0", features = ["catch-panic", "cors", "trace"] }
|
||||||
chrono = "0.4.45"
|
chrono = "0.4.45"
|
||||||
validator = { version = "0.20.0", features = ["derive"] }
|
validator = { version = "0.21.0", features = ["derive"] }
|
||||||
async-trait = "0.1.91"
|
async-trait = "0.1.91"
|
||||||
anyhow = "1.0.104"
|
anyhow = "1.0.104"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import {storeToRefs} from 'pinia'
|
|||||||
import {useServerStore} from '@/stores/server'
|
import {useServerStore} from '@/stores/server'
|
||||||
import {ref} from 'vue'
|
import {ref} from 'vue'
|
||||||
import {useRouter} from 'vue-router'
|
import {useRouter} from 'vue-router'
|
||||||
|
import ContextMenu from "@/components/ContextMenu.vue";
|
||||||
|
|
||||||
const serverStore = useServerStore()
|
const serverStore = useServerStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -74,7 +75,7 @@ const getServerColor = (str: string): string => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-app>
|
<v-app @contextmenu.prevent>
|
||||||
<!--Top bar-->
|
<!--Top bar-->
|
||||||
<v-system-bar>
|
<v-system-bar>
|
||||||
|
|
||||||
@@ -127,7 +128,8 @@ const getServerColor = (str: string): string => {
|
|||||||
|
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
<router-view/>
|
<router-view/>
|
||||||
|
<!-- Menu contextuel global -->
|
||||||
|
<ContextMenu/>
|
||||||
<v-dialog v-model="showDialog" width="400">
|
<v-dialog v-model="showDialog" width="400">
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>Create Server</v-card-title>
|
<v-card-title>Create Server</v-card-title>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {useCategoryStore} from '@/stores/category'
|
|||||||
import {ref, watch} from 'vue'
|
import {ref, watch} from 'vue'
|
||||||
import {useRoute} from 'vue-router'
|
import {useRoute} from 'vue-router'
|
||||||
import CreateChannelDialog from '@/components/channel/CreateChannelDialog.vue'
|
import CreateChannelDialog from '@/components/channel/CreateChannelDialog.vue'
|
||||||
|
import {type MenuItem, useContextMenu} from '@/composables/useContextMenu'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
serverId: string
|
serverId: string
|
||||||
@@ -16,6 +17,8 @@ const channelStore = useChannelStore()
|
|||||||
const categoryStore = useCategoryStore()
|
const categoryStore = useCategoryStore()
|
||||||
const {channels} = storeToRefs(channelStore)
|
const {channels} = storeToRefs(channelStore)
|
||||||
const {categories} = storeToRefs(categoryStore)
|
const {categories} = storeToRefs(categoryStore)
|
||||||
|
const {openContextMenu} = useContextMenu()
|
||||||
|
|
||||||
|
|
||||||
const loadServerData = async (targetServerId: string) => {
|
const loadServerData = async (targetServerId: string) => {
|
||||||
if (!targetServerId) return
|
if (!targetServerId) return
|
||||||
@@ -42,6 +45,37 @@ watch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const showDialog = ref(false)
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -69,6 +103,7 @@ const showDialog = ref(false)
|
|||||||
:title="channel.name"
|
:title="channel.name"
|
||||||
:to="`/server/${serverId}/channel/${channel.id}`"
|
:to="`/server/${serverId}/channel/${channel.id}`"
|
||||||
link
|
link
|
||||||
|
@contextmenu="onChannelContextMenu($event, channel)"
|
||||||
></v-list-item>
|
></v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
|
|||||||
Reference in New Issue
Block a user