Skip to content

Instantly share code, notes, and snippets.

@iBobik
Created January 2, 2025 13:16
Show Gist options
  • Save iBobik/0817437dd8a65d8b91a5dc9cdc6105ea to your computer and use it in GitHub Desktop.
Save iBobik/0817437dd8a65d8b91a5dc9cdc6105ea to your computer and use it in GitHub Desktop.
Custom integration of the https://photoswipe.com with the Nuxt Image.
<template>
<div
ref="galleryEl"
class="py-4 space-y-2 overflow-y-scroll snap-y"
:class="{ 'clip-right': !arrivedState.right }"
@mouseenter.passive="initializePhotoswipe"
@touchstart.passive="initializePhotoswipe"
>
<div class="flex gap-2 w-max">
<a v-for="image in album.images" :href="image.image!.url" @click="initializePhotoswipe" data-pswp-child>
<NuxtImg
class="rounded-lg snap-center"
:src="image.image!.url"
:width="Math.ceil(image.image!.width! / image.image!.height! * commonHeight)"
:height="commonHeight"
:alt="image.image!.alt"
/>
</a>
</div>
</div>
</template>
<script setup lang="ts">
import PhotoSwipeLightbox from 'photoswipe/lightbox'
import 'photoswipe/style.css'
const props = defineProps<{
uuid: string
}>()
const { getAlbum: album } = await GqlGetAlbum({ uuid: props.uuid })
if (!album) {
throw createError({ statusCode: 404, statusMessage: `Album ${props.uuid} not found` })
}
const img = useImage()
const commonHeight = 160
const galleryEl = ref<HTMLDivElement>()
let lightbox: PhotoSwipeLightbox | undefined = undefined
const { arrivedState } = useScroll(galleryEl)
function initializePhotoswipe () {
if (lightbox) return
lightbox = new PhotoSwipeLightbox({
gallery: galleryEl.value!,
childSelector: '[data-pswp-child]',
pswpModule: () => import('photoswipe')
})
lightbox.addFilter('itemData', (itemData, index) => {
console.log('photos', album!.images, index)
const image = album!.images[index].image!
return {
...img.getSizes(image.url, { sizes: 'sm:100vw md:100vw lg:100vw xl:100vw' }),
width: image.width!,
height: image.height!,
title: image.alt,
}
})
lightbox.init()
}
onUnmounted(() => lightbox?.destroy())
</script>
<style scoped>
.clip-right {
/* Arrow on right */
clip-path: polygon(calc(100% - 1rem) 0, calc(100% - 1rem) 30%, 100% 50%, calc(100% - 1rem) 70%, calc(100% - 1rem) 100%, 0% 100%, 0 0);
}
</style>
<template>
<div ref="galleryEl" class="p-2 space-y-2 overflow-y-scroll snap-y" @mouseenter.passive="initializePhotoswipe" @touchstart.passive="initializePhotoswipe">
<div v-for="row in photos" class="flex gap-2 w-max">
<a v-for="photo in row" :href="photo.image!.url" @click="initializePhotoswipe" data-pswp-child>
<NuxtImg
class="rounded-lg snap-center"
:src="photo.image!.url"
:width="Math.ceil(photo.image!.width! / photo.image!.height! * commonHeight)"
:height="commonHeight"
:alt="photo.description"
/>
<div class="hidden" data-pswp-caption-content>
<a v-if="photo.author" :href="photo.author.website ?? undefined" class="flex items-center gap-2" target="_blank">
<NuxtImg v-if="photo.author.avatar" :src="photo.author.avatar.url" class="w-8 h-8 rounded-full" preset="avatar" alt="photo.author.name" />
{{ photo.author.name }}
</a>
{{ photo.description }}
</div>
</a>
</div>
</div>
</template>
<script setup lang="ts">
import PhotoSwipeLightbox from 'photoswipe/lightbox'
// @ts-ignore
import PhotoSwipeDynamicCaption from 'photoswipe-dynamic-caption-plugin'
import 'photoswipe/style.css'
import 'photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css'
import { RoomOption } from '#gql/default'
const img = useImage()
const commonHeight = 160
const galleryEl = ref<HTMLDivElement>()
const props = defineProps<{
room?: `${RoomOption}`
}>()
const { listPhoto } = await GqlListPhotos({ room: props.room as RoomOption })
const photos = computed(() => [
listPhoto.filter((_, i) => i % 2 === 0),
listPhoto.filter((_, i) => i % 2 === 1)
])
let lightbox: PhotoSwipeLightbox | undefined = undefined
function initializePhotoswipe () {
if (lightbox) return
lightbox = new PhotoSwipeLightbox({
gallery: galleryEl.value!,
childSelector: '[data-pswp-child]',
pswpModule: () => import('photoswipe')
})
lightbox.addFilter('itemData', (itemData, index) => {
console.log('photos', photos, index)
const photo = photos.value[0][index] ?? photos.value[1][index - photos.value[0].length]
return {
...img.getSizes(photo.image!.url, { sizes: 'sm:100vw md:100vw lg:100vw xl:100vw' }),
width: photo.image!.width!,
height: photo.image!.height!,
title: photo.description + (photo.author ? ` by ${photo.author.name}` : ''),
}
})
new PhotoSwipeDynamicCaption(lightbox, {
type: 'below',
captionContent: '[data-pswp-caption-content]'
})
lightbox.init()
}
onUnmounted(() => lightbox?.destroy())
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment