Place: Add photo Transition In, Add Illustration system, Visual fixes

- Add a transition in on each photo component (scale down + fade in), TODO: Parallax on number
- Illustration takes two images and changes the source depending on the viewport size
This commit is contained in:
2020-03-10 21:25:48 +01:00
parent eb529b196e
commit debd9a41c1
6 changed files with 120 additions and 31 deletions

48
src/animations/Photo.js Normal file
View File

@@ -0,0 +1,48 @@
import anime from 'animejs'
import ScrollOut from 'scroll-out'
import { animDuration, animDurationLong } from '../utils/store'
import { debounce } from '../utils/functions'
/*
** Transition In
*/
export const animateIn = scope => {
// Title appearing
const titleReveal = ScrollOut({
once: true,
targets: scope,
offset: window.offsetHeight / 3,
onShown (el) {
// Title reveal
anime({
targets: el.querySelectorAll('h2 span'),
translateY: ['100%', 0],
duration: 1000,
delay: anime.stagger(120),
easing: 'easeOutQuart'
})
}
})
// Photo appearing
const photoReveal = ScrollOut({
once: true,
targets: scope.querySelector('picture'),
offset: window.offsetHeight / 3,
onShown (el) {
// Title reveal
anime({
targets: el.querySelector('img'),
scale: [1.12, 1],
opacity: [0, 1],
duration: 2000,
delay: 50,
easing: 'easeOutQuart'
})
}
})
// Number parallax
//! TODO
}

View File

@@ -1,10 +1,11 @@
<script> <script>
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { fly } from 'svelte/transition'
import { quartOut } from 'svelte/easing'
import { site, currentLocation } from '../utils/store' import { site, currentLocation } from '../utils/store'
import { getThumbnail, formatDate } from '../utils/functions' import { getThumbnail, formatDate } from '../utils/functions'
// Animations
import { animateIn } from '../animations/Photo'
// Props and variables // Props and variables
export let photo export let photo
export let index export let index
@@ -22,10 +23,11 @@
/* /*
** Run code on browser only ** Run code when mounted
*/ */
onMount(() => { onMount(() => {
animateIn(scope) animateIn(scope)
// Parallax on photo when the image has been loaded // Parallax on photo when the image has been loaded
// const parallaxNumber = basicScroll.default.create({ // const parallaxNumber = basicScroll.default.create({
// elem: photoElement.querySelector('.photo__number'), // elem: photoElement.querySelector('.photo__number'),
@@ -45,14 +47,13 @@
}) })
</script> </script>
<div class="photo"
bind:this={photoElement}
in:fly="{{ y: 40, duration: 1000, easing: quartOut }}"
>
<div class="photo" bind:this={scope}> <div class="photo" bind:this={scope}>
<div class="photo__location wrap"> <div class="photo__location wrap">
<div class="wrapper"> <div class="wrapper">
<h2 class="title-location">{photo.name.replace(', ', ',\n')}</h2> <h2 class="title-location">
<span>{photo.name.split(', ')[0]},</span>
<span>{photo.name.split(', ')[1]}</span>
</h2>
<p class="style-caps">{location.region}, {location.country.name}</p> <p class="style-caps">{location.region}, {location.country.name}</p>
</div> </div>
</div> </div>
@@ -71,7 +72,7 @@
width={defaultWidth} height={defaultHeight} width={defaultWidth} height={defaultHeight}
alt={imgAlt} alt={imgAlt}
class="lazyload" class="lazyload"
data-aos="scale-down-fade-in" data-aos-once="true"> >
{:else} {:else}
<source media="(min-width: 992px)" srcset={getThumbnail(photo.image.private_hash, 1300)}> <source media="(min-width: 992px)" srcset={getThumbnail(photo.image.private_hash, 1300)}>
@@ -85,7 +86,9 @@
<time class="photo__date" datetime={formatDate(photo.date, 'DATETIME')}> <time class="photo__date" datetime={formatDate(photo.date, 'DATETIME')}>
{formatDate(photo.date, 'FULL')} {formatDate(photo.date, 'FULL')}
</time> </time>
<span class="photo__number">{(index < 10 ? '0': '') + index}</span> <span class="photo__number">
{(index < 10 ? '0': '') + index}
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -4,8 +4,25 @@
// Preload data // Preload data
export async function preload (page, session) { export async function preload (page, session) {
// Load photos // Load photos
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}%&limit=-1&sort=-created_on,name`) // 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.place}%&limit=-1&sort=-created_on,name`)
const req = await this.fetch(apiEndpoints.gql, {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `{
photos (filter: { slug_has: "${page.params.place}" }, limit: -1) {
data {
id
name
slug
date
created_on
modified_on
}
}
}`})
})
const photos = await req.json() const photos = await req.json()
console.log(photos)
if (req.ok) { if (req.ok) {
return { photos: photos.data } return { photos: photos.data }
} }
@@ -50,7 +67,7 @@
let layoutSetting let layoutSetting
// Update current location // Update current location
const location = $locations.find(loc => loc.slug === $page.params.location) const location = $locations.find(loc => loc.slug === $page.params.place)
currentLocation.set(location) currentLocation.set(location)
currentPhotos.set(photos) currentPhotos.set(photos)
@@ -149,11 +166,9 @@
</div> </div>
</div> </div>
<div class="place__illustration"> <div class="place__illustration"
<div class="place__illustration--left side"></div> style="--url-desktop: url({location.illustration_desktop.full_url}); --url-mobile: url({location.illustration_mobile.full_url});"
<div class="place__illustration--center"></div> />
<div class="place__illustration--right side"></div>
</div>
</section> </section>
<section class="photos photos--{layoutSetting || 'list'}"> <section class="photos photos--{layoutSetting || 'list'}">

View File

@@ -15,11 +15,15 @@
h2 { h2 {
text-align: left; text-align: left;
white-space: pre-line; overflow: hidden;
@include breakpoint (xs) { @include breakpoint (xs) {
font-size: rem(40px); font-size: rem(40px);
} }
span {
display: block;
}
} }
p { p {
color: $color-lightgray; color: $color-lightgray;

View File

@@ -1,6 +1,7 @@
.photos { .photos {
position: relative; position: relative;
margin-top: -22px; margin-top: -22px;
overflow-x: hidden;
background-color: #fff; background-color: #fff;
@include breakpoint (sm) { @include breakpoint (sm) {
@@ -107,7 +108,6 @@
// Number // Number
&__number { &__number {
@include breakpoint (sm) { @include breakpoint (sm) {
transform: translate(-50%, var(--translate));
will-change: transform; will-change: transform;
} }
} }

View File

@@ -1,22 +1,28 @@
// Place section // Place section
.place { .place {
position: relative; position: relative;
background-position: 50% 0;
background-size: 100%;
background-repeat: no-repeat;
overflow-x: hidden; overflow-x: hidden;
// Title // Title
&__title { &__title {
position: relative; position: relative;
z-index: 2; z-index: 2;
padding: pxVW(400) 0 pxVW(400);
display: flex; display: flex;
flex-direction: column;
justify-content: center; justify-content: center;
align-items: flex-end; align-items: center;
padding: pxVW(350) 0 pxVW(200);
text-align: center;
@media screen and (orientation: portrait) and (max-width: $screen-xs) {
height: 144vw;
padding: 0;
}
@include breakpoint (sm) { @include breakpoint (sm) {
padding: pxVW(224) 0 pxVW(240); flex-direction: row;
align-items: flex-end;
padding: pxVW(208) 0 pxVW(320);
height: auto;
} }
@include breakpoint (xxl) { @include breakpoint (xxl) {
padding-top: 240px; padding-top: 240px;
@@ -26,7 +32,8 @@
h1 { h1 {
position: relative; position: relative;
z-index: 2; z-index: 2;
text-align: left; text-align: center;
display: inline-block;
pointer-events: none; pointer-events: none;
.anim-translate { .anim-translate {
@@ -37,16 +44,22 @@
&_bottom { &_bottom {
text-align: right; text-align: right;
margin-left: pxVW(128); margin-left: pxVW(128);
@include breakpoint (xl) {
margin-left: 128px;
}
} }
// Switcher button // Switcher button
.button-control--dashed { .button-control {
z-index: 1; z-index: 1;
margin: 32px auto 0;
flex-shrink: 0; flex-shrink: 0;
margin-left: -12px;
@include breakpoint (sm) { @include breakpoint (sm) {
margin-left: -24px; margin-left: -24px;
margin-right: 0;
margin-top: 0;
} }
} }
} }
@@ -146,7 +159,13 @@
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: url(/img/illustration.png) 0 0 no-repeat; background-image: var(--url-mobile);
background-position: 0 0;
background-repeat: no-repeat;
background-size: 100% auto; background-size: 100% auto;
@include breakpoint (sm) {
background-image: var(--url-desktop);
}
} }
} }