This commit is contained in:
2021-10-03 23:17:43 +02:00
7 changed files with 233 additions and 20 deletions

View File

@@ -0,0 +1,58 @@
<script lang="ts">
let isOpen: boolean = false
// Links
const links = [
{
"icon": "globe",
"alt": "Globe",
"url": "/locations",
"text": "Discover locations"
},
{
"icon": "photos",
"alt": "Photos",
"url": "/photos",
"text": "Browse all photos"
},
{
"icon": "bag",
"alt": "Shopping bag",
"url": "/shop",
"text": "Shop the prints"
}
]
/**
* Toggle switcher open state
*/
const toggleSwitcher = () => {
isOpen = !isOpen
}
</script>
<div class="switcher" class:is-open={isOpen}>
<nav class="switcher__links">
<ul>
{#each links as { icon, alt, url, text }}
<li>
<a href={url} sveltekit:prefetch sveltekit:noscroll>
<img src="/images/icons/{icon}.svg" alt={alt} class="icon" width="32" height="32" loading="lazy">
<span>{text}</span>
</a>
</li>
{/each}
</ul>
</nav>
<button class="switcher__button" title="{!isOpen ? 'Open' : 'Close'} menu"
on:click={toggleSwitcher}
>
<span>
<i />
<i />
<i />
</span>
</button>
</div>

View File

@@ -45,12 +45,18 @@ class WebglGlobe {
this._isHoverMarker = false this._isHoverMarker = false
let gl let gl
let canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
try { gl = canvas.getContext('webgl') }
catch (x) { try {
try { gl = canvas.getContext('experimental-webgl') } gl = canvas.getContext('webgl')
catch (x) { gl = null } } catch (x) {
try {
gl = canvas.getContext('experimental-webgl')
} catch (x) {
gl = null
} }
}
this.supportWebgl = gl !== null this.supportWebgl = gl !== null
if (this.supportWebgl) { if (this.supportWebgl) {
this.buildWebglScene() this.buildWebglScene()
@@ -58,7 +64,10 @@ class WebglGlobe {
} }
} }
// Build
/**
* Build scene
*/
buildWebglScene () { buildWebglScene () {
// Renderer // Renderer
this.renderer = new Renderer({ this.renderer = new Renderer({
@@ -104,7 +113,9 @@ class WebglGlobe {
this.scene = new Container() this.scene = new Container()
// Setup camera /**
* Setup camera
*/
this.camera = new Camera({ this.camera = new Camera({
fov: 1, fov: 1,
near: 0.1, near: 0.1,
@@ -153,6 +164,15 @@ class WebglGlobe {
// this.scene.add(this.refPlane) // this.scene.add(this.refPlane)
/**
* Add drag and touch event listeners
*/
const addDragingClass = () => this.$el.classList.add('is-dragging')
const removeDragingClass = () => this.$el.classList.remove('is-dragging')
this.$el.addEventListener('dragstart', addDragingClass)
this.$el.addEventListener('dragend', removeDragingClass)
/** /**
* Create DOM nodes for markers and 3D positions * Create DOM nodes for markers and 3D positions
*/ */
@@ -233,7 +253,10 @@ class WebglGlobe {
} }
} }
// Resize method
/**
* Resize method
*/
resize () { resize () {
if (!this.supportWebgl) { if (!this.supportWebgl) {
return return
@@ -247,7 +270,7 @@ class WebglGlobe {
// Remove retina on small screen (aka mobile) to boost perfs // Remove retina on small screen (aka mobile) to boost perfs
this.renderer.setPixelRatio(window.innerWidth < 768 ? 1 : window.devicePixelRatio) this.renderer.setPixelRatio(window.innerWidth < 768 ? 1 : window.devicePixelRatio)
this.renderer.resize(this.width , this.height) this.renderer.resize(this.width, this.height)
// Update camera aspect ratio // Update camera aspect ratio
this.camera.aspect = this.width / this.height this.camera.aspect = this.width / this.height
@@ -264,6 +287,7 @@ class WebglGlobe {
this.circleScreenSize = (this.height / 2) * (1 / this.options.cameraDistance) this.circleScreenSize = (this.height / 2) * (1 / this.options.cameraDistance)
} }
/** /**
* As the camera rotates arount the globe, we cant simply move the Y position of the camera or the globe * As the camera rotates arount the globe, we cant simply move the Y position of the camera or the globe
* Instead, we move the globe vertex inside the vertex shadder after compute the project on screen, so we pass the 'scroll' position to a uniform * Instead, we move the globe vertex inside the vertex shadder after compute the project on screen, so we pass the 'scroll' position to a uniform
@@ -282,7 +306,10 @@ class WebglGlobe {
} }
} }
// Destroy
/**
* Destroy the globe
*/
destroy () { destroy () {
this.disable() // Stop render loop this.disable() // Stop render loop
document.body.removeChild(this.$markerWrapper) document.body.removeChild(this.$markerWrapper)
@@ -290,6 +317,7 @@ class WebglGlobe {
this.camera.delete() // To remove event listeners this.camera.delete() // To remove event listeners
} }
/** /**
* Flag to stop rendering the webgl if the globe isnt visible * Flag to stop rendering the webgl if the globe isnt visible
* This helps saving perfs and battery * This helps saving perfs and battery
@@ -299,14 +327,16 @@ class WebglGlobe {
this.$markerWrapper.style.opacity = 1 this.$markerWrapper.style.opacity = 1
this._canUpdate = true this._canUpdate = true
} }
disable () { disable () {
this.renderer.canvas.style.opacity = 0 this.renderer.canvas.style.opacity = 0
this.$markerWrapper.style.opacity = 0 this.$markerWrapper.style.opacity = 0
this._canUpdate = false this._canUpdate = false
} }
// Update
/**
* Update
*/
update () { update () {
if (!this.supportWebgl || !this._canUpdate || !this.imageLoaded || !this.hasUpdateCameraPos) { if (!this.supportWebgl || !this._canUpdate || !this.imageLoaded || !this.hasUpdateCameraPos) {
return return

View File

@@ -3,6 +3,7 @@
import { setContext } from 'svelte' import { setContext } from 'svelte'
import '$utils/polyfills' import '$utils/polyfills'
// Components // Components
import Switcher from '$components/molecules/Switcher.svelte'
import Footer from '$components/organisms/Footer.svelte' import Footer from '$components/organisms/Footer.svelte'
export let data: any export let data: any
@@ -15,6 +16,8 @@
}) })
</script> </script>
<Switcher />
<slot /> <slot />
<Footer /> <Footer />

View File

@@ -48,11 +48,12 @@
from <strong>{count.locations} cities</strong> from <strong>{count.locations} cities</strong>
of <strong>{count.countries} countries</strong> of <strong>{count.countries} countries</strong>
</p> </p>
<div class="cards"> <div class="cards">
<BoxCTA <BoxCTA
url="{path}#locations" url="{path}#locations"
icon="/images/icons/globe.svg" icon="/images/icons/globe.svg"
label="discover locations" label="Discover locations"
alt="Globe" alt="Globe"
/> />
<BoxCTA <BoxCTA

View File

@@ -33,25 +33,28 @@
// } // }
// END DEBUG // // END DEBUG //
/* /*
** Cropped globe ** States and Variants
*/ */
// When dragging
&.is-grabbing {
cursor: grabbing;
}
// Cropped globe
&--cropped { &--cropped {
overflow: hidden; overflow: hidden;
height: clamp(300px, 30vw, 500px); height: clamp(300px, 30vw, 500px);
} }
/* /*
** Markers ** Markers
*/ */
&__markers { &__markers {
z-index: 210; z-index: 210;
// When dragging
&.is-grabbing {
cursor: grabbing;
}
// Marker // Marker
.marker { .marker {
position: absolute; position: absolute;

View File

@@ -0,0 +1,117 @@
.switcher {
$shadow-color: rgba(0, 0, 0, 0.05);
position: fixed;
z-index: 999;
bottom: 0;
left: 0;
@include bp (sm) {
bottom: 40px;
left: 40px;
}
// Links
&__links {
opacity: 0;
padding: 8px;
background: $color-primary-tertiary20;
border-radius: 12px;
margin-bottom: 16px;
pointer-events: none;
transform: translate3d(0, 8px, 0);
box-shadow: 0 6px 6px $shadow-color, 0 12px 12px $shadow-color, 0 24px 24px $shadow-color;
transition: opacity 0.8s var(--ease-quart), transform 0.8s var(--ease-quart);
li {
display: block;
line-height: 1.5;
}
a {
display: flex;
align-items: center;
padding: 8px 16px 8px 10px;
color: #fff;
font-weight: 900;
font-size: rem(16px);
text-decoration: none;
border-radius: 6px;
transition: background-color 0.4s ease-out;
&:hover {
background-color: rgba($color-tertiary, 0.15);
}
}
.icon {
display: block;
width: 32px;
height: 32px;
object-fit: contain;
margin-right: 16px;
}
}
// Button
&__button {
$shadow-color: rgba(0, 0, 0, 0.05);
width: 56px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
background: $color-primary-tertiary20;
border-radius: 100%;
box-shadow: 0 6px 6px $shadow-color, 0 12px 12px $shadow-color, 0 24px 24px $shadow-color;
transition: background-color 0.6s var(--ease-quart);
// Dots container
span {
display: inline-flex;
flex-flow: column;
transition: transform 0.8s var(--ease-quart);
}
// Dot
i {
display: block;
width: 6px;
height: 6px;
margin: 2px 0;
border-radius: 100%;
background: #fff;
transition: transform 0.8s var(--ease-quart);
}
// Hover
&:hover {
background-color: #7e5288;
i {
&:nth-child(1) { transform: translate3d(0, -2px, 0); }
&:nth-child(3) { transform: translate3d(0, 2px, 0); }
}
}
}
// Open state
&.is-open {
.switcher {
&__links {
opacity: 1;
pointer-events: auto;
transform: translate3d(0, 0, 0);
}
&__button {
span {
transform: rotate3d(70deg, 120deg, 180deg) translateZ(0);
}
i {
&:nth-child(1) { transform: translate3d(-7px, 8px, 0); }
&:nth-child(2) { transform: translate3d(7px, -2px, 0); }
&:nth-child(3) { transform: translate3d(0px, -3px, 0); }
}
}
}
}
}

View File

@@ -39,6 +39,7 @@
// Molecules // Molecules
@import "molecules/photo-card"; @import "molecules/photo-card";
@import "molecules/location"; @import "molecules/location";
@import "molecules/switcher";
// Organisms // Organisms
@import "organisms/locations"; @import "organisms/locations";