Skip to content

Commit 413c328

Browse files
committed
Merge branch 'feature/animation' into dev
2 parents 06d49a1 + 08463b2 commit 413c328

File tree

3 files changed

+84
-2
lines changed

3 files changed

+84
-2
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { motion, useAnimation } from 'framer-motion';
2+
import { useEffect } from 'react';
3+
4+
interface FloatItemProps {
5+
src: string;
6+
size?: string;
7+
duration?: number;
8+
interval?: number;
9+
}
10+
11+
// 랜덤 이동
12+
const getRandomPosition = () => ({
13+
x: Math.floor(Math.random() * 100 - 50),
14+
y: Math.floor(Math.random() * 100 - 50),
15+
});
16+
17+
const FloatingItem = ({ src, size = 'w-20', duration = 6, interval = 8000 }: FloatItemProps) => {
18+
const controls = useAnimation();
19+
20+
useEffect(() => {
21+
const animateRandomly = () => {
22+
const { x, y } = getRandomPosition();
23+
controls.start({
24+
x: `${x}vw`,
25+
y: `${y}vh`,
26+
transition: {
27+
duration,
28+
ease: 'easeInOut',
29+
},
30+
});
31+
};
32+
33+
animateRandomly(); // 첫 애니메이션
34+
const intervalId = setInterval(animateRandomly, interval);
35+
36+
return () => clearInterval(intervalId);
37+
}, [controls, duration, interval]);
38+
39+
return (
40+
<motion.img
41+
src={src}
42+
className={`absolute ${size} opacity-80 pointer-events-none`}
43+
style={{
44+
left: '50%',
45+
top: '50%',
46+
transform: 'translate(-50%, -50%)', // 중앙에서 시작
47+
}}
48+
animate={controls}
49+
alt="floating item"
50+
/>
51+
);
52+
};
53+
const FloatingBackground = () => {
54+
return (
55+
<div className="fixed inset-0 -z-1000 overflow-hidden pointer-events-none">
56+
<FloatingItem
57+
src="https://noticon-static.tammolo.com/dgggcrkxq/image/upload/v1741777507/noticon/dihnlmrn8aopedon41ur.gif"
58+
size="w-20"
59+
duration={5}
60+
interval={7000}
61+
/>
62+
<FloatingItem
63+
src="https://noticon-static.tammolo.com/dgggcrkxq/image/upload/v1683523256/noticon/kyp3frg9corycovxokx6.gif"
64+
size="w-16"
65+
duration={6}
66+
interval={9000}
67+
/>
68+
<FloatingItem
69+
src="https://noticon-static.tammolo.com/dgggcrkxq/image/upload/v1686670279/noticon/gvasp3qtaz16spmwoorl.gif"
70+
size="w-24"
71+
duration={7}
72+
interval={10000}
73+
/>
74+
</div>
75+
);
76+
};
77+
78+
export default FloatingBackground;

react-app/src/pages/ChangePW.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ const ChangePW = () => {
6060
className="w-[40%] aspect-square flex justify-center items-center object-contain m-5 pr-13 pt-13"
6161
/>
6262
)}
63-
<div className="flex flex-col justify-center w-full md:w-[50%] p-6 gap-6">
64-
<h2 className="font-gumi text-center text-[24px] md:text-[32px] mb-4">
63+
<div
64+
className={`flex flex-col justify-center ${isDesktop ? 'w-1/2 px-8' : 'w-full px-6 gap-[2vw]'}`}
65+
>
66+
<h2 className={`font-gumi text-center mb-8 ${isDesktop ? 'text-[3vw]' : 'text-[6vw]'}`}>
6567
<span className="text-[var(--color-primary-base)]"></span>로 정했다!
6668
</h2>
6769

react-app/src/pages/Main.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Button from '@/components/Button/Button';
2+
import FloatingBackground from '@/components/FloatingBackground/FloatingBackground';
23
import { useCallback, useEffect, useState } from 'react';
34
import { useNavigate } from 'react-router-dom';
45

@@ -43,6 +44,7 @@ const Main = () => {
4344

4445
return (
4546
<div className="flex flex-col justify-center items-center h-full px-4 text-center relative">
47+
<FloatingBackground />
4648
<div className="flex flex-col justify-center gap-6">
4749
<p className="text-base sm:text-lg md:text-xl text-gray-600 font-pb">
4850
{restTime > 0 ? '투표 결과 발표까지 남은 시간' : '투표 집계가 완료되었습니다.'}

0 commit comments

Comments
 (0)