From e53eaef552a7e6193db407a4cb11deada7b51c78 Mon Sep 17 00:00:00 2001 From: Nyavokevin <42602932+nyavokevin@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:41:20 +0300 Subject: [PATCH] fix animation --- .../ShuffleCard/ShuffleCardPresentation.vue | 143 ++++++++++++++---- 1 file changed, 111 insertions(+), 32 deletions(-) diff --git a/resources/js/components/organism/ShuffleCard/ShuffleCardPresentation.vue b/resources/js/components/organism/ShuffleCard/ShuffleCardPresentation.vue index 694010b..b947e6d 100644 --- a/resources/js/components/organism/ShuffleCard/ShuffleCardPresentation.vue +++ b/resources/js/components/organism/ShuffleCard/ShuffleCardPresentation.vue @@ -2,51 +2,113 @@ import CardShuffleTemplate from '@/components/template/CardShuffleTemplate.vue'; import { Card } from '@/types/cart'; import { router } from '@inertiajs/vue3'; -import { ref, watchEffect } from 'vue'; +import { ref, watchEffect, computed } from 'vue'; const props = defineProps<{ - drawCount?: number; // Optional prop for the shuffle animation - drawnCards?: Card[]; // Optional prop to directly display cards + drawCount?: number; // Optional: number of cards expected to be drawn + drawnCards?: Card[]; // Cards provided by the parent at start clientSessionId?: string; }>(); defineEmits(['drawCard']); -const isClicked = ref(false); +// Deck / animation state +const deckSize = 10; // spread ~10 cards as requested +const isSpread = ref(false); const isDrawing = ref(false); -const showResult = ref(false); +const drawingIndex = ref(null); +const revealedCards = ref([]); const isFlipped = ref([]); -const handleClick = () => { +const remainingDeckSize = computed(() => Math.max(0, deckSize - revealedCards.value.length)); + +const startDraw = (index: number) => { + if (!props.drawnCards || revealedCards.value.length >= props.drawnCards.length) return; + isDrawing.value = true; + drawingIndex.value = index; + + const DRAW_DURATION = 800; // keep in sync with CSS transition timing setTimeout(() => { - showResult.value = true; - }, 800); + const nextCard = props.drawnCards![revealedCards.value.length]; + if (nextCard) { + revealedCards.value.push(nextCard); + isFlipped.value.push(false); + } + // Restack after drawing + isSpread.value = false; + drawingIndex.value = null; + isDrawing.value = false; + }, DRAW_DURATION); }; -// This function is still needed for when the user clicks to draw on the /tirage page -const setDrawnCards = (cardData: Card[]) => { - // This method is called by the parent component after an API call - if (cardData) { - // Here, we assign the cards to a local state to be displayed - showResult.value = true; - isDrawing.value = false; - isFlipped.value = new Array(cardData.length).fill(false); - // The confetti and card data will be handled by the component that consumes this one +const handleDeckClick = () => { + if (isDrawing.value) return; + + // First click spreads the deck + if (!isSpread.value) { + isSpread.value = true; + return; } + + // If already spread, clicking deck auto-draws the middle card + if (props.drawnCards && revealedCards.value.length < props.drawnCards.length) { + const middleIndex = Math.ceil(remainingDeckSize.value / 2); + startDraw(middleIndex); + } else { + // No cards left to draw, just restack + isSpread.value = false; + } +}; + +const onCardClick = (i: number, e?: MouseEvent) => { + // Only handle and stop propagation when spread; otherwise let the deck click handler spread the deck + if (!isSpread.value || isDrawing.value) return; + if (e) e.stopPropagation(); + if (!props.drawnCards || revealedCards.value.length >= props.drawnCards.length) return; + startDraw(i); +}; + +const getCardStyle = (i: number) => { + if (drawingIndex.value === i) { + return { + transform: 'translateY(-220px) scale(1.05)', + zIndex: '100', + } as const; + } + if (isSpread.value) { + const mid = (remainingDeckSize.value + 1) / 2; + const offset = i - mid; // negative to left, positive to right + const x = offset * 40; // horizontal spacing + const rot = offset * 6; // slight fan rotation + return { + transform: `translateX(${x}px) rotate(${rot}deg)`, + zIndex: `${50 - Math.abs(offset)}`, + } as const; + } + // Stacked view with subtle 3D depth + return { + transform: `rotate(${-3 + i}deg) translateZ(-${10 * i}px)`, + } as const; }; const flipCard = (index: number) => { isFlipped.value[index] = !isFlipped.value[index]; }; -// Use watchEffect to react to the `drawnCards` prop changing +// Reset local animation state whenever given cards change watchEffect(() => { if (props.drawnCards && props.drawnCards.length > 0) { - showResult.value = false; - isFlipped.value = new Array(props.drawnCards.length).fill(false); - // The confetti and other logic is also triggered here. + isSpread.value = false; + isDrawing.value = false; + drawingIndex.value = null; + revealedCards.value = []; + isFlipped.value = []; } else { - showResult.value = false; + isSpread.value = false; + isDrawing.value = false; + drawingIndex.value = null; + revealedCards.value = []; + isFlipped.value = []; } }); @@ -62,6 +124,17 @@ const goToResult = () => { } }; +// Backward compatibility if a parent calls this method directly +const setDrawnCards = (cardData: Card[]) => { + if (cardData && cardData.length) { + isSpread.value = false; + isDrawing.value = false; + drawingIndex.value = null; + revealedCards.value = []; + isFlipped.value = new Array(cardData.length).fill(false); + } +}; + defineExpose({ setDrawnCards }); @@ -73,11 +146,17 @@ defineExpose({ setDrawnCards });
-
+
Card Back @@ -88,8 +167,8 @@ defineExpose({ setDrawnCards }); -
-
+
+
@@ -157,17 +236,17 @@ defineExpose({ setDrawnCards }); } /* Hover sur la pile */ -.card-stack:hover { +.card-stack:not(.spread):hover { transform: translateY(-10px) rotateX(2deg) rotateY(-2deg); } -.card-stack:hover .card:nth-child(1) { +.card-stack:not(.spread):hover .card:nth-child(1) { transform: rotateY(-5deg) rotateX(5deg) translateZ(30px) translateX(-20px); } -.card-stack:hover .card:nth-child(2) { +.card-stack:not(.spread):hover .card:nth-child(2) { transform: rotateY(0deg) rotateX(2deg) translateZ(20px); } -.card-stack:hover .card:nth-child(3) { +.card-stack:not(.spread):hover .card:nth-child(3) { transform: rotateY(5deg) rotateX(5deg) translateZ(10px) translateX(20px); }