286 lines
6.3 KiB
Vue
286 lines
6.3 KiB
Vue
<template>
|
|
<div class="gallery-page"
|
|
:class="{'is-mounted': isMounted }"
|
|
>
|
|
<GalleryImageViewer class="image-viewer"
|
|
ref="imageViewer"
|
|
:is-visible="imageViewerIsVisible"
|
|
:image-url="viewingImageUrl"
|
|
:has-next="activeImageIndex < galleries[activeGalleryIndex].images.length - 1"
|
|
:has-prev="activeImageIndex > 0"
|
|
@clickPrev="handleClickPrev"
|
|
@clickNext="handleClickNext"
|
|
@close="imageViewerIsVisible = false" />
|
|
<article class="gallery">
|
|
<h1 class="page-heading page-title"><span class="shadow-deco">{{ title }}</span></h1>
|
|
<GalleryFeatured class="gallery__featured load-transition load-transition--1"
|
|
:galleries="galleries"
|
|
:gallery-active="activeGalleryIndex"
|
|
@clicked="handleFeaturedClick" />
|
|
<GalleryThumbs class="gallery__thumbs load-transition load-transition--2"
|
|
:featured-height="featuredImageHeight"
|
|
:galleries="galleries"
|
|
:active-row="activeRow"
|
|
:active-index="activeImageIndex"
|
|
:show-image="showImage"
|
|
@thumbClick="handleThumbClick"/>
|
|
</article>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import GalleryFeatured from '@/components/GalleryFeatured'
|
|
import GalleryThumbs from '@/components/GalleryThumbs'
|
|
import GalleryImageViewer from '@/components/GalleryImageViewer'
|
|
|
|
export default {
|
|
components: {
|
|
GalleryFeatured,
|
|
GalleryThumbs,
|
|
GalleryImageViewer,
|
|
},
|
|
|
|
props: {
|
|
galleries: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
title: {
|
|
type: String,
|
|
required: false,
|
|
default () {
|
|
return 'My Galleries'
|
|
},
|
|
}
|
|
},
|
|
|
|
data () {
|
|
return {
|
|
isMounted: false,
|
|
featuredImageHeight: '16rem',
|
|
imageViewerIsVisible: false,
|
|
activeRow: 0,
|
|
activeGalleryIndex: 0,
|
|
activeImageIndex: 0,
|
|
showImage: 0,
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
viewingImageUrl () {
|
|
if (
|
|
this.galleries[this.activeGalleryIndex]
|
|
&& this.galleries[this.activeGalleryIndex].images
|
|
&& this.galleries[this.activeGalleryIndex].images[this.activeImageIndex]
|
|
) {
|
|
return this.galleries[this.activeGalleryIndex].images[this.activeImageIndex].url
|
|
} else {
|
|
// TOOD return 404 page - does this do it?
|
|
throw({ statusCode: 404, message: 'Image Not Found' })
|
|
}
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
$route () {
|
|
const query = this.$route.query
|
|
if (!query || !query.gallery) { return }
|
|
this.$nextTick(() => {
|
|
const gallery = parseInt(query.gallery)
|
|
const image = parseInt(query.image) || 0
|
|
|
|
if (gallery !== this.activeGalleryIndex) {
|
|
this.activeRow = gallery
|
|
this.activeGalleryIndex = gallery
|
|
}
|
|
if (image !== this.activeImageIndex) {
|
|
this.activeImageIndex = image
|
|
this.showImage = image
|
|
}
|
|
})
|
|
}
|
|
},
|
|
|
|
created () {
|
|
let query = this.$route.query
|
|
this.activeGalleryIndex = query.gallery ? parseInt(query.gallery) : 0
|
|
this.activeRow = this.activeGalleryIndex
|
|
this.activeImageIndex = query.image ? parseInt(query.image) : 0
|
|
},
|
|
|
|
mounted () {
|
|
window.addEventListener('resize', () => { this.imageViewerIsVisible = false })
|
|
this.$nextTick(() => {
|
|
this.isMounted = true
|
|
})
|
|
},
|
|
|
|
methods: {
|
|
handleFeaturedClick (index) {
|
|
this.activeRow = index
|
|
this.activeImageIndex = 0
|
|
this.activeGalleryIndex = index
|
|
this.setQueryString()
|
|
},
|
|
handleThumbClick(gallery, image) {
|
|
this.activeGalleryIndex = gallery
|
|
this.activeImageIndex = image
|
|
this.imageViewerIsVisible = true
|
|
this.setQueryString()
|
|
},
|
|
handleClickNext () {
|
|
this.activeImageIndex++;
|
|
},
|
|
handleClickPrev () {
|
|
this.activeImageIndex--;
|
|
},
|
|
setQueryString () {
|
|
this.$router.push({
|
|
path: this.$route.path,
|
|
query: {
|
|
gallery: this.activeGalleryIndex,
|
|
image: this.activeImageIndex,
|
|
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.gallery-page {
|
|
position: relative;
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
.image-viewer {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
top: 0;
|
|
left: 0;
|
|
}
|
|
|
|
@media (max-width: $bp__layout) {
|
|
.page-heading {
|
|
z-index: 5;
|
|
position: absolute;
|
|
width: 100%;
|
|
top: 0;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
font-size: 2rem;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.gallery-page {
|
|
padding-top: $site-menu__header-height;
|
|
}
|
|
|
|
.gallery {
|
|
position: relative;
|
|
height: 100%;
|
|
width: 100%;
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.gallery__thumbs {
|
|
z-index: 10;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
}
|
|
|
|
.gallery__featured {
|
|
width: 100vw;
|
|
}
|
|
|
|
.close-viewer {
|
|
font-size: 10em;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
@media (min-width: $bp__layout) {
|
|
.page-heading {
|
|
position: absolute;
|
|
font-size: 3.5rem;
|
|
top: 0;
|
|
left: 0;
|
|
margin-top: 0;
|
|
max-width: calc(100% - 3rem - #{$gallery-featured-width--compact});
|
|
|
|
@media (min-width: $bp__gallery-compact) {
|
|
max-width: calc(100% - 2rem - #{$gallery-featured-width});
|
|
}
|
|
}
|
|
|
|
.mobile-only {
|
|
display: none;
|
|
}
|
|
|
|
.gallery-page {
|
|
padding-left: $site-menu__header-width;
|
|
}
|
|
|
|
.gallery {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
position: relative;
|
|
height: 100%;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.gallery__featured {
|
|
order: 2;
|
|
flex: 0 0 $gallery-featured-width--compact;
|
|
overflow-y: auto;
|
|
|
|
@media (min-width: $bp__gallery-compact) {
|
|
flex-basis: $gallery-featured-width;
|
|
}
|
|
}
|
|
|
|
.gallery__thumbs {
|
|
order: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
padding-left: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.gallery__nav {
|
|
display: none;
|
|
}
|
|
|
|
.close-viewer {
|
|
display: none;
|
|
}
|
|
|
|
}
|
|
|
|
.load-transition {
|
|
transition: opacity 2s;
|
|
opacity: 0;
|
|
|
|
&--1 {
|
|
transition-delay: 2s;
|
|
}
|
|
|
|
&--2 {
|
|
transition-delay: 3s;
|
|
}
|
|
|
|
@at-root .is-mounted & {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
</style>
|