level-up/frontend/components/ObjectCardDropZone.vue
2025-04-11 21:03:18 +02:00

64 lines
No EOL
1.7 KiB
Vue

<template>
<div
class="flex items-center justify-center text-xl w-0 flex-grow py-4 bg-opacity-60"
:class="$style.root"
:data-has-floating="hasFloating"
>
<span>{{ label }}</span>
</div>
</template>
<style module lang="scss">
.root {
transition: transform 200ms ease;
&[data-has-floating="true"] {
transform: scale(1.2)
}
}
</style>
<script setup lang="ts">
import interact from "@interactjs/interact"
import { useCurrentElement } from "@vueuse/core"
import { onMounted, onUnmounted } from "vue"
const props = defineProps<{
label: string
hasFloating: boolean
}>()
const emit = defineEmits<{
"object-change": [string, boolean]
"object-drop": [string]
}>()
const element = useCurrentElement()
onMounted(() => {
const interactable = interact(element.value as HTMLElement).dropzone({
overlap: "pointer",
ondragenter(event) {
const draggedElement = event.relatedTarget
const objectId = draggedElement.dataset?.objectId
if (objectId === undefined) return
emit("object-change", objectId, true)
},
ondragleave(event) {
const draggedElement = event.relatedTarget
const objectId = draggedElement.dataset?.objectId
if (objectId === undefined) return
emit("object-change", objectId, false)
},
ondrop(event) {
const draggedElement = event.relatedTarget
const objectId = draggedElement.dataset?.objectId
if (objectId === undefined) return
emit("object-change", objectId, false)
emit("object-drop", objectId)
}
})
onUnmounted(() => interactable.unset())
})
</script>