mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
Inline, combine functions, lint
This commit is contained in:
parent
3ffa7c9d29
commit
d14c997ed3
3 changed files with 44 additions and 40 deletions
|
|
@ -53,12 +53,16 @@
|
||||||
|
|
||||||
const VIEWPORT_MULTIPLIER = 2; // Used to determine if timeline is "small"
|
const VIEWPORT_MULTIPLIER = 2; // Used to determine if timeline is "small"
|
||||||
|
|
||||||
let isInLeadOutSection = $state(false);
|
|
||||||
// The percentage of scroll through the month that is currently intersecting the top boundary of the viewport.
|
// The percentage of scroll through the month that is currently intersecting the top boundary of the viewport.
|
||||||
// Note: There may be multiple months visible within the viewport at any given time.
|
// Note: There may be multiple months visible within the viewport at any given time.
|
||||||
let viewportTopMonthScrollPercent = $state(0);
|
let viewportTopMonthScrollPercent = $state(0);
|
||||||
|
// The timeline month intersecting the top position of the viewport
|
||||||
let viewportTopMonth: TimelineYearMonth | undefined = $state(undefined);
|
let viewportTopMonth: TimelineYearMonth | undefined = $state(undefined);
|
||||||
|
// Overall scroll percentage through the entire timeline (0-1)
|
||||||
let timelineScrollPercent: number = $state(0);
|
let timelineScrollPercent: number = $state(0);
|
||||||
|
// Indicates whether the viewport is currently in the lead-out section (after all months)
|
||||||
|
let isInLeadOutSection = $state(false);
|
||||||
|
// Width of the scrubber component in pixels, used to adjust timeline margins
|
||||||
let scrubberWidth: number = $state(0);
|
let scrubberWidth: number = $state(0);
|
||||||
|
|
||||||
// note: don't throttle, debounce, or otherwise make this function async - it causes flicker
|
// note: don't throttle, debounce, or otherwise make this function async - it causes flicker
|
||||||
|
|
@ -66,16 +70,10 @@
|
||||||
const handleTimelineScroll = () => {
|
const handleTimelineScroll = () => {
|
||||||
isInLeadOutSection = false;
|
isInLeadOutSection = false;
|
||||||
|
|
||||||
// Handle small timeline edge case: scroll limited due to size of content
|
// Handle edge cases: small timeline (limited scroll) or lead-in area scrolling
|
||||||
if (isSmallTimeline()) {
|
|
||||||
handleSmallTimelineScroll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle scrolling of the lead-in area
|
|
||||||
const top = timelineManager.visibleWindow.top;
|
const top = timelineManager.visibleWindow.top;
|
||||||
if (top < timelineManager.topSectionHeight) {
|
if (isSmallTimeline() || top < timelineManager.topSectionHeight) {
|
||||||
handleLeadInScroll();
|
calculateTimelineScrollPercent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,29 +81,6 @@
|
||||||
handleMonthScroll();
|
handleMonthScroll();
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSmallTimeline = () => {
|
|
||||||
return timelineManager.timelineHeight < timelineManager.viewportHeight * VIEWPORT_MULTIPLIER;
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetScrubberMonth = () => {
|
|
||||||
viewportTopMonth = undefined;
|
|
||||||
viewportTopMonthScrollPercent = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const calculateTimelineScrollPercent = () => {
|
|
||||||
const maxScroll = timelineManager.getMaxScroll();
|
|
||||||
timelineScrollPercent = Math.min(1, timelineManager.visibleWindow.top / maxScroll);
|
|
||||||
resetScrubberMonth();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSmallTimelineScroll = () => {
|
|
||||||
calculateTimelineScrollPercent();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLeadInScroll = () => {
|
|
||||||
calculateTimelineScrollPercent();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMonthScroll = () => {
|
const handleMonthScroll = () => {
|
||||||
const scrollPosition = timelineManager.visibleWindow.top;
|
const scrollPosition = timelineManager.visibleWindow.top;
|
||||||
const months = timelineManager.months;
|
const months = timelineManager.months;
|
||||||
|
|
@ -118,12 +93,24 @@
|
||||||
viewportTopMonth = searchResult.month;
|
viewportTopMonth = searchResult.month;
|
||||||
viewportTopMonthScrollPercent = searchResult.monthScrollPercent;
|
viewportTopMonthScrollPercent = searchResult.monthScrollPercent;
|
||||||
isInLeadOutSection = false;
|
isInLeadOutSection = false;
|
||||||
} else {
|
return;
|
||||||
// We're in lead-out section
|
|
||||||
isInLeadOutSection = true;
|
|
||||||
timelineScrollPercent = 1;
|
|
||||||
resetScrubberMonth();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're in lead-out section
|
||||||
|
isInLeadOutSection = true;
|
||||||
|
timelineScrollPercent = 1;
|
||||||
|
resetScrubberMonth();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetScrubberMonth = () => {
|
||||||
|
viewportTopMonth = undefined;
|
||||||
|
viewportTopMonthScrollPercent = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const calculateTimelineScrollPercent = () => {
|
||||||
|
const maxScroll = timelineManager.getMaxScroll();
|
||||||
|
timelineScrollPercent = Math.min(1, timelineManager.visibleWindow.top / maxScroll);
|
||||||
|
resetScrubberMonth();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOverallPercentScroll = (percent: number, scrollTo?: (offset: number) => void) => {
|
const handleOverallPercentScroll = (percent: number, scrollTo?: (offset: number) => void) => {
|
||||||
|
|
@ -138,6 +125,10 @@
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isSmallTimeline = () => {
|
||||||
|
return timelineManager.timelineHeight < timelineManager.viewportHeight * VIEWPORT_MULTIPLIER;
|
||||||
|
};
|
||||||
|
|
||||||
// note: don't throttle, debounce, or otherwise make this function async - it causes flicker
|
// note: don't throttle, debounce, or otherwise make this function async - it causes flicker
|
||||||
// this function scrolls the timeline to the specified month group and offset, based on scrubber interaction
|
// this function scrolls the timeline to the specified month group and offset, based on scrubber interaction
|
||||||
const onScrub: ScrubberListener = (scrubberData) => {
|
const onScrub: ScrubberListener = (scrubberData) => {
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,31 @@
|
||||||
import { fade, fly } from 'svelte/transition';
|
import { fade, fly } from 'svelte/transition';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
/** Offset from the top of the timeline (e.g., for headers) */
|
||||||
timelineTopOffset?: number;
|
timelineTopOffset?: number;
|
||||||
|
/** Offset from the bottom of the timeline (e.g., for footers) */
|
||||||
timelineBottomOffset?: number;
|
timelineBottomOffset?: number;
|
||||||
|
/** Total height of the scrubber component */
|
||||||
height?: number;
|
height?: number;
|
||||||
|
/** Timeline manager instance that controls the timeline state */
|
||||||
timelineManager: TimelineManager;
|
timelineManager: TimelineManager;
|
||||||
|
/** Overall scroll percentage through the entire timeline (0-1), used when no specific month is targeted */
|
||||||
timelineScrollPercent?: number;
|
timelineScrollPercent?: number;
|
||||||
|
/** The percentage of scroll through the month that is currently intersecting the top boundary of the viewport */
|
||||||
viewportTopMonthScrollPercent?: number;
|
viewportTopMonthScrollPercent?: number;
|
||||||
|
/** The year/month of the timeline month at the top of the viewport */
|
||||||
viewportTopMonth?: TimelineYearMonth;
|
viewportTopMonth?: TimelineYearMonth;
|
||||||
|
/** Indicates whether the viewport is currently in the lead-out section (after all months) */
|
||||||
isInLeadOutSection?: boolean;
|
isInLeadOutSection?: boolean;
|
||||||
|
/** Width of the scrubber component in pixels (bindable for parent component margin adjustments) */
|
||||||
scrubberWidth?: number;
|
scrubberWidth?: number;
|
||||||
|
/** Callback fired when user interacts with the scrubber to navigate */
|
||||||
onScrub?: ScrubberListener;
|
onScrub?: ScrubberListener;
|
||||||
|
/** Callback fired when keyboard events occur on the scrubber */
|
||||||
onScrubKeyDown?: (event: KeyboardEvent, element: HTMLElement) => void;
|
onScrubKeyDown?: (event: KeyboardEvent, element: HTMLElement) => void;
|
||||||
|
/** Callback fired when scrubbing starts */
|
||||||
startScrub?: ScrubberListener;
|
startScrub?: ScrubberListener;
|
||||||
|
/** Callback fired when scrubbing stops */
|
||||||
stopScrub?: ScrubberListener;
|
stopScrub?: ScrubberListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ export function findMonthAtScrollPosition(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're after the last month
|
// Check if we're after the last month
|
||||||
const lastMonth = months[months.length - 1];
|
const lastMonth = months.at(-1)!;
|
||||||
const lastMonthBottom = (lastMonth.top + lastMonth.height) * maxScrollPercent;
|
const lastMonthBottom = (lastMonth.top + lastMonth.height) * maxScrollPercent;
|
||||||
if (scrollPosition >= lastMonthBottom - SUBPIXEL_TOLERANCE) {
|
if (scrollPosition >= lastMonthBottom - SUBPIXEL_TOLERANCE) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -293,7 +293,7 @@ export function findMonthAtScrollPosition(
|
||||||
if (scrollPosition >= monthTop - SUBPIXEL_TOLERANCE && scrollPosition < monthBottom - SUBPIXEL_TOLERANCE) {
|
if (scrollPosition >= monthTop - SUBPIXEL_TOLERANCE && scrollPosition < monthBottom - SUBPIXEL_TOLERANCE) {
|
||||||
// Found the month containing the scroll position
|
// Found the month containing the scroll position
|
||||||
const distanceIntoMonth = scrollPosition - monthTop;
|
const distanceIntoMonth = scrollPosition - monthTop;
|
||||||
let monthScrollPercent = Math.max(0, distanceIntoMonth / (month.height * maxScrollPercent));
|
const monthScrollPercent = Math.max(0, distanceIntoMonth / (month.height * maxScrollPercent));
|
||||||
|
|
||||||
// Handle month boundary edge case
|
// Handle month boundary edge case
|
||||||
if (monthScrollPercent > NEAR_END_THRESHOLD && mid < months.length - 1) {
|
if (monthScrollPercent > NEAR_END_THRESHOLD && mid < months.length - 1) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue