Photo viewer
This commit is contained in:
148
src/routes/viewer/[country]/[location]/[photo].svelte
Normal file
148
src/routes/viewer/[country]/[location]/[photo].svelte
Normal file
@@ -0,0 +1,148 @@
|
||||
<script context="module">
|
||||
// Svelte
|
||||
import { api, locations, currentLocation } from '../../../../store'
|
||||
|
||||
// Define to preload data or load the store
|
||||
let preloaded
|
||||
currentLocation.subscribe(store => {
|
||||
preloaded = (store) ? store : undefined
|
||||
})
|
||||
|
||||
// Sapper preload data
|
||||
export async function preload (page, session) {
|
||||
if (preloaded === undefined) {
|
||||
const photos = await this.fetch(`${api.rest}/items/photos?fields=id,name,slug,image.data,created_on&filter[location.slug][rlike]=%${page.params.location}%`)
|
||||
const photosData = await photos.json()
|
||||
return {
|
||||
photos: photosData.data
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
photos: preloaded.photos
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { stores } from '@sapper/app'
|
||||
const { page, session, preloading } = stores()
|
||||
|
||||
// Dependencies
|
||||
import dayjs from 'dayjs'
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
dayjs.extend(advancedFormat)
|
||||
|
||||
export let photos
|
||||
let currentIndex
|
||||
let indexFormated
|
||||
let viewerPhotos
|
||||
|
||||
// Define current location
|
||||
if ($currentLocation === undefined) {
|
||||
currentLocation.set({
|
||||
location: $locations.find(location => location.slug === $page.params.location),
|
||||
photos: photos
|
||||
})
|
||||
}
|
||||
|
||||
// Set current photo, index and siblings
|
||||
const setCurrentPhotos = () => {
|
||||
// Define index and prev/next photos
|
||||
currentIndex = photos.findIndex(photo => photo.slug === $page.params.photo)
|
||||
indexFormated = (currentIndex < 10) ? '0' + (currentIndex + 1) : currentIndex + 1
|
||||
viewerPhotos = {
|
||||
current: photos[currentIndex],
|
||||
// Last photo if first, otherwise index-1
|
||||
prev: (currentIndex === 0) ? photos[photos.length - 1] : photos[currentIndex - 1],
|
||||
// First photo if last, otherwise index+1
|
||||
next: (currentIndex === photos.length - 1) ? photos[0] : photos[currentIndex + 1]
|
||||
}
|
||||
}
|
||||
|
||||
// On photo page change
|
||||
page.subscribe(({ path, params, query }) => {
|
||||
if (path.includes('/viewer/')) {
|
||||
setCurrentPhotos()
|
||||
}
|
||||
})
|
||||
|
||||
// Define things
|
||||
const locationFull = `${$currentLocation.location.name}, ${$currentLocation.location.country.name}`
|
||||
const path = `/viewer/${$currentLocation.location.country.slug}/${$currentLocation.location.slug}/`
|
||||
|
||||
// Get thumbnail
|
||||
const getThumb = (photo, size) => {
|
||||
if (photo) {
|
||||
const thumbnail = photo.image.data.thumbnails.find(thumb => thumb.url.includes(`key=${size}`))
|
||||
return thumbnail.url
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard navigation
|
||||
const keyboardNav = event => {
|
||||
const keyCode = event.keyCode
|
||||
|
||||
// Previous
|
||||
if ([37,80].includes(keyCode)) document.getElementById('photo_prev').click()
|
||||
// Next
|
||||
else if ([39,78,32].includes(keyCode)) document.getElementById('photo_next').click()
|
||||
// Close
|
||||
else if ([27,67].includes(keyCode)) document.getElementById('photo_close').click()
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- <pre>{JSON.stringify(viewerPhotos, null, 2)}</pre> -->
|
||||
|
||||
<svelte:window on:keydown={keyboardNav} />
|
||||
|
||||
<div class="container">
|
||||
<div class="nav content">
|
||||
<a href="/choose" class="button is-info" id="photo_close">Change location</a>
|
||||
<a href="/location/{$currentLocation.location.country.slug}/{$currentLocation.location.slug}" class="button is-dark" id="photo_close">Close</a>
|
||||
</div>
|
||||
|
||||
<div class="photo">
|
||||
<div class="image">
|
||||
<img src="{getThumb(viewerPhotos.current, 'large')}" srcset="{getThumb(viewerPhotos.current, 'large')} 1x, {getThumb(viewerPhotos.current, 'large-2x')} 2x" alt="{viewerPhotos.current.name}">
|
||||
</div>
|
||||
<div class="details content">
|
||||
<strong class="is-size-5">{viewerPhotos.current.name}</strong> <br>
|
||||
<span>{locationFull}</span> <br>
|
||||
<span>{indexFormated}</span> <br>
|
||||
<span>{dayjs(viewerPhotos.current.date).format('MMM Do, YYYY')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<a href="{path + viewerPhotos.prev.slug}" id="photo_prev">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<img src="{getThumb(viewerPhotos.prev, 'thumbnail')}" alt="{viewerPhotos.prev.name}" width="200">
|
||||
</div>
|
||||
<div class="media-content content">
|
||||
<strong class="is-size-5">{viewerPhotos.prev.name}</strong> <br>
|
||||
<span>{locationFull}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="level-right">
|
||||
<a href="{path + viewerPhotos.next.slug}" id="photo_next">
|
||||
<div class="media">
|
||||
<div class="media-content content has-text-right">
|
||||
<strong class="is-size-5">{viewerPhotos.next.name}</strong> <br>
|
||||
<span>{locationFull}</span>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<img src="{getThumb(viewerPhotos.next, 'thumbnail')}" alt="{viewerPhotos.next.name}" width="200">
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user