Fix the locations list filters and add reveal transitions
Typically add a delay between two click (Limiter) to click again. Thanks Nico!
This commit is contained in:
@@ -1,2 +1,23 @@
|
|||||||
// import anime from 'animejs'
|
// import anime from 'animejs'
|
||||||
|
import { crossfade } from 'svelte/transition'
|
||||||
|
import { quartOut } from 'svelte/easing'
|
||||||
|
|
||||||
|
|
||||||
|
// Crossfade transition
|
||||||
|
export const [crossfadeSend, crossfadeReceive] = crossfade({
|
||||||
|
duration: d => Math.sqrt(d * 200),
|
||||||
|
|
||||||
|
fallback(node, params) {
|
||||||
|
const style = getComputedStyle(node)
|
||||||
|
const transform = style.transform === 'none' ? '' : style.transform
|
||||||
|
|
||||||
|
return {
|
||||||
|
duration: 600,
|
||||||
|
easing: quartOut,
|
||||||
|
css: t => `
|
||||||
|
transform: ${transform} scale(${t});
|
||||||
|
opacity: ${t}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
<script>
|
<script>
|
||||||
export let name
|
// Props
|
||||||
export let slug
|
export let location
|
||||||
export let country
|
|
||||||
|
|
||||||
const src = country.flag.full_url
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="location">
|
<div class="location" data-aos="location">
|
||||||
<a href="/location/{country.slug}/{slug}">
|
<a href="/location/{location.country.slug}/{location.slug}">
|
||||||
<img {src} alt={'Flag of ' + country.name} />
|
<img src={location.country.flag.full_url} alt="Flag of {location.country.name}">
|
||||||
<h3 class="location__city">{name}</h3>
|
<div class="anim-mask mask-city">
|
||||||
<p class="location__country style-caps">{country.name}</p>
|
<h3 class="location__city">{location.name}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="anim-mask mask-country">
|
||||||
|
<p class="location__country style-caps">{location.country.name}</p>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { flip } from 'svelte/animate'
|
import { flip } from 'svelte/animate'
|
||||||
import { crossfade } from 'svelte/transition'
|
|
||||||
import { quintOut } from 'svelte/easing'
|
|
||||||
import { locations, countries, continents } from '../store'
|
import { locations, countries, continents } from '../store'
|
||||||
|
import { crossfadeReceive, crossfadeSend } from '../animations'
|
||||||
|
import * as fn from '../functions'
|
||||||
|
|
||||||
|
// Dependencies
|
||||||
|
import AOS from 'aos'
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import Button from '../atoms/Button'
|
import Button from '../atoms/Button'
|
||||||
import Location from '../molecules/Location'
|
import Location from '../molecules/Location'
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
|
const transitionDuration = 800
|
||||||
|
let clickOrigin = Date.now()
|
||||||
let filterLocations
|
let filterLocations
|
||||||
let continentsToDisplay = []
|
let continentsToDisplay = []
|
||||||
let continentsFiltered = []
|
let continentsFiltered = []
|
||||||
@@ -20,31 +25,24 @@
|
|||||||
continentsFiltered = [...continentsToDisplay]
|
continentsFiltered = [...continentsToDisplay]
|
||||||
|
|
||||||
// Filter by continent
|
// Filter by continent
|
||||||
const toggleContinents = (event, continent) => continentsFiltered = (!continent) ? [...continentsToDisplay] : [continent]
|
// detects if click difference if too short
|
||||||
|
const toggleContinents = (event, continent) => {
|
||||||
// Crossfade animation
|
if (Date.now() - clickOrigin < transitionDuration) {
|
||||||
const [send, receive] = crossfade({
|
return
|
||||||
duration: d => Math.sqrt(d * 200),
|
|
||||||
fallback(node, params) {
|
|
||||||
const style = getComputedStyle(node)
|
|
||||||
const transform = style.transform === 'none' ? '' : style.transform
|
|
||||||
return {
|
|
||||||
duration: 600,
|
|
||||||
easing: quintOut,
|
|
||||||
css: t => `
|
|
||||||
transform: ${transform} scale(${t});
|
|
||||||
opacity: ${t}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
continentsFiltered = (!continent) ? [...continentsToDisplay] : [continent]
|
||||||
|
clickOrigin = Date.now()
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Run code on browser only
|
** Run code on browser only
|
||||||
*/
|
*/
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
// Scroll apparitions
|
||||||
|
if (process.browser) {
|
||||||
|
AOS.init()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -56,29 +54,23 @@
|
|||||||
<ul class="browse__continents" id="continents">
|
<ul class="browse__continents" id="continents">
|
||||||
{#if continentsToDisplay.length > 1}
|
{#if continentsToDisplay.length > 1}
|
||||||
<li on:click={e => toggleContinents(e)}>
|
<li on:click={e => toggleContinents(e)}>
|
||||||
<Button type="button" text="All" className="button-outline {(continentsFiltered.length <= 1) ? 'disabled' : ''}" />
|
<Button type="button" text="All" class="button-outline {(continentsFiltered.length <= 1) ? 'disabled' : ''}" />
|
||||||
</li>
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
{#each continentsToDisplay as continent}
|
{#each continentsToDisplay as continent}
|
||||||
<li on:click={e => toggleContinents(e, continent)}>
|
<li on:click={e => toggleContinents(e, continent)}>
|
||||||
<Button type="button" text={continent.name} className="button-outline {(!continentsFiltered.includes(continent)) ? 'disabled' : ''}" />
|
<Button type="button" text={continent.name} class="button-outline {(!continentsFiltered.includes(continent)) ? 'disabled' : ''}" />
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="browse__locations" id="locations_list">
|
<div class="browse__locations" id="locations_list">
|
||||||
{#each filteredLocations as location (location.id)}
|
{#each filteredLocations as location (location.id)}
|
||||||
<div
|
<div animate:flip="{{ duration: transitionDuration }}"
|
||||||
animate:flip="{{duration: 600}}"
|
in:crossfadeReceive="{{ key: location.id }}"
|
||||||
in:receive="{{key: location.id}}"
|
out:crossfadeSend="{{ key: location.id }}"
|
||||||
out:send="{{key: location.id}}"
|
|
||||||
>
|
>
|
||||||
<!-- Animation: Grid with auto-min is fucking up the transition -->
|
<Location {location} />
|
||||||
<Location
|
|
||||||
name={location.name}
|
|
||||||
slug={location.slug}
|
|
||||||
country={location.country}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -101,6 +101,40 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Location reveal
|
||||||
|
[data-aos="location"] {
|
||||||
|
img {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.15);
|
||||||
|
transition: opacity 0.6s $ease-quart, transform 0.6s $ease-quart;
|
||||||
|
will-change: opacity, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3, p {
|
||||||
|
transform: translateY(150%);
|
||||||
|
transition: transform 0.6s $ease-quart;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
transition: all 0.6s $ease-quart;
|
||||||
|
transition-delay: 100ms;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
transition-delay: 200ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.aos-animate {
|
||||||
|
img {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
h3, p {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
KEYFRAMES ANIMATIONS
|
KEYFRAMES ANIMATIONS
|
||||||
|
|||||||
@@ -37,12 +37,13 @@
|
|||||||
|
|
||||||
// Locations
|
// Locations
|
||||||
&__locations {
|
&__locations {
|
||||||
|
min-height: 200px;
|
||||||
margin-top: 112px;
|
margin-top: 112px;
|
||||||
|
|
||||||
@include breakpoint (sm) {
|
@include breakpoint (sm) {
|
||||||
display: flex;
|
display: flex;
|
||||||
// display: grid;
|
// display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
// grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
grid-column-gap: 120px;
|
grid-column-gap: 120px;
|
||||||
grid-row-gap: pxVW(120);
|
grid-row-gap: pxVW(120);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -59,7 +60,12 @@
|
|||||||
margin-bottom: 48px;
|
margin-bottom: 48px;
|
||||||
|
|
||||||
@include breakpoint (sm) {
|
@include breakpoint (sm) {
|
||||||
margin-bottom: 0;
|
margin-left: pxVW(72);
|
||||||
|
margin-right: pxVW(72);
|
||||||
|
}
|
||||||
|
@include breakpoint (xl) {
|
||||||
|
margin-left: 72px;
|
||||||
|
margin-right: 72px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@@ -82,17 +88,26 @@
|
|||||||
|
|
||||||
// City
|
// City
|
||||||
&__city {
|
&__city {
|
||||||
margin: 24px 0 16px;
|
|
||||||
font-family: $font-serif;
|
font-family: $font-serif;
|
||||||
font-size: rem(32px);
|
font-size: rem(32px);
|
||||||
color: $color-secondary;
|
color: $color-secondary;
|
||||||
transition: color 85ms ease-in-out;
|
|
||||||
|
|
||||||
@include breakpoint (sm) {
|
@include breakpoint (sm) {
|
||||||
font-size: rem(48px);
|
font-size: rem(48px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mask-city {
|
||||||
|
height: 40px;
|
||||||
|
margin: 24px 0 16px;
|
||||||
|
|
||||||
|
@include breakpoint (sm) {
|
||||||
|
height: 64px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.mask-country {
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
// Shape on hover
|
// Shape on hover
|
||||||
&:after {
|
&:after {
|
||||||
|
|||||||
Reference in New Issue
Block a user