From 79adb016e8440e5a3657ab724b0e47806e35ef00 Mon Sep 17 00:00:00 2001 From: midzelis Date: Thu, 25 Sep 2025 14:26:23 +0000 Subject: [PATCH] feat: photostream can have scrollbar, style options, standardize small/large layout sizes - Add configurable header height props for responsive layouts (smallHeaderHeight/largeHeaderHeight) - Add style customization props: styleMarginContentHorizontal, styleMarginTop, alwaysShowScrollbar - Replace hardcoded layout values with configurable props - Change root element from
to custom element for better semantic structure - Move viewport width binding to inner timeline element for more accurate measurements - Simplify HMR handler by removing file-specific checks - Add segment loading check to prevent rendering unloaded segments - Add spacing margin between month groups using layout options - Change scrollbar-width from 'auto' to 'thin' for consistency - Remove unused UpdatePayload type import --- .../components/timeline/Photostream.svelte | 75 ++++++++++++------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/web/src/lib/components/timeline/Photostream.svelte b/web/src/lib/components/timeline/Photostream.svelte index 5a78a3b1fb..c5777df308 100644 --- a/web/src/lib/components/timeline/Photostream.svelte +++ b/web/src/lib/components/timeline/Photostream.svelte @@ -8,7 +8,6 @@ import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { mobileDevice } from '$lib/stores/mobile-device.svelte'; import { onMount, type Snippet } from 'svelte'; - import type { UpdatePayload } from 'vite'; interface Props { segment: Snippet< @@ -35,6 +34,7 @@ enableRouting: boolean; timelineManager: PhotostreamManager; + alwaysShowScrollbar?: boolean; showSkeleton?: boolean; isShowDeleteConfirmation?: boolean; styleMarginRightOverride?: string; @@ -43,6 +43,18 @@ children?: Snippet; empty?: Snippet; handleTimelineScroll?: () => void; + + smallHeaderHeight?: { + rowHeight: number; + headerHeight: number; + }; + + largeHeaderHeight?: { + rowHeight: number; + headerHeight: number; + }; + styleMarginContentHorizontal?: string; + styleMarginTop?: string; } let { @@ -51,14 +63,27 @@ enableRouting, timelineManager = $bindable(), showSkeleton = $bindable(true), - styleMarginRightOverride, - isShowDeleteConfirmation = $bindable(false), showScrollbar, + styleMarginRightOverride, + styleMarginContentHorizontal = '0px', + styleMarginTop = '0px', + alwaysShowScrollbar, + + isShowDeleteConfirmation = $bindable(false), + children, skeleton, empty, header, handleTimelineScroll = () => {}, + smallHeaderHeight = { + rowHeight: 100, + headerHeight: 32, + }, + largeHeaderHeight = { + rowHeight: 235, + headerHeight: 48, + }, }: Props = $props(); let { gridScrollTarget } = assetViewingStore; @@ -70,15 +95,7 @@ const isEmpty = $derived(timelineManager.isInitialized && timelineManager.months.length === 0); $effect(() => { - const layoutOptions = maxMd - ? { - rowHeight: 100, - headerHeight: 32, - } - : { - rowHeight: 235, - headerHeight: 48, - }; + const layoutOptions = maxMd ? smallHeaderHeight : largeHeaderHeight; timelineManager.setLayoutOptions(layoutOptions); }); @@ -173,7 +190,7 @@ { + onAfterUpdate={() => { // when hmr happens, skeleton is initialized to true by default // normally, loading asset-grid is part of a navigation event, and the completion of // that event triggers a scroll-to-asset, if necessary, when then clears the skeleton. @@ -186,38 +203,41 @@ } void completeAfterNavigate({ scrollToAssetQueryParam: true }); }; - const assetGridUpdate = payload.updates.some((update) => update.path.endsWith('Photostream.svelte')); - if (assetGridUpdate) { - // wait 500ms for the update to be fully swapped in - setTimeout(finishHmr, 500); - } + + // wait 500ms for the update to be fully swapped in + setTimeout(finishHmr, 500); }} /> {@render header?.(scrollTo)} -
((timelineManager.viewportWidth = v), updateSlidingWindow())} bind:this={element} onscroll={() => (handleTimelineScroll(), updateSlidingWindow(), updateIsScrolling())} >
((timelineManager.viewportWidth = v), updateSlidingWindow())} >
{#each timelineManager.months as monthGroup (monthGroup.id)} - {@const shouldDisplay = monthGroup.intersecting} + {@const shouldDisplay = monthGroup.intersecting && monthGroup.isLoaded} {@const absoluteHeight = monthGroup.top} +
{#if !shouldDisplay} @@ -263,9 +285,12 @@ style:transform={`translate3d(0,${timelineManager.timelineHeight}px,0)`} >
-
+