[wip] Switch from Anime to Motion One for page animations
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
|
import type { Easing } from 'motion'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ease: Quart Out Array
|
* Ease: Quart Out Array
|
||||||
*/
|
*/
|
||||||
export const quartOut = [.165, .84, .44, 1]
|
export const quartOut: Easing = [.165, .84, .44, 1]
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
45
src/animations/reveal.ts
Normal file
45
src/animations/reveal.ts
Normal file
@@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
11
src/app.d.ts
vendored
11
src/app.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
/// <reference types="@sveltejs/kit" />
|
/// <reference types="@sveltejs/kit" />
|
||||||
|
|
||||||
|
|
||||||
// See https://kit.svelte.dev/docs/types#app
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
declare namespace App {
|
declare namespace App {
|
||||||
@@ -25,7 +26,7 @@ declare namespace svelte.JSX {
|
|||||||
/**
|
/**
|
||||||
* Custom Types
|
* Custom Types
|
||||||
*/
|
*/
|
||||||
declare type PhotoGridAbout = {
|
declare interface PhotoGridAbout {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
slug: string
|
slug: string
|
||||||
@@ -62,7 +63,7 @@ declare interface smoothScrollOptions {
|
|||||||
/**
|
/**
|
||||||
* Swipe options
|
* Swipe options
|
||||||
*/
|
*/
|
||||||
interface SwipeOptions {
|
declare interface SwipeOptions {
|
||||||
travelX?: number
|
travelX?: number
|
||||||
travelY?: number
|
travelY?: number
|
||||||
timeframe?: number
|
timeframe?: number
|
||||||
@@ -72,17 +73,17 @@ interface SwipeOptions {
|
|||||||
/**
|
/**
|
||||||
* Reveal Animation
|
* Reveal Animation
|
||||||
*/
|
*/
|
||||||
declare interface RevealOptions {
|
declare type RevealOptions = {
|
||||||
enable?: boolean
|
enable?: boolean
|
||||||
options?: TransitionOptions
|
options?: TransitionOptions
|
||||||
children?: string | HTMLElement
|
children?: string | HTMLElement
|
||||||
animation: any
|
animation: any
|
||||||
}
|
}
|
||||||
// Options interface
|
// Options interface
|
||||||
declare interface TransitionOptions {
|
declare type TransitionOptions = {
|
||||||
threshold?: number
|
threshold?: number
|
||||||
duration?: number
|
duration?: number
|
||||||
stagger?: number
|
stagger?: number
|
||||||
delay?: number
|
delay?: number
|
||||||
easing?: any
|
easing?: string | Easing
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
on:blur={() => sendHover(false)}
|
on:blur={() => sendHover(false)}
|
||||||
>
|
>
|
||||||
{#if url}
|
{#if url}
|
||||||
|
<div class="photo-card__content">
|
||||||
<a href={url} sveltekit:noscroll>
|
<a href={url} sveltekit:noscroll>
|
||||||
<Image
|
<Image
|
||||||
{id}
|
{id}
|
||||||
@@ -55,6 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<Image
|
<Image
|
||||||
{id}
|
{id}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { getContext } from 'svelte'
|
import { getContext } from 'svelte'
|
||||||
import { flip } from 'svelte/animate'
|
import { flip } from 'svelte/animate'
|
||||||
import { quartOut } from 'svelte/easing'
|
import { quartOut } from 'svelte/easing'
|
||||||
import { reveal, fly } from '$animations/index'
|
import reveal from '$animations/reveal'
|
||||||
import { send, receive } from '$animations/crossfade'
|
import { send, receive } from '$animations/crossfade'
|
||||||
import { throttle } from '$utils/functions'
|
import { throttle } from '$utils/functions'
|
||||||
import { sendEvent } from '$utils/analytics'
|
import { sendEvent } from '$utils/analytics'
|
||||||
@@ -67,14 +67,13 @@
|
|||||||
|
|
||||||
<ul class="browse__locations"
|
<ul class="browse__locations"
|
||||||
use:reveal={{
|
use:reveal={{
|
||||||
animation: fly,
|
children: '.location',
|
||||||
|
animation: { y: ['20%', 0], opacity: [0, 1] },
|
||||||
options: {
|
options: {
|
||||||
children: 'li',
|
stagger: 0.105,
|
||||||
stagger: 100,
|
duration: 1,
|
||||||
duration: 1200,
|
|
||||||
from: '20%',
|
|
||||||
},
|
|
||||||
threshold: 0.3,
|
threshold: 0.3,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#each filteredLocations as location (location)}
|
{#each filteredLocations as location (location)}
|
||||||
|
|||||||
@@ -3,14 +3,15 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { navigating, page } from '$app/stores'
|
import { page, navigating } from '$app/stores'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import anime, { type AnimeTimelineInstance } from 'animejs'
|
import { timeline } from 'motion'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime.js'
|
import relativeTime from 'dayjs/plugin/relativeTime.js'
|
||||||
import { getAssetUrlKey } from '$utils/helpers'
|
import { getAssetUrlKey } from '$utils/helpers'
|
||||||
|
import { quartOut } from '$animations/easings'
|
||||||
import { fetchAPI } from '$utils/api'
|
import { fetchAPI } from '$utils/api'
|
||||||
import { DURATION } from '$utils/contants'
|
import { DELAY, DURATION } from '$utils/contants'
|
||||||
import { photoFields } from '.'
|
import { photoFields } from '.'
|
||||||
// Components
|
// Components
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
@@ -146,43 +147,51 @@
|
|||||||
/**
|
/**
|
||||||
* Animations
|
* Animations
|
||||||
*/
|
*/
|
||||||
// Transition in
|
const animationDelay = $navigating ? DURATION.PAGE_IN : 0
|
||||||
const timeline: AnimeTimelineInstance = anime.timeline({
|
const animation = timeline([
|
||||||
duration: 1600,
|
|
||||||
easing: 'easeOutQuart',
|
|
||||||
autoplay: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Title word
|
// Title word
|
||||||
timeline.add({
|
['.location-page__intro .word', {
|
||||||
targets: '.location-page__intro .word',
|
y: ['110%', 0],
|
||||||
translateY: ['110%', 0],
|
}, {
|
||||||
delay: anime.stagger(200)
|
at: 0.2 + animationDelay,
|
||||||
}, 200 + ($navigating ? DURATION.PAGE_IN : 0))
|
}],
|
||||||
|
|
||||||
// Illustration
|
// Illustration
|
||||||
timeline.add({
|
['.location-page__illustration', {
|
||||||
targets: '.location-page__illustration',
|
|
||||||
scale: [1.06, 1],
|
scale: [1.06, 1],
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
duration: 2400,
|
}, {
|
||||||
}, 400 + ($navigating ? DURATION.PAGE_IN : 0))
|
at: 0.4 + animationDelay,
|
||||||
|
duration: 2.4,
|
||||||
|
}],
|
||||||
|
|
||||||
// Title of
|
// Title of
|
||||||
timeline.add({
|
['.location-page__intro .of', {
|
||||||
targets: '.location-page__intro .of',
|
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
duration: 1200,
|
}, {
|
||||||
}, 950 + ($navigating ? DURATION.PAGE_IN : 0))
|
at: 0.95 + animationDelay,
|
||||||
|
duration: 1.2,
|
||||||
|
}],
|
||||||
|
|
||||||
// Description
|
// Description
|
||||||
timeline.add({
|
['.location-page__description', {
|
||||||
targets: '.location-page__description',
|
y: ['10%', 0],
|
||||||
translateY: ['10%', 0],
|
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
}, 900 + ($navigating ? DURATION.PAGE_IN : 0))
|
}, {
|
||||||
|
at: 0.9 + animationDelay,
|
||||||
|
duration: 1.2,
|
||||||
|
}]
|
||||||
|
], {
|
||||||
|
delay: DELAY.PAGE_LOADING / 1000,
|
||||||
|
defaultOptions: {
|
||||||
|
duration: 1.6,
|
||||||
|
easing: quartOut,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
animation.stop()
|
||||||
|
|
||||||
requestAnimationFrame(timeline.play)
|
// Run animation
|
||||||
|
requestAnimationFrame(animation.play)
|
||||||
|
|
||||||
|
|
||||||
// Destroy
|
// Destroy
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import anime, { type AnimeTimelineInstance } from 'animejs'
|
import { stagger, timeline } from 'motion'
|
||||||
|
import { DELAY } from '$utils/contants'
|
||||||
|
import { quartOut } from 'svelte/easing'
|
||||||
// Components
|
// Components
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
import PageTransition from '$components/PageTransition.svelte'
|
import PageTransition from '$components/PageTransition.svelte'
|
||||||
@@ -19,39 +21,40 @@
|
|||||||
/**
|
/**
|
||||||
* Animations
|
* Animations
|
||||||
*/
|
*/
|
||||||
// Setup animations
|
const animation = timeline([
|
||||||
const timeline: AnimeTimelineInstance = anime.timeline({
|
// Heading
|
||||||
duration: 1600,
|
['.heading .text', {
|
||||||
easing: 'easeOutQuart',
|
y: [24, 0],
|
||||||
autoplay: false,
|
opacity: [0, 1],
|
||||||
})
|
}],
|
||||||
|
|
||||||
anime.set('.heading .text, .credits__category > ul > li', {
|
// Categories
|
||||||
opacity: 0,
|
['.credits__category', {
|
||||||
translateY: 24,
|
opacity: [0, 1],
|
||||||
})
|
}, {
|
||||||
anime.set('.credits__category', {
|
at: 0,
|
||||||
opacity: 0,
|
delay: stagger(0.35, { start: 0.5 }),
|
||||||
})
|
}],
|
||||||
|
|
||||||
// Elements
|
|
||||||
timeline.add({
|
|
||||||
targets: '.heading .text, .credits__category',
|
|
||||||
opacity: 1,
|
|
||||||
translateY: 0,
|
|
||||||
delay: anime.stagger(350),
|
|
||||||
}, 500)
|
|
||||||
|
|
||||||
// Names
|
// Names
|
||||||
timeline.add({
|
['.credits__category > ul > li', {
|
||||||
targets: '.credits__category > ul > li',
|
y: [24, 0],
|
||||||
opacity: 1,
|
opacity: [0, 1],
|
||||||
translateY: 0,
|
}, {
|
||||||
delay: anime.stagger(350),
|
at: 1.1,
|
||||||
}, 1100)
|
delay: stagger(0.35),
|
||||||
|
}],
|
||||||
|
], {
|
||||||
|
delay: DELAY.PAGE_LOADING / 1000,
|
||||||
|
defaultOptions: {
|
||||||
|
duration: 1.6,
|
||||||
|
easing: quartOut,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
animation.stop()
|
||||||
|
|
||||||
// Transition in
|
// Run animation
|
||||||
requestAnimationFrame(timeline.play)
|
requestAnimationFrame(animation.play)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores'
|
||||||
import { getContext, onMount } from 'svelte'
|
import { getContext, onMount } from 'svelte'
|
||||||
import anime, { type AnimeTimelineInstance } from 'animejs'
|
import { timeline, stagger } from 'motion'
|
||||||
import { DELAY } from '$utils/contants'
|
import { DELAY } from '$utils/contants'
|
||||||
import { sleep, smoothScroll } from '$utils/functions'
|
import { smoothScroll } from '$utils/functions'
|
||||||
import { reveal, fade as animeFade } from '$animations/index'
|
import { reveal, fade as animeFade } from '$animations/index'
|
||||||
|
import { quartOut } from '$animations/easings'
|
||||||
// Components
|
// Components
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
import PageTransition from '$components/PageTransition.svelte'
|
import PageTransition from '$components/PageTransition.svelte'
|
||||||
@@ -30,36 +31,42 @@
|
|||||||
const { settings, locations }: any = getContext('global')
|
const { settings, locations }: any = getContext('global')
|
||||||
|
|
||||||
let scrollY: number, innerHeight: number
|
let scrollY: number, innerHeight: number
|
||||||
let timeline: AnimeTimelineInstance
|
|
||||||
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
timeline = anime.timeline({
|
/**
|
||||||
duration: 1600,
|
* Animations
|
||||||
easing: 'easeOutQuart',
|
*/
|
||||||
autoplay: false,
|
const animation = timeline([
|
||||||
})
|
|
||||||
|
|
||||||
// Reveal text
|
// Reveal text
|
||||||
timeline.add({
|
['.homepage__headline', {
|
||||||
targets: '.homepage__headline',
|
y: [16, 0],
|
||||||
translateY: [16, 0],
|
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
}, 750)
|
}, {
|
||||||
|
at: 0.75,
|
||||||
|
}],
|
||||||
|
|
||||||
// Animate collage photos
|
// Animate collage photos
|
||||||
timeline.add({
|
['.collage .photo-card', {
|
||||||
targets: '.collage .photo-card',
|
y: ['33.33%', 0],
|
||||||
translateY: ['33.33%', 0],
|
rotate: [-4, 0],
|
||||||
rotate (item: HTMLElement) {
|
|
||||||
return [-4, getComputedStyle(item).getPropertyValue('--rotation')]
|
|
||||||
},
|
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
duration: 1200,
|
}, {
|
||||||
delay: anime.stagger(75),
|
at: 0,
|
||||||
}, 0)
|
duration: 1.2,
|
||||||
|
delay: stagger(0.075),
|
||||||
|
}]
|
||||||
|
], {
|
||||||
|
delay: DELAY.PAGE_LOADING / 1000,
|
||||||
|
defaultOptions: {
|
||||||
|
duration: 1.6,
|
||||||
|
easing: quartOut,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
animation.stop()
|
||||||
|
|
||||||
sleep(DELAY.PAGE_LOADING).then(timeline.play)
|
// Run animation
|
||||||
|
requestAnimationFrame(animation.play)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,13 @@
|
|||||||
import { goto } from '$app/navigation'
|
import { goto } from '$app/navigation'
|
||||||
import { getContext, onMount } from 'svelte'
|
import { getContext, onMount } from 'svelte'
|
||||||
import { fly } from 'svelte/transition'
|
import { fly } from 'svelte/transition'
|
||||||
import { quartOut } from 'svelte/easing'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import { quartOut as quartOutSvelte } from 'svelte/easing'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime.js'
|
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 { fetchAPI } from '$utils/api'
|
||||||
|
import { quartOut } from '$animations/easings'
|
||||||
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'
|
||||||
@@ -282,37 +284,30 @@
|
|||||||
const existingPhotos = photosGridEl.querySelectorAll('.photo')
|
const existingPhotos = photosGridEl.querySelectorAll('.photo')
|
||||||
existingPhotos.forEach(el => observerPhotos.observe(el))
|
existingPhotos.forEach(el => observerPhotos.observe(el))
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Animations
|
* Animations
|
||||||
*/
|
*/
|
||||||
// Transition in
|
const animation = timeline([
|
||||||
const timeline: AnimeTimelineInstance = anime.timeline({
|
|
||||||
duration: 1600,
|
|
||||||
easing: 'easeOutQuart',
|
|
||||||
autoplay: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Reveal text
|
// Reveal text
|
||||||
timeline.add({
|
['.photos-page__intro .discover, .photos-page__intro .filters__bar', {
|
||||||
targets: '.photos-page__intro .discover',
|
y: [16, 0],
|
||||||
translateY: [16, 0],
|
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
}, 900)
|
}, {
|
||||||
|
at: 0.4,
|
||||||
|
delay: stagger(0.25),
|
||||||
|
}]
|
||||||
|
], {
|
||||||
|
delay: DELAY.PAGE_LOADING / 1000,
|
||||||
|
defaultOptions: {
|
||||||
|
duration: 1.6,
|
||||||
|
easing: quartOut,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
animation.stop()
|
||||||
|
|
||||||
// Filters
|
// Run animation
|
||||||
timeline.add({
|
requestAnimationFrame(animation.play)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
// Destroy
|
// Destroy
|
||||||
@@ -351,9 +346,8 @@
|
|||||||
class:is-transitioning={filtersTransitioning}
|
class:is-transitioning={filtersTransitioning}
|
||||||
class:is-visible={filtersVisible}
|
class:is-visible={filtersVisible}
|
||||||
>
|
>
|
||||||
<span class="text-label filters__label">Filter photos</span>
|
|
||||||
|
|
||||||
<div class="filters__bar">
|
<div class="filters__bar">
|
||||||
|
<span class="text-label filters__label">Filter photos</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<Select
|
<Select
|
||||||
@@ -418,7 +412,7 @@
|
|||||||
{#if filtered}
|
{#if filtered}
|
||||||
<button class="reset button-link"
|
<button class="reset button-link"
|
||||||
on:click={resetFiltered}
|
on:click={resetFiltered}
|
||||||
transition:fly={{ y: 4, duration: 600, easing: quartOut }}
|
transition:fly={{ y: 4, duration: 600, easing: quartOutSvelte }}
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
|
import { stagger, timeline } from 'motion'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import anime, { type AnimeTimelineInstance } from 'animejs'
|
import { DELAY } from '$utils/contants'
|
||||||
|
import { quartOut } from '$animations/easings'
|
||||||
// Components
|
// Components
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
import PageTransition from '$components/PageTransition.svelte'
|
import PageTransition from '$components/PageTransition.svelte'
|
||||||
@@ -22,37 +24,36 @@
|
|||||||
/**
|
/**
|
||||||
* Animations
|
* Animations
|
||||||
*/
|
*/
|
||||||
// Setup animations
|
const animation = timeline([
|
||||||
const timeline: AnimeTimelineInstance = anime.timeline({
|
|
||||||
duration: 1600,
|
|
||||||
easing: 'easeOutQuart',
|
|
||||||
autoplay: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
anime.set('.heading .text, .subscribe__top .newsletter-form, .subscribe__issues', {
|
|
||||||
opacity: 0,
|
|
||||||
translateY: 24,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Elements
|
// Elements
|
||||||
timeline.add({
|
['.heading .text, .subscribe__top .newsletter-form, .subscribe__issues', {
|
||||||
targets: '.heading .text, .subscribe__top .newsletter-form, .subscribe__issues',
|
y: [24, 0],
|
||||||
opacity: 1,
|
opacity: [0, 1],
|
||||||
translateY: 0,
|
}, {
|
||||||
delay: anime.stagger(200),
|
at: 0.5,
|
||||||
}, 500)
|
delay: stagger(0.35),
|
||||||
|
}],
|
||||||
|
|
||||||
// Reveal each issue
|
// Reveal each issue
|
||||||
timeline.add({
|
['.subscribe__issues > ul > li', {
|
||||||
targets: '.subscribe__issues .issue',
|
y: [16, 0],
|
||||||
opacity: [0, 1],
|
opacity: [0, 1],
|
||||||
translateY: [16, 0],
|
}, {
|
||||||
delay: anime.stagger(150),
|
duration: 1,
|
||||||
duration: 1000,
|
at: 1.5,
|
||||||
}, 1000)
|
delay: stagger(0.15),
|
||||||
|
}],
|
||||||
|
], {
|
||||||
|
delay: DELAY.PAGE_LOADING / 1000,
|
||||||
|
defaultOptions: {
|
||||||
|
duration: 1.6,
|
||||||
|
easing: quartOut,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
animation.stop()
|
||||||
|
|
||||||
// Transition in
|
// Run animation
|
||||||
requestAnimationFrame(timeline.play)
|
requestAnimationFrame(animation.play)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -75,7 +76,8 @@
|
|||||||
<h2 class="title-small">Past Issues</h2>
|
<h2 class="title-small">Past Issues</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{#each issues as { issue, title, date_sent, link, thumbnail: { id } }}
|
{#each issues as { issue, title, date_sent, link, thumbnail: { id } }}
|
||||||
<li class="issue">
|
<li>
|
||||||
|
<div class="issue">
|
||||||
<a href={link} target="_blank" rel="external noreferrer noopener" tabindex="0">
|
<a href={link} target="_blank" rel="external noreferrer noopener" tabindex="0">
|
||||||
<Image
|
<Image
|
||||||
id={id}
|
id={id}
|
||||||
@@ -91,6 +93,7 @@
|
|||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
.photo-card {
|
.photo-card {
|
||||||
& > * {
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
a {
|
a {
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
|
border-radius: 8px;
|
||||||
box-shadow: 0 16px 12px rgba(#000, 0.15), 0 26px 52px rgba(#000, 0.2);
|
box-shadow: 0 16px 12px rgba(#000, 0.15), 0 26px 52px rgba(#000, 0.2);
|
||||||
transition: transform 0.7s var(--ease-quart);
|
transition: transform 0.7s var(--ease-quart);
|
||||||
|
transform: translateZ(0);
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Image
|
||||||
:global(picture) {
|
:global(picture) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: $color-primary-tertiary20;
|
background: $color-primary-tertiary20;
|
||||||
}
|
|
||||||
:global(img) {
|
:global(img) {
|
||||||
display: block;
|
display: block;
|
||||||
width: calc(100% + 2px);
|
width: calc(100% + 2px);
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
transition: opacity 0.7s var(--ease-quart);
|
transition: opacity 0.7s var(--ease-quart);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Informations
|
// Informations
|
||||||
&__info {
|
&__info {
|
||||||
@@ -92,7 +94,8 @@
|
|||||||
transition: opacity 0.8s var(--ease-quart);
|
transition: opacity 0.8s var(--ease-quart);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slightly zoom in and show info on hover
|
|
||||||
|
// Slightly zoom in, show gradient and info on hover
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
a:hover {
|
a:hover {
|
||||||
transform: scale(1.0375) rotate(2deg) translateZ(0);
|
transform: scale(1.0375) rotate(2deg) translateZ(0);
|
||||||
@@ -109,6 +112,7 @@
|
|||||||
transition-delay: 180ms;
|
transition-delay: 180ms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,15 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
transform: rotate(var(--rotation)) translateZ(0);
|
|
||||||
|
|
||||||
@include bp (sm) {
|
@include bp (sm) {
|
||||||
height: clamp(156px, 18vw, 400px);
|
height: clamp(156px, 18vw, 400px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > :global(*) {
|
||||||
|
transform: rotate(var(--rotation)) translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
// First row
|
// First row
|
||||||
// Mobile: Top left
|
// Mobile: Top left
|
||||||
&:nth-child(1) {
|
&:nth-child(1) {
|
||||||
|
|||||||
@@ -254,7 +254,6 @@
|
|||||||
** Filters
|
** Filters
|
||||||
*/
|
*/
|
||||||
.filters {
|
.filters {
|
||||||
position: relative;
|
|
||||||
max-width: 982px;
|
max-width: 982px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
@@ -265,6 +264,7 @@
|
|||||||
|
|
||||||
// Bar
|
// Bar
|
||||||
&__bar {
|
&__bar {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -364,7 +364,7 @@
|
|||||||
|
|
||||||
@include bp (sm) {
|
@include bp (sm) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 64px;
|
left: 32px;
|
||||||
top: 52%;
|
top: 52%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user