☠️ RESET for v2

This commit is contained in:
2021-09-14 13:00:12 +02:00
parent 511b0c85e5
commit bdbf511a75
124 changed files with 1612 additions and 11094 deletions

View File

@@ -0,0 +1,57 @@
<script lang="ts">
import { setContext } from 'svelte'
// Other
import '$utils/polyfills'
import '../style/style.scss'
export let data: any
// Set global data
setContext('global', data)
// console.log(data)
</script>
<slot />
<script context="module" lang="ts">
import { fetchAPI } from '$utils/api'
export async function load ({ page, session, fetch, context }) {
const res = await fetchAPI(`
query {
location {
name
slug
country {
id
}
}
country {
name
slug
}
continent {
name
slug
}
settings {
seo_name
seo_title
seo_description
}
}
`)
const { data } = res
return {
props: {
data,
}
}
}
</script>

View File

@@ -1,49 +0,0 @@
<script>
import { onMount } from 'svelte'
import { site, pageReady } from 'utils/store'
// Components
import IconArrow from 'atoms/IconArrow'
import TitleSite from 'atoms/TitleSite'
import Button from 'atoms/Button'
import Footer from 'organisms/Footer'
// Props
export let status
export let error
onMount(() => {
pageReady.set(true)
})
</script>
<svelte:head>
<title>Houses Of - {error.message}</title>
</svelte:head>
{#if process.env.NODE_ENV === 'development' && error.stack}
<div class="wrap">
<pre>{error.stack}</pre>
</div>
{/if}
<main class="housesof" class:is-transitioning={!$pageReady}>
<section class="page">
<div class="wrap">
<div class="page__top">
<a href="/" class="button-control button-control--lightpink dir-left" on:click|preventDefault={() => window.location = '/'}>
<IconArrow direction="left" color="#fff" class="icon" />
<IconArrow direction="left" color="#fff" class="icon" hidden="true" />
</a>
<TitleSite />
</div>
<div class="page__description style-description">
<p>Oh no… Looks like something wrong just happened. Like a nasty error {status}.</p>
<Button href="/" class="button" text="Go back to homepage" />
</div>
</div>
<Footer />
</section>
</main>

View File

@@ -1,126 +0,0 @@
<script context="module">
import mainQuery from 'utils/mainQuery'
export async function preload (page, session) {
await this.fetch(apiEndpoints.gql, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': 'bearer ' + process.env.CONFIG.API_TOKEN
},
body: JSON.stringify({ query: mainQuery })
})
.then(res => res.json())
.then(res => {
const { data } = res
// Manipulate countries data
data.countries.data.forEach(country => {
const matchingContinent = data.continents.data.find(continent => continent.id === country.continent.id)
// Replace continent with request data
country.continent = matchingContinent
// Add countries to each continents
matchingContinent.countries = []
matchingContinent.countries.push(country)
})
// Replace each location's country with request data
data.locations.data.forEach(location => {
location.country = data.countries.data.find(country => country.id === location.country.id)
})
// Filter and keep only the latest photo for each location
// https://stackoverflow.com/questions/61636965/
const latestPhotos = Object.values(data.photos.data.reduce((photos, photo) => {
if (photos.hasOwnProperty(photo.location.id)) {
if (new Date(photos[photo.location.id].created_on) < new Date(photo.created_on)) {
photos[photo.location.id] = photo
}
} else {
photos[photo.location.id] = photo
}
return photos
}, {}))
// Add last updated date to each location
data.locations.data.forEach(location => {
const latestPhoto = latestPhotos.find(photo => photo.location.id === location.id)
if (latestPhoto) {
location.last_updated = latestPhoto.created_on
}
})
// Set data into store
site.set(data.site.data[0])
continents.set(data.continents.data)
countries.set(data.countries.data)
locations.set(data.locations.data)
})
}
</script>
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import {
apiEndpoints,
site,
continents,
countries,
locations,
pageReady
} from 'utils/store'
// Dependencies
import lazySizes from 'lazysizes'
// Components
import AnalyticsTracker from 'utils/AnalyticsTracker'
import Transition from 'utils/Transition'
// Variables
const { page } = stores()
// Settings
lazySizes.cfg.lazyClass = 'lazyload'
/*
** Head stuff
*/
// Preconnect
const preconnect = [
'https://api.housesof.world',
'https://www.googletagmanager.com',
'https://stats.g.doubleclick.net',
'https://www.google-analytics.com',
]
// Preload assets
const preload = {
fonts: [
'/fonts/G-Light.woff2',
'/fonts/G-Regular.woff2',
'/fonts/G-Semibold.woff2',
'/fonts/M-Extralight.woff2',
'/fonts/M-Light.woff2',
]
}
</script>
<style lang="scss" global>
@import "../style/style.scss";
</style>
<svelte:head>
<link rel="canonical" href="{process.env.CONFIG.PROD_URL}{$page.path}">
{#each preconnect as host}
<link rel="preconnect" href={host} crossorigin>
<link rel="dns-prefetch" href={host}>
{/each}
{#each preload.fonts as font}
<link rel="preload" href={font} as="font" type="font/woff2" crossorigin>
{/each}
</svelte:head>
<slot />
<Transition />
<AnalyticsTracker {stores} id={process.env.CONFIG.GA_TRACKER_ID} />

View File

@@ -1,81 +0,0 @@
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import {
site,
currentLocation,
currentPhotos,
pageReady,
pageAnimation
} from 'utils/store'
// Dependencies
import Lazy from 'svelte-lazy'
// Components
import IconArrow from 'atoms/IconArrow'
import TitleSite from 'atoms/TitleSite'
import InteractiveGlobe from 'molecules/InteractiveGlobe'
import Locations from 'organisms/Locations'
import Footer from 'organisms/Footer'
import Transition from 'utils/Transition'
import SocialMetas from 'utils/SocialMetas'
// Animations
import { animateIn } from 'animations/page'
// Variables
const { page } = stores()
pageAnimation.set(animateIn)
const pageTitle = `${$site.seo_name} - ${$site.seo_title_default} across the globe`
// Reset current location
currentLocation.set()
currentPhotos.set()
/*
** Run code when mounted
*/
onMount(() => {
// Page is loaded
pageReady.set(true)
})
</script>
<svelte:head>
<title>{pageTitle}</title>
<meta name="description" content={$site.seo_description_default}>
<SocialMetas
url="{process.env.CONFIG.PROD_URL}{$page.path}"
title="{pageTitle}"
description={$site.seo_description_default}
image={$site.seo_share_image.full_url}
/>
</svelte:head>
<main class="housesof" class:is-transitioning={!$pageReady}>
<section class="page explore">
<div class="wrap">
<div class="page__top">
<a href="/" class="button-control button-control--lightpink dir-left" aria-label="Back to homepage" rel="prefetch">
<IconArrow direction="left" color="#fff" class="icon" />
<IconArrow direction="left" color="#fff" class="icon" hidden="true" />
</a>
<TitleSite />
</div>
<div class="explore__description page__description page__part style-description">
<p>{$site.explore_globe}</p>
</div>
</div>
{#if process.browser}
<Lazy offset={window.innerHeight} fadeOption={null}>
<InteractiveGlobe />
</Lazy>
{/if}
<Locations />
</section>
<Footer />
</main>

View File

@@ -1,90 +0,0 @@
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import { site, pageReady, pageAnimation } from 'utils/store'
// Dependencies
import Lazy from 'svelte-lazy'
// Components
import IconArrow from 'atoms/IconArrow'
import TitleSite from 'atoms/TitleSite'
import LinkTranslate from 'atoms/LinkTranslate'
import InteractiveGlobe from 'molecules/InteractiveGlobe'
import Footer from 'organisms/Footer'
import SocialMetas from 'utils/SocialMetas'
// Animations
import { animateIn } from 'animations/page'
// Variables
const { page } = stores()
pageAnimation.set(animateIn)
const pageTitle = `${$site.seo_name} - Credits`
/*
** Run code when mounted
*/
onMount(() => {
// Page is loaded
pageReady.set(true)
})
</script>
<svelte:head>
<title>{pageTitle}</title>
<meta name="description" content={$site.credits_text}>
<SocialMetas
url="{process.env.CONFIG.PROD_URL}{$page.path}"
title="{pageTitle}"
description={$site.credits_text}
image={$site.seo_share_image.full_url}
/>
</svelte:head>
<main class="housesof page--credits" class:is-transitioning={!$pageReady}>
<section class="page">
<div class="wrap">
<div class="page__top">
<a href="/" class="button-control button-control--lightpink dir-left">
<IconArrow direction="left" color="#fff" class="icon" />
<IconArrow direction="left" color="#fff" class="icon" hidden="true" />
</a>
<TitleSite />
</div>
<div class="page__description page__part style-description">
<p>{$site.credits_text}</p>
</div>
{#if $site.credits_list}
<div class="page__list page__part">
{#each $site.credits_list as { title, credits }}
<div class="page__category">
<h2 class="title-category">{title}</h2>
{#each credits as { name, role, website }, i}
<dl>
<dt class="style-location">
{#if website}
<LinkTranslate href={website} text={name} target="_blank" rel="noopener" />
{:else}
{name}
{/if}
</dt>
<dd class="style-caps style-caps style-caps--transparent">{role}</dd>
</dl>
{/each}
</div>
{/each}
</div>
{/if}
</div>
{#if process.browser}
<Lazy offset={window.innerHeight} fadeOption={null}>
<InteractiveGlobe type="part" opacity="0.5" />
</Lazy>
{/if}
<Footer />
</section>
</main>

View File

@@ -1,137 +1,21 @@
<script context="module">
// Variables
let limit = process.env.CONFIG.HOME_PHOTOS_LIMIT
// Preload data (photos to display)
export async function preload (page, session) {
// Load Carousel photos
const fields = [
'id', 'name', 'image.private_hash',
'location.id', 'location.name', 'location.slug',
'location.country.name', 'location.country.slug'
]
const sort = '?' // Random sort
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=${fields.join()}&status=published&sort=${sort}&limit=${limit}`, {
'Authorization': 'bearer ' + process.env.CONFIG.API_TOKEN
})
const photos = await req.json()
if (req.ok) {
return { photos: photos.data }
}
this.error(404, 'Not found')
}
</script>
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import {
apiEndpoints,
site,
currentLocation,
currentPhotos,
pageReady,
pageAnimation
} from 'utils/store'
import { charsToSpan, smoothScroll } from 'utils/functions'
// Dependencies
import Lazy from 'svelte-lazy'
<script lang="ts">
import { getContext } from 'svelte'
// Components
import Button from 'atoms/Button'
import IconGlobeSmall from 'atoms/IconGlobeSmall'
import InteractiveGlobe from 'molecules/InteractiveGlobe'
import Carousel from 'organisms/Carousel'
import Fullscreen from 'organisms/Fullscreen'
import Locations from 'organisms/Locations'
import Footer from 'organisms/Footer'
import SocialMetas from 'utils/SocialMetas'
// Animations
import { animateIn } from 'animations/index'
pageAnimation.set(animateIn)
import Metas from '$components/Metas.svelte'
import Locations from '$components/organisms/Locations.svelte'
// Props and Variables
export let photos = ''
const { page } = stores()
let winWidth = 0
// Reset current location if existing
currentLocation.set()
currentPhotos.set()
/*
** Run code when mounted
*/
onMount(() => {
// Page is loaded
pageReady.set(true)
})
const globalData: any = getContext('global')
console.log(globalData)
</script>
<svelte:head>
<title>{$site.seo_name} - {$site.seo_title_default} across the globe</title>
<meta name="description" content={$site.seo_description_default}>
<SocialMetas
url="{process.env.CONFIG.PROD_URL}"
title="{$site.seo_name} - {$site.seo_title_default} across the globe"
description={$site.seo_description_default}
image={$site.seo_share_image.full_url}
/>
</svelte:head>
<Metas
title="Houses Of"
description=""
image=""
/>
<svelte:window bind:innerWidth={winWidth} />
<h1>Houses Of</h1>
<main class="housesof" class:is-transitioning={!$pageReady}>
<section class="intro">
<div class="anim-mask">
<div class="anim title-parallax" id="title-houses">
<h1 class="title-massive" aria-label="Houses">
{@html charsToSpan('Houses')}
</h1>
</div>
</div>
<div class="wrap" id="intro-description">
<div class="intro__description style-description">
<p>{$site.description}</p>
<Button type="a" href="#choose" class="button" text="Explore locations" on:click={smoothScroll}>
<IconGlobeSmall width="22" color="#666" />
</Button>
</div>
</div>
<div id="intro-carousel">
<Carousel {photos} locationUrl={true} />
<Fullscreen />
</div>
</section>
<section class="explore explore--homepage">
<div class="of" id="title-of" role="heading" aria-level="2" aria-label="of">
<div class="anim-mask">
{@html charsToSpan('of')}
</div>
</div>
<div class="explore__description style-description" id="choose">
<p>{$site.explore_globe}</p>
</div>
{#if process.browser}
<Lazy offset={window.innerHeight} fadeOption={null}>
<InteractiveGlobe />
</Lazy>
{/if}
<div class="anim-mask anim-title">
<h1 class="title-massive title-parallax" id="title-world" aria-label="World">
{@html charsToSpan('World')}
</h1>
</div>
<Locations />
</section>
<Footer />
</main>
<Locations
locations={globalData.location}
/>

View File

@@ -1,209 +0,0 @@
<script context="module">
import { apiEndpoints } from 'utils/store'
// Preload data
export async function preload (page, session) {
// Load photos
const fields = [
'id', 'name', 'slug', 'date', 'image.private_hash',
'location.id', 'location.name', 'location.slug', 'location.region',
'location.country.name', 'location.country.slug', 'city',
'created_on', 'modified_on'
].join(',')
const sort = ['-created_on', 'name'].join(',')
const limit = -1
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=${fields}&status=published&filter[location.slug][rlike]=%${page.params.place}%&limit=${limit}&sort=${sort}`, {
'Authorization': 'bearer ' + process.env.CONFIG.API_TOKEN
})
const photos = await req.json()
if (req.ok) {
return { photos: photos.data }
}
this.error(404, 'Not found')
}
</script>
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import {
site,
locations,
currentLocation,
currentPhotos,
pageReady,
pageAnimation
} from 'utils/store'
import { formatDate, relativeTime, getThumbnail } from 'utils/functions'
// Components
import IconGlobe from 'atoms/IconGlobe'
import IconGlobeSmall from 'atoms/IconGlobeSmall'
import LinkChange from 'atoms/LinkChange'
import ToggleLayout from 'atoms/ToggleLayout'
import Photo from 'molecules/Photo'
import Switcher from 'molecules/Switcher'
import Pagination from 'organisms/Pagination'
import Footer from 'organisms/Footer'
import SocialMetas from 'utils/SocialMetas'
// Animations
import { animateIn } from 'animations/place'
// Props and variables
export let photos
const { page } = stores()
pageAnimation.set(animateIn)
let layoutSetting
let windowWidth
$: latestPhoto = photos[0]
// Update current location
const location = $locations.find(loc => loc.slug === $page.params.place)
const { description, country, illu_desktop, illu_desktop_2x, illu_mobile } = location
currentLocation.set(location)
currentPhotos.set(photos)
// Define dates
$: latestPhotoModified = latestPhoto ? latestPhoto.modified_on.replace(' ', 'T') : ''
$: dateUpdatedFull = latestPhoto ? formatDate(latestPhotoModified, 'FULL') : ''
$: dateUpdatedDatetime = latestPhoto ? formatDate(latestPhotoModified, 'DATETIME') : ''
$: dateUpdatedRelative = latestPhoto ? relativeTime(latestPhotoModified, 2592000000) : ''
/*
** Pagination
*/
let photosPerPage = $site.photos_per_page
// Hide photos by default
photos.forEach((photo, index) => photo.hidden = (index + 1 > photosPerPage) ? true : false)
let paginatedPhotos = photos.filter(photo => photo.hidden === false)
// Update pagination event from Pagination component
const updatePagination = event => paginatedPhotos = event.detail
/*
** Run code when mounted
*/
onMount(() => {
// Page is loaded
pageReady.set(true)
// Get layout setting from storage
layoutSetting = localStorage.getItem('photosLayout')
})
</script>
<svelte:head>
<title>{$site.seo_name} {$site.seo_title_default} of {location.name}, {country.name}</title>
<meta name="description" content="{$site.seo_name} {location.name} {description}">
<SocialMetas
url="{process.env.CONFIG.PROD_URL}/location/{country.slug}/{location.slug}"
title="{$site.seo_name} {$site.seo_title_default} of {location.name}, {country.name}"
description="{$site.seo_name} {location.name} {description}"
image={latestPhoto ? getThumbnail(latestPhoto.image.private_hash, 1200, 630) : null}
/>
</svelte:head>
<svelte:window bind:innerWidth={windowWidth} />
<main class="housesof" class:is-transitioning={!$pageReady}>
<section class="place">
<div class="place__title">
<h1 class="title-location title-location--big" aria-label="Houses of {location.name}" data-rellax-speed="-2.75" data-rellax-max-y="200">
<span class="place__title_top anim-mask">
<span class="place__title_houses">Houses</span>
<em class="place__title_of">of</em>
</span>
<span class="place__title_bottom anim-mask">
<span class="place__title_name">{location.name}</span>
</span>
</h1>
<div data-rellax-speed={windowWidth <= 768 ? -2.5 : -1.75} data-rellax-max-y="200">
<a href="/choose" class="button-control button-control--big button-control--dashed" aria-label="Change location">
<span class="center">
<IconGlobe width={windowWidth <= 768 ? 32 : 44} color="#fff" />
<span>Change</span>
</span>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="50%" cy="50%" r="43%" />
</svg>
</a>
</div>
</div>
<div class="place__wrap wrap">
<div class="place__description">
<div class="wrapper">
<p>{$site.description}</p>
{#if description}
<p>
Houses Of
<LinkChange href="/choose" text={location.name}>
<IconGlobeSmall width="14" color="#999" />
</LinkChange>
{description}
</p>
{/if}
{#if photos.length}
<p class="updated style-caps">
<strong>Updated</strong>
<time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{dateUpdatedRelative}</time>
</p>
<ToggleLayout />
{/if}
</div>
</div>
</div>
{#if illu_desktop || illu_desktop_2x || illu_mobile}
<div class="place__illustration">
<div class="parallax" data-rellax-speed="-5" data-rellax-max-y="400">
<div class="place__illustration_img"
style="{`--url-desktop: ${illu_desktop ? `url(${illu_desktop.full_url});` : undefined}`}
{`--url-desktop-2x: ${illu_desktop_2x ? `url(${illu_desktop_2x.full_url});` : undefined}`}
{`--url-mobile: ${illu_mobile ? `url(${illu_mobile.full_url});` : undefined}`}"
/>
</div>
</div>
{/if}
</section>
<section class="photos photos--{layoutSetting || 'list'}">
<div class="photos__sidewrap wrap">
<aside class="photos__side">
<Switcher type="switcher--side" />
{#if photos.length}
<p class="updated style-caps">
<strong>Updated</strong>
<time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{dateUpdatedRelative}</time>
</p>
{/if}
</aside>
</div>
{#if photos}
<div class="photos__view wrap">
{#each paginatedPhotos as photo}
<Photo {photo} index={photos.length - photos.indexOf(photo)} />
{/each}
</div>
<Pagination {photos} {paginatedPhotos} {photosPerPage}
on:updatePagination={updatePagination}
/>
{:else}
<div class="wrap" style="padding-top: 20vw; padding-bottom: 20vw;">
<p style="text-align: center; color: #333;">No photo for {location.name}</p>
</div>
{/if}
</section>
<Footer />
</main>

View File

@@ -1,79 +0,0 @@
const fs = require('fs')
const fetch = require('node-fetch')
import { apiEndpoints } from 'utils/store'
import { formatDate } from 'utils/functions'
// Variables
let baseURL
const pages = ['']
// Get routes and push it to array
const routesExclude = ['sitemap', 'index', 'location', 'viewer']
fs.readdirSync('./src/routes').forEach(file => {
const filename = file.split('.')[0]
if (!file.startsWith('.') && !filename.startsWith('_') && routesExclude.indexOf(filename) === -1) {
pages.push(filename)
}
})
// Render function
const render = (pages, locations) => {
return `<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
>
${pages.map(page => `
<url>
<loc>${baseURL}/${page}</loc>
<priority>0.75</priority>
</url>`).join('\n')}
${locations.map(loc => `
<url>
<loc>${baseURL}/location/${loc.country.slug}/${loc.slug}</loc>
<priority>1</priority>
<lastmod>${formatDate(loc.updated, 'DATETIME')}</lastmod>
<changefreq>weekly</changefreq>
</url>`).join('\n')
}
</urlset>`
}
// Get function
export async function get (req, res, next) {
let locations
// Define base url from request
baseURL = `https://${req.headers.host}`
// Get locations
await fetch(`${apiEndpoints.rest}/items/locations?fields=slug,country.slug,modified_on&status=published&sort=created_on`)
.then(res => res.json())
.then(res => {
locations = res.data
})
// Add last modified date to each location from its last photo
const updatedLocations = locations.map(async (location, i) => {
await fetch(`${apiEndpoints.rest}/items/photos?fields=created_on&limit=1&sort=-created_on&status=published&filter[location.slug][rlike]=%${location.slug}`)
.then(res => res.json())
.then(res => {
const latestPhoto = res.data[0]
location.updated = latestPhoto ? latestPhoto.created_on : location.modified_on
})
return location
})
await Promise.all(updatedLocations)
// Set headers
res.setHeader('Cache-Control', 'max-age=0, s-max-age=600') // 10 minutes
res.setHeader('Content-Type', 'application/rss+xml')
// Render sitemap
const sitemap = render(pages, locations)
res.end(sitemap)
}

View File

@@ -1,75 +0,0 @@
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import { site, pageReady, pageAnimation } from 'utils/store'
// Dependencies
import Lazy from 'svelte-lazy'
// Components
import IconArrow from 'atoms/IconArrow'
import TitleSite from 'atoms/TitleSite'
import LinkTranslate from 'atoms/LinkTranslate'
import InteractiveGlobe from 'molecules/InteractiveGlobe'
import NewsletterForm from 'molecules/NewsletterForm'
import Footer from 'organisms/Footer'
import SocialMetas from 'utils/SocialMetas'
// Animations
import { animateIn } from 'animations/page'
// Variables
const { page } = stores()
pageAnimation.set(animateIn)
const pageTitle = `${$site.seo_name} - Keep Updated`
/*
** Run code when mounted
*/
onMount(() => {
// Page is loaded
pageReady.set(true)
})
</script>
<svelte:head>
<title>{pageTitle}</title>
<meta name="description" content={$site.subscribe_text}>
<SocialMetas
url="{process.env.CONFIG.PROD_URL}{$page.path}"
title="{pageTitle}"
description={$site.subscribe_text}
image={$site.seo_share_image.full_url}
/>
</svelte:head>
<main class="housesof page--credits" class:is-transitioning={!$pageReady}>
<section class="page">
<div class="wrap">
<div class="page__top">
<a href="/" class="button-control button-control--lightpink dir-left">
<IconArrow direction="left" color="#fff" class="icon" />
<IconArrow direction="left" color="#fff" class="icon" hidden="true" />
</a>
<TitleSite />
</div>
<div class="newsletter newsletter--column">
<div class="newsletter__text style-description page__part">
<p>{$site.newsletter_text}</p>
</div>
<div class="page__part">
<NewsletterForm title={true} />
</div>
</div>
</div>
{#if process.browser}
<Lazy offset={window.innerHeight} fadeOption={null}>
<InteractiveGlobe type="part" opacity="0.5" />
</Lazy>
{/if}
<Footer />
</section>
</main>

View File

@@ -1,137 +0,0 @@
<script context="module">
// Define either to preload data or use the store
let preloaded
currentPhotos.subscribe(store => preloaded = store ? store : undefined)
// Preload data
export async function preload (page, session) {
// Load the photos if not loaded
if (!preloaded) {
const fields = [
'id', 'name', 'slug', 'date', 'image.private_hash',
'location.id', 'location.name', 'location.slug',
'location.country.name', 'location.country.slug'
]
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=${fields.join()}&status=published&filter[location.slug][rlike]=%${page.params.place}%`, {
'Authorization': 'bearer ' + process.env.CONFIG.API_TOKEN
})
const photos = await req.json()
if (req.ok) {
return { photos: photos.data }
}
}
// Use the store otherwise
else return {
photos: preloaded
}
this.error(404, 'Not found')
}
</script>
<script>
import { onMount } from 'svelte'
import { stores } from '@sapper/app'
import {
apiEndpoints,
site,
locations,
currentLocation,
currentPhotos,
pageReady,
pageAnimation
} from 'utils/store'
import { getThumbnail } from 'utils/functions'
// Components
import IconGlobe from 'atoms/IconGlobe'
import IconCross from 'atoms/IconCross'
import Carousel from 'organisms/Carousel'
import Fullscreen from 'organisms/Fullscreen'
import Transition from 'utils/Transition'
import SocialMetas from 'utils/SocialMetas'
// Animations
import { animateIn } from 'animations/viewer'
// Props
export let photos
const { page } = stores()
pageAnimation.set(animateIn)
// Update store current location
currentLocation.set($locations.find(loc => loc.slug === $page.params.place))
currentPhotos.set(photos)
let windowWidth
let gotoLink
let currentPhoto = photos.find(photo => photo.slug === $page.params.photo)
// Photo has changed (from Carousel)
const photoChanged = event => {
const currentPhoto = event.detail
const windowPathname = window.location.pathname
if (currentPhoto) {
const newUrl = windowPathname.substring(0, windowPathname.lastIndexOf('/') + 1) + currentPhoto.slug
// Go to page via a sapper-noscroll link to avoid scroll jump (hacky)
if (gotoLink && newUrl) {
gotoLink.href = newUrl
gotoLink.click()
}
}
}
/*
** Run code when mounted
*/
onMount(() => {
// Page is loaded
pageReady.set(true)
})
</script>
<svelte:head>
{#if $currentLocation}
<title>{$site.seo_name} {$site.seo_title_default} of {$currentLocation.name}, {$currentLocation.country.name}</title>
<meta name="description" content="{$site.seo_name} {$currentLocation.name} {$currentLocation.description}">
<SocialMetas
url="{process.env.CONFIG.PROD_URL}/viewer/{currentPhoto.location.country.slug}/{currentPhoto.location.slug}/{currentPhoto.slug}"
title="{$site.seo_name} - {$site.seo_title_default} of {$currentLocation.name}, {$currentLocation.country.name}"
description="{$site.seo_name} {$currentLocation.name} {$currentLocation.description}"
image={getThumbnail(currentPhoto.image.private_hash, 1200, 630)}
/>
{/if}
</svelte:head>
<svelte:window bind:innerWidth={windowWidth} />
<main class="housesof" class:is-transitioning={!$pageReady}>
<section class="viewer">
<div class="viewer__top">
<p class="tip">Tap for fullscreen</p>
<div class="viewer__buttons">
<a href="/choose" class="button-control button-control--dashed" aria-label="Change the location" rel="prefetch">
<IconGlobe color="#fff" width={windowWidth >= 768 ? 22 : 18} />
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="50%" cy="50%" r="{windowWidth >= 768 ? 32 : 24}px"></circle>
</svg>
</a>
{#if $currentLocation}
<a href="/location/{$currentLocation.country.slug}/{$currentLocation.slug}" class="button-control button-control--lightpink dir-bottom" aria-label="Back to photos" rel="prefetch">
<IconCross color="#fff" width="18" class="icon" />
<IconCross color="#fff" width="18" class="icon" hidden="true" />
</a>
{/if}
</div>
<a href="/" bind:this={gotoLink} aria-hidden="true" hidden class="hidden" sapper-noscroll>&nbsp;</a>
</div>
<Carousel {photos} viewer={true}
on:photoChange={photoChanged}
/>
<Fullscreen />
</section>
</main>