Use PageTransition component on every route

- Scrolls back to top when mounting new page with a timeout of the delay
- Rename photo Viewer class
- Change Shop posters section text from p to label
This commit is contained in:
2021-12-07 21:58:17 +01:00
parent f15a2f2e47
commit 06db598b90
14 changed files with 79 additions and 66 deletions

View File

@@ -1,14 +1,28 @@
<script lang="ts"> <script lang="ts">
import { page } from '$app/stores'
import { onMount, tick } from 'svelte'
import { fade } from 'svelte/transition' import { fade } from 'svelte/transition'
import { scrollToTop } from '$utils/functions'
import { DURATION } from '$utils/contants'
export let path = '' export let name: string
onMount(async () => {
// Disable when changing filters on /photos and shop?
if (!$page.query.get('country') && !$page.path.includes('/shop/poster')) {
await tick()
setTimeout(() => {
// Scroll back to top between page transitions
scrollToTop()
}, DURATION.PAGE_DELAY)
}
})
</script> </script>
{#key path}
<div <main class={name}
in:fade={{ duration: 400, delay: 500 }} in:fade={{ duration: DURATION.PAGE_IN, delay: DURATION.PAGE_DELAY }}
out:fade={{ duration: 400 }} out:fade={{ duration: DURATION.PAGE_OUT }}
> >
<slot /> <slot />
</div> </main>
{/key}

View File

@@ -16,6 +16,7 @@
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import SplitText from '$components/SplitText.svelte' import SplitText from '$components/SplitText.svelte'
import PageTransition from '$components/PageTransition.svelte'
import Image from '$components/atoms/Image.svelte' import Image from '$components/atoms/Image.svelte'
import Icon from '$components/atoms/Icon.svelte' import Icon from '$components/atoms/Icon.svelte'
import IconArrow from '$components/atoms/IconArrow.svelte' import IconArrow from '$components/atoms/IconArrow.svelte'
@@ -227,22 +228,22 @@
easing: 'easeOutQuart', easing: 'easeOutQuart',
}) })
anime.set('.viewer-photo__picture', { anime.set('.viewer__picture', {
opacity: 0, opacity: 0,
}) })
anime.set('.viewer-photo__picture.is-1', { anime.set('.viewer__picture.is-1', {
translateY: 24, translateY: 24,
}) })
// Photos // Photos
timeline.add({ timeline.add({
targets: '.viewer-photo__picture.is-1', targets: '.viewer__picture.is-1',
opacity: 1, opacity: 1,
translateY: 0, translateY: 0,
duration: 900, duration: 900,
}, 250) }, 250)
timeline.add({ timeline.add({
targets: '.viewer-photo__picture:not(.is-0):not(.is-1)', targets: '.viewer__picture:not(.is-0):not(.is-1)',
opacity: 1, opacity: 1,
translateX (element: HTMLElement, index: number) { translateX (element: HTMLElement, index: number) {
const x = getComputedStyle(element).getPropertyValue('--offset-x').trim() const x = getComputedStyle(element).getPropertyValue('--offset-x').trim()
@@ -253,7 +254,7 @@
// Prev/Next buttons // Prev/Next buttons
timeline.add({ timeline.add({
targets: '.viewer-photo__controls button', targets: '.viewer__controls button',
translateX (item: HTMLElement) { translateX (item: HTMLElement) {
let direction = item.classList.contains('prev') ? -1 : 1 let direction = item.classList.contains('prev') ? -1 : 1
return [16 * direction, 0] return [16 * direction, 0]
@@ -264,25 +265,25 @@
// Infos // Infos
timeline.add({ timeline.add({
targets: '.viewer-photo__info > *', targets: '.viewer__info > *',
translateY: [24, 0], translateY: [24, 0],
opacity: [0, 1], opacity: [0, 1],
delay: anime.stagger(200) delay: anime.stagger(200)
}, 400) }, 400)
anime.set('.viewer-photo__index', { anime.set('.viewer__index', {
opacity: 0 opacity: 0
}) })
// Index // Index
timeline.add({ timeline.add({
targets: '.viewer-photo__index', targets: '.viewer__index',
opacity: 1, opacity: 1,
duration: 900, duration: 900,
}, 600) }, 600)
// Fly each number // Fly each number
timeline.add({ timeline.add({
targets: '.viewer-photo__index .char', targets: '.viewer__index .char',
translateY: ['100%', 0], translateY: ['100%', 0],
delay: anime.stagger(200), delay: anime.stagger(200),
duration: 1000, duration: 1000,
@@ -313,25 +314,25 @@
{/if} {/if}
<main class="viewer-photo"> <PageTransition name="viewer">
<div class="container grid"> <div class="container grid">
<p class="viewer-photo__notice text-label">Tap for fullscreen</p> <p class="viewer__notice text-label">Tap for fullscreen</p>
<ButtonCircle <ButtonCircle
tag="a" tag="a"
url={previousUrl} url={previousUrl}
color="purple" color="purple"
class="viewer-photo__close shadow-box-dark" class="viewer__close shadow-box-dark"
> >
<svg width="12" height="12"> <svg width="12" height="12">
<use xlink:href="#cross"> <use xlink:href="#cross">
</svg> </svg>
</ButtonCircle> </ButtonCircle>
<div class="viewer-photo__carousel"> <div class="viewer__carousel">
<div class="viewer-photo__images" use:swipe on:swipe={handleSwipe} on:tap={toggleFullscreen}> <div class="viewer__images" use:swipe on:swipe={handleSwipe} on:tap={toggleFullscreen}>
{#each visiblePhotos as photo, index (photo.id)} {#each visiblePhotos as photo, index (photo.id)}
<div class="viewer-photo__picture is-{currentIndex === 0 ? index + 1 : index}"> <div class="viewer__picture is-{currentIndex === 0 ? index + 1 : index}">
<Image <Image
class="photo" class="photo"
id={photo.image.id} id={photo.image.id}
@@ -347,7 +348,7 @@
</div> </div>
{/each} {/each}
<div class="viewer-photo__controls"> <div class="viewer__controls">
<ButtonCircle class="prev shadow-box-dark" disabled={!canGoNext} clone={true} on:click={goToPrevious}> <ButtonCircle class="prev shadow-box-dark" disabled={!canGoNext} clone={true} on:click={goToPrevious}>
<IconArrow color="pink" flip={true} /> <IconArrow color="pink" flip={true} />
</ButtonCircle> </ButtonCircle>
@@ -357,12 +358,12 @@
</div> </div>
<div class="viewer-photo__index title-index"> <div class="viewer__index title-index">
<SplitText text="{(currentPhotoIndex < 10) ? '0' : ''}{currentPhotoIndex}" mode="chars" /> <SplitText text="{(currentPhotoIndex < 10) ? '0' : ''}{currentPhotoIndex}" mode="chars" />
</div> </div>
</div> </div>
<div class="viewer-photo__info"> <div class="viewer__info">
<h1 class="title-medium">{currentPhoto.title}</h1> <h1 class="title-medium">{currentPhoto.title}</h1>
<div class="detail text-info"> <div class="detail text-info">
@@ -383,7 +384,7 @@
</div> </div>
{#if isFullscreen} {#if isFullscreen}
<div class="viewer-photo__fullscreen" bind:this={fullscreenEl} on:click={toggleFullscreen}> <div class="viewer__fullscreen" bind:this={fullscreenEl} on:click={toggleFullscreen}>
<div class="inner" transition:scale={{ easing: quartOut, start: 1.1, duration: 1000 }}> <div class="inner" transition:scale={{ easing: quartOut, start: 1.1, duration: 1000 }}>
<Image <Image
id={currentPhoto.image.id} id={currentPhoto.image.id}
@@ -400,7 +401,7 @@
</div> </div>
</div> </div>
{/if} {/if}
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -11,6 +11,7 @@
import { DURATION } from '$utils/contants' import { DURATION } from '$utils/contants'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import Icon from '$components/atoms/Icon.svelte' import Icon from '$components/atoms/Icon.svelte'
import Button from '$components/atoms/Button.svelte' import Button from '$components/atoms/Button.svelte'
import IconEarth from '$components/atoms/IconEarth.svelte' import IconEarth from '$components/atoms/IconEarth.svelte'
@@ -209,7 +210,7 @@
<svelte:window bind:scrollY /> <svelte:window bind:scrollY />
<main class="location-page"> <PageTransition name="location-page">
<section class="location-page__intro grid" bind:this={introEl}> <section class="location-page__intro grid" bind:this={introEl}>
<h1 class="title" class:is-short={location.name.length <= 4}> <h1 class="title" class:is-short={location.name.length <= 4}>
<span class="housesof mask"> <span class="housesof mask">
@@ -349,7 +350,7 @@
</p> </p>
</div> </div>
{/if} {/if}
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -8,7 +8,6 @@
import '$utils/polyfills' import '$utils/polyfills'
// Components // Components
import SVGSprite from '$components/SVGSprite.svelte' import SVGSprite from '$components/SVGSprite.svelte'
import PageTransition from '$components/PageTransition.svelte'
import Switcher from '$components/molecules/Switcher.svelte' import Switcher from '$components/molecules/Switcher.svelte'
import Footer from '$components/organisms/Footer.svelte' import Footer from '$components/organisms/Footer.svelte'
@@ -41,14 +40,6 @@
setTimeout(() => { setTimeout(() => {
$pageLoading = false $pageLoading = false
}, DURATION.PAGE_IN * 1.25) }, DURATION.PAGE_IN * 1.25)
// Scroll back to top between page transitions
setTimeout(() => {
// Disable scroll when changing filters on /photos and shop?
if (!$page.query.get('country') && !$page.path.includes('/shop/poster')) {
scrollToTop()
}
}, DURATION.PAGE_OUT + 1)
} }
}) })
@@ -60,9 +51,7 @@
<Switcher isOver={!!$page.params.location && !!$page.params.photo} /> <Switcher isOver={!!$page.params.location && !!$page.params.photo} />
<PageTransition path={$page.path}>
<slot /> <slot />
</PageTransition>
{#if !$page.params.photo} {#if !$page.params.photo}
<Footer /> <Footer />

View File

@@ -5,6 +5,7 @@
import type { AnimeTimelineInstance } from 'animejs' import type { AnimeTimelineInstance } from 'animejs'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import SiteTitle from '$components/atoms/SiteTitle.svelte' import SiteTitle from '$components/atoms/SiteTitle.svelte'
import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
import Image from '$components/atoms/Image.svelte' import Image from '$components/atoms/Image.svelte'
@@ -69,7 +70,7 @@
/> />
<main class="credits"> <PageTransition name="credits">
<section class="credits__heading"> <section class="credits__heading">
<SiteTitle variant="inline" /> <SiteTitle variant="inline" />
<p class="text-medium">{data.credits.text}</p> <p class="text-medium">{data.credits.text}</p>
@@ -145,7 +146,7 @@
</section> </section>
<InteractiveGlobe type="cropped" /> <InteractiveGlobe type="cropped" />
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -6,6 +6,7 @@
import type { AnimeTimelineInstance } from 'animejs' import type { AnimeTimelineInstance } from 'animejs'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import SplitText from '$components/SplitText.svelte' import SplitText from '$components/SplitText.svelte'
import Button from '$components/atoms/Button.svelte' import Button from '$components/atoms/Button.svelte'
import IconEarth from '$components/atoms/IconEarth.svelte' import IconEarth from '$components/atoms/IconEarth.svelte'
@@ -85,7 +86,7 @@
image="" image=""
/> />
<main class="homepage"> <PageTransition name="homepage">
<section class="homepage__intro"> <section class="homepage__intro">
<ScrollingTitle <ScrollingTitle
tag="h1" tag="h1"
@@ -101,7 +102,7 @@
{settings.description} {settings.description}
</p> </p>
<Button text="Explore locations" url="{path}#locations"> <Button text="Explore locations" url="#locations">
<IconEarth animate={true} /> <IconEarth animate={true} />
</Button> </Button>
</div> </div>
@@ -169,7 +170,7 @@
</div> </div>
</div> </div>
</div> </div>
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -2,6 +2,7 @@
import { getContext } from 'svelte' import { getContext } from 'svelte'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
import Locations from '$components/organisms/Locations.svelte' import Locations from '$components/organisms/Locations.svelte'
import Shop from '$components/organisms/Shop.svelte' import Shop from '$components/organisms/Shop.svelte'
@@ -17,7 +18,7 @@
image="" image=""
/> />
<main class="explore"> <PageTransition name="explore">
<Heading <Heading
text="Explore the globe to discover unique locations across the world" text="Explore the globe to discover unique locations across the world"
/> />
@@ -33,4 +34,4 @@
<Newsletter /> <Newsletter />
</div> </div>
</section> </section>
</main> </PageTransition>

View File

@@ -12,6 +12,7 @@
import { map, lerp, throttle } from '$utils/functions' import { map, lerp, throttle } from '$utils/functions'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import SplitText from '$components/SplitText.svelte' import SplitText from '$components/SplitText.svelte'
import IconEarth from '$components/atoms/IconEarth.svelte' import IconEarth from '$components/atoms/IconEarth.svelte'
import Button from '$components/atoms/Button.svelte' import Button from '$components/atoms/Button.svelte'
@@ -339,7 +340,7 @@
/> />
<main class="photos"> <PageTransition name="photos">
<section class="photos__intro" <section class="photos__intro"
class:is-passed={scrolledPastIntro} class:is-passed={scrolledPastIntro}
> >
@@ -498,7 +499,7 @@
</div> </div>
</div> </div>
</section> </section>
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -6,6 +6,7 @@
import type { AnimeTimelineInstance } from 'animejs' import type { AnimeTimelineInstance } from 'animejs'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import SiteTitle from '$components/atoms/SiteTitle.svelte' import SiteTitle from '$components/atoms/SiteTitle.svelte'
import Image from '$components/atoms/Image.svelte' import Image from '$components/atoms/Image.svelte'
import ButtonCart from '$components/atoms/ButtonCart.svelte' import ButtonCart from '$components/atoms/ButtonCart.svelte'
@@ -103,7 +104,8 @@
image="" image=""
/> />
<main class="shop-page">
<PageTransition name="shop-page">
<Cart /> <Cart />
<section class="shop-page__intro" bind:this={introEl}> <section class="shop-page__intro" bind:this={introEl}>
@@ -180,7 +182,9 @@
</div> </div>
</section> </section>
{#key product}
<slot /> <slot />
{/key}
{#if posters} {#if posters}
<section class="shop-page__posters grid"> <section class="shop-page__posters grid">
@@ -195,12 +199,12 @@
{/each} {/each}
</div> </div>
<div class="subscribe"> <div class="subscribe">
<p>Subscribe to be notified when new posters become available</p> <label class="subscribe__text" for="SUB_EMAIL">Subscribe to be notified when new posters become available</label>
<EmailForm /> <EmailForm />
</div> </div>
</section> </section>
{/if} {/if}
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -6,10 +6,11 @@
import type { AnimeTimelineInstance } from 'animejs' import type { AnimeTimelineInstance } from 'animejs'
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
import Image from '$components/atoms/Image.svelte' import Image from '$components/atoms/Image.svelte'
import Heading from '$components/molecules/Heading.svelte' import Heading from '$components/molecules/Heading.svelte'
import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'; import EmailForm from '$components/molecules/EmailForm.svelte'
import EmailForm from '$components/molecules/EmailForm.svelte'; import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
export let data: any export let data: any
export let issues: any export let issues: any
@@ -69,7 +70,7 @@
image="" image=""
/> />
<main class="subscribe"> <PageTransition name="subscribe">
<div class="subscribe__top"> <div class="subscribe__top">
<Heading <Heading
text={data.newsletter_page_text} text={data.newsletter_page_text}
@@ -104,7 +105,7 @@
</section> </section>
<InteractiveGlobe type="cropped" /> <InteractiveGlobe type="cropped" />
</main> </PageTransition>
<script context="module" lang="ts"> <script context="module" lang="ts">

View File

@@ -1,4 +1,4 @@
.viewer-photo { .viewer {
position: relative; position: relative;
height: 100vh; height: 100vh;
display: flex; display: flex;
@@ -424,7 +424,7 @@
// Close button // Close button
&__close { &__close {
position: fixed; position: fixed !important;
z-index: 2; z-index: 2;
top: 16px; top: 16px;
right: calc(16px + 44px + 12px); right: calc(16px + 44px + 12px);

View File

@@ -108,7 +108,8 @@
text-align: left; text-align: left;
} }
p { &__text {
display: block;
font-size: rem(18px); font-size: rem(18px);
color: $color-cream; color: $color-cream;
font-weight: 300; font-weight: 300;

View File

@@ -26,6 +26,7 @@
@import "pages/credits"; @import "pages/credits";
@import "pages/subscribe"; @import "pages/subscribe";
@import "pages/location"; @import "pages/location";
@import "pages/viewer";
@import "pages/shop"; @import "pages/shop";
// Modules // Modules
@@ -70,9 +71,5 @@
// Layouts // Layouts
@import "layouts/poster"; @import "layouts/poster";
// Pages
@import "pages/viewer-photo";
// Misc // Misc
@import "animations"; @import "animations";

View File

@@ -7,4 +7,5 @@ export const DELAY = {
export const DURATION = { export const DURATION = {
PAGE_IN: 400, PAGE_IN: 400,
PAGE_OUT: 400, PAGE_OUT: 400,
PAGE_DELAY: 600,
} }