Created
September 4, 2017 13:34
-
-
Save varna/ad00d04b6dd25096e45ab671edc64a8e to your computer and use it in GitHub Desktop.
Nuxt plugin for v-img directive
This file contains 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
import Vue from 'vue' | |
import ComponentGallery from '~/components/Gallery.vue' | |
export default async ({ app, store, params, isClient }) => { | |
const gallery = (Vue, options) => { | |
const Screen = Vue.extend(ComponentGallery) | |
const defaultOptions = { | |
altAsTitle: true | |
} | |
options = Object.assign(defaultOptions, options) | |
Vue.directive('img', { | |
bind (el, binding) { | |
// Defaults | |
let cursor = 'pointer' | |
let src = el.src | |
let group = binding.arg || null | |
let title | |
let id | |
if (options.altAsTitle) title = el.alt | |
// Overriding options if they're provided in binding.value | |
if (typeof binding.value !== 'undefined') { | |
cursor = binding.value.cursor || cursor | |
src = binding.value.src || src | |
group = binding.value.group || group | |
title = binding.value.title || title | |
id = binding.value.id || id | |
} | |
// Setting up data attributes for groups of images | |
el.setAttribute('data-vue-img-group', group || '') | |
el.setAttribute('data-vue-img-src', src) | |
el.setAttribute('data-vue-img-title', title || '') | |
el.setAttribute('data-vue-img-id', id) | |
if (!src) console.error('v-img element missing src parameter.') | |
// Applying options | |
el.style.cursor = cursor | |
// Finding existing vm, or creating new one | |
let vm = window.vueImg | |
if (!vm) { | |
const element = document.createElement('div') | |
element.setAttribute('id', 'componentGallery') | |
document.querySelector('body').appendChild(element) | |
vm = window.vueImg = new Screen().$mount('#componentGallery') | |
} | |
// Updating vm's data, changin body overflow and position, | |
// which will be turn back on close | |
el.addEventListener('click', () => { | |
// document.querySelector('body').classList.add('body-fs-v-img') | |
const images = [ | |
...document.querySelectorAll( | |
`img[data-vue-img-group="${group}"]` | |
) | |
] | |
if (images.length === 0) { | |
Vue.set(vm, 'images', [src]) | |
Vue.set(vm, 'titles', [title]) | |
Vue.set(vm, 'ids', [id]) | |
} else { | |
Vue.set(vm, 'images', images.map(e => e.dataset.vueImgSrc)) | |
Vue.set(vm, 'titles', images.map(e => e.dataset.vueImgTitle)) | |
Vue.set(vm, 'ids', images.map(e => e.dataset.vueImgId)) | |
Vue.set(vm, 'currentImageIndex', images.indexOf(el)) | |
} | |
Vue.set(vm, 'closed', false) | |
Vue.set(vm, 'store', app.store) | |
// console.log(app.store) | |
}) | |
} | |
}) | |
} | |
Vue.use(gallery) | |
} |
This file contains 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> | |
<transition | |
appear | |
name='fade' | |
> | |
<div | |
v-if='!closed' | |
id='gallery' | |
@click.self='close()' | |
> | |
<!-- | |
Count of total images in array and current position. | |
We're showing wrapper element of this counter just to | |
position other elements with flex, space-between | |
--> | |
<header> | |
<!-- Left side of header --> | |
<span | |
v-if='images.length > 1' | |
v-text='currentImageIndex + 1 + "/" + images.length' | |
/> | |
<!-- <span class='title-v-img'> | |
{{ titles[currentImageIndex] }} | |
</span> --> | |
<!-- <span>{{ $t('done') }}</span> --> | |
<!-- <span>{{ app }}</span> --> | |
<!-- Right side of header (spacer fills center) --> | |
<v-spacer /> | |
<v-btn | |
icon | |
@click.native.stop="report" | |
class="yellow--text text--lighten-2" | |
> | |
<v-icon>report_problem</v-icon> | |
<!-- <app-modal-report v-model="dialog" /> --> | |
</v-btn> | |
<v-btn | |
icon | |
@click="close" | |
class="red--text text--lighten-2" | |
> | |
<v-icon>close</v-icon> | |
</v-btn> | |
</header> | |
<!-- Controls start --> | |
<!-- Button (Previous) --> | |
<transition appear name='fade'> | |
<div | |
@click='prev' | |
class='navigate' | |
v-if="visibleUI && images.length !== 1" | |
style="left: 1rem" | |
> | |
<v-icon x-large dark>navigate_before</v-icon> | |
</div> | |
</transition> | |
<!-- Button (next) --> | |
<transition appear name='fade'> | |
<div | |
@click='next' | |
class='navigate' | |
v-if="visibleUI && images.length !== 1" | |
style="right: 1rem" | |
> | |
<v-icon x-large dark>navigate_next</v-icon> | |
</div> | |
</transition> | |
<div class="content-v-img"> | |
<img :src="images[currentImageIndex]" | |
@click="next"> | |
</div> | |
</div> | |
</transition> | |
</template> | |
<script> | |
import Report from '~/components/Modals/Report' | |
export default { | |
components: { | |
'app-modal-report': Report | |
}, | |
data () { | |
return { | |
images: [], | |
titles: [], | |
ids: [], | |
visibleUI: true, | |
currentImageIndex: 0, | |
closed: true, | |
uiTimeout: null, | |
dialog: false | |
} | |
}, | |
methods: { | |
close () { | |
// document.querySelector('body').classList.remove('body-fs-v-img') | |
this.images = [] | |
this.ids = [] | |
this.currentImageIndex = 0 | |
this.closed = true | |
}, | |
next () { | |
// if next index not exists in array of images, set index to first element | |
if (this.currentImageIndex + 1 < this.images.length) { | |
this.currentImageIndex++ | |
} else { | |
this.currentImageIndex = 0 | |
} | |
}, | |
prev () { | |
// if prev index not exists in array of images, set index to last element | |
if (this.currentImageIndex > 0) { | |
this.currentImageIndex-- | |
} else { | |
this.currentImageIndex = this.images.length - 1 | |
} | |
}, | |
showUI () { | |
// UI's hidden, we reveal it for some time only on mouse move and | |
// ImageScreen appear | |
clearTimeout(this.uiTimeout) | |
this.visibleUI = true | |
this.uiTimeout = setTimeout(() => { | |
this.visibleUI = false | |
}, 3500) | |
}, | |
report () { | |
console.log('report: ' + this.ids[this.currentImageIndex]) | |
console.log(this.store) | |
} | |
}, | |
created () { | |
window.addEventListener('keyup', (e) => { | |
// esc key and 'q' for quit | |
if (e.keyCode === 27 || e.keyCode === 81) this.close() | |
// arrow right and 'l' key (vim-like binding) | |
if (e.keyCode === 39 || e.keyCode === 76) this.next() | |
// arrow left and 'h' key (vim-like binding) | |
if (e.keyCode === 37 || e.keyCode === 72) this.prev() | |
}) | |
window.addEventListener('scroll', () => { | |
this.close() | |
}) | |
window.addEventListener('mousemove', () => { | |
this.showUI() | |
}) | |
} | |
} | |
</script> | |
<style lang="stylus" scoped> | |
#gallery | |
position: fixed | |
top: 0 | |
left: 0 | |
overflow: hidden | |
height: 100% | |
width: 100% | |
color: white | |
background-color: rgba(0, 0, 0, .7) | |
-ms-touch-action: none | |
touch-action: none | |
z-index: 10 | |
header | |
display: flex | |
align-items: center | |
width: 100% | |
height: 4.5rem; | |
position: absolute | |
background-color: rgba(0, 0, 0, .5) | |
z-index: 11 | |
&:first-child | |
padding-left: 1rem | |
.navigate | |
position: absolute | |
z-index: 11 | |
top: 50% | |
margin-top: -1rem | |
color: rgba(0, 0, 0, .5) | |
cursor: pointer | |
user-select: none | |
i | |
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), | |
0 1px 2px rgba(0, 0, 0, 0.24) | |
transition: all 0.3s cubic-bezier(.25, .8, .25, 1) | |
background-color: rgba(255, 255, 255, .5) | |
&:hover | |
color: rgba(255, 255, 255, .8) | |
background-color: rgba(0, 0, 0, .5) | |
.fade-enter, | |
.fade-leave-to | |
opacity: 0 | |
.fade-enter-active, | |
.fade-leave-active | |
-webkit-transition: opacity .3s ease-in-out | |
transition: opacity .3s ease-in-out | |
img | |
width: auto | |
height: auto | |
max-width: 100% | |
max-height: 100% | |
position: absolute | |
top: 0 | |
left: 0 | |
right: 0 | |
bottom: 0 | |
margin: auto | |
-webkit-user-select: none | |
-moz-user-select: none | |
-ms-user-select: none | |
user-select: none | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment