You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-07-07 06:16:05 +02:00
feat(web): add justify layout for GalleryViewer (#2207)
* Implemented justify layout * Fixed issue with asset selection does not show style for selected assets * pr feedback * PR feedback * fix test * Added flip animation
This commit is contained in:
@ -3,8 +3,9 @@
|
||||
import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { AssetResponseDto, SharedLinkResponseDto, ThumbnailFormat } from '@api';
|
||||
|
||||
import AssetViewer from '../../asset-viewer/asset-viewer.svelte';
|
||||
import justifiedLayout from 'justified-layout';
|
||||
import { flip } from 'svelte/animate';
|
||||
|
||||
export let assets: AssetResponseDto[];
|
||||
export let sharedLink: SharedLinkResponseDto | undefined = undefined;
|
||||
@ -17,20 +18,27 @@
|
||||
let currentViewAssetIndex = 0;
|
||||
|
||||
let viewWidth: number;
|
||||
let thumbnailSize = 300;
|
||||
|
||||
$: isMultiSelectionMode = selectedAssets.size > 0;
|
||||
|
||||
$: {
|
||||
if (assets.length < 6) {
|
||||
thumbnailSize = Math.min(320, Math.floor(viewWidth / assets.length - assets.length));
|
||||
} else {
|
||||
if (viewWidth > 600) thumbnailSize = Math.floor(viewWidth / 6 - 6);
|
||||
else if (viewWidth > 400) thumbnailSize = Math.floor(viewWidth / 4 - 6);
|
||||
else if (viewWidth > 300) thumbnailSize = Math.floor(viewWidth / 2 - 6);
|
||||
else if (viewWidth > 200) thumbnailSize = Math.floor(viewWidth / 2 - 6);
|
||||
else if (viewWidth > 100) thumbnailSize = Math.floor(viewWidth / 1 - 6);
|
||||
function getAssetRatio(asset: AssetResponseDto): number {
|
||||
const height = asset.exifInfo?.exifImageHeight;
|
||||
const width = asset.exifInfo?.exifImageWidth;
|
||||
const orientation = Number(asset.exifInfo?.orientation);
|
||||
|
||||
if (height && width) {
|
||||
if (orientation) {
|
||||
if (orientation == 6 || orientation == -90) {
|
||||
return height / width;
|
||||
} else {
|
||||
return width / height;
|
||||
}
|
||||
}
|
||||
|
||||
return width / height;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const viewAssetHandler = (event: CustomEvent) => {
|
||||
@ -93,18 +101,29 @@
|
||||
|
||||
{#if assets.length > 0}
|
||||
<div class="flex flex-wrap gap-1 w-full pb-20" bind:clientWidth={viewWidth}>
|
||||
{#each assets as asset (asset.id)}
|
||||
<Thumbnail
|
||||
{asset}
|
||||
{thumbnailSize}
|
||||
readonly={disableAssetSelect}
|
||||
publicSharedKey={sharedLink?.key}
|
||||
format={assets.length < 7 ? ThumbnailFormat.Jpeg : ThumbnailFormat.Webp}
|
||||
on:click={(e) => (isMultiSelectionMode ? selectAssetHandler(e) : viewAssetHandler(e))}
|
||||
on:select={selectAssetHandler}
|
||||
selected={selectedAssets.has(asset)}
|
||||
/>
|
||||
{/each}
|
||||
{#if viewWidth}
|
||||
{@const geoArray = assets.map(getAssetRatio)}
|
||||
{@const justifiedLayoutResult = justifiedLayout(geoArray, {
|
||||
targetRowHeight: 235,
|
||||
containerWidth: Math.floor(viewWidth)
|
||||
})}
|
||||
|
||||
{#each assets as asset, index (asset.id)}
|
||||
<div animate:flip={{ duration: 500 }}>
|
||||
<Thumbnail
|
||||
{asset}
|
||||
thumbnailWidth={justifiedLayoutResult.boxes[index].width || 235}
|
||||
thumbnailHeight={justifiedLayoutResult.boxes[index].height || 235}
|
||||
readonly={disableAssetSelect}
|
||||
publicSharedKey={sharedLink?.key}
|
||||
format={assets.length < 7 ? ThumbnailFormat.Jpeg : ThumbnailFormat.Webp}
|
||||
on:click={(e) => (isMultiSelectionMode ? selectAssetHandler(e) : viewAssetHandler(e))}
|
||||
on:select={selectAssetHandler}
|
||||
selected={selectedAssets.has(asset)}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
Reference in New Issue
Block a user