unified gost cards (mouse + touch)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<article role="button" @click.stop="cardClick" @keydown.enter.stop="cardClick" @keydown.space.prevent.stop="cardClick"
|
<article :role="props.role" @click.stop="cardClick" @keydown.enter.stop="cardClick" draggable="true"
|
||||||
|
@dragstart="dragStart" @dragend="dragEnd" @drag="dragMove" @keydown.space.prevent.stop="cardClick"
|
||||||
@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" class="card" :class="[
|
@touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" class="card" :class="[
|
||||||
isFaceUp ? 'face-up' : 'face-down',
|
isFaceUp ? 'face-up' : 'face-down',
|
||||||
{ 'current-track': playerStore.currentTrack?.id === track.id },
|
{ 'current-track': playerStore.currentTrack?.id === track.id },
|
||||||
@@ -7,7 +8,7 @@
|
|||||||
]">
|
]">
|
||||||
<div class="flip-inner" ref="cardElement">
|
<div class="flip-inner" ref="cardElement">
|
||||||
<!-- Face-Up -->
|
<!-- Face-Up -->
|
||||||
<main draggable="true" @dragstart="dragStart" @dragend="dragEnd"
|
<main
|
||||||
class="face-up backdrop-blur-sm border-2 z-10 card w-56 h-80 p-3 hover:shadow-xl hover:scale-110 transition-all rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
class="face-up backdrop-blur-sm border-2 z-10 card w-56 h-80 p-3 hover:shadow-xl hover:scale-110 transition-all rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
||||||
|
|
||||||
<div v-if="isPlaylistTrack" class="flex items-center justify-center size-7 absolute top-7 left-7">
|
<div v-if="isPlaylistTrack" class="flex items-center justify-center size-7 absolute top-7 left-7">
|
||||||
@@ -60,7 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<!-- Clone fantôme pour le drag tactile -->
|
<!-- Clone fantôme unifié pour drag souris ET tactile -->
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="isDragging && touchClone" ref="ghostElement"
|
<div v-if="isDragging && touchClone" ref="ghostElement"
|
||||||
class="ghost-card fixed pointer-events-none z-[9999] w-56 h-80" :style="{
|
class="ghost-card fixed pointer-events-none z-[9999] w-56 h-80" :style="{
|
||||||
@@ -99,12 +100,14 @@ import { useDataStore } from '~/store/data';
|
|||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
track?: Track;
|
track?: Track;
|
||||||
isFaceUp?: boolean;
|
isFaceUp?: boolean;
|
||||||
|
role?: string;
|
||||||
}>(), {
|
}>(), {
|
||||||
track: () => {
|
track: () => {
|
||||||
const dataStore = useDataStore();
|
const dataStore = useDataStore();
|
||||||
return dataStore.getRandomPlaylistTrack() || {} as Track;
|
return dataStore.getRandomPlaylistTrack() || {} as Track;
|
||||||
},
|
},
|
||||||
isFaceUp: true,
|
isFaceUp: true,
|
||||||
|
role: 'button'
|
||||||
})
|
})
|
||||||
|
|
||||||
const playerStore = usePlayerStore()
|
const playerStore = usePlayerStore()
|
||||||
@@ -120,7 +123,7 @@ const isDragging = ref(false)
|
|||||||
const cardElement = ref<HTMLElement | null>(null)
|
const cardElement = ref<HTMLElement | null>(null)
|
||||||
const ghostElement = ref<HTMLElement | null>(null)
|
const ghostElement = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
// État pour le tactile
|
// État unifié pour souris et tactile
|
||||||
const touchClone = ref<{ x: number, y: number } | null>(null)
|
const touchClone = ref<{ x: number, y: number } | null>(null)
|
||||||
const touchStartPos = ref<{ x: number, y: number } | null>(null)
|
const touchStartPos = ref<{ x: number, y: number } | null>(null)
|
||||||
const longPressTimer = ref<number | null>(null)
|
const longPressTimer = ref<number | null>(null)
|
||||||
@@ -135,18 +138,40 @@ const cardClick = () => {
|
|||||||
hasMovedDuringPress.value = false
|
hasMovedDuringPress.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drag desktop
|
// Drag desktop - utilise maintenant ghostElement
|
||||||
const dragStart = (event: DragEvent) => {
|
const dragStart = (event: DragEvent) => {
|
||||||
if (event.dataTransfer && cardElement.value) {
|
if (event.dataTransfer && cardElement.value) {
|
||||||
event.dataTransfer.effectAllowed = 'move';
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
event.dataTransfer.setData('application/json', JSON.stringify(props.track));
|
event.dataTransfer.setData('application/json', JSON.stringify(props.track));
|
||||||
|
|
||||||
|
// Créer une image transparente pour masquer l'image par défaut du navigateur
|
||||||
|
const img = new Image();
|
||||||
|
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||||
|
event.dataTransfer.setDragImage(img, 0, 0);
|
||||||
|
|
||||||
|
// Activer le clone fantôme
|
||||||
isDragging.value = true
|
isDragging.value = true
|
||||||
|
touchClone.value = {
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Nouveau: suivre le mouvement de la souris pendant le drag
|
||||||
|
const dragMove = (event: DragEvent) => {
|
||||||
|
if (isDragging.value && touchClone.value && event.clientX !== 0 && event.clientY !== 0) {
|
||||||
|
touchClone.value = {
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance();
|
||||||
const dragEnd = (event: DragEvent) => {
|
const dragEnd = (event: DragEvent) => {
|
||||||
isDragging.value = false
|
isDragging.value = false
|
||||||
|
touchClone.value = null
|
||||||
|
|
||||||
if (event.dataTransfer?.dropEffect === 'move' && instance?.vnode?.el?.parentNode) {
|
if (event.dataTransfer?.dropEffect === 'move' && instance?.vnode?.el?.parentNode) {
|
||||||
instance.vnode.el.parentNode.removeChild(instance.vnode.el);
|
instance.vnode.el.parentNode.removeChild(instance.vnode.el);
|
||||||
@@ -400,7 +425,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ghost card styles */
|
/* Ghost card styles - maintenant unifié pour souris et tactile */
|
||||||
.ghost-card {
|
.ghost-card {
|
||||||
transition: none;
|
transition: none;
|
||||||
|
|
||||||
@@ -417,4 +442,4 @@ onUnmounted(() => {
|
|||||||
perspective: 1000px;
|
perspective: 1000px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user