Skip to content

Commit

Permalink
feat: replace deprecated react-images with lightgallery (#268)
Browse files Browse the repository at this point in the history
This PR does a couple of this. I recently updated by Instagram data to
include video media and all children for carousels. Altogether, this PR
does the following.

* Replaces react-images with
[lightGallery](https://www.lightgalleryjs.com/) for the Home page
Instagram module.
* Adds support for carousel children in the Instagram items.
* Adds support for videos in the Instagram items, thanks to
lightGallery's built-in support.

## Before


https://github.com/user-attachments/assets/b0b169cb-c24f-4605-b04e-762b76d92db7

## After


https://github.com/user-attachments/assets/d3f976ac-4629-4c2b-9921-9210f1ca93b9
  • Loading branch information
chrisvogt authored Dec 8, 2024
1 parent 0def266 commit 8045e94
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 208 deletions.
3 changes: 2 additions & 1 deletion theme/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gatsby-theme-chrisvogt",
"description": "My personal blog and website.",
"version": "0.32.1",
"version": "0.33.0",
"author": "Chris Vogt <[email protected]> (https://www.chrisvogt.me)",
"main": "index.js",
"license": "MIT",
Expand Down Expand Up @@ -90,6 +90,7 @@
"gatsby-transformer-json": "^5.13.1",
"gatsby-transformer-remark": "^6.13.1",
"gatsby-transformer-sharp": "^5.13.1",
"lightgallery": "^2.8.2",
"lodash": "^4.17.21",
"lottie-react-web": "^2.2.2",
"prettier": "3.3.3",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/** @jsx jsx */
import { jsx } from 'theme-ui'
import { faImages } from '@fortawesome/free-solid-svg-icons'
import { faImages, faVideo } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

const InstagramWidgetItem = ({ handleClick, index, post: { caption, cdnMediaURL, id, mediaType } = {} }) => {
const isCarousel = mediaType === 'CAROUSEL_ALBUM'
const isVideo = mediaType === 'VIDEO'

return (
<button
Expand All @@ -16,17 +17,17 @@ const InstagramWidgetItem = ({ handleClick, index, post: { caption, cdnMediaURL,
variant: 'styles.InstagramItem'
}}
>
{isCarousel && (
{(isCarousel || isVideo) && (
<div
data-testid='carousel-icon'
data-testid={isVideo ? 'video-icon' : 'carousel-icon'}
sx={{
color: 'white',
position: 'absolute',
top: 2,
right: 2
}}
>
<FontAwesomeIcon icon={faImages} />
<FontAwesomeIcon icon={isVideo ? faVideo : faImages} />
</div>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,37 @@ describe('InstagramWidgetItem', () => {
...defaultProps,
post: {
...defaultProps.post,
mediaType: 'CAROUSEL_ALBUM' // Make sure this value is exactly what triggers the isCarousel condition
mediaType: 'CAROUSEL_ALBUM'
}
}

render(<InstagramWidgetItem {...carouselProps} />)

// Debugging: log mediaType to verify it's correct
console.log('mediaType:', carouselProps.post.mediaType)

const carouselIcon = screen.getByTestId('carousel-icon')
expect(carouselIcon).toBeInTheDocument()
})

it('does not display the carousel icon when mediaType is not CAROUSEL_ALBUM', () => {
it('displays the video icon when mediaType is VIDEO', () => {
const videoProps = {
...defaultProps,
post: {
...defaultProps.post,
mediaType: 'VIDEO'
}
}

render(<InstagramWidgetItem {...videoProps} />)

const videoIcon = screen.getByTestId('video-icon')
expect(videoIcon).toBeInTheDocument()
})

it('does not display any icon when mediaType is IMAGE', () => {
render(<InstagramWidgetItem {...defaultProps} />)

const carouselIcon = screen.queryByTestId('carousel-icon')
const videoIcon = screen.queryByTestId('video-icon')
expect(carouselIcon).not.toBeInTheDocument()
expect(videoIcon).not.toBeInTheDocument()
})
})
111 changes: 54 additions & 57 deletions theme/src/components/widgets/instagram/instagram-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ import { jsx } from 'theme-ui'

import { Grid } from '@theme-ui/components'
import { RectShape } from 'react-placeholder/lib/placeholders'
import { useCallback, useState } from 'react'
import { useCallback, useState, useEffect, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useEffect } from 'react'
import Carousel, { Modal, ModalGateway } from 'react-images'
import { faInstagram } from '@fortawesome/free-brands-svg-icons'
import LightGallery from 'lightgallery/react'
import lgThumbnail from 'lightgallery/plugins/thumbnail'
import lgZoom from 'lightgallery/plugins/zoom'
import lgVideo from 'lightgallery/plugins/video'
import lgAutoplay from 'lightgallery/plugins/autoplay'
import 'lightgallery/css/lightgallery.css'
import 'lightgallery/css/lg-thumbnail.css'
import 'lightgallery/css/lg-zoom.css'
import 'lightgallery/css/lg-video.css'
import 'lightgallery/css/lg-autoplay.css'
import ReactPlaceholder from 'react-placeholder'
import VanillaTilt from 'vanilla-tilt'

Expand Down Expand Up @@ -45,16 +52,15 @@ export default () => {
const media = useSelector(getMedia)
const metrics = useSelector(getMetrics)

const [isShowingMore, setIsShowingMore] = useState(false)
const lightGalleryRef = useRef(null)

useEffect(() => {
if (isLoading) {
dispatch(fetchDataSource('instagram', instagramDataSource))
}
}, [dispatch, instagramDataSource, isLoading])

const [currentImage, setCurrentImage] = useState(0)
const [viewerIsOpen, setViewerIsOpen] = useState(false)
const [isShowingMore, setIsShowingMore] = useState(false)

useEffect(() => {
if (isShowingMore || !isLoading) {
VanillaTilt.init(document.querySelectorAll('.instagram-item-button'), {
Expand All @@ -67,15 +73,17 @@ export default () => {
}
}, [isLoading, isShowingMore])

const openLightbox = useCallback((event, { index }) => {
setCurrentImage(index)
setViewerIsOpen(true)
}, [])

const closeLightbox = () => {
setCurrentImage(0)
setViewerIsOpen(false)
}
const openLightbox = useCallback(
index => {
const instance = lightGalleryRef.current
if (instance) {
instance.openGallery(index)
} else {
console.error('LightGallery instance is not initialized')
}
},
[lightGalleryRef]
)

const callToAction = (
<CallToAction
Expand All @@ -92,9 +100,7 @@ export default () => {

return (
<Widget id='instagram' hasFatalError={hasFatalError}>
<WidgetHeader aside={callToAction} icon={faInstagram}>
Instagram
</WidgetHeader>
<WidgetHeader aside={callToAction}>Instagram</WidgetHeader>

<ProfileMetricsBadge metrics={metrics} isLoading={isLoading} />

Expand Down Expand Up @@ -125,7 +131,7 @@ export default () => {
showLoadingAnimation
type='rect'
>
<WidgetItem handleClick={openLightbox} index={idx} post={post} />
<WidgetItem handleClick={() => openLightbox(idx)} index={idx} post={post} />
</ReactPlaceholder>
))}
</Grid>
Expand All @@ -137,44 +143,35 @@ export default () => {
</div>
)}

<ModalGateway>
{viewerIsOpen && (
<Modal onClose={closeLightbox}>
{!isLoading && (
<Carousel
currentIndex={currentImage}
styles={{
// NOTE(cvogt): these styles were copy + pasted from craigrich/ruff-guide
// as a temporary fix for the `autoSize` feature not working as intended.
container: base => ({
...base,
height: '100vh'
}),
view: base => ({
...base,
alignItems: 'center',
display: 'flex ',
height: 'calc(100vh - 54px)',
justifyContent: 'center',
'& > img': {
maxHeight: 'calc(100vh - 94px)'
<LightGallery
onInit={ref => {
lightGalleryRef.current = ref.instance
}}
plugins={[lgThumbnail, lgZoom, lgVideo, lgAutoplay]}
licenseKey={process.env.GATSBY_LIGHT_GALLERY_LICENSE_KEY}
dynamic
dynamicEl={media.map(post => ({
thumb: post.cdnMediaURL,
subHtml: post.caption || '',
...(post.mediaType !== 'VIDEO' ? { src: post.cdnMediaURL } : {}),
video:
post.mediaType === 'VIDEO' && post.mediaURL
? {
source: [
{
src: post.mediaURL,
type: 'video/mp4'
}
})
}}
views={media.map(x => ({
...x,
source: {
download: `${x.cdnMediaURL}?auto=format`,
fullscreen: `${x.cdnMediaURL}?auto=format`,
regular: `${x.cdnMediaURL}?auto=format`,
thumbnail: `${x.cdnMediaURL}?h=280&w=280&fit=crop&crop=faces,focalpoint&auto=format`
],
attributes: {
controls: true // Enable controls for the video
}
}))}
/>
)}
</Modal>
)}
</ModalGateway>
}
: undefined
}))}
autoplayVideoOnSlide={true} // Add this option
speed={500}
/>
</Widget>
)
}
Loading

0 comments on commit 8045e94

Please sign in to comment.