fix: merge two files into one

This commit is contained in:
whbbit1999
2025-07-14 16:32:53 +08:00
parent b4932d2695
commit c4d956fb13
2 changed files with 73 additions and 46 deletions

View File

@@ -1,41 +0,0 @@
<template>
<Motion
as="div"
class="absolute cursor-grab"
:style="{ x, y, rotateX, rotateY }"
drag
:drag-constraints="{ top: 0, right: 0, bottom: 0, left: 0 }"
:dragElastic="0.6"
:whileTap="{ cursor: 'grabbing' }"
:onDragEnd="handleDragEnd"
>
<slot />
</Motion>
</template>
<script lang="ts" setup>
import type { PanInfo } from 'motion-v';
import { Motion, useMotionValue, useTransform } from 'motion-v';
interface CardRotateProps {
sensitivity: number;
}
const { sensitivity } = defineProps<CardRotateProps>();
const emits = defineEmits<{
(e: 'sendToBack'): void;
}>();
const x = useMotionValue(0);
const y = useMotionValue(0);
const rotateX = useTransform(y, [-100, 100], [60, -60]);
const rotateY = useTransform(x, [-100, 100], [-60, 60]);
function handleDragEnd(_: PointerEvent, info: PanInfo) {
if (Math.abs(info.offset.x) > sensitivity || Math.abs(info.offset.y) > sensitivity) {
emits('sendToBack');
} else {
x.set(0);
y.set(0);
}
}
</script>

View File

@@ -4,7 +4,21 @@
:style="{ width: cardDimensions.width + 'px', height: cardDimensions.height + 'px', perspective: 600 }" :style="{ width: cardDimensions.width + 'px', height: cardDimensions.height + 'px', perspective: 600 }"
> >
<template v-for="(card, index) in cards" :key="card.id"> <template v-for="(card, index) in cards" :key="card.id">
<CardRotate :sensitivity="sensitivity" @send-to-back="sendToBack(card.id)"> <Motion
as="div"
class="absolute cursor-grab"
:style="{
x: cardStates.get(card.id)?.x,
y: cardStates.get(card.id)?.y,
rotateX: cardStates.get(card.id)?.rotateX,
rotateY: cardStates.get(card.id)?.rotateY
}"
drag
:drag-constraints="{ top: 0, right: 0, bottom: 0, left: 0 }"
:dragElastic="0.6"
:whileTap="{ cursor: 'grabbing', scale: 1.02 }"
:onDragEnd="(e, info) => handleDragEnd(e, info, card.id)"
>
<Motion <Motion
as="div" as="div"
class="rounded-2xl overflow-hidden border-4 border-white" class="rounded-2xl overflow-hidden border-4 border-white"
@@ -27,15 +41,15 @@
> >
<img :src="card.img" :alt="`card-${card.id}`" className="w-full h-full object-cover pointer-events-none" /> <img :src="card.img" :alt="`card-${card.id}`" className="w-full h-full object-cover pointer-events-none" />
</Motion> </Motion>
</CardRotate> </Motion>
</template> </template>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Motion } from 'motion-v'; import type { PanInfo } from 'motion-v';
import { ref } from 'vue'; import { Motion, useMotionValue, useTransform } from 'motion-v';
import CardRotate from './CardRotate.vue'; import { onBeforeMount, ref } from 'vue';
interface StackProps { interface StackProps {
className?: string; className?: string;
@@ -67,6 +81,60 @@ const cards = ref(
] ]
); );
type CardState = {
x: ReturnType<typeof useMotionValue<number>>;
y: ReturnType<typeof useMotionValue<number>>;
rotateX: ReturnType<typeof useMotionValue<number>>;
rotateY: ReturnType<typeof useMotionValue<number>>;
reset: () => void;
};
const cardStates = new Map<number, CardState>();
function createCardState(): CardState {
const x = useMotionValue(0);
const y = useMotionValue(0);
const rotateX = useTransform(y, [-100, 100], [60, -60]);
const rotateY = useTransform(x, [-100, 100], [-60, 60]);
return {
x,
y,
rotateX,
rotateY,
reset() {
x.set(0);
y.set(0);
}
};
}
onBeforeMount(() => {
cards.value.forEach(card => {
if (!cardStates.has(card.id)) {
cardStates.set(card.id, createCardState());
}
});
});
function getCardState(cardId: number): CardState {
let state = cardStates.get(cardId);
if (!state) {
state = createCardState();
cardStates.set(cardId, state);
}
return state;
}
function handleDragEnd(_: PointerEvent, info: PanInfo, cardId: number) {
if (Math.abs(info.offset.x) > props.sensitivity || Math.abs(info.offset.y) > props.sensitivity) {
sendToBack(cardId);
} else {
getCardState(cardId).reset();
}
}
const sendToBack = (id: number) => { const sendToBack = (id: number) => {
const newCards = [...cards.value]; const newCards = [...cards.value];
const index = newCards.findIndex(card => card.id === id); const index = newCards.findIndex(card => card.id === id);