1
0
mirror of https://github.com/immich-app/immich.git synced 2025-04-22 13:08:08 +02:00

fix(web): fix scrollbar not allowing the user to go fully top or bottom (#8637)

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Ethan Margaillan 2024-04-15 14:21:47 +02:00 committed by GitHub
parent 3c7f70ec30
commit 0f74b17000
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -3,6 +3,8 @@
import type { DateTime } from 'luxon'; import type { DateTime } from 'luxon';
import { fromLocalDateTime } from '$lib/utils/timeline-util'; import { fromLocalDateTime } from '$lib/utils/timeline-util';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { clamp } from 'lodash-es';
import { locale } from '$lib/stores/preferences.store';
export let timelineY = 0; export let timelineY = 0;
export let height = 0; export let height = 0;
@ -12,8 +14,10 @@
let isDragging = false; let isDragging = false;
let isAnimating = false; let isAnimating = false;
let hoverLabel = ''; let hoverLabel = '';
let hoverY = 0;
let clientY = 0; let clientY = 0;
let windowHeight = 0; let windowHeight = 0;
let scrollBar: HTMLElement | undefined;
const toScrollY = (timelineY: number) => (timelineY / $assetStore.timelineHeight) * height; const toScrollY = (timelineY: number) => (timelineY / $assetStore.timelineHeight) * height;
const toTimelineY = (scrollY: number) => Math.round((scrollY * $assetStore.timelineHeight) / height); const toTimelineY = (scrollY: number) => Math.round((scrollY * $assetStore.timelineHeight) / height);
@ -21,7 +25,16 @@
const HOVER_DATE_HEIGHT = 30; const HOVER_DATE_HEIGHT = 30;
const MIN_YEAR_LABEL_DISTANCE = 16; 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); $: scrollY = toScrollY(timelineY);
class Segment { class Segment {
@ -58,6 +71,21 @@
const dispatch = createEventDispatcher<{ scrollTimeline: number }>(); const dispatch = createEventDispatcher<{ scrollTimeline: number }>();
const scrollTimeline = () => dispatch('scrollTimeline', toTimelineY(hoverY)); 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 handleMouseEvent = (event: { clientY: number; isDragging?: boolean }) => {
const wasDragging = isDragging; const wasDragging = isDragging;
@ -81,7 +109,12 @@
}; };
</script> </script>
<svelte:window bind:innerHeight={windowHeight} /> <svelte:window
bind:innerHeight={windowHeight}
on:mousemove={({ clientY }) => (isDragging || isHover) && handleMouseEvent({ clientY })}
on:mousedown={({ clientY }) => isHover && handleMouseEvent({ clientY, isDragging: true })}
on:mouseup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })}
/>
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
@ -93,20 +126,15 @@
style:height={height + 'px'} style:height={height + 'px'}
style:background-color={isDragging ? 'transparent' : 'transparent'} style:background-color={isDragging ? 'transparent' : 'transparent'}
draggable="false" draggable="false"
bind:this={scrollBar}
on:mouseenter={() => (isHover = true)} on:mouseenter={() => (isHover = true)}
on:mouseleave={() => { on:mouseleave={() => (isHover = false)}
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 })}
> >
{#if isHover} {#if isHover || isDragging}
<div <div
class="pointer-events-none absolute right-0 z-[100] w-[100px] rounded-tl-md border-b-2 border-immich-primary bg-immich-bg py-1 pl-1 pr-6 text-sm font-medium shadow-lg dark:border-immich-dark-primary dark:bg-immich-dark-gray dark:text-immich-dark-fg" id="time-label"
style:top="{Math.max(hoverY - HOVER_DATE_HEIGHT, 0)}px" class="pointer-events-none absolute right-0 z-[100] w-[100px] 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"
style:top="{clamp(hoverY - HOVER_DATE_HEIGHT, 0, height - HOVER_DATE_HEIGHT - 2)}px"
> >
{hoverLabel} {hoverLabel}
</div> </div>
@ -121,15 +149,12 @@
{/if} {/if}
<!-- Time Segment --> <!-- Time Segment -->
{#each segments as segment} {#each segments as segment}
{@const label = `${segment.date.toLocaleString({ month: 'short' })} ${segment.date.year}`}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div <div
id="time-segment" id="time-segment"
class="relative" class="relative"
data-date={segment.date}
style:height={segment.height + 'px'} style:height={segment.height + 'px'}
aria-label={segment.timeGroup + ' ' + segment.count} aria-label={segment.timeGroup + ' ' + segment.count}
on:mousemove={() => (hoverLabel = label)}
> >
{#if segment.hasLabel} {#if segment.hasLabel}
<div <div