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}
-
-
-
{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
-