diff --git a/src/assets/icons/main1.svg b/src/assets/icons/main1.svg new file mode 100644 index 0000000..1364f32 --- /dev/null +++ b/src/assets/icons/main1.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/main2.svg b/src/assets/icons/main2.svg new file mode 100644 index 0000000..9406c86 --- /dev/null +++ b/src/assets/icons/main2.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/index.tsx b/src/assets/index.tsx index efd0247..cc13ee4 100644 --- a/src/assets/index.tsx +++ b/src/assets/index.tsx @@ -16,6 +16,8 @@ import AIImage from '@/assets/icons/ai_image.svg?react'; import HomeBanner from '@/assets/icons/home_banner.jpg'; import KakaoLogin from '@/assets/icons/kakao_login.png'; import LoginImage from '@/assets/icons/login_image.svg?react'; +import MainImage1 from '@/assets/icons/main1.svg?react'; +import MainImage2 from '@/assets/icons/main2.svg?react'; export { InfoIcon, @@ -36,4 +38,6 @@ export { HomeBanner, LoginImage, KakaoLogin, + MainImage1, + MainImage2, }; diff --git a/src/component/common/Badge/Badge.tsx b/src/component/common/Badge/Badge.tsx index 8792646..9a6ea97 100644 --- a/src/component/common/Badge/Badge.tsx +++ b/src/component/common/Badge/Badge.tsx @@ -17,7 +17,9 @@ export default function Badge({ type, children, color, count, percent, size = 's const label = type === 'parkingTag' ? ( - {children} + {children} + ) : type === 'parkingCount' ? ( + {children} ) : ( <>{children} ); diff --git a/src/component/common/Footer/Footer.tsx b/src/component/common/Footer/Footer.tsx new file mode 100644 index 0000000..0f426f4 --- /dev/null +++ b/src/component/common/Footer/Footer.tsx @@ -0,0 +1,18 @@ +export default function Footer() { + return ( + + ); +} diff --git a/src/component/home/FeatureSlides.tsx b/src/component/home/FeatureSlides.tsx new file mode 100644 index 0000000..3e01c72 --- /dev/null +++ b/src/component/home/FeatureSlides.tsx @@ -0,0 +1,122 @@ +import { useEffect, useRef, useState } from 'react'; +import { Image } from '@/component'; + +type SlideItem = { + id: string | number; + src: string; + title?: string; + desc?: string; +}; + +type FeatureSlidesProps = { + title?: string; + slides: SlideItem[]; +}; + +export default function FeatureSlides({ + title = 'AI 맞춤 여행지 탐색', + slides, +}: FeatureSlidesProps) { + const trackRef = useRef(null); + const itemRefs = useRef<(HTMLDivElement | null)[]>([]); + const [active, setActive] = useState(0); + + useEffect(() => { + const root = trackRef.current; + if (!root) return; + const items = itemRefs.current.filter(Boolean) as HTMLDivElement[]; + if (!items.length) return; + + const io = new IntersectionObserver( + (entries) => { + const visible = entries + .filter((e) => e.isIntersecting) + .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]; + if (!visible) return; + const idx = items.findIndex((el) => el === visible.target); + if (idx !== -1) setActive(idx); + }, + { root, threshold: [0.6] }, + ); + + items.forEach((el) => io.observe(el)); + return () => io.disconnect(); + }, [slides.length]); + + const goTo = (idx: number) => { + itemRefs.current[idx]?.scrollIntoView({ + behavior: 'smooth', + inline: 'start', + block: 'nearest', + }); + }; + + const scrollByDir = (dir: 'left' | 'right') => { + const el = trackRef.current; + if (!el) return; + const amount = el.clientWidth * 0.9; + el.scrollBy({ left: dir === 'left' ? -amount : amount, behavior: 'smooth' }); + }; + + return ( +
+

{title}

+ +
+
+ {slides.map((s, idx) => ( +
{ + itemRefs.current[idx] = el; + }} + className="w-full shrink-0 snap-center items-center justify-center" + > +
+ {s.title +
+ {s.title &&
{s.title}
} + {s.desc &&
{s.desc}
} +
+ ))} +
+ + {/*좌우 화살표(오버레이)*/} + + +
+ + {/*페이지 도트*/} +
+ {slides.map((_, idx) => ( +
+
+ ); +} diff --git a/src/pages/home/Homepage.tsx b/src/pages/home/Homepage.tsx index ff1ba7d..fea49e9 100644 --- a/src/pages/home/Homepage.tsx +++ b/src/pages/home/Homepage.tsx @@ -1,5 +1,7 @@ +import { MainImage1, MainImage2 } from '@/assets'; import HomeBanner from '@/assets/icons/home_banner.jpg'; import { Header, Sidebar, Image, Button } from '@/component'; +import Footer from '@/component/common/Footer/Footer'; import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -18,12 +20,12 @@ export default function HomePage() {
{' '} -
+
-
+
*해당 사진 속 장소는 강릉입니다.
-
+
혼잡한 도시는 이제 그만
지금 가장 여유롭고 한적한 여행지를 찾아드립니다. @@ -32,6 +34,49 @@ export default function HomePage() { 바로가기
+ {/*메인 카드: 관광지 탐색*/} +
+
+ +
관광지 탐색
+
+ 원하는 분위기, 가고 싶은 지역의 +
조용한 여행지를 찾아보세요. +
+
+ 내가 원하는 조용한 여행지, +
이제 손쉽게 찾을 수 있어요. +
+ +
+
+ {/*메인 카드: AI 탐색*/} +
+
+ +
AI 맞춤 여행지 찾기
+
1. 정보 입력하기
+
출발지, 테마, 거리를 입력해주세요
+
2. AI 분석 중!
+
+ 입력한 정보를 바탕으로 +
+ AI가 딱 맞는 여행지를 찾고 있어요. +
+
3. 추천 결과 확인
+
+ 딱 맞는 여행지의 상세정보와 실제 후기 +
+ 주차장 위치까지 한눈에 확인해보세요. +
+ +
+
+