Carousel: Use the counter as a component
- Add animation when changing photos - Reusable and scalable to more than XX photos
This commit is contained in:
37
src/atoms/Counter.svelte
Normal file
37
src/atoms/Counter.svelte
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
|
// Props
|
||||||
|
export let currentIndex = 0
|
||||||
|
export let className = null
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
$: actualIndex = currentIndex + 1
|
||||||
|
$: amount = String(actualIndex).length
|
||||||
|
$: index = (actualIndex < 10) ? String(actualIndex).padStart(2, '0') : String(actualIndex)
|
||||||
|
$: digits = index.split('')
|
||||||
|
let counter
|
||||||
|
const numbers = [...Array(10).keys()]
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Run code when mounted
|
||||||
|
*/
|
||||||
|
onMount(() => {
|
||||||
|
// Set each digit column's height = its spans combined (in order to translate in tens of %)
|
||||||
|
counter.querySelectorAll('div').forEach(column => {
|
||||||
|
const spans = column.querySelectorAll('span')
|
||||||
|
column.style.height = spans[0].offsetHeight * spans.length + 'px'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="counter {className}" bind:this={counter}>
|
||||||
|
{#each digits as digit}
|
||||||
|
<div class="counter__column" style="transform: translateY(-{digit}0%);">
|
||||||
|
{#each numbers as number}
|
||||||
|
<span>{number}</span>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
// Components
|
// Components
|
||||||
import IconArrow from '../atoms/IconArrow'
|
import IconArrow from '../atoms/IconArrow'
|
||||||
|
import Counter from '../atoms/Counter'
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
export let photos
|
export let photos
|
||||||
@@ -42,6 +43,9 @@
|
|||||||
} else if (direction === 'next') {
|
} else if (direction === 'next') {
|
||||||
currentIndex++
|
currentIndex++
|
||||||
currentIndex = (currentIndex >= photos.length) ? 0 : currentIndex
|
currentIndex = (currentIndex >= photos.length) ? 0 : currentIndex
|
||||||
|
} else {
|
||||||
|
currentIndex = direction
|
||||||
|
console.log('Go to photo', direction, currentIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send current photo to event
|
// Send current photo to event
|
||||||
@@ -182,9 +186,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if viewer}
|
{#if viewer}
|
||||||
<div class="carousel__number">
|
<Counter {currentIndex} className="carousel__number" />
|
||||||
{currentIndex < 10 ? 0 : ''}{photos.length - currentIndex}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -207,25 +209,13 @@
|
|||||||
<p class="carousel__date">{formatDate(currentPhoto.date, 'FULL')}</p>
|
<p class="carousel__date">{formatDate(currentPhoto.date, 'FULL')}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if !viewer}
|
|
||||||
<ol class="carousel__dots">
|
<ol class="carousel__dots">
|
||||||
{#each photos as page, index}
|
{#each photos as page, index}
|
||||||
<li class:active={page === currentPhoto} on:click={() => currentIndex = index}>
|
<li class:active={page === currentPhoto} on:click={() => goToPhoto(index)}>
|
||||||
<button aria-label="Go to photo #{index + 1}"></button>
|
<button aria-label="Go to photo #{index + 1}"></button>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ol>
|
</ol>
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if viewer}
|
|
||||||
<ol class="carousel__dots">
|
|
||||||
{#each photos as page}
|
|
||||||
<li class:active={page === currentPhoto}>
|
|
||||||
<button></button>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ol>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
22
src/style/atoms/_counter.scss
Normal file
22
src/style/atoms/_counter.scss
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Counter
|
||||||
|
.counter {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
font-family: $font-serif-extra;
|
||||||
|
font-size: pxVW(672);
|
||||||
|
color: rgba($color-tertiary, 0.4);
|
||||||
|
text-align: center;
|
||||||
|
// pointer-events: none;
|
||||||
|
// user-select: none;
|
||||||
|
|
||||||
|
// Column
|
||||||
|
&__column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
line-height: 0.85;
|
||||||
|
text-align: right;
|
||||||
|
margin: 0 -16px;
|
||||||
|
transition: transform 0.6s $ease-quart;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,10 @@
|
|||||||
max-width: 1280px;
|
max-width: 1280px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
@include breakpoint (1600px) {
|
@include breakpoint (sm) {
|
||||||
|
max-width: 85%;
|
||||||
|
}
|
||||||
|
@include breakpoint (1680px) {
|
||||||
max-width: 1424px;
|
max-width: 1424px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,9 +23,6 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
||||||
@include breakpoint (sm) {
|
|
||||||
max-width: 85%;
|
|
||||||
}
|
|
||||||
@include breakpoint (xl) {
|
@include breakpoint (xl) {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
@@ -194,8 +194,12 @@
|
|||||||
&__locations {
|
&__locations {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
min-height: 56px;
|
||||||
|
|
||||||
|
@include breakpoint (sm) {
|
||||||
min-height: 128px;
|
min-height: 128px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Location
|
// Location
|
||||||
&__location {
|
&__location {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
@import "atoms/toggle";
|
@import "atoms/toggle";
|
||||||
@import "atoms/link";
|
@import "atoms/link";
|
||||||
@import "atoms/switcher";
|
@import "atoms/switcher";
|
||||||
|
@import "atoms/counter";
|
||||||
|
|
||||||
// Molecules
|
// Molecules
|
||||||
@import "molecules/location";
|
@import "molecules/location";
|
||||||
|
|||||||
Reference in New Issue
Block a user