Skip to content

Commit ee9197a

Browse files
authored
feat: 메인페이지 인기 섹션 UI 구현 #45-2
Feat/45-2 메인페이지 인기 체험 섹션 UI 구현
2 parents dfa49a4 + e1e05ee commit ee9197a

File tree

6 files changed

+94
-2
lines changed

6 files changed

+94
-2
lines changed

src/app/(with-header)/components/BannerSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function BannerSection() {
1717
<div className='absolute inset-0 bg-gradient-to-r from-black to-transparent' />
1818

1919
{/* 텍스트 콘텐츠 */}
20-
<div className='relative z-10 flex flex-col items-start w-220 max-w-1152 md:w-440 lg:w-full pl-24 pt-74 md:pl-32 lg:pl-0 md:pt-144 lg:pt-159 lg:ml-auto lg:mr-auto gap-8 lg:gap-20 h-full text-white font-bold break-keep'>
20+
<div className='relative z-10 flex flex-col items-start w-220 max-w-1200 md:w-440 lg:w-full pl-24 pt-74 md:pl-32 lg:pl-0 md:pt-144 lg:pt-159 lg:ml-auto lg:mr-auto gap-8 lg:gap-20 h-full text-white font-bold break-keep'>
2121
<h2 className='text-2xl md:text-[54px] md:leading-[64px] lg:text-[68px] lg:leading-[78px]'>
2222
함께 배우면 즐거운<br />
2323
스트릿 댄스
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Image from 'next/image';
2+
3+
export default function ExperienceCard() {
4+
return (
5+
<div className='relative w-186 h-186 md:w-384 md:h-384 rounded-[20px] overflow-hidden shadow-md bg-white'>
6+
{/* 배경 이미지 */}
7+
<Image
8+
src='/test/image1.png'
9+
alt='체험 이미지'
10+
className='w-full object-cover'
11+
fill
12+
/>
13+
{/* 어두운 오버레이 */}
14+
<div className='absolute inset-0 bg-gradient-to-r from-black to-transparent' />
15+
{/* 텍스트 정보 블록 (카드 하단 위치 고정) */}
16+
<div className='absolute bottom-12 flex flex-col gap-6 md:gap-20 px-20 py-12 text-white'>
17+
{/* 별점 정보 */}
18+
<span className='text-md'>⭐ 4.9 (293)</span>
19+
{/* 체험명 (줄바꿈 포함, 반응형 크기) */}
20+
<p className='text-2lg md:text-3xl font-semibold'>함께 배우면 즐거운<br />스트릿 댄스</p>
21+
{/* 가격 정보 */}
22+
<p className='text-lg md:text-xl'>₩ 38,000 <span className='text-gray-600 text-md'>/ 인</span></p>
23+
</div>
24+
</div>
25+
);
26+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use client';
2+
3+
import { useRef } from 'react';
4+
import ExperienceCard from '@/app/(with-header)/components/ExperienceCard';
5+
import IconArrowRight from '@assets/svg/right-arrow';
6+
import IconArrowLeft from '@assets/svg/left-arrow';
7+
8+
export default function PopularExperiences() {
9+
// 카드 슬라이더를 참조할 DOM ref
10+
const sliderRef = useRef<HTMLDivElement>(null);
11+
12+
// 좌우 버튼 클릭 시 한 장씩 슬라이드 이동
13+
const scrollByCard = (direction: 'left' | 'right') => {
14+
if (!sliderRef.current) return;
15+
16+
// 첫 번째 카드 요소를 찾아서 너비 측정
17+
const card = sliderRef.current.querySelector('.card');
18+
if (!(card instanceof HTMLElement)) return;
19+
20+
const cardWidth = card.offsetWidth; // 카드 너비
21+
const gap = parseInt(getComputedStyle(sliderRef.current).gap) || 0; // gap 값
22+
const distance = cardWidth + gap; // 한 번에 이동할 거리
23+
24+
// 슬라이더 스크롤 이동 (좌/우 방향에 따라)
25+
sliderRef.current.scrollBy({
26+
left: direction === 'left' ? -distance : distance,
27+
behavior: 'smooth',
28+
});
29+
};
30+
31+
return (
32+
<section className='pt-24 md:pt-34 pl-24 lg:pl-0 pb-40 lg:pb-33 lg:max-w-1200 lg:w-full mx-auto'>
33+
{/* 섹션 제목 + 좌우 화살표 버튼 */}
34+
<div className='flex justify-between items-center pb-16 md:pb-32 mb-6'>
35+
<h2 className='text-xl md:text-3xl font-bold'>🔥 인기 체험</h2>
36+
<div className='flex gap-2'>
37+
<IconArrowLeft size={32} onClick={() => scrollByCard('left')} className='text-2xl px-3' />
38+
<IconArrowRight size={32} onClick={() => scrollByCard('right')} className='text-2xl px-3' />
39+
</div>
40+
</div>
41+
42+
{/* 가로 슬라이드 카드 리스트 */}
43+
<div
44+
ref={sliderRef}
45+
className='flex gap-16 md:gap-32 lg:gap-24 overflow-x-auto scroll-smooth no-scrollbar'
46+
>
47+
{[...Array(4)].map((_, idx) => (
48+
// 카드 wrapper: flex-shrink-0으로 크기 고정 + 'card' 클래스로 식별
49+
<div key={idx} className='flex-shrink-0 card'>
50+
<ExperienceCard />
51+
</div>
52+
))}
53+
</div>
54+
</section>
55+
);
56+
}

src/app/(with-header)/components/SearchBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default function SearchBar() {
1313
};
1414

1515
return (
16-
<section className='flex lg:w-full lg:max-w-1152 lg:ml-auto lg:mr-auto justify-center px-16 lg:px-0'>
16+
<section className='flex lg:w-full lg:max-w-1200 lg:ml-auto lg:mr-auto justify-center px-16 lg:px-0'>
1717
<div className='flex flex-col w-full gap-15 md:gap-32 px-24 py-16 md:px-24 md:py-32 rounded-[16px] bg-white shadow-md'>
1818
<div className='flex items-start gap-2 mb-4'>
1919
<h3 className='text-lg md:text-xl font-bold text-left'>

src/app/(with-header)/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import BannerSection from '@/app/(with-header)/components/BannerSection';
2+
import PopularExperiences from '@/app/(with-header)/components/PopularExperiences';
23

34
export default function HomePage() {
45
return (
56
<main>
67
<BannerSection />
8+
<PopularExperiences />
79
</main>
810
);
911
}

src/app/globals.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,11 @@
131131

132132
--spacing: 0.0625rem;
133133
}
134+
135+
.no-scrollbar::-webkit-scrollbar {
136+
display: none;
137+
}
138+
.no-scrollbar {
139+
-ms-overflow-style: none;
140+
scrollbar-width: none;
141+
}

0 commit comments

Comments
 (0)