From f7c987f0352ecf172b5c4c98a672fbd4aa8199c4 Mon Sep 17 00:00:00 2001 From: Min Idzelis Date: Sat, 21 Jun 2025 03:40:29 +0000 Subject: [PATCH] refactor(web): extract asset-grid-without-scrubber from asset-grid component Separated scrubber logic into asset-grid component, creating a asset-grid-without-scrubber for modularity. Names not final yet, much more left to do. --- .../asset-grid-without-scrubber.svelte | 375 ++++++++++++++ .../components/photos-page/asset-grid.svelte | 466 ++++-------------- .../scrubber/scrubber.svelte | 36 +- .../timeline-manager.svelte.ts | 10 + web/src/lib/utils/timeline-util.ts | 11 +- 5 files changed, 505 insertions(+), 393 deletions(-) create mode 100644 web/src/lib/components/photos-page/asset-grid-without-scrubber.svelte diff --git a/web/src/lib/components/photos-page/asset-grid-without-scrubber.svelte b/web/src/lib/components/photos-page/asset-grid-without-scrubber.svelte new file mode 100644 index 0000000000..6633b0f27c --- /dev/null +++ b/web/src/lib/components/photos-page/asset-grid-without-scrubber.svelte @@ -0,0 +1,375 @@ + + + + + + +{@render header?.(scrollTop)} + + +
((timelineManager.viewportWidth = v), updateSlidingWindow())} + bind:this={element} + onscroll={() => (handleTimelineScroll(), updateSlidingWindow(), updateIsScrolling())} +> +
+
+ {@render children?.()} + {#if isEmpty} + + {@render empty?.()} + {/if} +
+ + {#each timelineManager.months as monthGroup (monthGroup.viewId)} + {@const display = monthGroup.intersecting} + {@const absoluteHeight = monthGroup.top} + + {#if !monthGroup.isLoaded} +
+ +
+ {:else if display} +
+ +
+ {/if} + {/each} + +
+
+
+ + + {#if $showAssetViewer} + + {/if} + + + diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index fcb655ee6b..caec698491 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -1,26 +1,14 @@ - - - - -{#if timelineManager.months.length > 0} - -{/if} - - -
((timelineManager.viewportWidth = v), updateSlidingWindow())} - bind:this={element} - onscroll={() => (handleTimelineScroll(), updateSlidingWindow(), updateIsScrolling())} + {onEscape} + {children} + {empty} + {handleTimelineScroll} > -
-
- {@render children?.()} - {#if isEmpty} - - {@render empty?.()} - {/if} -
- - {#each timelineManager.months as monthGroup (monthGroup.viewId)} - {@const display = monthGroup.intersecting} - {@const absoluteHeight = monthGroup.top} - - {#if !monthGroup.isLoaded} -
- -
- {:else if display} -
- -
- {/if} - {/each} - -
-
-
- - - {#if $showAssetViewer} - - {/if} - - - + {#snippet header(handleScrollTop)} + {#if timelineManager.months.length > 0} + onScrub({ ...args, handleScrollTop })} + bind:scrubberWidth + /> + {/if} + {/snippet} + diff --git a/web/src/lib/components/shared-components/scrubber/scrubber.svelte b/web/src/lib/components/shared-components/scrubber/scrubber.svelte index 4e49f9a012..83f9919279 100644 --- a/web/src/lib/components/shared-components/scrubber/scrubber.svelte +++ b/web/src/lib/components/shared-components/scrubber/scrubber.svelte @@ -295,12 +295,24 @@ const scrollPercent = toTimelineY(hoverY); if (wasDragging === false && isDragging) { - void startScrub?.(segmentDate!, scrollPercent, monthGroupPercentY); - void onScrub?.(segmentDate!, scrollPercent, monthGroupPercentY); + void startScrub?.({ + scrubberMonth: segmentDate!, + overallScrollPercent: scrollPercent, + scrubberMonthScrollPercent: monthGroupPercentY, + }); + void onScrub?.({ + scrubberMonth: segmentDate!, + overallScrollPercent: scrollPercent, + scrubberMonthScrollPercent: monthGroupPercentY, + }); } if (wasDragging && !isDragging) { - void stopScrub?.(segmentDate!, scrollPercent, monthGroupPercentY); + void stopScrub?.({ + scrubberMonth: segmentDate!, + overallScrollPercent: scrollPercent, + scrubberMonthScrollPercent: monthGroupPercentY, + }); return; } @@ -308,7 +320,11 @@ return; } - void onScrub?.(segmentDate!, scrollPercent, monthGroupPercentY); + void onScrub?.({ + scrubberMonth: segmentDate!, + overallScrollPercent: scrollPercent, + scrubberMonthScrollPercent: monthGroupPercentY, + }); }; /* eslint-disable tscompat/tscompat */ const getTouch = (event: TouchEvent) => { @@ -412,7 +428,11 @@ } if (next) { event.preventDefault(); - void onScrub?.({ year: next.year, month: next.month }, -1, 0); + void onScrub?.({ + scrubberMonth: { year: next.year, month: next.month }, + overallScrollPercent: -1, + scrubberMonthScrollPercent: 0, + }); return true; } } @@ -422,7 +442,11 @@ const next = segments[idx + 1]; if (next) { event.preventDefault(); - void onScrub?.({ year: next.year, month: next.month }, -1, 0); + void onScrub?.({ + scrubberMonth: { year: next.year, month: next.month }, + overallScrollPercent: -1, + scrubberMonthScrollPercent: 0, + }); return true; } } diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts index 8aacd0a90a..803b6c3dd4 100644 --- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts +++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts @@ -41,6 +41,7 @@ export class TimelineManager { isInitialized = $state(false); months: MonthGroup[] = $state([]); topSectionHeight = $state(0); + bottomSectionHeight = $state(60); timelineHeight = $derived(this.months.reduce((accumulator, b) => accumulator + b.height, 0) + this.topSectionHeight); assetCount = $derived(this.months.reduce((accumulator, b) => accumulator + b.assetsCount, 0)); @@ -540,4 +541,13 @@ export class TimelineManager { isMismatched(this.#options.isTrashed, asset.isTrashed) ); } + + getMaxScrollPercent() { + const totalHeight = this.timelineHeight + this.bottomSectionHeight + this.topSectionHeight; + return (totalHeight - this.viewportHeight) / totalHeight; + } + + getMaxScroll() { + return this.topSectionHeight + this.bottomSectionHeight + (this.timelineHeight - this.viewportHeight); + } } diff --git a/web/src/lib/utils/timeline-util.ts b/web/src/lib/utils/timeline-util.ts index c3e41c01be..cfe9454d26 100644 --- a/web/src/lib/utils/timeline-util.ts +++ b/web/src/lib/utils/timeline-util.ts @@ -22,11 +22,12 @@ export type TimelinePlainDateTime = TimelinePlainDate & { millisecond: number; }; -export type ScrubberListener = ( - scrubberMonth: { year: number; month: number }, - overallScrollPercent: number, - scrubberMonthScrollPercent: number, -) => void | Promise; +export type ScrubberListener = (args: { + scrubberMonth: { year: number; month: number }; + overallScrollPercent: number; + scrubberMonthScrollPercent: number; + handleScrollTop?: (top: number) => void; +}) => void | Promise; // used for AssetResponseDto.dateTimeOriginal, amongst others export const fromISODateTime = (isoDateTime: string, timeZone: string): DateTime =>