Files
housesof/src/organisms/Carousel.svelte
2020-03-11 17:23:58 +01:00

211 lines
7.3 KiB
Svelte

<script>
import { onMount, createEventDispatcher } from 'svelte'
import { stores } from '@sapper/app'
import { currentLocation } from '../utils/store'
import { getThumbnail, formatDate } from '../utils/functions'
const dispatch = createEventDispatcher()
const { page } = stores()
// Animations
import { animateIn } from '../animations/Carousel'
// Components
import IconArrow from '../atoms/IconArrow'
import Counter from '../atoms/Counter'
// Props
export let photos
export let viewer = false
export let init = undefined
// Variables
let scope
let hover
let currentIndex = 0
$: currentPhoto = photos[currentIndex] || null
$: prevPhoto = photos[currentIndex - 1] || photos[photos.length - 1]
$: nextPhoto = photos[currentIndex + 1] || photos[0]
/*
** Navigate to a photo
*/
// Go to specific photo on Init
if (init) {
currentIndex = photos.findIndex(photo => photo.slug === init.params.photo)
}
// Change the current index depending on direction
const goToPhoto = direction => {
if (direction === 'prev') {
currentIndex--
currentIndex = (currentIndex < 0) ? photos.length - 1 : currentIndex
} else if (direction === 'next') {
currentIndex++
currentIndex = (currentIndex >= photos.length) ? 0 : currentIndex
} else {
currentIndex = direction
console.log('Go to photo', direction, currentIndex)
}
// Send current photo to event
sendCurrentPhoto({ init: false })
}
// Send current photo to event
const sendCurrentPhoto = ({ init = false }) => {
dispatch('photoChange', {
currentPhoto: photos[currentIndex],
init
})
}
/*
** Drag and touch navigation
*/
let touchStartX = 0
let touchStartY = 0
let touchEndX = 0
let touchEndY = 0
const swipeStart = event => {
touchStartX = event.changedTouches[0].screenX
touchStartY = event.changedTouches[0].screenY
}
const swipeEnd = event => {
touchEndX = event.changedTouches[0].screenX
touchEndY = event.changedTouches[0].screenY
if (touchEndX <= touchStartX) goToPhoto('next')
if (touchEndX >= touchStartX) goToPhoto('prev')
}
/*
** Keyboard navigation
*/
const keyboardNav = event => {
if ([37,80,74].includes(event.keyCode)) {
goToPhoto('prev')
} else if ([39,78,75].includes(event.keyCode)) {
goToPhoto('next')
}
}
/*
** Run code on browser only
*/
onMount(() => {
// Entering transition
animateIn(scope)
// Hover function
hover = event => {
const button = event.currentTarget.querySelector('button')
const photoActive = document.querySelector('.gallery__photo--active')
let photoToHover
if (event.currentTarget.dataset.to === 'prev') {
photoToHover = (photoActive.previousSibling != null) ? photoActive.previousSibling : photoActive.parentNode.lastChild
} else {
photoToHover = (photoActive.nextSibling != null) ? photoActive.nextSibling : photoActive.parentNode.firstChild
}
// Toggle class and focus of the button
if (event.type === 'mouseenter') {
photoToHover.classList.add('hover')
button.classList.add('hover')
} else if (event.type === 'mouseleave') {
photoToHover.classList.remove('hover')
button.classList.remove('hover')
}
}
// Send current photo to event for init
sendCurrentPhoto({ init: true })
})
</script>
<svelte:window on:keydown={keyboardNav} />
<div class="carousel"
on:touchstart={swipeStart}
on:touchend={swipeEnd}
bind:this={scope}
>
<div class="wrap">
<div class="gallery">
<div class="gallery__images">
{#each photos as photo, index}
<picture class="gallery__photo"
class:gallery__photo--prev={photo === prevPhoto}
class:gallery__photo--active={photo === currentPhoto}
class:gallery__photo--next={photo === nextPhoto}
>
<source media="(min-width: 968px)" srcset={getThumbnail(photo.image.private_hash, 1400)}>
<source media="(min-width: 800px)" srcset={getThumbnail(photo.image.private_hash, 900)}>
<source media="(min-width: 500px)" srcset={getThumbnail(photo.image.private_hash, 600)}>
<source media="(min-width: 300px)" srcset={getThumbnail(photo.image.private_hash, 400)}>
<img src="{getThumbnail(photo.image.private_hash, 900)}" alt="{photo.name}, {photo.location.name}, {photo.location.country.name}">
</picture>
{/each}
</div>
<div class="carousel__controls">
<div class="carousel__area carousel__area--prev" data-to="prev"
on:mouseenter={hover} on:mouseleave={hover}
on:click={() => goToPhoto('prev')}
>
<button class="button-control button-control--white dir-left" aria-label="Previous">
<IconArrow direction="left" color="#ff6c89" class="icon" />
<IconArrow direction="left" color="#fff" class="icon" hidden="true" />
</button>
</div>
<div class="carousel__area carousel__area--next" data-to="next"
on:mouseenter={hover} on:mouseleave={hover}
on:click={() => goToPhoto('next')}
>
<button class="button-control button-control--white dir-right" aria-label="Next">
<IconArrow direction="right" color="#ff6c89" class="icon" />
<IconArrow direction="right" color="#fff" class="icon" hidden="true" />
</button>
</div>
</div>
{#if viewer}
<Counter {currentIndex} className="carousel__number" />
{/if}
</div>
<div class="carousel__infos">
<div class="carousel__locations">
{#each photos as photo, index}
<div class="carousel__location style-location"
class:carousel__location--prev={photo === prevPhoto}
class:carousel__location--active={photo === currentPhoto}
class:carousel__location--next={photo === nextPhoto}
>
<p class="street">{photo.name}</p>
<p class="state style-caps style-caps--transparent">
{photo.location.name}, {photo.location.country.name}
</p>
</div>
{/each}
</div>
{#if viewer}
<p class="carousel__date">{formatDate(currentPhoto.date, 'FULL')}</p>
{/if}
</div>
</div>
<ol class="carousel__dots">
{#each photos as page, index}
<li class:active={page === currentPhoto} on:click={() => goToPhoto(index)}>
<button aria-label="Go to photo #{index + 1}"></button>
</li>
{/each}
</ol>
</div>