Skip to content

Commit

Permalink
Merge pull request #92 from softeerbootcamp4th/feat/#90-general-anima…
Browse files Browse the repository at this point in the history
…tion

[Feat] 공통 애니메이션 정의
  • Loading branch information
sooyeoniya authored Aug 5, 2024
2 parents 5181f22 + 8c7ed30 commit 4e19057
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 17 deletions.
19 changes: 19 additions & 0 deletions client/src/constants/animation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Transition, Variants } from "framer-motion";

export const DISSOLVE: Variants | Transition = {
initial: { opacity: 0 },
animate: { opacity: 1 },
transition: { duration: 0.5 },
};

export const ASCEND: Variants | Transition = {
initial: { y: 40, opacity: 0 },
animate: { y: 0, opacity: 1 },
transition: { duration: 0.5 },
};

export const ASCEND_DESCEND: Variants | Transition = {
initial: { y: 40 },
animate: { y: 0 },
transition: { duration: 0.5, repeat: Infinity, repeatType: "mirror" },
};
31 changes: 21 additions & 10 deletions client/src/features/CasperCustom/CasperCustomFinishing.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { motion } from "framer-motion";
import { CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper";
import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext";
import MyCasperCardBack from "./MyCasperCardBack";
import MyCasperCardFront from "./MyCasperCardFront";
import { CasperCardType } from "../CasperShowCase/TransitionCasperCards";
import CasperFlipCard from "./CasperFlipCard";

interface CasperCustomFinishingProps {
navigateNextStep: () => void;
}

export default function CasperCustomFinishing({ navigateNextStep }: CasperCustomFinishingProps) {
const { casperName, expectations } = useCasperCustomStateContext();
const { casperName, expectations, selectedCasperIdx } = useCasperCustomStateContext();
const [isFlipped, setIsFlipped] = useState<boolean>(false);

const card: Omit<CasperCardType, "id"> = {
casperName,
expectations,
selectedCasperIdx,
};

useEffect(() => {
// TODO: flip 애니메이션 후 next step으로 넘어가게 하기
setTimeout(() => {
navigateNextStep();
setIsFlipped(true);
}, 3000);

setTimeout(() => {
navigateNextStep();
}, 6000);
}, []);

return (
<div className="flex">
<MyCasperCardFront casperName={casperName} hasRandomButton={false} />
<MyCasperCardBack casperName={casperName} expectations={expectations} />
</div>
<motion.div className="flex">
<CasperFlipCard size={CASPER_SIZE_OPTION.LG} card={card} isFlipped={isFlipped} />
</motion.div>
);
}
56 changes: 56 additions & 0 deletions client/src/features/CasperCustom/CasperFlipCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { motion } from "framer-motion";
import { CASPER_CARD_SIZE, CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper";
import { CasperCardType } from "../CasperShowCase/TransitionCasperCards";
import CasperCardBackUI from "./CasperCardBackUI";
import CasperCardFrontUI from "./CasperCardFrontUI";

interface CasperFlipCardProps {
size: (typeof CASPER_SIZE_OPTION)[keyof typeof CASPER_SIZE_OPTION];
card: Omit<CasperCardType, "id">;
isFlipped: boolean;
}

export default function CasperFlipCard({ size, card, isFlipped }: CasperFlipCardProps) {
return (
<div style={{ perspective: "1000px" }}>
<motion.div
style={{
width: CASPER_CARD_SIZE[size].CARD_WIDTH,
height: CASPER_CARD_SIZE[size].CARD_HEIGHT,
position: "relative",
transformStyle: "preserve-3d",
}}
animate={{ rotateY: isFlipped ? 180 : 0 }}
transition={{ duration: 0.3 }}
>
<div
className="absolute w-full h-full"
style={{
backfaceVisibility: "hidden",
}}
>
<CasperCardFrontUI
size={size}
casperName={card.casperName}
hasRandomButton={false}
selectedCasperIdx={card.selectedCasperIdx}
/>
</div>
<div
className="absolute w-full h-full"
style={{
backfaceVisibility: "hidden",
transform: "rotateY(180deg)",
}}
>
<CasperCardBackUI
size={size}
casperName={card.casperName}
expectations={card.expectations}
selectedCasperIdx={card.selectedCasperIdx}
/>
</div>
</motion.div>
</div>
);
}
26 changes: 19 additions & 7 deletions client/src/features/CasperShowCase/TransitionCasperCards.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useEffect, useRef, useState } from "react";
import { motion, useAnimation } from "framer-motion";
import { CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper";
import { CARD_TRANSITION } from "@/constants/CasperShowCase/showCase";
import { SelectedCasperIdxType } from "@/types/casperCustom";
import CasperCardFrontUI from "../CasperCustom/CasperCardFrontUI";
import CasperFlipCard from "../CasperCustom/CasperFlipCard";

export interface CasperCardType {
id: string;
Expand Down Expand Up @@ -53,13 +54,24 @@ export default function TransitionCasperCards({
}, [transitionControls, totalWidth]);

const renderCardItem = (cardItem: CasperCardType, id: string) => {
const [isFlipped, setIsFlipped] = useState<boolean>(false);

const handleMouseEnter = () => {
stopAnimation();
setIsFlipped(true);
};

const handleMouseLeave = () => {
startAnimation(x);
setIsFlipped(false);
};

return (
<div key={id} onMouseEnter={stopAnimation} onMouseLeave={() => startAnimation(x)}>
<CasperCardFrontUI
size="sm"
casperName={cardItem.casperName}
hasRandomButton={false}
selectedCasperIdx={cardItem.selectedCasperIdx}
<div key={id} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<CasperFlipCard
card={cardItem}
size={CASPER_SIZE_OPTION.SM}
isFlipped={isFlipped}
/>
</div>
);
Expand Down

0 comments on commit 4e19057

Please sign in to comment.