@@ -80,6 +80,67 @@ const useStyles = createUseStyles({
8080 '.mapboxgl-ctrl-attrib-inner' : {
8181 display : 'none !important'
8282 }
83+ } ,
84+ modal : {
85+ position : 'fixed' ,
86+ top : 0 ,
87+ left : 0 ,
88+ right : 0 ,
89+ bottom : 0 ,
90+ backgroundColor : 'rgba(0, 0, 0, 0.9)' ,
91+ display : 'flex' ,
92+ justifyContent : 'center' ,
93+ alignItems : 'center' ,
94+ zIndex : 1000 ,
95+ cursor : 'pointer'
96+ } ,
97+ modalImage : {
98+ maxWidth : '90vw' ,
99+ maxHeight : '90vh' ,
100+ objectFit : 'contain' ,
101+ borderRadius : 8
102+ } ,
103+ closeButton : {
104+ position : 'absolute' ,
105+ top : 20 ,
106+ right : 20 ,
107+ color : 'white' ,
108+ fontSize : 30 ,
109+ cursor : 'pointer' ,
110+ width : 40 ,
111+ height : 40 ,
112+ display : 'flex' ,
113+ justifyContent : 'center' ,
114+ alignItems : 'center' ,
115+ borderRadius : '50%' ,
116+ backgroundColor : 'rgba(255, 255, 255, 0.1)' ,
117+ '&:hover' : {
118+ backgroundColor : 'rgba(255, 255, 255, 0.2)'
119+ }
120+ } ,
121+ navButton : {
122+ position : 'absolute' ,
123+ top : '50%' ,
124+ transform : 'translateY(-50%)' ,
125+ color : 'white' ,
126+ fontSize : 40 ,
127+ cursor : 'pointer' ,
128+ width : 60 ,
129+ height : 60 ,
130+ display : 'flex' ,
131+ justifyContent : 'center' ,
132+ alignItems : 'center' ,
133+ borderRadius : '50%' ,
134+ backgroundColor : 'rgba(255, 255, 255, 0.1)' ,
135+ '&:hover' : {
136+ backgroundColor : 'rgba(255, 255, 255, 0.2)'
137+ } ,
138+ '&.prev' : {
139+ left : 20
140+ } ,
141+ '&.next' : {
142+ right : 20
143+ }
83144 }
84145} ) ;
85146
@@ -131,6 +192,14 @@ const calculateColorFromCoordinates = (longitude: number, latitude: number): str
131192 return `hsl(${ hue } , ${ saturation } %, ${ lightness } %)` ;
132193} ;
133194
195+ // Add this function before the GlobeMap component
196+ const getRandomImages = ( images : string [ ] , count : number = 5 ) : string [ ] => {
197+ if ( images . length <= count ) return images ;
198+
199+ const shuffled = [ ...images ] . sort ( ( ) => 0.5 - Math . random ( ) ) ;
200+ return shuffled . slice ( 0 , count ) ;
201+ } ;
202+
134203export function GlobeMap ( {
135204 width = '100%' ,
136205 height = 500 ,
@@ -149,6 +218,8 @@ export function GlobeMap({
149218 const [ viewState , setViewState ] = useState ( initialViewState ) ;
150219 const [ selectedMarker , setSelectedMarker ] = useState < MarkerData | null > ( null ) ;
151220 const [ showCards , setShowCards ] = useState ( false ) ;
221+ const [ selectedImage , setSelectedImage ] = useState < string | null > ( null ) ;
222+ const [ currentImageIndex , setCurrentImageIndex ] = useState < number > ( 0 ) ;
152223 const mapRef = useRef ( null ) ;
153224 const classes = useStyles ( ) ;
154225 console . log ( showCards ) ;
@@ -197,7 +268,7 @@ export function GlobeMap({
197268 // Reset cards when selected marker changes
198269 useEffect ( ( ) => {
199270 if ( ! selectedMarker ) {
200- // setShowCards(false);
271+ setShowCards ( false ) ;
201272 }
202273 } , [ selectedMarker ] ) ;
203274
@@ -215,6 +286,39 @@ export function GlobeMap({
215286 return ( ) => clearInterval ( rotationInterval ) ;
216287 } , [ enableAnimation ] ) ;
217288
289+ const handleModalClick = ( e : React . MouseEvent ) => {
290+ if ( e . target === e . currentTarget ) {
291+ setSelectedImage ( null ) ;
292+ }
293+ } ;
294+
295+ const handleCloseClick = ( ) => {
296+ setSelectedImage ( null ) ;
297+ } ;
298+
299+ const handleImageClick = ( src : string ) => {
300+ const images = selectedMarker ?. images || defaultImages ;
301+ const index = images . indexOf ( src ) ;
302+ setCurrentImageIndex ( index ) ;
303+ setSelectedImage ( src ) ;
304+ } ;
305+
306+ const handlePrevImage = ( e : React . MouseEvent ) => {
307+ e . stopPropagation ( ) ;
308+ const images = selectedMarker ?. images || defaultImages ;
309+ const newIndex = ( currentImageIndex - 1 + images . length ) % images . length ;
310+ setCurrentImageIndex ( newIndex ) ;
311+ setSelectedImage ( images [ newIndex ] ) ;
312+ } ;
313+
314+ const handleNextImage = ( e : React . MouseEvent ) => {
315+ e . stopPropagation ( ) ;
316+ const images = selectedMarker ?. images || defaultImages ;
317+ const newIndex = ( currentImageIndex + 1 ) % images . length ;
318+ setCurrentImageIndex ( newIndex ) ;
319+ setSelectedImage ( images [ newIndex ] ) ;
320+ } ;
321+
218322 return (
219323 < div style = { { width, height, position : 'relative' } } >
220324 { /* @ts -ignore - Using @ts-ignore to bypass type issues with react-map-gl */ }
@@ -292,13 +396,40 @@ export function GlobeMap({
292396 < div className = { classes . globeMapBounceCardsContainer } >
293397 < BounceCards
294398 className = { classes . globeMapBounceCards }
295- images = { selectedMarker . images || defaultImages }
399+ images = { getRandomImages ( selectedMarker . images || defaultImages ) }
296400 containerWidth = { 500 }
297401 containerHeight = { 250 }
298402 animationDelay = { 0.2 }
299403 animationStagger = { 0.08 }
300404 transformStyles = { defaultTransformStyles }
301405 enableHover = { true }
406+ onImageClick = { handleImageClick }
407+ />
408+ </ div >
409+ ) }
410+
411+ { /* Fullscreen Modal */ }
412+ { selectedImage && (
413+ < div className = { classes . modal } onClick = { handleModalClick } >
414+ < div className = { classes . closeButton } onClick = { handleCloseClick } >
415+ ×
416+ </ div >
417+ < div
418+ className = { `${ classes . navButton } prev` }
419+ onClick = { handlePrevImage }
420+ >
421+ ‹
422+ </ div >
423+ < div
424+ className = { `${ classes . navButton } next` }
425+ onClick = { handleNextImage }
426+ >
427+ ›
428+ </ div >
429+ < img
430+ className = { classes . modalImage }
431+ src = { selectedImage }
432+ alt = "Fullscreen view"
302433 />
303434 </ div >
304435 ) }
0 commit comments