From f771a73b67952617c57aae0be49f678f06d85a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Pe=CC=81ault?= Date: Sun, 14 Aug 2022 00:45:44 +0200 Subject: [PATCH] [wip] Switch from Anime to Motion One for page animations --- src/animations/easings.ts | 5 +- src/animations/reveal.ts | 45 ++++++++++ src/app.d.ts | 11 +-- src/components/molecules/PhotoCard.svelte | 46 +++++----- src/components/organisms/Locations.svelte | 13 ++- src/routes/[country]/[location]/index.svelte | 85 ++++++++++-------- src/routes/credits.svelte | 67 +++++++------- src/routes/index.svelte | 59 ++++++------ src/routes/photos.svelte | 56 ++++++------ src/routes/subscribe.svelte | 95 ++++++++++---------- src/style/molecules/_photo-card.scss | 26 +++--- src/style/organisms/_collage.scss | 5 +- src/style/pages/_photos.scss | 4 +- 13 files changed, 295 insertions(+), 222 deletions(-) create mode 100644 src/animations/reveal.ts diff --git a/src/animations/easings.ts b/src/animations/easings.ts index e9321fe..b7a0933 100644 --- a/src/animations/easings.ts +++ b/src/animations/easings.ts @@ -1,7 +1,10 @@ +import type { Easing } from 'motion' + + /** * Ease: Quart Out Array */ -export const quartOut = [.165, .84, .44, 1] +export const quartOut: Easing = [.165, .84, .44, 1] /** diff --git a/src/animations/reveal.ts b/src/animations/reveal.ts new file mode 100644 index 0000000..bc4fe29 --- /dev/null +++ b/src/animations/reveal.ts @@ -0,0 +1,45 @@ +import { animate, inView, stagger } from 'motion' +import { quartOut } from '$animations/easings' + +const defaultOptions = { + stagger: null, + delay: 0, + duration: 1.6, + easing: quartOut, +} + +export default (node: Element | any, { + enable = true, + children = undefined, + animation = [], + options = defaultOptions, +}: RevealOptions) => { + if (!enable) return + + // Define targets from children, if empty get node + const targets = children ? node.querySelectorAll(children) : [node] + + // If animation has opacity starting with 0, hide it first + if (animation.opacity && animation.opacity[0] === 0) { + targets.forEach((el: HTMLElement) => el.style.opacity = '0') + } + + // Create inView instance + inView(node, ({ isIntersecting }) => { + const anim = animate( + targets, + animation, + { + delay: options.stagger ? stagger(options.stagger, { start: options.delay }) : options.delay, + duration: options.duration, + easing: options.easing, + } + ) + anim.stop() + + // Run animation if in view and tab is active + isIntersecting && requestAnimationFrame(anim.play) + }, { + amount: options.threshold, + }) +} \ No newline at end of file diff --git a/src/app.d.ts b/src/app.d.ts index fd825fe..52dba5b 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,5 +1,6 @@ /// + // See https://kit.svelte.dev/docs/types#app // for information about these interfaces declare namespace App { @@ -25,7 +26,7 @@ declare namespace svelte.JSX { /** * Custom Types */ -declare type PhotoGridAbout = { +declare interface PhotoGridAbout { id: string title: string slug: string @@ -62,7 +63,7 @@ declare interface smoothScrollOptions { /** * Swipe options */ -interface SwipeOptions { +declare interface SwipeOptions { travelX?: number travelY?: number timeframe?: number @@ -72,17 +73,17 @@ interface SwipeOptions { /** * Reveal Animation */ -declare interface RevealOptions { +declare type RevealOptions = { enable?: boolean options?: TransitionOptions children?: string | HTMLElement animation: any } // Options interface -declare interface TransitionOptions { +declare type TransitionOptions = { threshold?: number duration?: number stagger?: number delay?: number - easing?: any + easing?: string | Easing } \ No newline at end of file diff --git a/src/components/molecules/PhotoCard.svelte b/src/components/molecules/PhotoCard.svelte index bad959d..249f963 100644 --- a/src/components/molecules/PhotoCard.svelte +++ b/src/components/molecules/PhotoCard.svelte @@ -33,28 +33,30 @@ on:blur={() => sendHover(false)} > {#if url} - - - {#if title && location} -
- Flag of {location.country.name} -

{title} - {city ? `${city}, ` : ''}{location.name}, {location.country.name}

-
- {/if} -
+ {:else} {#each filteredLocations as location (location)} diff --git a/src/routes/[country]/[location]/index.svelte b/src/routes/[country]/[location]/index.svelte index e0ae4cd..44fb1e6 100644 --- a/src/routes/[country]/[location]/index.svelte +++ b/src/routes/[country]/[location]/index.svelte @@ -3,14 +3,15 @@ diff --git a/src/routes/index.svelte b/src/routes/index.svelte index a83c66b..9f88a18 100644 --- a/src/routes/index.svelte +++ b/src/routes/index.svelte @@ -5,10 +5,11 @@ diff --git a/src/routes/photos.svelte b/src/routes/photos.svelte index 58eae9c..c6df037 100644 --- a/src/routes/photos.svelte +++ b/src/routes/photos.svelte @@ -7,11 +7,13 @@ import { goto } from '$app/navigation' import { getContext, onMount } from 'svelte' import { fly } from 'svelte/transition' - import { quartOut } from 'svelte/easing' import dayjs from 'dayjs' + import { quartOut as quartOutSvelte } from 'svelte/easing' import relativeTime from 'dayjs/plugin/relativeTime.js' - import anime, { type AnimeTimelineInstance } from 'animejs' + import { stagger, timeline } from 'motion' + import { DELAY } from '$utils/contants' import { fetchAPI } from '$utils/api' + import { quartOut } from '$animations/easings' import { map, lerp, throttle } from '$utils/functions' // Components import Metas from '$components/Metas.svelte' @@ -282,37 +284,30 @@ const existingPhotos = photosGridEl.querySelectorAll('.photo') existingPhotos.forEach(el => observerPhotos.observe(el)) + /** * Animations */ - // Transition in - const timeline: AnimeTimelineInstance = anime.timeline({ - duration: 1600, - easing: 'easeOutQuart', - autoplay: false, + const animation = timeline([ + // Reveal text + ['.photos-page__intro .discover, .photos-page__intro .filters__bar', { + y: [16, 0], + opacity: [0, 1], + }, { + at: 0.4, + delay: stagger(0.25), + }] + ], { + delay: DELAY.PAGE_LOADING / 1000, + defaultOptions: { + duration: 1.6, + easing: quartOut, + }, }) + animation.stop() - // Reveal text - timeline.add({ - targets: '.photos-page__intro .discover', - translateY: [16, 0], - opacity: [0, 1], - }, 900) - - // Filters - timeline.add({ - targets: '.photos-page__intro .filters', - translateY: [16, 0], - opacity: [0, 1], - complete ({ animatables }) { - const element = animatables[0].target - // Remove style to not interfere with CSS when scrolling back up over photos - element.removeAttribute('style') - } - }, 1300) - - // Play animation - requestAnimationFrame(timeline.play) + // Run animation + requestAnimationFrame(animation.play) // Destroy @@ -351,9 +346,8 @@ class:is-transitioning={filtersTransitioning} class:is-visible={filtersVisible} > - Filter photos -
+ Filter photos