unified gost cards (mouse + touch)
All checks were successful
Deploy App / build (push) Successful in 31s
Deploy App / deploy (push) Successful in 15s

This commit is contained in:
valere
2025-12-24 12:25:58 +01:00
parent ad938abf79
commit d8fe645e5c

View File

@@ -1,5 +1,6 @@
<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="[
isFaceUp ? 'face-up' : 'face-down',
{ 'current-track': playerStore.currentTrack?.id === track.id },
@@ -7,7 +8,7 @@
]">
<div class="flip-inner" ref="cardElement">
<!-- 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">
<div v-if="isPlaylistTrack" class="flex items-center justify-center size-7 absolute top-7 left-7">
@@ -60,7 +61,7 @@
</div>
</article>
<!-- Clone fantôme pour le drag tactile -->
<!-- Clone fantôme unifié pour drag souris ET tactile -->
<Teleport to="body">
<div v-if="isDragging && touchClone" ref="ghostElement"
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<{
track?: Track;
isFaceUp?: boolean;
role?: string;
}>(), {
track: () => {
const dataStore = useDataStore();
return dataStore.getRandomPlaylistTrack() || {} as Track;
},
isFaceUp: true,
role: 'button'
})
const playerStore = usePlayerStore()
@@ -120,7 +123,7 @@ const isDragging = ref(false)
const cardElement = 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 touchStartPos = ref<{ x: number, y: number } | null>(null)
const longPressTimer = ref<number | null>(null)
@@ -135,18 +138,40 @@ const cardClick = () => {
hasMovedDuringPress.value = false
}
// Drag desktop
// Drag desktop - utilise maintenant ghostElement
const dragStart = (event: DragEvent) => {
if (event.dataTransfer && cardElement.value) {
event.dataTransfer.effectAllowed = 'move';
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
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 dragEnd = (event: DragEvent) => {
isDragging.value = false
touchClone.value = null
if (event.dataTransfer?.dropEffect === 'move' && instance?.vnode?.el?.parentNode) {
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 {
transition: none;
@@ -417,4 +442,4 @@ onUnmounted(() => {
perspective: 1000px;
}
}
</style>
</style>