fix animation
This commit is contained in:
parent
0f066ce52a
commit
e53eaef552
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user