fix animation

This commit is contained in:
Nyavokevin 2025-09-17 14:41:20 +03:00
parent 0f066ce52a
commit e53eaef552

View File

@ -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<number | null>(null);
const revealedCards = ref<Card[]>([]);
const isFlipped = ref<boolean[]>([]);
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 });
</script>
@ -73,11 +146,17 @@ defineExpose({ setDrawnCards });
<transition class="card-stack-fade">
<div
class="card-stack relative mt-4 mb-4 flex h-[500px] w-[300px] items-center justify-center"
:class="{ clicked: isClicked, drawing: isDrawing }"
@click="handleClick"
v-show="!showResult"
:class="{ spread: isSpread, drawing: isDrawing }"
@click="handleDeckClick"
v-show="!drawnCards || revealedCards.length < drawnCards.length"
>
<div v-for="i in 8" :key="i" class="card" :style="{ transform: `rotate(${-3 + i}deg) translateZ(-${10 * i}px);` }">
<div
v-for="i in remainingDeckSize"
:key="i"
class="card"
:style="getCardStyle(i)"
@click="onCardClick(i, $event)"
>
<div class="card-back">
<div class="card-inner-content">
<img src="cards/1.png" alt="Card Back" class="card-back-image" />
@ -88,8 +167,8 @@ defineExpose({ setDrawnCards });
</transition>
<!-- Show result only after clicking and when drawnCards is available -->
<transition class="card-result-slide">
<div v-if="showResult && drawnCards" class="cards-result-container">
<div v-for="(card, index) in drawnCards" :key="index" class="card-result-wrapper">
<div v-if="revealedCards.length > 0" class="cards-result-container">
<div v-for="(card, index) in revealedCards" :key="index" class="card-result-wrapper">
<div class="result-card" :class="{ flipped: isFlipped[index] }" @click="flipCard(index)">
<div class="card-face card-unknown-front">
<div class="card-inner-content">
@ -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);
}