diff --git a/package-lock.json b/package-lock.json index 09826f90..855d7b28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "react-intersection-observer": "^9.14.0", "react-kakao-maps-sdk": "^1.1.27", "react-modal": "^3.16.1", + "react-responsive": "^10.0.0", "tailwind-merge": "^2.5.4", "zod": "^3.23.8", "zustand": "^5.0.1" @@ -8049,6 +8050,12 @@ } } }, + "node_modules/css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==", + "license": "BSD" + }, "node_modules/css-select": { "version": "4.3.0", "dev": true, @@ -10275,6 +10282,12 @@ "dev": true, "license": "MIT" }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" + }, "node_modules/icss-utils": { "version": "5.1.0", "dev": true, @@ -11160,6 +11173,15 @@ "dev": true, "license": "MIT" }, + "node_modules/matchmediaquery": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.4.2.tgz", + "integrity": "sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA==", + "license": "MIT", + "dependencies": { + "css-mediaquery": "^0.1.2" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -12981,6 +13003,24 @@ } } }, + "node_modules/react-responsive": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-10.0.0.tgz", + "integrity": "sha512-N6/UiRLGQyGUqrarhBZmrSmHi2FXSD++N5VbSKsBBvWfG0ZV7asvUBluSv5lSzdMyEVjzZ6Y8DL4OHABiztDOg==", + "license": "MIT", + "dependencies": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.4.2", + "prop-types": "^15.6.1", + "shallow-equal": "^3.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.3", "dev": true, @@ -13678,6 +13718,12 @@ "sha.js": "bin.js" } }, + "node_modules/shallow-equal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz", + "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==", + "license": "MIT" + }, "node_modules/sharp": { "version": "0.33.5", "dev": true, diff --git a/package.json b/package.json index 7c935ea5..b570e560 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "react-intersection-observer": "^9.14.0", "react-kakao-maps-sdk": "^1.1.27", "react-modal": "^3.16.1", + "react-responsive": "^10.0.0", "tailwind-merge": "^2.5.4", "zod": "^3.23.8", "zustand": "^5.0.1" diff --git a/public/images/land/2.webp b/public/images/land/2.webp deleted file mode 100644 index 56f950bb..00000000 Binary files a/public/images/land/2.webp and /dev/null differ diff --git a/public/images/land/concept.jpg b/public/images/land/concept.jpg new file mode 100644 index 00000000..13588a73 Binary files /dev/null and b/public/images/land/concept.jpg differ diff --git a/public/images/land/s2.jpg b/public/images/land/s2.jpg new file mode 100644 index 00000000..86eb7dd4 Binary files /dev/null and b/public/images/land/s2.jpg differ diff --git a/public/images/land/s2.webp b/public/images/land/s2.webp deleted file mode 100644 index 4be85591..00000000 Binary files a/public/images/land/s2.webp and /dev/null differ diff --git a/public/images/land/s3.jpg b/public/images/land/s3.jpg new file mode 100644 index 00000000..fcf17e15 Binary files /dev/null and b/public/images/land/s3.jpg differ diff --git a/public/images/land/s4.jpg b/public/images/land/s4.jpg new file mode 100644 index 00000000..9ffee162 Binary files /dev/null and b/public/images/land/s4.jpg differ diff --git a/public/images/land/step1.jpg b/public/images/land/step1.jpg index f2e1c78d..96314234 100644 Binary files a/public/images/land/step1.jpg and b/public/images/land/step1.jpg differ diff --git a/public/images/land/step2-1.jpg b/public/images/land/step2-1.jpg new file mode 100644 index 00000000..60fffed8 Binary files /dev/null and b/public/images/land/step2-1.jpg differ diff --git a/public/images/land/step2-2.jpg b/public/images/land/step2-2.jpg new file mode 100644 index 00000000..0770538f Binary files /dev/null and b/public/images/land/step2-2.jpg differ diff --git a/public/images/land/step2.jpg b/public/images/land/step2.jpg deleted file mode 100644 index 026a8d65..00000000 Binary files a/public/images/land/step2.jpg and /dev/null differ diff --git a/public/images/land/step3-1.jpg b/public/images/land/step3-1.jpg new file mode 100644 index 00000000..b7bae13e Binary files /dev/null and b/public/images/land/step3-1.jpg differ diff --git a/public/images/land/step3-2.jpg b/public/images/land/step3-2.jpg new file mode 100644 index 00000000..619a7823 Binary files /dev/null and b/public/images/land/step3-2.jpg differ diff --git a/public/images/land/step3.jpg b/public/images/land/step3.jpg deleted file mode 100644 index 15d10109..00000000 Binary files a/public/images/land/step3.jpg and /dev/null differ diff --git a/public/images/land/step4.jpg b/public/images/land/step4.jpg deleted file mode 100644 index 3d46e066..00000000 Binary files a/public/images/land/step4.jpg and /dev/null differ diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index 5c048ad8..13146e7f 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -4,30 +4,64 @@ import React, { useEffect, useRef, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import Image from "next/image"; import Lenis from "@studio-freight/lenis"; +import { useMediaQuery } from "react-responsive"; const slides = [ - { id: 1, image: "/brand.png", title: "Brand Image" }, + { + id: 1, + title: "쉽고 빨라요", + content: "1분만에 알바폼을 만들어 보세요!\n링크를 복사하여 어디서든지 사용하세요.", + image: "/images/land/s2.jpg", + }, { id: 2, - title: "어디서든 지원받으세요", - content: "다양한 사이트, SNS, 문자까지 언제 어디서든 직원을 구해보세요", - image: "/images/land/s2.webp", + title: "한 곳에서 쉽게 관리하세요", + content: "워크폼 관리 페이지에서 지원 현황을 확인하고\n지원자별 상태를 관리할 수 있습니다.", + image: "/images/land/s3.jpg", }, { id: 3, - title: "한 곳에서 쉽게 관리하세요", - content: "워크폼 관리 페이지에서 지원 현황을 확인하고, 지원자별 상태를 관리할 수 있습니다다", - image: "/images/land/2.webp", + title: "쉽고 빠르게 지원하세요", + content: "간단한 정보만 입력해도\n알바 지원이 가능합니다.", + image: "/images/land/s4.jpg", }, { id: 4, - title: "쉽고 빨라요", - content: "1분만에 워크폼을 만들어보세요! 링크를 복사하여 어디서든 사용하세요", - image: "/images/land/2.webp", + title: "workroot에 가입하세요", + content: "오늘의 선택이 내일의 열매가 됩니다.", + image: "/images/land/step1.jpg", + }, + { + id: 5, + title: "지원자 이용 방법", + content: "언제든 다시 볼 수 있게\n공고를 스크랩하세요", + image: "/images/land/step2-2.jpg", + blackAreaTitle: "사장님 이용 방법", + blackAreaContent: "워크채널 우측의 [폼 만들기] 버튼을 클릭하고\n인재 채용을 시작하세요", + blackAreaImage: "/images/land/step2-1.jpg", + }, + { + id: 6, + title: "", + content: "마이페이지에서 스크랩한 공고를 분석하고\n지원 계획을 세우세요", + image: "/images/land/step3-2.jpg", + blackAreaTitle: "", + blackAreaContent: "내 워크폼에서 작성한 공고를\n손쉽게 수정하고 삭제할 수 있어요", + blackAreaImage: "/images/land/step3-1.jpg", }, ]; +const bounceAnimation = { + y: [0, -10, 0], + transition: { + repeat: Infinity, + duration: 1.5, + ease: "easeInOut", + }, +}; + export default function LandingPage() { + const isLargeScreen = useMediaQuery({ minWidth: 641 }); const [currentSlide, setCurrentSlide] = useState(0); const [isLoaded, setIsLoaded] = useState(false); const containerRef = useRef(null); @@ -37,12 +71,12 @@ export default function LandingPage() { useEffect(() => { setIsLoaded(true); lenisRef.current = new Lenis({ - duration: 1.2, + duration: 0.8, // 1.2에서 0.8로 변경 easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), smoothWheel: true, - wheelMultiplier: 5, - touchMultiplier: 3, - infinite: true, + wheelMultiplier: 2, + touchMultiplier: 1.2, + infinite: false, }); function raf(time: number) { @@ -52,22 +86,35 @@ export default function LandingPage() { requestAnimationFrame(raf); + let lastScrollTime = 0; + const scrollThreshold = 500; // ms + lenisRef.current.on("scroll", ({ progress }: { progress: number }) => { + const currentTime = Date.now(); + if (currentTime - lastScrollTime < scrollThreshold) return; + if (!isScrollingRef.current) { const totalSlides = slides.length; - const newSlideIndex = Math.floor(progress * totalSlides) % totalSlides; + const newSlideIndex = Math.min(slides.length - 1, Math.max(0, Math.round(progress * (totalSlides - 1)))); + if (newSlideIndex !== currentSlide) { setCurrentSlide(newSlideIndex); isScrollingRef.current = true; - const targetScroll = (newSlideIndex / totalSlides) * containerRef.current!.scrollHeight || 0; + const targetScroll = + (newSlideIndex / (totalSlides - 1)) * + (isLargeScreen ? containerRef.current!.scrollHeight : containerRef.current!.scrollWidth); + lenisRef.current?.scrollTo(targetScroll, { immediate: false, - duration: 800, + duration: 600, // 800에서 600으로 변경 easing: (t: number) => t * (2 - t), }); + + lastScrollTime = currentTime; + setTimeout(() => { isScrollingRef.current = false; - }, 800); + }, 600); // 800에서 600으로 변경 } } }); @@ -90,7 +137,7 @@ export default function LandingPage() { document.documentElement.style.overflow = ""; style.remove(); }; - }, [currentSlide]); + }, [currentSlide, isLargeScreen]); return ( @@ -101,71 +148,175 @@ export default function LandingPage() { exit={{ opacity: 0 }} transition={{ duration: 1 }} ref={containerRef} - className="h-[400vh] overflow-hidden bg-gradient-to-br from-[#1a1a1a] to-[#2a2a2a]" + className={`h-[400vh] min-h-[768px] overflow-hidden bg-gradient-to-br from-[#1a1a1a] to-[#2a2a2a] ${ + isLargeScreen ? "" : "flex flex-col" + }`} > -
+
- Brand Logo + {currentSlide === 0 ? ( + Brand Logo + ) : currentSlide === 4 || currentSlide === 5 ? ( + + + {slides[currentSlide].blackAreaTitle} + + +
+ {slides[currentSlide].blackAreaTitle +
+
+ + {slides[currentSlide].blackAreaContent} + +
+ ) : ( + +
+ Brand Logo +
+
+ )}
+ {currentSlide === 0 && ( + + + + + scroll + + )}
{currentSlide > 0 && ( {slides[currentSlide].title} - {slides[currentSlide].title} +
+ {slides[currentSlide].title +
{slides[currentSlide].content} @@ -175,7 +326,9 @@ export default function LandingPage() {
{currentSlide > 0 && ( -
+
{slides.slice(1).map((_, index) => (