Skip to content

Commit e7870b9

Browse files
committed
feat(web): add PhotoSwipe lightbox for richtext images
1 parent f7e1680 commit e7870b9

4 files changed

Lines changed: 86 additions & 14 deletions

File tree

pnpm-lock.yaml

Lines changed: 17 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"cms": "workspace:*",
2525
"geist": "^1.7.0",
2626
"payload": "3.85.0",
27+
"photoswipe": "^5.4.4",
2728
"schema-dts": "^1.1.5"
2829
},
2930
"devDependencies": {
Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
import type { UploadNode } from '@jhb.software/astro-payload-richtext-lexical'
33
import type { Image } from 'cms/src/payload-types'
4-
import Img from '../../Img.astro'
4+
import Img, { getFileSize } from '../../Img.astro'
55
66
type Props = { node: UploadNode }
77
@@ -11,13 +11,27 @@ const { node } = Astro.props
1111
{
1212
(() => {
1313
if (node.relationTo === 'images' && typeof node.value === 'object') {
14+
const image = node.value as unknown as Image
15+
// Use the largest available size for the lightbox to balance quality and performance.
16+
const lightboxSize = getFileSize('xl', image)
17+
const galleryId = `richtext-image-${image.id}`
18+
1419
return (
15-
<Img
16-
image={node.value as unknown as Image}
17-
size="md"
18-
class="w-full rounded-2xl md:max-w-128"
19-
/>
20+
<div data-pswp-gallery={galleryId}>
21+
<a
22+
href={lightboxSize.url}
23+
data-pswp-width={lightboxSize.width}
24+
data-pswp-height={lightboxSize.height}
25+
class="block w-full cursor-zoom-in overflow-hidden md:max-w-128"
26+
>
27+
<Img image={image} size="md" class="w-full" />
28+
</a>
29+
</div>
2030
)
2131
}
2232
})()
2333
}
34+
35+
<script>
36+
import '@/scripts/photoswipe'
37+
</script>

web/src/scripts/photoswipe.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import PhotoSwipe from 'photoswipe'
2+
import PhotoSwipeLightbox from 'photoswipe/lightbox'
3+
import 'photoswipe/style.css'
4+
5+
const lightboxes: PhotoSwipeLightbox[] = []
6+
7+
function initPhotoSwipe() {
8+
lightboxes.forEach((lb) => lb.destroy())
9+
lightboxes.length = 0
10+
11+
const galleries = document.querySelectorAll('[data-pswp-gallery]')
12+
13+
if (galleries.length === 0) return
14+
15+
galleries.forEach((gallery) => {
16+
const galleryId = gallery.getAttribute('data-pswp-gallery')
17+
18+
const galleryLightbox = new PhotoSwipeLightbox({
19+
pswpModule: PhotoSwipe,
20+
children: 'a',
21+
gallery: `[data-pswp-gallery="${galleryId}"]`,
22+
showHideAnimationType: 'fade',
23+
showAnimationDuration: 333,
24+
hideAnimationDuration: 333,
25+
bgClickAction: 'close',
26+
tapAction: 'close',
27+
arrowPrev: true,
28+
arrowNext: true,
29+
padding: {
30+
top: 46,
31+
bottom: 46,
32+
left: 17,
33+
right: 17,
34+
},
35+
})
36+
37+
galleryLightbox.init()
38+
lightboxes.push(galleryLightbox)
39+
})
40+
}
41+
42+
document.addEventListener('DOMContentLoaded', initPhotoSwipe)
43+
document.addEventListener('astro:page-load', initPhotoSwipe)
44+
45+
document.addEventListener('astro:before-preparation', () => {
46+
lightboxes.forEach((lb) => lb.destroy())
47+
lightboxes.length = 0
48+
})

0 commit comments

Comments
 (0)