1+ import useMouseDrag from "@/hooks/useMouseDrag" ;
2+ import styled from "@emotion/styled" ;
3+ import { useRef , useState } from "react" ;
4+
5+ export const Carousel = ( { images} :{ images :string [ ] } ) => {
6+ const scrollRef = useRef < HTMLDivElement > ( null ) ;
7+ const [ currentIndex , setCurrentIndex ] = useState ( 0 ) ;
8+
9+ const maxIndex = images . length ;
10+
11+ const mod = ( n :number , m :number ) => ( n % m + m ) % m ;
12+ useMouseDrag ( scrollRef , ( start , end ) => {
13+ if ( end . x - start . x > 100 ) {
14+ setCurrentIndex ( mod ( currentIndex - 1 , maxIndex ) ) ;
15+ } else if ( start . x - end . x > 100 ) {
16+ setCurrentIndex ( mod ( currentIndex + 1 , maxIndex ) ) ;
17+ }
18+ } ) ;
19+
20+
21+ return (
22+ < SC . Wrapper ref = { scrollRef } >
23+ < SC . ScrollBox >
24+ { [ ...images ] . map ( image => (
25+ < SC . Slide key = { image } >
26+ < img src = { image } draggable = { false } alt = "image" style = { { width : '100%' , height : '100%' , objectFit : 'cover' } } />
27+
28+ </ SC . Slide >
29+ ) ) }
30+ </ SC . ScrollBox >
31+
32+ < SC . DotContainer >
33+ { [ ...images ] . map ( ( _ , idx ) => (
34+ < SC . Dot key = { idx } active = { idx === currentIndex } />
35+ ) ) }
36+ </ SC . DotContainer >
37+ </ SC . Wrapper >
38+ ) ;
39+ } ;
40+
41+
42+ const SC = {
43+ Wrapper : styled . section `
44+ display: flex;
45+ position: relative;
46+ width: 100%;
47+ flex-direction: column;
48+ align-items: center;
49+ ` ,
50+
51+ ScrollBox : styled . div `
52+ display: flex;
53+ overflow-x: auto;
54+ scroll-snap-type: x mandatory;
55+ -webkit-overflow-scrolling: touch;
56+ width: 100%;
57+ scroll-behavior: smooth;
58+
59+ &::-webkit-scrollbar {
60+ display: none;
61+ }
62+ ` ,
63+ Slide : styled . div `
64+ flex-shrink: 0;
65+ scroll-snap-align: start;
66+ width: 100%;
67+ min-width: 100%;
68+ height: 313px;
69+ ` ,
70+ DotContainer : styled . div `
71+ display: flex;
72+ position: absolute;
73+ bottom: 10px;
74+ margin-top: 1rem;
75+ gap: 0.5rem;
76+ ` ,
77+ Dot : styled . div < { active : boolean } > `
78+ width: 8px;
79+ height: 8px;
80+ border-radius: 50%;
81+
82+ background-color: ${ ( { active, theme } ) => ( active ? theme . color . gray [ 500 ] : theme . color . gray [ 100 ] ) } ;
83+ transition: background-color 0.3s;
84+ ` ,
85+ } ;
86+
87+
0 commit comments