From de127fe8cea4790af23a23c74153b6187fe5b776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 22:19:52 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=BA=90=EB=9F=AC=EC=85=80=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=EC=9D=84=20=ED=81=B4=EB=A6=AD=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=EC=A1=B0=EC=9E=91=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/main/components/Carousel.tsx | 157 +++++++++++++++--- apps/jurumarble/src/app/page.tsx | 11 +- 2 files changed, 139 insertions(+), 29 deletions(-) diff --git a/apps/jurumarble/src/app/main/components/Carousel.tsx b/apps/jurumarble/src/app/main/components/Carousel.tsx index db0286e0..c9350f90 100644 --- a/apps/jurumarble/src/app/main/components/Carousel.tsx +++ b/apps/jurumarble/src/app/main/components/Carousel.tsx @@ -3,6 +3,12 @@ import Path from "lib/Path"; import Image from "next/image"; import { useRouter } from "next/navigation"; import styled, { css } from "styled-components"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { SvgIcPrevious, SvgNext } from "src/assets/icons/components"; + +const SLIDE_MOVE_COUNT = 1; +const ORIGINAL_IMAGE_LENGTH = 10; +const MOVE_DISTANCE = 300; interface Props { hotDrinkList: GetHotDrinkResponse[]; @@ -10,42 +16,112 @@ interface Props { function Carousel({ hotDrinkList }: Props) { const router = useRouter(); + const slideRef = useRef(null); + const [currentSlide, setCurrentSlide] = useState(1); + const [isAnimation, setIsAnimation] = useState(true); + const [isFlowing, setIsFlowing] = useState(true); + + const onNextSlide = useCallback(() => { + setCurrentSlide((prev) => prev + SLIDE_MOVE_COUNT); + }, [currentSlide]); + + const onPrevSlide = useCallback(() => { + setCurrentSlide((prev) => prev - SLIDE_MOVE_COUNT); + }, [currentSlide]); + + useEffect(() => { + if (!slideRef.current) return; + + if (currentSlide === ORIGINAL_IMAGE_LENGTH + 1) { + setTimeout(() => { + setIsAnimation(false); + slideRef.current!.style.transform = `translateX(-${ + MOVE_DISTANCE * ORIGINAL_IMAGE_LENGTH + }px)`; + setCurrentSlide(1); + }, 500); + + setTimeout(() => { + setIsAnimation(true); + }, 600); + } else if (currentSlide === 0) { + setTimeout(() => { + setIsAnimation(false); + slideRef.current!.style.transform = `translateX(+${MOVE_DISTANCE}px)`; + setCurrentSlide(ORIGINAL_IMAGE_LENGTH); + }, 500); + + setTimeout(() => { + setIsAnimation(true); + }, 600); + } + slideRef.current.style.transform = `translateX(-${MOVE_DISTANCE * (currentSlide - 1)}px)`; + }, [currentSlide]); + + useEffect(() => { + let intervalId: NodeJS.Timeout; + if (isFlowing) { + intervalId = setInterval(() => { + setCurrentSlide((prev) => prev + SLIDE_MOVE_COUNT); + }, 3500); + } + return () => clearTimeout(intervalId); + }, [isFlowing, currentSlide]); + return ( - - - {hotDrinkList.map((hotDrink: GetHotDrinkResponse, index: number) => { - const { drinkId, image, name, manufactureAddress } = hotDrink; - return ( - router.push(`${Path.DRINK_INFO_PAGE}/${drinkId}`)}> - - - {index + 1} - 전통주 - - - {name} - {manufactureAddress} - - - - ); - })} - - + <> + + + {hotDrinkList.map((hotDrink: GetHotDrinkResponse, index: number) => { + const { drinkId, image, name, manufactureAddress } = hotDrink; + return ( + router.push(`${Path.DRINK_INFO_PAGE}/${drinkId}`)} + > + + + {index + 1} + 전통주 + + + {name} + {manufactureAddress} + + + + ); + })} + + + + + + + + + + + + + + ); } const Container = styled.div` - height: 188px; margin-top: 32px; + overflow: hidden; `; -const Slides = styled.ol` +const Slides = styled.ol<{ isAnimation: boolean }>` display: flex; - height: 168px; - overflow-x: auto; - scroll-snap-type: x mandatory; + /* overflow-x: auto; + scroll-snap-type: x mandatory; */ gap: 8px; + transition: transform 0.5s ease-in-out; + ${({ isAnimation }) => isAnimation && `transform: translateX(-${MOVE_DISTANCE}px);`} + /** @Todo 모바일에서는 보이게 하기 **/ @@ -60,7 +136,7 @@ const Slide = styled.li` width: 292px; height: 120px; padding-top: 20px; - scroll-snap-align: start; + /* scroll-snap-align: start; */ cursor: pointer; `; @@ -120,4 +196,31 @@ const AreaName = styled.span` `} `; +const CarouselControlContainer = styled.div` + margin-top: 28px; + display: flex; + align-items: center; + gap: 20px; +`; + +const DivideLine = styled.div` + ${({ theme }) => css` + background-color: ${theme.colors.line_01}; + height: 2px; + width: 100%; + `} +`; + +const SlideButtonContainer = styled.div` + display: flex; + gap: 10px; +`; + +const SlideButton = styled.button` + border-radius: 100px; + border: 1px solid ${({ theme }) => theme.colors.line_01}; + width: 40px; + height: 40px; +`; + export default Carousel; diff --git a/apps/jurumarble/src/app/page.tsx b/apps/jurumarble/src/app/page.tsx index d651d314..c2239b55 100644 --- a/apps/jurumarble/src/app/page.tsx +++ b/apps/jurumarble/src/app/page.tsx @@ -1,9 +1,8 @@ "use client"; import BottomBar from "components/BottomBar"; -import DivideLine from "components/DivideLine"; import Header from "components/Header"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import Banner from "./main/components/Banner"; import HotDrinkContainer from "./main/components/HotDrinkContainer"; import HotDrinkVoteContainer from "./main/components/HotDrinkVoteContainer"; @@ -39,4 +38,12 @@ const BottomSection = styled.section` overflow: auto; `; +const DivideLine = styled.div` + ${({ theme }) => css` + background-color: ${theme.colors.bg_01}; + height: 8px; + margin: 40px 0 8px 0; + `} +`; + export default MainPage;