mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
feat(web): responsive date group header height (#17944)
* feat: responsive date group header height * update tests * feat(web): improve perf when changing mobile orientation (#17945) fix: improve perf when changing mobile orientation
This commit is contained in:
parent
07290580a6
commit
0e4cf9ac57
@ -131,7 +131,7 @@
|
||||
>
|
||||
<!-- Date group title -->
|
||||
<div
|
||||
class="flex z-[100] pt-[calc(1.75rem+1px)] pb-5 h-6 place-items-center text-xs font-medium text-immich-fg bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg md:text-sm"
|
||||
class="flex z-[100] pt-7 pb-5 max-md:pt-5 max-md:pb-3 h-6 place-items-center text-xs font-medium text-immich-fg bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg md:text-sm"
|
||||
style:width={dateGroup.width + 'px'}
|
||||
>
|
||||
{#if !singleSelect && ((hoveredDateGroup === dateGroup.groupTitle && isMouseOverGroup) || assetInteraction.selectedGroup.has(dateGroup.groupTitle))}
|
||||
|
@ -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) => {
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
<div class="overflow-clip" style:height={height + 'px'}>
|
||||
<div
|
||||
class="flex z-[100] pt-[calc(1.75rem+1px)] pb-5 h-6 place-items-center text-xs font-medium text-immich-fg bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg md:text-sm"
|
||||
class="flex z-[100] pt-7 pb-5 h-6 place-items-center text-xs font-medium text-immich-fg bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg md:text-sm"
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -35,9 +35,7 @@ export type AssetStoreOptions = Omit<AssetApiGetTimeBucketsRequest, 'size'> & {
|
||||
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(() => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user