1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 07:01:59 +00:00

feat(web): scrubber label and animation (#13815)

* feat(web): scrubber label and animation

* tune x fly in distance

* refactor

* lint and minor fix

* fly height
This commit is contained in:
Alex 2024-10-30 09:38:35 -05:00 committed by GitHub
parent 0d62ff11f1
commit 244c8cb4d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 4 deletions

View file

@ -36,6 +36,7 @@
import { page } from '$app/stores'; import { page } from '$app/stores';
import type { UpdatePayload } from 'vite'; import type { UpdatePayload } from 'vite';
import { generateId } from '$lib/utils/generate-id'; import { generateId } from '$lib/utils/generate-id';
import { isTimelineScrolling } from '$lib/stores/timeline.store';
export let isSelectionMode = false; export let isSelectionMode = false;
export let singleSelect = false; export let singleSelect = false;
@ -331,7 +332,17 @@
} }
}; };
let scrollObserverTimer: NodeJS.Timeout;
const _handleTimelineScroll = () => { const _handleTimelineScroll = () => {
$isTimelineScrolling = true;
if (scrollObserverTimer) {
clearTimeout(scrollObserverTimer);
}
scrollObserverTimer = setTimeout(() => {
$isTimelineScrolling = false;
}, 1000);
leadout = false; leadout = false;
if ($assetStore.timelineHeight < safeViewport.height * 2) { if ($assetStore.timelineHeight < safeViewport.height * 2) {
// edge case - scroll limited due to size of content, must adjust - use the overall percent instead // edge case - scroll limited due to size of content, must adjust - use the overall percent instead

View file

@ -1,9 +1,12 @@
<script lang="ts"> <script lang="ts">
import type { AssetStore, AssetBucket, BucketListener } from '$lib/stores/assets.store'; import type { AssetStore, AssetBucket, BucketListener } from '$lib/stores/assets.store';
import type { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { fromLocalDateTime, type ScrubberListener } from '$lib/utils/timeline-util'; import { fromLocalDateTime, type ScrubberListener } from '$lib/utils/timeline-util';
import { clamp } from 'lodash-es'; import { clamp } from 'lodash-es';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { isTimelineScrolling } from '$lib/stores/timeline.store';
import { parseUtcDate } from '$lib/utils/date-time';
import { fly } from 'svelte/transition';
export let timelineTopOffset = 0; export let timelineTopOffset = 0;
export let timelineBottomOffset = 0; export let timelineBottomOffset = 0;
@ -72,6 +75,7 @@
$: timelineFullHeight = $assetStore.timelineHeight + timelineTopOffset + timelineBottomOffset; $: timelineFullHeight = $assetStore.timelineHeight + timelineTopOffset + timelineBottomOffset;
$: relativeTopOffset = toScrollY(timelineTopOffset / timelineFullHeight); $: relativeTopOffset = toScrollY(timelineTopOffset / timelineFullHeight);
$: relativeBottomOffset = toScrollY(timelineBottomOffset / timelineFullHeight); $: relativeBottomOffset = toScrollY(timelineBottomOffset / timelineFullHeight);
$: formatedDate = scrubBucket?.bucketDate ? parseUtcDate(scrubBucket?.bucketDate).toFormat('MMM yyyy') : '';
const listener: BucketListener = (event) => { const listener: BucketListener = (event) => {
const { type } = event; const { type } = event;
@ -210,8 +214,9 @@
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<div <div
transition:fly={{ x: 50, duration: 250 }}
id="immich-scrubbable-scrollbar" id="immich-scrubbable-scrollbar"
class={`absolute right-0 z-[1] select-none bg-immich-bg hover:cursor-row-resize`} class="absolute right-0 z-[1] select-none bg-immich-bg hover:cursor-row-resize"
style:padding-top={HOVER_DATE_HEIGHT + 'px'} style:padding-top={HOVER_DATE_HEIGHT + 'px'}
style:padding-bottom={HOVER_DATE_HEIGHT + 'px'} style:padding-bottom={HOVER_DATE_HEIGHT + 'px'}
class:invisible class:invisible
@ -235,9 +240,20 @@
<!-- Scroll Position Indicator Line --> <!-- Scroll Position Indicator Line -->
{#if !isDragging} {#if !isDragging}
<div <div
class="absolute right-0 h-[2px] w-10 bg-immich-primary dark:bg-immich-dark-primary" class="absolute right-0 {$isTimelineScrolling && formatedDate
? 'h-[0px]'
: 'h-[2px]'} w-10 bg-immich-primary dark:bg-immich-dark-primary"
style:top="{scrollY + HOVER_DATE_HEIGHT}px" style:top="{scrollY + HOVER_DATE_HEIGHT}px"
/> >
{#if $isTimelineScrolling && formatedDate}
<p
transition:fly={{ y: -15, duration: 350 }}
class="truncate opacity-85 pointer-events-none absolute right-0 bottom-0 z-[100] min-w-20 max-w-64 w-fit rounded-tl-md border-b-2 border-immich-primary bg-immich-bg py-1 px-1 text-sm font-medium shadow-[0_0_8px_rgba(0,0,0,0.25)] dark:border-immich-dark-primary dark:bg-immich-dark-gray dark:text-immich-dark-fg"
>
{formatedDate}
</p>
{/if}
</div>
{/if} {/if}
<div id="lead-in" class="relative" style:height={relativeTopOffset + 'px'} data-label={segments.at(0)?.dateFormatted}> <div id="lead-in" class="relative" style:height={relativeTopOffset + 'px'} data-label={segments.at(0)?.dateFormatted}>
{#if relativeTopOffset > 6} {#if relativeTopOffset > 6}

View file

@ -0,0 +1,3 @@
import { writable } from 'svelte/store';
export const isTimelineScrolling = writable(false);