Skip to content

Commit

Permalink
Add thumbnail navigator to image modal
Browse files Browse the repository at this point in the history
  • Loading branch information
José Luis Pereira committed Jul 3, 2022
1 parent 7852686 commit b6b4844
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 39 deletions.
32 changes: 10 additions & 22 deletions src/components/Gallery/GalleryImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
print:hidden
bg-white
dark:bg-slate-800
dark:border-slate-800"
dark:border-slate-600"
>
<div class="h-80 max-h-80 flex items-center justify-center">
<img
Expand All @@ -18,33 +18,20 @@
>
</div>
</div>
<div class="flex flex-row overflow-x-auto print:flex-wrap">
<div
v-for="(image, index) in images"
:key="image.id"
class="
pr-1
pt-1
pb-1
last:pr-0"
>
<GalleryThumbnail
:image="image"
:title="image.depictions.map(d => d.label).join(';')"
@click="
galleryIndex = index;
isImageViewerOpen = true
"
/>
</div>
</div>
<GalleryThumbnailList
class="pt-2 pb-2"
:images="images"
@select-index="galleryIndex = $event; isImageViewerOpen = true"
/>
</div>

<ImageViewer
v-if="isImageViewerOpen"
:image="currentImage"
:index="galleryIndex"
:images="images"
:next="galleryIndex < (props.images.length - 1)"
:previous="galleryIndex > 0"
@select-index="galleryIndex = $event"
@next="nextImage()"
@previous="previousImage()"
@close="isImageViewerOpen = false"
Expand All @@ -53,6 +40,7 @@

<script setup>
import { ref, computed, watch } from 'vue'
import GalleryThumbnailList from './GalleryThumbnailList.vue';
const props = defineProps({
images: {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Gallery/GalleryThumbnail.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template>
<div
class="bg-white dark:bg-gray-800 flex flex-col justify-center cursor-pointer w-24 h-24 border dark:border-gray-700"
class="bg-white dark:bg-gray-800 flex flex-col justify-center cursor-pointer w-24 h-24 dark:border-gray-600 rounded-md shadow box-border"
:title="title"
>
<img
class="h-24 w-24 max-h-24 max-w-24 object-cover"
class="max-h-24 max-w-24 h-24 w-24 object-cover rounded-md"
:src="image.thumb"
>
</div>
Expand Down
33 changes: 33 additions & 0 deletions src/components/Gallery/GalleryThumbnailList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>
<div class="flex flex-row overflow-x-auto print:flex-wrap">
<div
v-for="(image, index) in images"
:key="image.id"
class="
pr-2
last:pr-0"
>
<GalleryThumbnail
:image="image"
:class="{ 'border-2 border-primary-500 dark:border-primary-500': current === index }"
:title="image.depictions.map(d => d.label).join(';')"
@click="emit('selectIndex', index)"
/>
</div>
</div>
</template>

<script setup>
defineProps({
images: {
type: Array,
default: () => []
},
current: {
type: Number,
default: undefined
}
})
const emit = defineEmits(['selectIndex'])
</script>
53 changes: 38 additions & 15 deletions src/components/Gallery/ImageViewer.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
<template>
<div
class="fixed image__viewer bg-opacity-50 bg-black overflow-y-hidden overflow-x-hidden w-full h-full top-0 left-0 flex items-center justify-center"
class="fixed z-[10000] bg-opacity-60 bg-black overflow-y-hidden overflow-x-hidden w-full h-full top-0 left-0 flex flex-col items-center justify-center backdrop-blur-md"
@click="emit('close')"
>
<div
class="container bg-white dark:bg-slate-900 relative max-h-full w-full md:h-auto rounded-lg shadow-sm"
class="min-w-96 dark:bg-slate-900 relative rounded-lg shadow-sm mb-24"
@click.stop
>
<VSpinner v-if="isLoading" />
<div class="relative p-4 rounded-t-lg">
<div class="relative rounded-t-lg w-auto bg-white">
<img
ref="imageElement"
class="mx-auto cursor-zoom-out max-w-7 w-auto max-w-full max-h-[80vh]"
class="mx-auto cursor-zoom-out max-w-7 w-auto max-w-full max-h-[70vh]"
:src="image.original"
@click="emit('close')"
>
</div>

<div class="bg-white dark:bg-slate-900 attributions bottom-0 h-24 p-4 rounded-b-lg align-middle flex justify-between flex-col text-center">
<div
class="
bg-white
dark:bg-slate-900
dark:text-white
attributions
bottom-0
h-24
p-4
rounded-b-lg
align-middle
flex
justify-between
flex-col
text-center"
>
<ImageDepictions
class="my-auto"
:depictions="image.depictions"
Expand All @@ -39,22 +54,34 @@
@click="emit('previous')"
/>
</div>
<GalleryThumbnailList
class="bottom-0 fixed overflow-x-auto max-w-full pb-2"
:current="index"
:images="images"
@select-index="emit('selectIndex', $event)"
@click.stop
/>
</div>
</template>

<script setup>
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { onMounted, onUnmounted, ref, watch, computed } from 'vue'
import ImageAttribution from './ImageAttribution.vue';
import ImageDepictions from './ImageDepictions.vue';
import ControlNextImage from './ControlImageNext.vue'
import ControlPreviousImage from './ControlImagePrevious.vue'
const props = defineProps({
image: {
index: {
type: Object,
required: true
},
images: {
type: Array,
default: () => []
},
next: {
type: Boolean,
default: false
Expand All @@ -69,7 +96,8 @@ const props = defineProps({
const emit = defineEmits([
'close',
'previous',
'next'
'next',
'selectIndex'
])
const handleKeyboard = ({ key }) => {
Expand All @@ -92,20 +120,15 @@ const handleKeyboard = ({ key }) => {
const imageElement = ref(null)
const isLoading = ref(false)
const image = computed(() => props.images[props.index])
document.addEventListener('keyup', handleKeyboard)
onMounted(() => imageElement.value.addEventListener('load', () => isLoading.value = false))
onUnmounted(() => document.removeEventListener('keyup', handleKeyboard))
watch(
() => props.image,
() => props.index,
() => isLoading.value = true
)
</script>

<style>
.image__viewer {
z-index: 10000;
}
</style>

0 comments on commit b6b4844

Please sign in to comment.