feat: 모바일 홈 화면 섹션별 애니메이션 추가
- 히어로 섹션: 페이드인 + 텍스트 슬라이드업 - 멤버 섹션: 프로필 팝 애니메이션 - 앨범 섹션: 카드 슬라이드업 - 일정 섹션: 카드 슬라이드인 - 순차적 딜레이로 자연스러운 로딩 효과
This commit is contained in:
parent
dc879fc60d
commit
d6eb8d410c
1 changed files with 47 additions and 13 deletions
|
|
@ -35,9 +35,19 @@ function MobileHome() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* 히어로 섹션 */}
|
{/* 히어로 섹션 */}
|
||||||
<section className="relative bg-gradient-to-br from-primary to-primary-dark py-12 px-4 overflow-hidden">
|
<motion.section
|
||||||
|
className="relative bg-gradient-to-br from-primary to-primary-dark py-12 px-4 overflow-hidden"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
>
|
||||||
<div className="absolute inset-0 bg-black/10" />
|
<div className="absolute inset-0 bg-black/10" />
|
||||||
<div className="relative text-center text-white">
|
<motion.div
|
||||||
|
className="relative text-center text-white"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.2, duration: 0.5 }}
|
||||||
|
>
|
||||||
<h1 className="text-3xl font-bold mb-1">fromis_9</h1>
|
<h1 className="text-3xl font-bold mb-1">fromis_9</h1>
|
||||||
<p className="text-lg font-light mb-3">프로미스나인</p>
|
<p className="text-lg font-light mb-3">프로미스나인</p>
|
||||||
<p className="text-sm opacity-80 leading-relaxed">
|
<p className="text-sm opacity-80 leading-relaxed">
|
||||||
|
|
@ -45,14 +55,19 @@ function MobileHome() {
|
||||||
이제는 약속해 소중히 간직해,<br />
|
이제는 약속해 소중히 간직해,<br />
|
||||||
당신의 아이돌로 성장하겠습니다!
|
당신의 아이돌로 성장하겠습니다!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</motion.div>
|
||||||
{/* 장식 */}
|
{/* 장식 */}
|
||||||
<div className="absolute right-0 top-0 w-32 h-32 rounded-full bg-white/10 -translate-y-1/2 translate-x-1/2" />
|
<div className="absolute right-0 top-0 w-32 h-32 rounded-full bg-white/10 -translate-y-1/2 translate-x-1/2" />
|
||||||
<div className="absolute left-0 bottom-0 w-24 h-24 rounded-full bg-white/5 translate-y-1/2 -translate-x-1/2" />
|
<div className="absolute left-0 bottom-0 w-24 h-24 rounded-full bg-white/5 translate-y-1/2 -translate-x-1/2" />
|
||||||
</section>
|
</motion.section>
|
||||||
|
|
||||||
{/* 멤버 섹션 */}
|
{/* 멤버 섹션 */}
|
||||||
<section className="px-4 py-6">
|
<motion.section
|
||||||
|
className="px-4 py-6"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.3, duration: 0.5 }}
|
||||||
|
>
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h2 className="text-lg font-bold">멤버</h2>
|
<h2 className="text-lg font-bold">멤버</h2>
|
||||||
<button
|
<button
|
||||||
|
|
@ -63,10 +78,13 @@ function MobileHome() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-5 gap-2">
|
<div className="grid grid-cols-5 gap-2">
|
||||||
{members.map((member) => (
|
{members.map((member, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={member.id}
|
key={member.id}
|
||||||
className="text-center"
|
className="text-center"
|
||||||
|
initial={{ opacity: 0, scale: 0.8 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
transition={{ delay: 0.4 + index * 0.05, duration: 0.3 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
>
|
>
|
||||||
<div className="aspect-square rounded-full overflow-hidden bg-gray-200 mb-1">
|
<div className="aspect-square rounded-full overflow-hidden bg-gray-200 mb-1">
|
||||||
|
|
@ -82,10 +100,15 @@ function MobileHome() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</motion.section>
|
||||||
|
|
||||||
{/* 앨범 섹션 */}
|
{/* 앨범 섹션 */}
|
||||||
<section className="px-4 py-6 bg-gray-50">
|
<motion.section
|
||||||
|
className="px-4 py-6 bg-gray-50"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.5, duration: 0.5 }}
|
||||||
|
>
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h2 className="text-lg font-bold">앨범</h2>
|
<h2 className="text-lg font-bold">앨범</h2>
|
||||||
<button
|
<button
|
||||||
|
|
@ -96,11 +119,14 @@ function MobileHome() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
{albums.map((album) => (
|
{albums.map((album, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={album.id}
|
key={album.id}
|
||||||
onClick={() => navigate(`/album/${album.folder_name}`)}
|
onClick={() => navigate(`/album/${album.folder_name}`)}
|
||||||
className="bg-white rounded-xl overflow-hidden shadow-sm"
|
className="bg-white rounded-xl overflow-hidden shadow-sm"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.6 + index * 0.1, duration: 0.3 }}
|
||||||
whileTap={{ scale: 0.98 }}
|
whileTap={{ scale: 0.98 }}
|
||||||
>
|
>
|
||||||
<div className="aspect-square bg-gray-200">
|
<div className="aspect-square bg-gray-200">
|
||||||
|
|
@ -119,10 +145,15 @@ function MobileHome() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</motion.section>
|
||||||
|
|
||||||
{/* 일정 섹션 */}
|
{/* 일정 섹션 */}
|
||||||
<section className="px-4 py-4">
|
<motion.section
|
||||||
|
className="px-4 py-4"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.7, duration: 0.5 }}
|
||||||
|
>
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h2 className="text-lg font-bold">다가오는 일정</h2>
|
<h2 className="text-lg font-bold">다가오는 일정</h2>
|
||||||
<button
|
<button
|
||||||
|
|
@ -134,7 +165,7 @@ function MobileHome() {
|
||||||
</div>
|
</div>
|
||||||
{schedules.length > 0 ? (
|
{schedules.length > 0 ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{schedules.map((schedule) => {
|
{schedules.map((schedule, index) => {
|
||||||
const scheduleDate = new Date(schedule.date);
|
const scheduleDate = new Date(schedule.date);
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const currentYear = today.getFullYear();
|
const currentYear = today.getFullYear();
|
||||||
|
|
@ -152,6 +183,9 @@ function MobileHome() {
|
||||||
<motion.div
|
<motion.div
|
||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
className="flex gap-4 bg-white p-4 rounded-xl shadow-sm border border-gray-100 overflow-hidden"
|
className="flex gap-4 bg-white p-4 rounded-xl shadow-sm border border-gray-100 overflow-hidden"
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: 0.8 + index * 0.1, duration: 0.3 }}
|
||||||
whileTap={{ scale: 0.98 }}
|
whileTap={{ scale: 0.98 }}
|
||||||
onClick={() => navigate('/schedule')}
|
onClick={() => navigate('/schedule')}
|
||||||
>
|
>
|
||||||
|
|
@ -223,7 +257,7 @@ function MobileHome() {
|
||||||
<p>다가오는 일정이 없습니다</p>
|
<p>다가오는 일정이 없습니다</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</motion.section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue