Drag and Drop operation on MusicCard

This commit is contained in:
2025-11-21 01:40:53 +05:00
parent b860ea95d3
commit 133558c4ab
6 changed files with 96 additions and 4 deletions

View File

@ -0,0 +1,42 @@
<script setup lang="ts">
import { useDraggable } from '@vue-dnd-kit/core';
import { computed } from 'vue';
const { index, source } = defineProps<{
index: number;
source: any[];
}>();
const { elementRef, handleDragStart, isOvered, isDragging } = useDraggable({
data: computed(() => ({
index,
source,
})),
});
</script>
<template>
<div ref="elementRef" @pointerdown="handleDragStart" :class="{
'is-over': isOvered,
'is-dragging': isDragging,
}" class="draggable">
<slot />
</div>
</template>
<style>
.draggable {
cursor: move;
user-select: none;
touch-action: none;
}
.is-dragging {
opacity: 0.2;
}
.is-over {
padding-top: 0.5rem;
border-top: 2px solid var(--border);
}
</style>

View File

@ -2,9 +2,11 @@
import { Search } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { InputWithIcon } from '@/components/ui/input'
import MusicCard from '@/components/ui/musiccard/MusicCard.vue'
import { Outline } from '@/components/ui/outline'
import { SidebarTrigger } from '@/components/ui/sidebar'
import MusicCard from '~/components/internal/musiccard/MusicCard.vue'
import { DnDOperations, useDroppable } from '@vue-dnd-kit/core'
import Draggable from '~/components/action/Draggable.vue'
const searchValue = ref('')
@ -66,6 +68,15 @@ const selectTrack = (trackId: number) => {
track.selected = track.id === trackId
})
}
const { elementRef: tracksRef } = useDroppable({
data: {
source: tracks.value,
},
events: {
onDrop: DnDOperations.applyTransfer,
},
});
</script>
<template>
@ -88,9 +99,16 @@ const selectTrack = (trackId: number) => {
<InputWithIcon v-model="searchValue" :icon="Search" placeholder="Search..." type="search" icon-size="5"
id="user-search" class="w-full" />
<MusicCard v-for="track in filteredTracks" :key="track.id" :title="track.title" :author="track.author"
:authorLabel="track.authorLabel" :badges="track.badges" :imageUrl="track.imageUrl"
:date="track.date" :selected="track.selected" @click="selectTrack(track.id)" />
<div ref="tracksRef" class="space-y-2">
<TransitionGroup name="list" ref="tracksRef">
<Draggable v-for="(track, index) in filteredTracks" :key="track.id" :index="index"
:source="tracks">
<MusicCard :key="track.id" :title="track.title" :author="track.author"
:authorLabel="track.authorLabel" :badges="track.badges" :imageUrl="track.imageUrl"
:date="track.date" :selected="track.selected" @click="selectTrack(track.id)" />
</Draggable>
</TransitionGroup>
</div>
</div>
<template #sidebar>
<Outline padding="none" class="h-full" side="left">
@ -104,3 +122,25 @@ const selectTrack = (trackId: number) => {
</NuxtLayout>
</div>
</template>
<style>
.list-move {
transition: 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.list-enter-active,
.list-leave-active {
transition: 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateY(-20px);
}
.list-leave-active {
position: absolute;
pointer-events: none;
}
</style>

View File

@ -0,0 +1,6 @@
// ~/plugins/vue-dnd-kit.client.ts
import VueDnDKitPlugin from '@vue-dnd-kit/core';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueDnDKitPlugin);
});