Add Fullscreen in viewer, Track links with Google Analytics, Use .env file
All checks were successful
continuous-integration/drone/push Build is passing

- Fullscreen is a component that watches a store value set by the Carousel component on a picture click
- Use a .env file for API and website related settings and informations
- Google Analytics is now in place, tracking each routes link and viewer photo change
This commit is contained in:
2020-03-28 15:21:51 +01:00
parent 23db9e343c
commit 0635b65abf
20 changed files with 384 additions and 138 deletions

10
.env Normal file
View File

@@ -0,0 +1,10 @@
# Website
PROD_URL=https://housesof.world
# API
API_TOKEN=NJk0urljsdSvApUDzWxGgoO6
API_URL_DEV=http://api.housesof.localhost/how
API_URL_PROD=https://api.housesof.world/_
# Tracking
GA_TRACKER_ID=UA-4060922-27

View File

@@ -37,6 +37,7 @@
"@rollup/plugin-replace": "^2.3.1", "@rollup/plugin-replace": "^2.3.1",
"autoprefixer": "^9.7.5", "autoprefixer": "^9.7.5",
"babel-plugin-module-resolver": "^4.0.0", "babel-plugin-module-resolver": "^4.0.0",
"dotenv": "^8.2.0",
"eslint-config-standard": "^14.1.1", "eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "^2.20.1", "eslint-plugin-import": "^2.20.1",
"eslint-plugin-node": "^11.0.0", "eslint-plugin-node": "^11.0.0",

8
pnpm-lock.yaml generated
View File

@@ -19,6 +19,7 @@ devDependencies:
'@rollup/plugin-replace': 2.3.1_rollup@2.2.0 '@rollup/plugin-replace': 2.3.1_rollup@2.2.0
autoprefixer: 9.7.5 autoprefixer: 9.7.5
babel-plugin-module-resolver: 4.0.0 babel-plugin-module-resolver: 4.0.0
dotenv: 8.2.0
eslint-config-standard: 14.1.1_13a54f81caffeb9134dc06c172bdde71 eslint-config-standard: 14.1.1_13a54f81caffeb9134dc06c172bdde71
eslint-plugin-import: 2.20.1 eslint-plugin-import: 2.20.1
eslint-plugin-node: 11.0.0 eslint-plugin-node: 11.0.0
@@ -1649,6 +1650,12 @@ packages:
node: '>=6.0.0' node: '>=6.0.0'
resolution: resolution:
integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
/dotenv/8.2.0:
dev: true
engines:
node: '>=8'
resolution:
integrity: sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
/ecc-jsbn/0.1.2: /ecc-jsbn/0.1.2:
dependencies: dependencies:
jsbn: 0.1.1 jsbn: 0.1.1
@@ -4574,6 +4581,7 @@ specifiers:
autoprefixer: ^9.7.5 autoprefixer: ^9.7.5
babel-plugin-module-resolver: ^4.0.0 babel-plugin-module-resolver: ^4.0.0
compression: ^1.7.4 compression: ^1.7.4
dotenv: ^8.2.0
eslint-config-standard: ^14.1.1 eslint-config-standard: ^14.1.1
eslint-plugin-import: ^2.20.1 eslint-plugin-import: ^2.20.1
eslint-plugin-node: ^11.0.0 eslint-plugin-node: ^11.0.0

View File

@@ -7,13 +7,18 @@ import babel from 'rollup-plugin-babel'
// import browsersync from 'rollup-plugin-browsersync' // import browsersync from 'rollup-plugin-browsersync'
import autoPreprocess from 'svelte-preprocess' import autoPreprocess from 'svelte-preprocess'
import { terser } from 'rollup-plugin-terser' import { terser } from 'rollup-plugin-terser'
import config from 'sapper/config/rollup' import sapperConfig from 'sapper/config/rollup'
import { config } from 'dotenv'
import pkg from './package.json' import pkg from './package.json'
// Define environment and things // Define environment and things
const mode = process.env.NODE_ENV const mode = process.env.NODE_ENV
const dev = mode === 'development' const dev = mode === 'development'
const legacy = !!process.env.SAPPER_LEGACY_BUILD const legacy = !!process.env.SAPPER_LEGACY_BUILD
const replaceOptions = {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.CONFIG': JSON.stringify(config().parsed)
}
// Svelte // Svelte
const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning) const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning)
@@ -33,24 +38,20 @@ export default {
** Client ** Client
*/ */
client: { client: {
input: config.client.input(), input: sapperConfig.client.input(),
output: { output: sapperConfig.client.output(),
...config.client.output(),
// ...dev && { exports: 'named' }
},
// experimentalCodeSplitting: true,
plugins: [ plugins: [
// Javascript // Javascript
replace({ replace({
'process.browser': true, 'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode) ...replaceOptions
}), }),
svelte({ svelte({
dev, dev,
preprocess,
hydratable: true, hydratable: true,
emitCss: true, emitCss: true,
// css: css => css.write('static/bundle.css'), // css: css => css.write('static/bundle.css')
preprocess
}), }),
resolve({ resolve({
browser: true, browser: true,
@@ -79,17 +80,17 @@ export default {
** Server ** Server
*/ */
server: { server: {
input: config.server.input(), input: sapperConfig.server.input(),
output: config.server.output(), output: sapperConfig.server.output(),
plugins: [ plugins: [
replace({ replace({
'process.browser': false, 'process.browser': false,
'process.env.NODE_ENV': JSON.stringify(mode) ...replaceOptions
}), }),
svelte({ svelte({
dev, dev,
generate: 'ssr', preprocess,
preprocess generate: 'ssr'
}), }),
resolve({ resolve({
browser: true, browser: true,
@@ -101,7 +102,6 @@ export default {
external: Object.keys(pkg.dependencies).concat( external: Object.keys(pkg.dependencies).concat(
require('module').builtinModules || Object.keys(process.binding('natives')) require('module').builtinModules || Object.keys(process.binding('natives'))
), ),
onwarn, onwarn,
}, },
@@ -110,13 +110,13 @@ export default {
** Service worker ** Service worker
*/ */
// serviceworker: { // serviceworker: {
// input: config.serviceworker.input(), // input: sapperConfig.serviceworker.input(),
// output: config.serviceworker.output(), // output: sapperConfig.serviceworker.output(),
// plugins: [ // plugins: [
// resolve(), // resolve(),
// replace({ // replace({
// 'process.browser': true, // 'process.browser': true,
// 'process.env.NODE_ENV': JSON.stringify(mode) // ...replaceOptions
// }), // }),
// commonjs(), // commonjs(),
// !dev && terser() // !dev && terser()

View File

@@ -0,0 +1,9 @@
<script>
export let width = 18
export let color = '#fff'
export let hidden = undefined
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 18" {width} fill={color} class={$$props.class} aria-hidden={hidden}>
<path fill-rule="evenodd" d="M8.36 0a7.76 7.76 0 016.02 12.63l3.99 3.99a.81.81 0 11-1.15 1.14l-3.99-3.99A7.76 7.76 0 118.35 0zm0 1.62a6.14 6.14 0 10.01 12.28 6.14 6.14 0 00-.01-12.28zm2.38 5.32a.81.81 0 110 1.62H5.98a.81.81 0 110-1.62z"/>
</svg>

View File

@@ -1,7 +1,7 @@
<script> <script>
import { onMount, createEventDispatcher } from 'svelte' import { onMount, createEventDispatcher } from 'svelte'
import { stores } from '@sapper/app' import { stores } from '@sapper/app'
import { currentLocation } from '../utils/store' import { currentLocation, fullscreen } from '../utils/store'
import { getThumbnail, formatDate } from '../utils/functions' import { getThumbnail, formatDate } from '../utils/functions'
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const { page } = stores() const { page } = stores()
@@ -50,6 +50,8 @@
// Dispatch current photo // Dispatch current photo
sendCurrentPhoto() sendCurrentPhoto()
// Reset fullscreen value if open
fullscreen.set()
} }
// Send current photo to event // Send current photo to event
@@ -145,6 +147,7 @@
class:gallery__photo--prev={photo === prevPhoto} class:gallery__photo--prev={photo === prevPhoto}
class:gallery__photo--active={photo === currentPhoto} class:gallery__photo--active={photo === currentPhoto}
class:gallery__photo--next={photo === nextPhoto} class:gallery__photo--next={photo === nextPhoto}
on:click={event => viewer && fullscreen.set(currentPhoto)}
> >
<source media="(min-width: 968px)" srcset={getThumbnail(photo.image.private_hash, 1400)}> <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: 800px)" srcset={getThumbnail(photo.image.private_hash, 900)}>

View File

@@ -0,0 +1,82 @@
<script>
import { fullscreen } from '../utils/store'
import { throttle, getThumbnail } from '../utils/functions'
// Dependencies
import imagesLoaded from 'imagesloaded'
// Components
import IconGlobe from '../atoms/IconGlobe'
import IconZoomOut from '../atoms/IconZoomOut'
// Variables
let scope
let loading = false
let open = false
let closed = false
// Wait for fullscreen store value
$: {
if ($fullscreen) openFullscreen($fullscreen)
else closeFullscreen()
}
/*
** Functions
*/
// Open fullscreen
const openFullscreen = throttle(currentPhoto => {
loading = true
if (!open) {
const img = document.createElement('img')
const imgContainer = scope.querySelector('.fullscreen__image')
img.src = getThumbnail(currentPhoto.image.private_hash, null, 1600, 'crop', 80)
img.alt = `${currentPhoto.name}, ${currentPhoto.location.name}, ${currentPhoto.location.country.name}`
img.width = 2400
img.height = 1600
imgContainer.append(img)
// Show fullscreen when new image is loaded
imagesLoaded(scope, instance => {
open = true
loading = false
closed = false
// Scroll to photo's center
imgContainer.scrollTo((img.clientWidth - scope.clientWidth) / 2, 0)
})
}
}, 800)
// Close fullscreen
const closeFullscreen = throttle(() => {
// Reset values
open = false
closed = true
// Clear image and reset fullscreen store value
setTimeout(() => {
scope.querySelector('.fullscreen__image').innerHTML = ''
fullscreen.set()
}, 800) // Transition duration
}, 800)
</script>
<div class="fullscreen" bind:this={scope}>
<div class="fullscreen__image" class:is-open={open} on:click={closeFullscreen} />
<div class="fullscreen__loading" class:is-hidden={!loading}>
<IconGlobe width="24" color="#fff" animated="true" />
</div>
<div class="fullscreen__close" class:is-visible={open}>
<button class="button-control button-control--gray button-control--shadow dir-top" aria-label="Close"
on:click={closeFullscreen}
>
<IconZoomOut color="#fff" width="22" class="icon" />
<IconZoomOut color="#fff" width="22" class="icon" hidden="true" />
</button>
</div>
</div>

View File

@@ -71,9 +71,11 @@
countries, countries,
locations locations
} from '../utils/store' } from '../utils/store'
import { stores } from '@sapper/app'
// Components // Components
import Transition from '../utils/Transition' import Transition from '../utils/Transition'
import AnalyticsTracker from '../utils/AnalyticsTracker'
// Props // Props
export const segment = null export const segment = null
@@ -96,7 +98,6 @@
$locations.forEach(loc => loc.country = $countries.find(cont => cont.id === loc.country.id)) $locations.forEach(loc => loc.country = $countries.find(cont => cont.id === loc.country.id))
</script> </script>
<style lang="scss" global> <style lang="scss" global>
@import "../style/style.scss"; @import "../style/style.scss";
</style> </style>
@@ -104,3 +105,5 @@
<slot></slot> <slot></slot>
<Transition /> <Transition />
<AnalyticsTracker {stores} id={process.env.CONFIG.GA_TRACKER_ID} />

View File

@@ -6,21 +6,26 @@
let preloaded let preloaded
currentPhotos.subscribe(store => preloaded = store ? store : undefined) currentPhotos.subscribe(store => preloaded = store ? store : undefined)
// Preload data // Preload data
export async function preload (page, session) { export async function preload (page, session) {
// Load the photos if not loaded // Load the photos if not loaded
if (!preloaded) { if (!preloaded) {
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=id,name,slug,date,image.*,location.*,location.country.*,created_on,modified_on&filter[location.slug][rlike]=%${page.params.location}%`) // Fields
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()}&filter[location.slug][rlike]=%${page.params.place}%`)
const photos = await req.json() const photos = await req.json()
return { if (req.ok) {
photos: photos.data return { photos: photos.data }
} }
} }
// Use the store otherwise // Use the store otherwise
else return { else return {
photos: preloaded photos: preloaded
} }
this.error(404, 'Not found')
} }
</script> </script>
@@ -34,33 +39,33 @@
pageReady, pageReady,
pageTransition pageTransition
} from '../../../../utils/store' } from '../../../../utils/store'
import { getThumbnail } from '../../../../utils/functions' import { getThumbnail, analyticsUpdate } from '../../../../utils/functions'
const { page } = stores()
const dispatch = createEventDispatcher()
// Components // Components
import IconGlobe from '../../../../atoms/IconGlobe' import IconGlobe from '../../../../atoms/IconGlobe'
import IconCross from '../../../../atoms/IconCross' import IconCross from '../../../../atoms/IconCross'
import Carousel from '../../../../organisms/Carousel' import Carousel from '../../../../organisms/Carousel'
import Fullscreen from '../../../../organisms/Fullscreen'
import SocialMetas from '../../../../utils/SocialMetas' import SocialMetas from '../../../../utils/SocialMetas'
// Animations // Animations
import { animateIn } from '../../../../animations/viewer' import { animateIn } from '../../../../animations/viewer'
pageTransition.onAnimationEnd = animateIn pageTransition.onAnimationEnd = animateIn
// Props // Props
export let photos export let photos
// Variables // Variables
const { page } = stores()
const dispatch = createEventDispatcher()
let windowWidth let windowWidth
let currentPhoto = photos.find(photo => photo.slug === $page.params.photo) let currentPhoto = photos.find(photo => photo.slug === $page.params.photo)
// Update store current location // Update store current location
if (!$currentLocation) currentLocation.set($locations.find(loc => loc.slug === $page.params.location)) if (!$currentLocation) currentLocation.set($locations.find(loc => loc.slug === $page.params.place))
if (!$currentPhotos) currentPhotos.set(photos) if (!$currentPhotos) currentPhotos.set(photos)
// The photo has changed from the carousel // Photo has changed from the Carousel component
const photoChanged = event => { const photoChanged = event => {
currentPhoto = event.detail.currentPhoto currentPhoto = event.detail.currentPhoto
@@ -69,6 +74,7 @@
const windowPathname = window.location.pathname const windowPathname = window.location.pathname
const newUrl = windowPathname.substring(0, windowPathname.lastIndexOf('/') + 1) + currentPhoto.slug const newUrl = windowPathname.substring(0, windowPathname.lastIndexOf('/') + 1) + currentPhoto.slug
history.pushState('', document.title, newUrl) history.pushState('', document.title, newUrl)
analyticsUpdate(newUrl)
} }
} }
@@ -77,11 +83,7 @@
// On init, send an event to the Carousel component with the photoSlug to set currentIndex and then change the photo // On init, send an event to the Carousel component with the photoSlug to set currentIndex and then change the photo
// Pop event from browser (prev/next) // Pop event from browser (prev/next)
const changedUrl = event => { const changedUrl = event => dispatch('changedUrl', { currentPhoto: currentPhoto })
dispatch('changedUrl', {
currentPhoto: currentPhoto
})
}
/* /*
@@ -91,25 +93,21 @@
// Page is loaded // Page is loaded
pageReady.set(true) pageReady.set(true)
/* dispatch('changeUrl', { page: $page })
!!! TODO:
- Change the title with the current photo name and update Metas (with window location url)
*/
dispatch('changeUrl', {
page: $page
})
}) })
</script> </script>
<svelte:head> <svelte:head>
<!-- TODO:
- Change the title with the current photo name and update Metas (with window location url)
-->
<title>{$site.seo_name} Photos of {$currentLocation.name}, {$currentLocation.country.name}</title> <title>{$site.seo_name} Photos of {$currentLocation.name}, {$currentLocation.country.name}</title>
<meta name="description" content="{$site.seo_name} {$currentLocation.name} {$currentLocation.description}"> <meta name="description" content="{$site.seo_name} {$currentLocation.name} {$currentLocation.description}">
<SocialMetas <SocialMetas
url="https://{$page.host}/viewer/{currentPhoto.location.country.slug}/{currentPhoto.location.slug}/{currentPhoto.slug}"
title="{$site.seo_name} - Beautiful homes of {$currentLocation.name}, {$currentLocation.country.name}" title="{$site.seo_name} - Beautiful homes of {$currentLocation.name}, {$currentLocation.country.name}"
description="{$site.seo_name} {$currentLocation.name} {$currentLocation.description}" description="{$site.seo_name} {$currentLocation.name} {$currentLocation.description}"
image={getThumbnail(currentPhoto.image.private_hash, 1200, 630)} image={getThumbnail(currentPhoto.image.private_hash, 1200, 630)}
url="//{$page.host.split(':3000')[0]}/viewer/{currentPhoto.location.country.slug}/{currentPhoto.location.slug}/{currentPhoto.slug}"
/> />
</svelte:head> </svelte:head>
@@ -119,14 +117,14 @@
<div class="viewer__top"> <div class="viewer__top">
<p class="tip">Tap for fullscreen</p> <p class="tip">Tap for fullscreen</p>
<div class="buttons"> <div class="viewer__buttons">
<a href="/choose" class="button-control button-control--dashed" aria-label="Change the location" rel="prefetch"> <a href="/choose" class="button-control button-control--dashed" aria-label="Change the location" rel="prefetch">
<IconGlobe color="#fff" width={windowWidth >= 768 ? 22 : 18} /> <IconGlobe color="#fff" width={windowWidth >= 768 ? 22 : 18} />
<svg> <svg>
<circle cx="50%" cy="50%" r="{windowWidth >= 768 ? 32 : 24}px"></circle> <circle cx="50%" cy="50%" r="{windowWidth >= 768 ? 32 : 24}px"></circle>
</svg> </svg>
</a> </a>
<a href="/location/{$currentLocation.country.slug}/{$currentLocation.slug}" class="button-control button-control--pink dir-bottom" aria-label="Close"> <a href="/location/{$currentLocation.country.slug}/{$currentLocation.slug}" class="button-control button-control--pink dir-bottom" aria-label="Back to photos" rel="prefetch">
<IconCross color="#fff" width="18" class="icon" /> <IconCross color="#fff" width="18" class="icon" />
<IconCross color="#fff" width="18" class="icon" hidden="true" /> <IconCross color="#fff" width="18" class="icon" hidden="true" />
</a> </a>
@@ -134,9 +132,11 @@
</div> </div>
<Carousel <Carousel
viewer="true"
photos={photos} photos={photos}
viewer={true}
init={$page} init={$page}
on:photoChange={photoChanged} on:photoChange={photoChanged}
/> />
<Fullscreen />
</section> </section>

View File

@@ -68,6 +68,15 @@
} }
/*
** Effects
*/
&--shadow {
box-shadow: 0 0 10px rgba(#000, 0.4);
}
/* /*
** Directions ** Directions
*/ */

View File

@@ -0,0 +1,83 @@
.fullscreen {
position: fixed;
z-index: 200;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
// Photo
&__image {
width: 100%;
height: 100%;
overflow-x: auto;
opacity: 0;
transform: scale(1.1);
transition: transform 0.8s $ease-quart, opacity 0.8s $ease-quart;
will-change: transform, opacity;
img {
position: relative;
z-index: 200;
display: block;
height: 100%;
width: auto;
}
// Open
&.is-open {
opacity: 1;
transform: scale(1);
pointer-events: auto;
}
}
// Controls
&__close {
position: fixed;
z-index: 201;
bottom: 24px;
left: 0;
width: 100%;
display: flex;
justify-content: center;
opacity: 0;
transform: scale(1.1) translateY(24px);
transition: transform 0.8s $ease-quart, opacity 0.8s $ease-quart;
will-change: transform, opacity;
// Visible state
&.is-visible {
opacity: 1;
transform: scale(1) translateY(0);
}
}
// Loading
&__loading {
position: absolute;
z-index: 202;
top: 50%;
left: 50%;
opacity: 1;
transform: translate(-50%, -50%);
transform-origin: 50% 50%;
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
background-color: $color-primary;
border-radius: 100%;
transition: transform 0.8s $ease-quart, opacity 0.8s $ease-quart;
will-change: transform, opacity;
// Hidden state
&.is-hidden {
transform: scale(1.05) translate(-50%, -50%);
opacity: 0;
}
}
}

View File

@@ -44,9 +44,10 @@
display: none; display: none;
} }
} }
}
// Buttons // Buttons
.buttons { &__buttons {
display: flex; display: flex;
a { a {
@@ -57,7 +58,6 @@
} }
} }
} }
}
/* /*
@@ -86,12 +86,10 @@
right: 0; right: 0;
// Specific box shadow for images // Specific box shadow for images
&__images { &__photo {
&--photo {
box-shadow: 0 pxVW(16px) pxVW(40) rgba(#2E025C, 0.4); box-shadow: 0 pxVW(16px) pxVW(40) rgba(#2E025C, 0.4);
} }
} }
}
// Informations // Informations
&__infos { &__infos {

View File

@@ -31,6 +31,7 @@
// Organisms // Organisms
@import "organisms/carousel"; @import "organisms/carousel";
@import "organisms/photos"; @import "organisms/photos";
@import "organisms/fullscreen";
@import "organisms/locations"; @import "organisms/locations";
@import "organisms/pagination"; @import "organisms/pagination";
@import "organisms/footer"; @import "organisms/footer";

View File

@@ -0,0 +1,27 @@
<script>
import { analyticsUpdate } from '../utils/functions'
// Props
export let stores
export let id
// Variables
const { page } = stores()
// Init Google Analytics
if (typeof window !== 'undefined') {
window.dataLayer = window.dataLayer || []
window.gtag = function gtag() {
window.dataLayer.push(arguments)
}
window.gtag('js', new Date())
window.gtag('config', id)
}
// Push new page to GA
$: analyticsUpdate($page.path, id)
</script>
<svelte:head>
<script async src="https://www.googletagmanager.com/gtag/js?id={id}"></script>
</svelte:head>

View File

@@ -175,3 +175,15 @@ export const parallaxAnime = (element, anime) => {
} }
} }
} }
/*
** Google Analytics send page
*/
export const analyticsUpdate = (page, id = process.env.CONFIG.GA_TRACKER_ID) => {
if (typeof gtag !== 'undefined') {
window.gtag('config', id, {
page_path: page
})
}
}

View File

@@ -8,10 +8,9 @@ export const dev = process.env.NODE_ENV === 'development'
/* ========================================================================== /* ==========================================================================
Site related Site related
========================================================================== */ ========================================================================== */
const apiEndpoint = dev ? 'http://api.housesof.localhost/how' : 'https://api.housesof.world/_' const apiEndpoint = dev ? process.env.CONFIG.API_URL_DEV : process.env.CONFIG.API_URL_PROD
const apiAccessToken = 'NJk0urljsdSvApUDzWxGgoO6'
export const apiEndpoints = { export const apiEndpoints = {
gql: `${apiEndpoint}/gql?access_token=${apiAccessToken}`, gql: `${apiEndpoint}/gql?access_token=${process.env.CONFIG.API_TOKEN}`,
rest: apiEndpoint rest: apiEndpoint
} }
@@ -30,6 +29,7 @@ export let pageReady = writable(false)
export const pageTransition = { export const pageTransition = {
onAnimationEnd () {} onAnimationEnd () {}
} }
export let fullscreen = writable()
/* ========================================================================== /* ==========================================================================

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB