Skip to content

Commit 8940247

Browse files
committed
refactor: split slider to multiple components
1 parent f6ae2d7 commit 8940247

3 files changed

Lines changed: 169 additions & 112 deletions

File tree

Lines changed: 18 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { useEffect, useRef, useState } from 'react';
1+
import { useRef, useState } from 'react';
22
import Swiper from 'swiper';
3-
import { Navigation, A11y } from 'swiper/modules';
43
import 'swiper/css';
54
import 'swiper/css/navigation';
5+
import PreviewSlider from './Slider/PreviewSlider'
6+
import FullscreenSlider from './Slider/FullscreenSlider'
67

78
interface Props {
89
images: string[];
@@ -12,65 +13,10 @@ export default function FullscreenSliderModal({ images }: Props) {
1213
const [isFullscreen, setIsFullscreen] = useState(false);
1314
const previewSwiperRef = useRef<HTMLDivElement>(null);
1415
const fullscreenSwiperRef = useRef<HTMLDivElement>(null);
15-
const nextButtonRef = useRef<HTMLDivElement>(null);
16-
const prevButtonRef = useRef<HTMLDivElement>(null);
17-
const fullNextButtonRef = useRef<HTMLDivElement>(null);
18-
const fullPrevButtonRef = useRef<HTMLDivElement>(null);
1916

2017
const [previewSwiper, setPreviewSwiper] = useState<Swiper | null>(null);
2118
const [fullscreenSwiper, setFullscreenSwiper] = useState<Swiper | null>(null);
2219

23-
useEffect(() => {
24-
if (previewSwiperRef.current) {
25-
const swiper = new Swiper(previewSwiperRef.current, {
26-
modules: [Navigation, A11y],
27-
slidesPerView: 1,
28-
spaceBetween: 20,
29-
navigation: {
30-
nextEl: nextButtonRef.current,
31-
prevEl: prevButtonRef.current,
32-
},
33-
loop: true,
34-
a11y: {
35-
prevSlideMessage: 'Previous slide',
36-
nextSlideMessage: 'Next slide',
37-
},
38-
});
39-
setPreviewSwiper(swiper);
40-
return () => swiper.destroy();
41-
}
42-
}, []);
43-
44-
useEffect(() => {
45-
if (isFullscreen && fullscreenSwiperRef.current) {
46-
const swiper = new Swiper(fullscreenSwiperRef.current, {
47-
modules: [Navigation, A11y],
48-
slidesPerView: 1,
49-
navigation: {
50-
nextEl: fullNextButtonRef.current,
51-
prevEl: fullPrevButtonRef.current,
52-
},
53-
loop: true,
54-
a11y: {
55-
prevSlideMessage: 'Previous slide',
56-
nextSlideMessage: 'Next slide',
57-
},
58-
});
59-
60-
if (previewSwiper) {
61-
swiper.slideTo(previewSwiper.realIndex);
62-
}
63-
64-
setFullscreenSwiper(swiper);
65-
document.body.style.overflow = 'hidden';
66-
67-
return () => {
68-
swiper.destroy();
69-
document.body.style.overflow = 'auto';
70-
};
71-
}
72-
}, [isFullscreen, previewSwiper]);
73-
7420
const openFullscreen = () => {
7521
setIsFullscreen(true);
7622
};
@@ -85,61 +31,21 @@ export default function FullscreenSliderModal({ images }: Props) {
8531

8632
return (
8733
<>
88-
<div className="relative mt-8">
89-
<button
90-
onClick={openFullscreen}
91-
className="absolute top-4 right-4 bg-black/70 text-white px-3 py-1 rounded text-sm flex items-center gap-1 z-10"
92-
aria-label="View in fullscreen"
93-
>
94-
Fullscreen
95-
</button>
96-
<div className="swiper" ref={previewSwiperRef}>
97-
<div className="swiper-wrapper">
98-
{images.map((image, index) => (
99-
<div key={`preview-${index}`} className="swiper-slide">
100-
<img
101-
src={image}
102-
alt={`Preview ${index + 1}`}
103-
className="w-full h-auto object-contain rounded-lg cursor-zoom-in"
104-
loading="lazy"
105-
onClick={openFullscreen}
106-
/>
107-
</div>
108-
))}
109-
</div>
110-
<div ref={prevButtonRef} className="swiper-button-prev"></div>
111-
<div ref={nextButtonRef} className="swiper-button-next"></div>
112-
</div>
113-
</div>
114-
115-
{isFullscreen && (
116-
<div className="fixed inset-0 bg-black/70 z-50 p-4 w-full h-full">
117-
<button
118-
className="absolute top-4 right-4 text-center text-white z-10 hover:cursor-pointer text-2xl rounded-full"
119-
onClick={closeFullscreen}
120-
aria-label="Close fullscreen"
121-
>
122-
&times;
123-
</button>
124-
125-
<div className="flex justify-center items-center swiper w-full h-full" ref={fullscreenSwiperRef}>
126-
<div className="swiper-wrapper" onClick={closeFullscreen}>
127-
{images.map((image, index) => (
128-
<div key={`full-${index}`} className="swiper-slide">
129-
<img
130-
src={image}
131-
alt={`Slide ${index + 1}`}
132-
className="w-full h-full object-contain"
133-
loading="lazy"
134-
/>
135-
</div>
136-
))}
137-
</div>
138-
<div ref={fullPrevButtonRef} className="swiper-button-prev text-white"></div>
139-
<div ref={fullNextButtonRef} className="swiper-button-next text-white"></div>
140-
</div>
141-
</div>
142-
)}
34+
<PreviewSlider
35+
images={images}
36+
setPreviewSwiper={setPreviewSwiper}
37+
handleOnFullscreenClick={openFullscreen}
38+
previewSwiperRef={previewSwiperRef}
39+
/>
40+
41+
<FullscreenSlider
42+
images={images}
43+
fullscreenSwiperRef={fullscreenSwiperRef}
44+
handleCloseFullscreen={closeFullscreen}
45+
isFullscreen={isFullscreen}
46+
previewSwiper={previewSwiper}
47+
setFullscreenSwiper={setFullscreenSwiper}
48+
/>
14349
</>
14450
);
14551
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { useEffect, useRef } from 'react';
2+
import Swiper from 'swiper';
3+
import { Navigation, A11y } from 'swiper/modules';
4+
import 'swiper/css';
5+
import 'swiper/css/navigation';
6+
7+
interface Props {
8+
images: string[];
9+
isFullscreen: boolean;
10+
fullscreenSwiperRef: React.RefObject<HTMLDivElement | null>;
11+
previewSwiper: Swiper | null;
12+
handleCloseFullscreen: () => void;
13+
setFullscreenSwiper: (swiper: Swiper) => void;
14+
}
15+
16+
export default function FullscreenSliderModal({ images, fullscreenSwiperRef, previewSwiper, handleCloseFullscreen, isFullscreen, setFullscreenSwiper }: Props) {
17+
const fullNextButtonRef = useRef<HTMLDivElement>(null);
18+
const fullPrevButtonRef = useRef<HTMLDivElement>(null);
19+
20+
useEffect(() => {
21+
if (isFullscreen && fullscreenSwiperRef.current) {
22+
const swiper = new Swiper(fullscreenSwiperRef.current, {
23+
modules: [Navigation, A11y],
24+
slidesPerView: 1,
25+
navigation: {
26+
nextEl: fullNextButtonRef.current,
27+
prevEl: fullPrevButtonRef.current,
28+
},
29+
loop: true,
30+
a11y: {
31+
prevSlideMessage: 'Previous slide',
32+
nextSlideMessage: 'Next slide',
33+
},
34+
});
35+
36+
if (previewSwiper) {
37+
swiper.slideTo(previewSwiper.realIndex);
38+
}
39+
40+
setFullscreenSwiper(swiper);
41+
document.body.style.overflow = 'hidden';
42+
43+
return () => {
44+
swiper.destroy();
45+
document.body.style.overflow = 'auto';
46+
};
47+
}
48+
}, [isFullscreen, previewSwiper]);
49+
50+
return (
51+
<>
52+
{isFullscreen && (
53+
<div className="fixed inset-0 bg-black/70 z-50 p-4 w-full h-full">
54+
<button
55+
className="absolute top-4 right-4 text-center text-white z-10 hover:cursor-pointer text-2xl rounded-full"
56+
onClick={handleCloseFullscreen}
57+
aria-label="Close fullscreen"
58+
>
59+
&times;
60+
</button>
61+
62+
<div className="flex justify-center items-center swiper w-full h-full" ref={fullscreenSwiperRef}>
63+
<div className="swiper-wrapper" onClick={handleCloseFullscreen}>
64+
{images.map((image, index) => (
65+
<div key={`full-${index}`} className="swiper-slide">
66+
<img
67+
src={image}
68+
alt={`Slide ${index + 1}`}
69+
className="w-full h-full object-contain"
70+
loading="lazy"
71+
/>
72+
</div>
73+
))}
74+
</div>
75+
<div ref={fullPrevButtonRef} className="swiper-button-prev text-white"></div>
76+
<div ref={fullNextButtonRef} className="swiper-button-next text-white"></div>
77+
</div>
78+
</div>
79+
)}
80+
</>
81+
);
82+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import Swiper from 'swiper';
2+
3+
import { useEffect, useRef } from 'react';
4+
import { Navigation, A11y } from 'swiper/modules';
5+
6+
import 'swiper/css';
7+
import 'swiper/css/navigation';
8+
9+
interface Props {
10+
images: string[],
11+
previewSwiperRef: React.RefObject<HTMLDivElement | null>,
12+
setPreviewSwiper: (swiper: Swiper) => void,
13+
handleOnFullscreenClick: () => void,
14+
}
15+
16+
export default function PreviewSlider({ handleOnFullscreenClick, images, previewSwiperRef, setPreviewSwiper }: Props) {
17+
const nextButtonRef = useRef<HTMLDivElement>(null);
18+
const prevButtonRef = useRef<HTMLDivElement>(null);
19+
20+
useEffect(() => {
21+
if (previewSwiperRef.current) {
22+
const swiper = new Swiper(previewSwiperRef.current, {
23+
modules: [Navigation, A11y],
24+
slidesPerView: 1,
25+
spaceBetween: 20,
26+
navigation: {
27+
nextEl: nextButtonRef.current,
28+
prevEl: prevButtonRef.current,
29+
},
30+
loop: true,
31+
a11y: {
32+
prevSlideMessage: 'Previous slide',
33+
nextSlideMessage: 'Next slide',
34+
},
35+
});
36+
setPreviewSwiper(swiper);
37+
return () => swiper.destroy();
38+
}
39+
}, []);
40+
41+
return (
42+
<div className="relative mt-8">
43+
<button
44+
onClick={handleOnFullscreenClick}
45+
className="absolute top-4 right-4 bg-black/70 text-white px-3 py-1 rounded text-sm flex items-center gap-1 z-10"
46+
aria-label="View in fullscreen"
47+
>
48+
Fullscreen
49+
</button>
50+
<div className="swiper" ref={previewSwiperRef}>
51+
<div className="swiper-wrapper">
52+
{images.map((image, index) => (
53+
<div key={`preview-${index}`} className="swiper-slide">
54+
<img
55+
src={image}
56+
alt={`Preview ${index + 1}`}
57+
className="w-full h-auto object-contain rounded-lg cursor-zoom-in"
58+
loading="lazy"
59+
onClick={handleOnFullscreenClick}
60+
/>
61+
</div>
62+
))}
63+
</div>
64+
<div ref={prevButtonRef} className="swiper-button-prev"></div>
65+
<div ref={nextButtonRef} className="swiper-button-next"></div>
66+
</div>
67+
</div>
68+
)
69+
}

0 commit comments

Comments
 (0)