diff --git a/src/components/group/MyGroupBox.tsx b/src/components/group/MyGroupBox.tsx index 3d104d07..b1e297b1 100644 --- a/src/components/group/MyGroupBox.tsx +++ b/src/components/group/MyGroupBox.tsx @@ -65,7 +65,7 @@ export function MyGroupBox({ onMyGroupsClick }: MyGroupProps) { navigate(`detail/joined/${roomId}`); }; - const { scrollRef, cardRefs, infiniteGroups, current } = useInfiniteCarousel(groups); + const { scrollRef, cardRefs, infiniteGroups } = useInfiniteCarousel(groups); return ( @@ -97,11 +97,6 @@ export function MyGroupBox({ onMyGroupsClick }: MyGroupProps) { /> ))} - - {groups.map((_, i) => ( - - ))} - ) : ( @@ -155,21 +150,6 @@ const Carousel = styled.div` scroll-snap-type: x mandatory; `; -const Dots = styled.div` - display: flex; - justify-content: center; - gap: 12px; - margin: 30px 0; -`; - -const Dot = styled.div<{ active: boolean }>` - width: 4px; - height: 4px; - border-radius: 50%; - background: ${({ active }) => (active ? colors.white : colors.grey[300])}; - transition: background-color 0.3s; -`; - const LoadingContainer = styled.div` display: flex; justify-content: center; diff --git a/src/components/group/RecruitingGroupCarousel.tsx b/src/components/group/RecruitingGroupCarousel.tsx index 5f69cfd9..157eff3a 100644 --- a/src/components/group/RecruitingGroupCarousel.tsx +++ b/src/components/group/RecruitingGroupCarousel.tsx @@ -1,7 +1,7 @@ -import { useRef, useEffect, useCallback } from 'react'; import styled from '@emotion/styled'; import type { Group } from './MyGroupBox'; import { RecruitingGroupBox } from './RecruitingGroupBox'; +import { useInfiniteCarousel } from '@/hooks/useInfiniteCarousel'; export interface Section { title: string; @@ -13,59 +13,26 @@ interface Props { } export function RecruitingGroupCarousel({ sections }: Props) { - const scrollRef = useRef(null); - const itemRefs = useRef>([]); + const sectionGroups = sections.map(sec => ({ + ...sec.groups[0], + title: sec.title, + groups: sec.groups, + })); - const handleScroll = useCallback(() => { - const container = scrollRef.current; - if (!container) return; - - const centerX = container.offsetWidth / 2; - const scrollLeft = container.scrollLeft; - - itemRefs.current.forEach(item => { - if (!item) return; - const itemCenter = item.offsetLeft + item.offsetWidth / 2; - const dist = Math.abs(itemCenter - scrollLeft - centerX); - const ratio = Math.min(dist / centerX, 1); - const scale = 1 - ratio * 0.1; - item.style.transform = `scale(${scale})`; - }); - }, []); - - useEffect(() => { - const container = scrollRef.current; - if (!container || sections.length === 0) return; - - const mid = Math.floor(sections.length / 2); - const midItem = itemRefs.current[mid]; - if (midItem) { - const centerX = container.offsetWidth / 2; - const targetScroll = midItem.offsetLeft + midItem.offsetWidth / 2 - centerX; - container.scrollTo({ left: targetScroll, behavior: 'auto' }); - } - handleScroll(); - }, [sections.length, handleScroll]); - - useEffect(() => { - const container = scrollRef.current; - if (!container) return; - container.addEventListener('scroll', handleScroll, { passive: true }); - return () => { - container.removeEventListener('scroll', handleScroll); - }; - }, [handleScroll]); + const { scrollRef, cardRefs, infiniteGroups } = useInfiniteCarousel(sectionGroups, { + scaleAmount: 0.08, + }); return ( - {sections.map((sec, i) => ( + {infiniteGroups.map((g, i) => ( { - itemRefs.current[i] = el; + cardRefs.current[i] = el; }} > - + ))} @@ -88,4 +55,5 @@ const Item = styled.div` max-width: 640px; scroll-snap-align: center; transition: transform 0.2s; + height: 800px; `; diff --git a/src/hooks/useInfiniteCarousel.ts b/src/hooks/useInfiniteCarousel.ts index 50afb840..47c04504 100644 --- a/src/hooks/useInfiniteCarousel.ts +++ b/src/hooks/useInfiniteCarousel.ts @@ -3,7 +3,7 @@ import type { Group } from '../components/group/MyGroupBox'; const CLONE_COUNT = 10; -export function useInfiniteCarousel(groups: Group[]) { +export function useInfiniteCarousel(groups: Group[], options?: { scaleAmount?: number }) { const scrollRef = useRef(null); const cardRefs = useRef<(HTMLDivElement | null)[]>([]); const [current, setCurrent] = useState(0); @@ -14,6 +14,8 @@ export function useInfiniteCarousel(groups: Group[]) { const middleIndex = useMemo(() => Math.floor(infiniteGroups.length / 2), [infiniteGroups]); + const scaleAmount = options?.scaleAmount ?? 0.17; + const handleScroll = useCallback(() => { const container = scrollRef.current; if (!container) return; @@ -28,7 +30,7 @@ export function useInfiniteCarousel(groups: Group[]) { if (!card) return; const cardCenter = card.offsetLeft + card.offsetWidth / 2; const distance = Math.abs(center - (cardCenter - scrollLeft)); - const scale = Math.max(0.83, 1 - (distance / center) * 0.17); + const scale = Math.max(0.83, 1 - (distance / center) * scaleAmount); card.style.transform = `scale(${scale})`; if (distance < minDist) { @@ -49,7 +51,7 @@ export function useInfiniteCarousel(groups: Group[]) { container.scrollLeft = left; } } - }, [groups.length, middleIndex]); + }, [groups.length, middleIndex, scaleAmount]); useEffect(() => { const container = scrollRef.current; diff --git a/src/pages/group/Group.tsx b/src/pages/group/Group.tsx index 2d401992..415fcdf6 100644 --- a/src/pages/group/Group.tsx +++ b/src/pages/group/Group.tsx @@ -36,7 +36,6 @@ const Group = () => { const [sections, setSections] = useState([ { title: '마감 임박한 독서 모임방', groups: [] }, { title: '인기 있는 독서 모임방', groups: [] }, - { title: '인플루언서·작가 독서 모임방', groups: [] }, ]); const fetchAllRoomsData = async () => { @@ -62,14 +61,12 @@ const Group = () => { setSections([ { title: '마감 임박한 독서 모임방', groups: deadlineRoomsData }, { title: '인기 있는 독서 모임방', groups: popularRoomsData }, - { title: '인플루언서·작가 독서 모임방', groups: [] }, ]); } catch (error) { console.error('방 목록 조회 오류:', error); setSections([ { title: '마감 임박한 독서 모임방', groups: [] }, { title: '인기 있는 독서 모임방', groups: [] }, - { title: '인플루언서·작가 독서 모임방', groups: [] }, ]); } };