mirror of
https://github.com/immich-app/immich.git
synced 2026-06-04 13:15:22 -04:00
e79a98fa82
Change-Id: I0a37b417ee4c247dcc93d442c976eede6a6a6964
75 lines
2.3 KiB
Svelte
75 lines
2.3 KiB
Svelte
<script lang="ts">
|
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
|
import { filterIntersecting } from '$lib/managers/timeline-manager/utils.svelte';
|
|
import type { ViewerAsset } from '$lib/managers/timeline-manager/viewer-asset.svelte';
|
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
|
import type { CommonPosition } from '$lib/utils/layout-utils';
|
|
import type { Snippet } from 'svelte';
|
|
import { flip } from 'svelte/animate';
|
|
import { scale } from 'svelte/transition';
|
|
|
|
type Props = {
|
|
animationTargetAssetId?: string | null;
|
|
suspendTransitions?: boolean;
|
|
viewerAssets: ViewerAsset[];
|
|
width: number;
|
|
height: number;
|
|
thumbnail: Snippet<
|
|
[
|
|
{
|
|
asset: TimelineAsset;
|
|
position: CommonPosition;
|
|
},
|
|
]
|
|
>;
|
|
customThumbnailLayout?: Snippet<[asset: TimelineAsset]>;
|
|
};
|
|
|
|
let { isUploading } = uploadAssetsStore;
|
|
|
|
const {
|
|
animationTargetAssetId,
|
|
suspendTransitions = false,
|
|
viewerAssets,
|
|
width,
|
|
height,
|
|
thumbnail,
|
|
customThumbnailLayout,
|
|
}: Props = $props();
|
|
|
|
const transitionDuration = $derived(suspendTransitions && !$isUploading ? 0 : 150);
|
|
const scaleDuration = $derived(transitionDuration === 0 ? 0 : transitionDuration + 100);
|
|
</script>
|
|
|
|
<!-- Image grid -->
|
|
<div data-image-grid class="relative overflow-clip" style:height={height + 'px'} style:width={width + 'px'}>
|
|
{#each filterIntersecting(viewerAssets) as viewerAsset (viewerAsset.id)}
|
|
{@const position = viewerAsset.position!}
|
|
{@const asset = viewerAsset.asset!}
|
|
{@const transitionName = animationTargetAssetId === asset.id ? 'hero' : undefined}
|
|
|
|
<!-- note: don't remove data-asset-id - its used by web e2e tests -->
|
|
<div
|
|
data-asset-id={asset.id}
|
|
class="absolute"
|
|
data-transition-name={transitionName}
|
|
style:view-transition-name={transitionName}
|
|
style:top={position.top + 'px'}
|
|
style:inset-inline-start={position.left + 'px'}
|
|
style:width={position.width + 'px'}
|
|
style:height={position.height + 'px'}
|
|
out:scale|global={{ start: 0.1, duration: scaleDuration }}
|
|
animate:flip={{ duration: transitionDuration }}
|
|
>
|
|
{@render thumbnail({ asset, position })}
|
|
{@render customThumbnailLayout?.(asset)}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
|
|
<style>
|
|
[data-image-grid] {
|
|
user-select: none;
|
|
}
|
|
</style>
|