refactor(frontend) : reorganize components into subdirectories and fix imports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
89
frontend/components/time-tracking/TimeEntryContextMenu.vue
Normal file
89
frontend/components/time-tracking/TimeEntryContextMenu.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="visible"
|
||||
ref="menuEl"
|
||||
class="fixed z-50 min-w-36 rounded-md border border-neutral-200 bg-white py-1 shadow-lg"
|
||||
:style="{ top: `${y}px`, left: `${x}px` }"
|
||||
>
|
||||
<button
|
||||
v-if="entry"
|
||||
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-neutral-700 hover:bg-neutral-100"
|
||||
@click="onCopy"
|
||||
>
|
||||
<Icon name="mdi:content-copy" size="16" />
|
||||
Copier
|
||||
</button>
|
||||
<button
|
||||
v-if="canPaste"
|
||||
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-neutral-700 hover:bg-neutral-100"
|
||||
@click="onPaste"
|
||||
>
|
||||
<Icon name="mdi:content-paste" size="16" />
|
||||
Coller
|
||||
</button>
|
||||
<button
|
||||
v-if="entry"
|
||||
class="flex w-full items-center gap-2 px-4 py-2 text-sm text-red-600 hover:bg-red-50"
|
||||
@click="onDelete"
|
||||
>
|
||||
<Icon name="mdi:delete-outline" size="16" />
|
||||
Supprimer
|
||||
</button>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { TimeEntry } from '~/services/dto/time-entry'
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
x: number
|
||||
y: number
|
||||
entry?: TimeEntry | null
|
||||
canPaste: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void
|
||||
(e: 'copy', entry: TimeEntry): void
|
||||
(e: 'paste'): void
|
||||
(e: 'delete', entry: TimeEntry): void
|
||||
}>()
|
||||
|
||||
const menuEl = ref<HTMLElement | null>(null)
|
||||
|
||||
function onCopy() {
|
||||
if (props.entry) emit('copy', props.entry)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
function onPaste() {
|
||||
emit('paste')
|
||||
emit('close')
|
||||
}
|
||||
|
||||
function onDelete() {
|
||||
if (props.entry) emit('delete', props.entry)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
function onClickOutside(event: MouseEvent) {
|
||||
if (menuEl.value && !menuEl.value.contains(event.target as Node)) {
|
||||
emit('close')
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.visible, (v) => {
|
||||
if (v) {
|
||||
setTimeout(() => document.addEventListener('click', onClickOutside), 0)
|
||||
} else {
|
||||
document.removeEventListener('click', onClickOutside)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', onClickOutside)
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user