From 5a4bf00d105f6e67d498f0cabd871fd129734513 Mon Sep 17 00:00:00 2001 From: jyn Date: Tue, 29 Apr 2025 23:43:18 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EB=AA=A8=EB=B0=94?= =?UTF-8?q?=EC=9D=BC=20=EC=A7=84=EC=9E=85=20=EB=98=90=EB=8A=94=20=EB=B2=97?= =?UTF-8?q?=EC=96=B4=EB=82=98=EB=A9=B4=20=EC=BA=90=EB=9F=AC=EC=85=80=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EB=A6=AC=EC=85=8B./10=EB=AF=B8=EB=A7=8C?= =?UTF-8?q?=20=EB=93=9C=EB=9E=98=EA=B7=B8=EB=8A=94=20=ED=81=B4=EB=A6=AD?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=EC=8B=9D=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Carousel/Carousel.jsx | 69 ++++++++++++++++--- src/components/Carousel/Carousel.module.scss | 13 ---- .../RecipientCard/RecipientCard.jsx | 23 +++++-- src/hooks/useWindowWidth.jsx | 14 ---- 4 files changed, 77 insertions(+), 42 deletions(-) delete mode 100644 src/hooks/useWindowWidth.jsx diff --git a/src/components/Carousel/Carousel.jsx b/src/components/Carousel/Carousel.jsx index 792d046..065201c 100644 --- a/src/components/Carousel/Carousel.jsx +++ b/src/components/Carousel/Carousel.jsx @@ -1,26 +1,63 @@ import { useState, useEffect } from 'react'; import styles from './Carousel.module.scss'; import RecipientCard from '../RecipientCard/RecipientCard'; -import useWindowWidth from '../../hooks/useWindowWidth'; export default function Carousel({ recipients }) { const [index, setIndex] = useState(0); const [offsetX, setOffsetX] = useState({}); // 캐러셀 x좌표 const [startX, setstartX] = useState(0); // 터치 스크롤 시작 x좌표 const [isBouncing, setBouncing] = useState(false); // 캐러셀 끝이면 bouncing 모션 - const isDesktop = useWindowWidth() > 1200; + const [deviceType, setDeviceType] = useState(getDeviceType()); + const windowSize = getDeviceType(); + const isDesktop = windowSize === 'desktop'; + const isMobile = windowSize === 'mobile'; // 캐러셀 버튼 작동과정: button onclick --> settingIndex(), setIndex --> useEffect( setOffsetX(),[index] ): x좌표 상태 업데이트: 캐러셀 이동 useEffect(() => { - setOffsetX({ - transform: `translateX(-${index * 295}px)`, - }); + if (isMobile) { + setOffsetX({ + transform: `translateX(-${index * 228}px)`, + }); + } else { + setOffsetX({ + transform: `translateX(-${index * 295}px)`, + }); + } }, [index]); function settingIndex(direction) { setIndex((prev) => (direction === 'next' ? prev + 1 : prev - 1)); // next? next index : back index } + // 화면 리사이즈 감지 + function getDeviceType() { + const width = window.innerWidth; + if (width < 768) return 'mobile'; + if (width <= 1200) return 'bigTablet'; + if (width <= 1023) return 'tablet'; + return 'desktop'; + } + + useEffect(() => { + function handleResize() { + const newType = getDeviceType(); + const isMobile = deviceType === 'mobile'; + const willBeMobile = newType === 'mobile'; + + // mobile → non-mobile 또는 non-mobile → mobile 로 변경될 때만 + const crossedMobileBoundary = isMobile !== willBeMobile; + if (crossedMobileBoundary) { + setIndex(0); + } + if (newType !== deviceType) { + setDeviceType(newType); + } + } + + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, [deviceType]); + // 터치, 마우스 드래그 감지 --> 캐러셀 한 칸 이동 function handleStart(e) { if (isDesktop) return; @@ -45,12 +82,22 @@ export default function Carousel({ recipients }) { return; } } else if (isNext) { - if (index === 5) { - setBouncing(true); - return; - } else if (index < 5) { - settingIndex('next'); - return; + if (isMobile) { + if (index === 6) { + setBouncing(true); + return; + } else if (index < 6) { + settingIndex('next'); + return; + } + } else { + if (index === 5) { + setBouncing(true); + return; + } else if (index < 5) { + settingIndex('next'); + return; + } } } } diff --git a/src/components/Carousel/Carousel.module.scss b/src/components/Carousel/Carousel.module.scss index c444225..182df77 100644 --- a/src/components/Carousel/Carousel.module.scss +++ b/src/components/Carousel/Carousel.module.scss @@ -94,19 +94,6 @@ display: none; } } -// 태블릿 -@media (max-width: 1023px) { - // .carousel__cardset-wrapper { - // width: 100vw; - // } - // .carousel::before, - // .carousel::after { - // display: none; - // } - // .carousel__direction-button { - // display: none; - // } -} //모바일 @media (max-width: 767px) { diff --git a/src/components/RecipientCard/RecipientCard.jsx b/src/components/RecipientCard/RecipientCard.jsx index d92b6c2..41ad6c1 100644 --- a/src/components/RecipientCard/RecipientCard.jsx +++ b/src/components/RecipientCard/RecipientCard.jsx @@ -16,12 +16,27 @@ export default function RecipientCard({ Recipient }) { } = Recipient; const navigate = useNavigate(); const [isDragging, setIsDragging] = useState(false); + const [startX, setStartX] = useState(null); function handleCardClick() { if (!isDragging) { navigate(`/post/${id}`); } } + function handleStart(e) { + const x = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX; + setStartX(x); + setIsDragging(false); + } + + function handleMove(e) { + if (startX === null) return; + const x = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX; + const distance = Math.abs(x - startX); + if (distance >= 10) { + setIsDragging(true); + } + } return (
setIsDragging(false)} - onTouchStart={() => setIsDragging(false)} - onMouseMove={() => setIsDragging(true)} - onTouchMove={() => setIsDragging(true)} + onMouseDown={handleStart} + onTouchStart={handleStart} + onMouseMove={handleMove} + onTouchMove={handleMove} > {backgroundColor === 'blue' &&
}

{ - function handleResize() { - setWindowWidth(window.innerWidth); - } - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, []); - return windowWidth; -}