diff --git a/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte b/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte index bef58fe250..2573a7730c 100644 --- a/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte +++ b/web/src/lib/components/shared-components/scrollbar/scrollbar.svelte @@ -3,6 +3,8 @@ import type { DateTime } from 'luxon'; import { fromLocalDateTime } from '$lib/utils/timeline-util'; import { createEventDispatcher } from 'svelte'; + import { clamp } from 'lodash-es'; + import { locale } from '$lib/stores/preferences.store'; export let timelineY = 0; export let height = 0; @@ -12,8 +14,10 @@ let isDragging = false; let isAnimating = false; let hoverLabel = ''; + let hoverY = 0; let clientY = 0; let windowHeight = 0; + let scrollBar: HTMLElement | undefined; const toScrollY = (timelineY: number) => (timelineY / $assetStore.timelineHeight) * height; const toTimelineY = (scrollY: number) => Math.round((scrollY * $assetStore.timelineHeight) / height); @@ -21,7 +25,16 @@ const HOVER_DATE_HEIGHT = 30; const MIN_YEAR_LABEL_DISTANCE = 16; - $: hoverY = height - windowHeight + clientY; + $: { + hoverY = clamp(height - windowHeight + clientY, 0, height); + if (scrollBar) { + const rect = scrollBar.getBoundingClientRect(); + const x = rect.left + rect.width / 2; + const y = rect.top + Math.min(hoverY, height - 1); + updateLabel(x, y); + } + } + $: scrollY = toScrollY(timelineY); class Segment { @@ -58,6 +71,21 @@ const dispatch = createEventDispatcher<{ scrollTimeline: number }>(); const scrollTimeline = () => dispatch('scrollTimeline', toTimelineY(hoverY)); + const updateLabel = (cursorX: number, cursorY: number) => { + const segment = document.elementsFromPoint(cursorX, cursorY).find(({ id }) => id === 'time-segment'); + if (!segment) { + return; + } + const attr = (segment as HTMLElement).dataset.date; + if (!attr) { + return; + } + hoverLabel = new Date(attr).toLocaleString($locale, { + month: 'short', + year: 'numeric', + }); + }; + const handleMouseEvent = (event: { clientY: number; isDragging?: boolean }) => { const wasDragging = isDragging; @@ -81,7 +109,12 @@ }; - + (isDragging || isHover) && handleMouseEvent({ clientY })} + on:mousedown={({ clientY }) => isHover && handleMouseEvent({ clientY, isDragging: true })} + on:mouseup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })} +/> @@ -93,20 +126,15 @@ style:height={height + 'px'} style:background-color={isDragging ? 'transparent' : 'transparent'} draggable="false" + bind:this={scrollBar} on:mouseenter={() => (isHover = true)} - on:mouseleave={() => { - isHover = false; - isDragging = false; - }} - on:mouseenter={({ clientY, buttons }) => handleMouseEvent({ clientY, isDragging: !!buttons })} - on:mousemove={({ clientY }) => handleMouseEvent({ clientY })} - on:mousedown={({ clientY }) => handleMouseEvent({ clientY, isDragging: true })} - on:mouseup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })} + on:mouseleave={() => (isHover = false)} > - {#if isHover} + {#if isHover || isDragging} {hoverLabel} @@ -121,15 +149,12 @@ {/if} {#each segments as segment} - {@const label = `${segment.date.toLocaleString({ month: 'short' })} ${segment.date.year}`} - - (hoverLabel = label)} > {#if segment.hasLabel}