Created
January 2, 2025 13:16
-
-
Save iBobik/0817437dd8a65d8b91a5dc9cdc6105ea to your computer and use it in GitHub Desktop.
Custom integration of the https://photoswipe.com with the Nuxt Image.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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