@@ -7,20 +7,27 @@ import AuthorIcon from '../AuthorIcon';
77import localStyles from './style.module.css' ;
88import 'styles/globals.css' ;
99import Image from 'next/image' ;
10+ import { Swiper , SwiperSlide } from 'swiper/react' ;
11+ import 'swiper/css' ;
12+ import 'swiper/css/pagination' ;
13+ import { Autoplay , Pagination } from 'swiper/modules' ;
1014
1115const Marker = ( {
1216 type,
1317 coordinates,
1418 city,
1519 country,
1620 author,
17- photo ,
21+ photos ,
1822 date,
19- orientation
23+ orientation,
24+ visits
2025} : IPin ) => {
2126 const icon = useMemo ( ( ) => getIcon ( type ) , [ type ] ) ;
2227 const name = useMemo ( ( ) => getNameString ( author ) , [ author ] ) ;
23-
28+ const [ slide , setSlide ] = useState ( 0 ) ;
29+ const [ width , setWidth ] = useState ( 0 ) ;
30+ const [ height , setHeight ] = useState ( 0 ) ;
2431 const [ imageOrientation , setImageOrientation ] = useState (
2532 orientation || 'vertical'
2633 ) ;
@@ -29,27 +36,27 @@ const Marker = ({
2936 setImageOrientation ( img . width > img . height ? 'horizontal' : 'vertical' ) ;
3037 } ;
3138
32- const popupClassName = useMemo ( ( ) => {
39+ useEffect ( ( ) => {
40+ if ( orientation || ! photos ) return ;
41+ const img = new window . Image ( ) ;
42+ if ( visits ) img . src = photos [ slide ] ?? visits [ slide - photos . length ] . photo ;
43+ else img . src = photos [ slide ] ;
44+ img . onload = ( ) => handleImageLoad ( img ) ;
45+ } , [ photos , orientation , slide , visits ] ) ;
46+
47+ useEffect ( ( ) => {
48+ let sizes = '' ;
3349 const isMobile = window . innerWidth <= 500 ;
3450
3551 if ( isMobile ) {
36- return imageOrientation === 'horizontal' ? '401:250' : '351:550' ;
52+ sizes = imageOrientation === 'horizontal' ? '401:250' : '351:550' ;
3753 } else {
38- return imageOrientation === 'horizontal' ? '651:400' : '301:470' ;
54+ sizes = imageOrientation === 'horizontal' ? '651:400' : '301:470' ;
3955 }
40- } , [ imageOrientation ] ) ;
4156
42- useEffect ( ( ) => {
43- if ( orientation || ! photo ) return ;
44- const img = new window . Image ( ) ;
45- img . src = photo ;
46- img . onload = ( ) => handleImageLoad ( img ) ;
47- } , [ photo , orientation ] ) ;
48-
49- const [ width , height ] = useMemo (
50- ( ) => popupClassName . split ( ':' ) . map ( Number ) ,
51- [ popupClassName ]
52- ) ;
57+ setWidth ( sizes . split ( ':' ) . map ( Number ) [ 0 ] ) ;
58+ setHeight ( sizes . split ( ':' ) . map ( Number ) [ 1 ] ) ;
59+ } , [ imageOrientation ] ) ;
5360
5461 return (
5562 < MarkerContainer
@@ -58,33 +65,79 @@ const Marker = ({
5865 title = { `${ name } at ${ city } ` }
5966 >
6067 < Popup className = { localStyles . popup } >
61- < div className = { localStyles . imageContainer } style = { { width, height } } >
62- < Image
63- alt = { `${ name } at ${ city } ` }
64- src = { photo }
65- width = { width }
66- height = { height }
67- className = { localStyles . roundedImage }
68- />
69- < div className = { localStyles . textOverlay } >
70- < h1 className = { localStyles . title } >
71- { city } , { country }
72- </ h1 >
73- < span className = { localStyles . light } >
74- < i className = "bi bi-calendar" > </ i > { getFullDateString ( date ) } (
75- { getRelativeTimeString ( date ) } )
76- </ span >
77- < br />
78- < span className = { localStyles . light } >
79- < i className = "bi bi-signpost-fill" > </ i > { ' ' }
80- { Math . round ( getDistance ( coordinates ) ) } km away
81- </ span >
82- < br />
83- < span >
84- < AuthorIcon author = { author } /> { name }
85- </ span >
86- </ div >
87- </ div >
68+ < Swiper
69+ slidesPerView = { 1 }
70+ spaceBetween = { 15 }
71+ pagination = { { clickable : true , type : 'bullets' } }
72+ modules = { [ Autoplay , Pagination ] }
73+ centeredSlides
74+ style = { { width, height } }
75+ onSlideChange = { ( swiper ) => setSlide ( swiper . realIndex ) }
76+ >
77+ { photos . map ( ( photo , idx ) => (
78+ < SwiperSlide key = { idx } >
79+ < div className = { localStyles . imageContainer } >
80+ < Image
81+ alt = { `${ name } at ${ city } ` }
82+ src = { photo }
83+ width = { width }
84+ height = { height }
85+ className = { localStyles . roundedImage }
86+ />
87+ { idx === 0 && (
88+ < div className = { localStyles . textOverlay } >
89+ < h1 className = { localStyles . title } >
90+ { city } , { country }
91+ </ h1 >
92+ < span className = { localStyles . light } >
93+ < i className = "bi bi-calendar-fill" > </ i > { ' ' }
94+ { getRelativeTimeString ( date ) } •{ ' ' }
95+ { date . replace ( / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) $ / , '$3/$2/$1' ) }
96+ </ span >
97+ < br />
98+ < span className = { localStyles . light } >
99+ < i className = "bi bi-signpost-fill" > </ i > { ' ' }
100+ { Math . round ( getDistance ( coordinates ) ) } km away
101+ </ span >
102+ < br />
103+ < span >
104+ < AuthorIcon author = { author } /> { name }
105+ </ span >
106+ </ div >
107+ ) }
108+ </ div >
109+ </ SwiperSlide >
110+ ) ) }
111+ { visits &&
112+ visits . map ( ( visit , idx ) => (
113+ < SwiperSlide key = { idx } >
114+ < div className = { localStyles . imageContainer } >
115+ < Image
116+ alt = { `${ visit . visitors } at ${ city } ` }
117+ src = { visit . photo }
118+ width = { width }
119+ height = { height }
120+ className = { localStyles . roundedImage }
121+ />
122+ < div className = { localStyles . textOverlay } >
123+ < span className = { localStyles . light } >
124+ < i className = "bi bi-car-front-fill" > </ i > Visited{ ' ' }
125+ { getRelativeTimeString ( visit . date ) } •{ ' ' }
126+ { visit . date . replace (
127+ / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) $ / ,
128+ '$3/$2/$1'
129+ ) }
130+ </ span >
131+ < br />
132+ < span >
133+ < AuthorIcon author = { visit . visitors } /> { ' ' }
134+ { getNameString ( visit . visitors ) }
135+ </ span >
136+ </ div >
137+ </ div >
138+ </ SwiperSlide >
139+ ) ) }
140+ </ Swiper >
88141 </ Popup >
89142 </ MarkerContainer >
90143 ) ;
0 commit comments