diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte
index ecb25b06975..f20c04d3d47 100644
--- a/web/src/lib/components/photos-page/asset-date-group.svelte
+++ b/web/src/lib/components/photos-page/asset-date-group.svelte
@@ -131,7 +131,7 @@
>
{#if !singleSelect && ((hoveredDateGroup === dateGroup.groupTitle && isMouseOverGroup) || assetInteraction.selectedGroup.has(dateGroup.groupTitle))}
diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte
index da4387a4909..e46aaefe0e2 100644
--- a/web/src/lib/components/photos-page/asset-grid.svelte
+++ b/web/src/lib/components/photos-page/asset-grid.svelte
@@ -88,7 +88,16 @@
const usingMobileDevice = $derived(mobileDevice.pointerCoarse);
$effect(() => {
- assetStore.rowHeight = maxMd ? 100 : 235;
+ const layoutOptions = maxMd
+ ? {
+ rowHeight: 100,
+ headerHeight: 32,
+ }
+ : {
+ rowHeight: 235,
+ headerHeight: 48,
+ };
+ assetStore.setLayoutOptions(layoutOptions);
});
const scrollTo = (top: number) => {
diff --git a/web/src/lib/components/photos-page/skeleton.svelte b/web/src/lib/components/photos-page/skeleton.svelte
index 5c438874503..87ff91c511c 100644
--- a/web/src/lib/components/photos-page/skeleton.svelte
+++ b/web/src/lib/components/photos-page/skeleton.svelte
@@ -9,7 +9,7 @@
{title}
diff --git a/web/src/lib/stores/assets-store.spec.ts b/web/src/lib/stores/assets-store.spec.ts
index 0685103a1b2..3d0292bde8a 100644
--- a/web/src/lib/stores/assets-store.spec.ts
+++ b/web/src/lib/stores/assets-store.spec.ts
@@ -48,15 +48,15 @@ describe('AssetStore', () => {
expect(plainBuckets).toEqual(
expect.arrayContaining([
- expect.objectContaining({ bucketDate: '2024-03-01T00:00:00.000Z', bucketHeight: 304 }),
- expect.objectContaining({ bucketDate: '2024-02-01T00:00:00.000Z', bucketHeight: 4515.333_333_333_333 }),
+ expect.objectContaining({ bucketDate: '2024-03-01T00:00:00.000Z', bucketHeight: 303 }),
+ expect.objectContaining({ bucketDate: '2024-02-01T00:00:00.000Z', bucketHeight: 4514.333_333_333_333 }),
expect.objectContaining({ bucketDate: '2024-01-01T00:00:00.000Z', bucketHeight: 286 }),
]),
);
});
it('calculates timeline height', () => {
- expect(assetStore.timelineHeight).toBe(5105.333_333_333_333);
+ expect(assetStore.timelineHeight).toBe(5103.333_333_333_333);
});
});
diff --git a/web/src/lib/stores/assets-store.svelte.ts b/web/src/lib/stores/assets-store.svelte.ts
index e048fabbc80..b4b4a4ade22 100644
--- a/web/src/lib/stores/assets-store.svelte.ts
+++ b/web/src/lib/stores/assets-store.svelte.ts
@@ -35,9 +35,7 @@ export type AssetStoreOptions = Omit
& {
timelineAlbumId?: string;
deferInit?: boolean;
};
-export type AssetStoreLayoutOptions = {
- rowHeight: number;
-};
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function updateObject(target: any, source: any): boolean {
if (!target) {
@@ -110,7 +108,6 @@ export class AssetDateGroup {
readonly date: DateTime;
readonly dayOfMonth: number;
intersetingAssets: IntersectingAsset[] = $state([]);
- dodo: IntersectingAsset[] = $state([]);
height = $state(0);
width = $state(0);
@@ -121,6 +118,7 @@ export class AssetDateGroup {
left: number = $state(0);
row = $state(0);
col = $state(0);
+ deferredLayout = false;
constructor(bucket: AssetBucket, index: number, date: DateTime, dayOfMonth: number) {
this.index = index;
@@ -195,6 +193,10 @@ export class AssetDateGroup {
}
layout(options: CommonLayoutOptions) {
+ if (!this.bucket.intersecting) {
+ this.deferredLayout = true;
+ return;
+ }
const assets = this.intersetingAssets.map((intersetingAsset) => intersetingAsset.asset!);
const geometry = getJustifiedLayoutFromAssets(assets, options);
this.width = geometry.containerWidth;
@@ -547,6 +549,11 @@ export type LiteBucket = {
bucketDateFormattted: string;
};
+type AssetStoreLayoutOptions = {
+ rowHeight?: number;
+ headerHeight?: number;
+ gap?: number;
+};
export class AssetStore {
// --- public ----
isInitialized = $state(false);
@@ -596,7 +603,7 @@ export class AssetStore {
#unsubscribers: Unsubscriber[] = [];
#rowHeight = $state(235);
- #headerHeight = $state(49);
+ #headerHeight = $state(48);
#gap = $state(12);
#options: AssetStoreOptions = AssetStore.#INIT_OPTIONS;
@@ -608,36 +615,46 @@ export class AssetStore {
constructor() {}
- set headerHeight(value) {
+ setLayoutOptions({ headerHeight = 48, rowHeight = 235, gap = 12 }: AssetStoreLayoutOptions) {
+ let changed = false;
+ changed ||= this.#setHeaderHeight(headerHeight);
+ changed ||= this.#setGap(gap);
+ changed ||= this.#setRowHeight(rowHeight);
+ if (changed) {
+ this.refreshLayout();
+ }
+ }
+
+ #setHeaderHeight(value: number) {
if (this.#headerHeight == value) {
- return;
+ return false;
}
this.#headerHeight = value;
- this.refreshLayout();
+ return true;
}
get headerHeight() {
return this.#headerHeight;
}
- set gap(value) {
+ #setGap(value: number) {
if (this.#gap == value) {
- return;
+ return false;
}
this.#gap = value;
- this.refreshLayout();
+ return true;
}
get gap() {
return this.#gap;
}
- set rowHeight(value) {
+ #setRowHeight(value: number) {
if (this.#rowHeight == value) {
- return;
+ return false;
}
this.#rowHeight = value;
- this.refreshLayout();
+ return true;
}
get rowHeight() {
@@ -815,6 +832,15 @@ export class AssetStore {
}
bucket.intersecting = actuallyIntersecting || preIntersecting;
bucket.actuallyIntersecting = actuallyIntersecting;
+ if (preIntersecting || actuallyIntersecting) {
+ const hasDeferred = bucket.dateGroups.some((group) => group.deferredLayout);
+ if (hasDeferred) {
+ this.#updateGeometry(bucket, true);
+ for (const group of bucket.dateGroups) {
+ group.deferredLayout = false;
+ }
+ }
+ }
}
#processPendingChanges = throttle(() => {