Files
immich/web/src/lib/components/photos-page/memory-lane.svelte
Thomas 43ffcf7e8f use animation frames for memory autoplay (#2771)
The current implementation mixes intervals and animation frames, which is a
little convoluted. The use of intervals means that the animation is not going
to be smooth and may have strange behaviour when the window is moved to the
background. It's possible that the current animation frames could pile up and
run all at once which would be undesirable.

Moving everything into animation frames means the code is simpler and easier to
reason about. It should also be more performant and less buggy.

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2023-06-15 21:27:32 -05:00

96 lines
2.7 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import { DateTime } from 'luxon';
import { MemoryLaneResponseDto, api } from '@api';
import ChevronLeft from 'svelte-material-icons/ChevronLeft.svelte';
import ChevronRight from 'svelte-material-icons/ChevronRight.svelte';
import { memoryStore } from '$lib/stores/memory.store';
import { goto } from '$app/navigation';
let memoryLane: MemoryLaneResponseDto[] = [];
$: shouldRender = memoryLane.length > 0;
onMount(async () => {
const { data } = await api.assetApi.getMemoryLane({
timestamp: DateTime.local().startOf('day').toISO()
});
memoryLane = data;
$memoryStore = data;
});
let memoryLaneElement: HTMLElement;
let offsetWidth = 0;
let innerWidth = 0;
$: isOverflow = offsetWidth < innerWidth;
function scrollLeft() {
memoryLaneElement.scrollTo({
left: memoryLaneElement.scrollLeft - 400,
behavior: 'smooth'
});
}
function scrollRight() {
memoryLaneElement.scrollTo({
left: memoryLaneElement.scrollLeft + 400,
behavior: 'smooth'
});
}
</script>
{#if shouldRender}
<section
id="memory-lane"
bind:this={memoryLaneElement}
class="relative overflow-x-hidden whitespace-nowrap mt-5 transition-all"
bind:offsetWidth
>
{#if isOverflow}
<div class="sticky left-0 z-20">
<div class="absolute right-0 top-[6rem] z-20">
<button
class="rounded-full opacity-50 hover:opacity-100 p-2 border border-gray-500 bg-gray-100 text-gray-500"
on:click={scrollRight}
>
<ChevronRight size="36" /></button
>
</div>
<div class="absolute left-0 top-[6rem] z-20">
<button
class="rounded-full opacity-50 hover:opacity-100 p-2 border border-gray-500 bg-gray-100 text-gray-500"
on:click={scrollLeft}><ChevronLeft size="36" /></button
>
</div>
</div>
{/if}
<div class="inline-block" bind:offsetWidth={innerWidth}>
{#each memoryLane as memory, i (memory.title)}
<button
class="memory-card relative inline-block mr-8 rounded-xl aspect-video h-[215px]"
on:click={() => goto(`/memory?memory=${i}`)}
>
<img
class="rounded-xl h-full w-full object-cover"
src={api.getAssetThumbnailUrl(memory.assets[0].id, 'JPEG')}
alt={memory.title}
draggable="false"
/>
<p class="absolute bottom-2 left-4 text-lg text-white z-10">{memory.title}</p>
<div
class="absolute top-0 left-0 w-full h-full rounded-xl bg-gradient-to-t from-black/40 via-transparent to-transparent z-0 hover:bg-black/20 transition-all"
/>
</button>
{/each}
</div>
</section>
{/if}
<style>
.memory-card {
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
}
</style>