mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
perf(web): optimize images and modules (#7088)
* perf: optimize images and modules * fix: tests * fix: missing font * fix: delay showing the loading spinner * simplify * simplify * pr feedback * chore: merge main * fix: enum --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
parent
3480fe5326
commit
36e5d298db
10 changed files with 796 additions and 59 deletions
|
|
@ -1,6 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { api } from '$lib/api';
|
||||
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
|
|
@ -21,7 +20,7 @@
|
|||
|
||||
$: imageData = album.albumThumbnailAssetId
|
||||
? getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Webp)
|
||||
: noThumbnailUrl;
|
||||
: null;
|
||||
|
||||
const dispatchClick = createEventDispatcher<OnClick>();
|
||||
const dispatchShowContextMenu = createEventDispatcher<OnShowContextMenu>();
|
||||
|
|
@ -50,7 +49,7 @@
|
|||
dispatchShowContextMenu('showalbumcontextmenu', getContextMenuPosition(e));
|
||||
|
||||
onMount(async () => {
|
||||
imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || noThumbnailUrl;
|
||||
imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || null;
|
||||
});
|
||||
|
||||
const getAlbumOwnerInfo = () => getUserById({ id: album.ownerId });
|
||||
|
|
@ -81,15 +80,26 @@
|
|||
{/if}
|
||||
|
||||
<div class={`relative aspect-square`}>
|
||||
<img
|
||||
loading={preload ? 'eager' : 'lazy'}
|
||||
src={imageData}
|
||||
alt={album.id}
|
||||
class={`z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg`}
|
||||
data-testid="album-image"
|
||||
draggable="false"
|
||||
/>
|
||||
<div class="absolute top-0 h-full w-full rounded-3xl" />
|
||||
{#if album.albumThumbnailAssetId}
|
||||
<img
|
||||
loading={preload ? 'eager' : 'lazy'}
|
||||
src={imageData}
|
||||
alt={album.id}
|
||||
class="z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg"
|
||||
data-testid="album-image"
|
||||
draggable="false"
|
||||
/>
|
||||
{:else}
|
||||
<enhanced:img
|
||||
loading={preload ? 'eager' : 'lazy'}
|
||||
src="$lib/assets/no-thumbnail.png"
|
||||
sizes="min(271px,186px)"
|
||||
alt={album.id}
|
||||
class="z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg"
|
||||
data-testid="album-image"
|
||||
draggable="false"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<script lang="ts">
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
import { AppRoute, QueryParameter, timeToLoadTheMap } from '$lib/constants';
|
||||
import { boundingBoxesArray } from '$lib/stores/people.store';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { websocketEvents } from '$lib/stores/websocket';
|
||||
import { getAssetThumbnailUrl, getPeopleThumbnailUrl, isSharedLink } from '$lib/utils';
|
||||
import { getAssetFilename } from '$lib/utils/asset-utils';
|
||||
import { delay, getAssetFilename } from '$lib/utils/asset-utils';
|
||||
import { autoGrowHeight } from '$lib/utils/autogrow';
|
||||
import { clickOutside } from '$lib/utils/click-outside';
|
||||
import {
|
||||
|
|
@ -38,8 +38,8 @@
|
|||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||
import PersonSidePanel from '../faces-page/person-side-panel.svelte';
|
||||
import ChangeLocation from '../shared-components/change-location.svelte';
|
||||
import Map from '../shared-components/map/map.svelte';
|
||||
import UserAvatar from '../shared-components/user-avatar.svelte';
|
||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
||||
|
||||
export let asset: AssetResponseDto;
|
||||
export let albums: AlbumResponseDto[] = [];
|
||||
|
|
@ -609,27 +609,37 @@
|
|||
|
||||
{#if latlng && $featureFlags.loaded && $featureFlags.map}
|
||||
<div class="h-[360px]">
|
||||
<Map
|
||||
mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]}
|
||||
center={latlng}
|
||||
zoom={15}
|
||||
simplified
|
||||
useLocationPin
|
||||
>
|
||||
<svelte:fragment slot="popup" let:marker>
|
||||
{@const { lat, lon } = marker}
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<p class="font-bold">{lat.toPrecision(6)}, {lon.toPrecision(6)}</p>
|
||||
<a
|
||||
href="https://www.openstreetmap.org/?mlat={lat}&mlon={lon}&zoom=15#map=15/{lat}/{lon}"
|
||||
target="_blank"
|
||||
class="font-medium text-immich-primary"
|
||||
>
|
||||
Open in OpenStreetMap
|
||||
</a>
|
||||
{#await import('../shared-components/map/map.svelte')}
|
||||
{#await delay(timeToLoadTheMap) then}
|
||||
<!-- show the loading spinner only if loading the map takes too much time -->
|
||||
<div class="flex items-center justify-center h-full w-full">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Map>
|
||||
{/await}
|
||||
{:then component}
|
||||
<svelte:component
|
||||
this={component.default}
|
||||
mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]}
|
||||
center={latlng}
|
||||
zoom={15}
|
||||
simplified
|
||||
useLocationPin
|
||||
>
|
||||
<svelte:fragment slot="popup" let:marker>
|
||||
{@const { lat, lon } = marker}
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<p class="font-bold">{lat.toPrecision(6)}, {lon.toPrecision(6)}</p>
|
||||
<a
|
||||
href="https://www.openstreetmap.org/?mlat={lat}&mlon={lon}&zoom=15#map=15/{lat}/{lon}"
|
||||
target="_blank"
|
||||
class="font-medium text-immich-primary"
|
||||
>
|
||||
Open in OpenStreetMap
|
||||
</a>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</svelte:component>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,14 +168,22 @@
|
|||
class:hover:opacity-70={previousMemory}
|
||||
>
|
||||
<button class="relative h-full w-full rounded-2xl" disabled={!previousMemory} on:click={toPreviousMemory}>
|
||||
<img
|
||||
class="h-full w-full rounded-2xl object-cover"
|
||||
src={previousMemory
|
||||
? getAssetThumbnailUrl(previousMemory.assets[0].id, ThumbnailFormat.Jpeg)
|
||||
: noThumbnailUrl}
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
{#if previousMemory}
|
||||
<img
|
||||
class="h-full w-full rounded-2xl object-cover"
|
||||
src={getAssetThumbnailUrl(previousMemory.assets[0].id, ThumbnailFormat.Jpeg)}
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
{:else}
|
||||
<enhanced:img
|
||||
class="h-full w-full rounded-2xl object-cover"
|
||||
src={noThumbnailUrl}
|
||||
sizes="min(271px,186px)"
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if previousMemory}
|
||||
<div class="absolute bottom-4 right-4 text-left text-white">
|
||||
|
|
@ -233,12 +241,22 @@
|
|||
class:hover:opacity-70={nextMemory}
|
||||
>
|
||||
<button class="relative h-full w-full rounded-2xl" on:click={toNextMemory} disabled={!nextMemory}>
|
||||
<img
|
||||
class="h-full w-full rounded-2xl object-cover"
|
||||
src={nextMemory ? getAssetThumbnailUrl(nextMemory.assets[0].id, ThumbnailFormat.Jpeg) : noThumbnailUrl}
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
{#if nextMemory}
|
||||
<img
|
||||
class="h-full w-full rounded-2xl object-cover"
|
||||
src={getAssetThumbnailUrl(nextMemory.assets[0].id, ThumbnailFormat.Jpeg)}
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
{:else}
|
||||
<enhanced:img
|
||||
class="h-full w-full rounded-2xl object-cover"
|
||||
src={noThumbnailUrl}
|
||||
sizes="min(271px,186px)"
|
||||
alt=""
|
||||
draggable="false"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if nextMemory}
|
||||
<div class="absolute bottom-4 left-4 text-left text-white">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import ConfirmDialogue from './confirm-dialogue.svelte';
|
||||
import Map from './map/map.svelte';
|
||||
import LoadingSpinner from './loading-spinner.svelte';
|
||||
import { delay } from '$lib/utils/asset-utils';
|
||||
import { timeToLoadTheMap } from '$lib/constants';
|
||||
|
||||
export const title = 'Change Location';
|
||||
export let asset: AssetResponseDto | undefined = undefined;
|
||||
|
||||
|
|
@ -48,14 +51,24 @@
|
|||
<div slot="prompt" class="flex flex-col w-full h-full gap-2">
|
||||
<label for="datetime">Pick a location</label>
|
||||
<div class="h-[500px] min-h-[300px] w-full">
|
||||
<Map
|
||||
mapMarkers={lat && lng && asset ? [{ id: asset.id, lat, lon: lng }] : []}
|
||||
{zoom}
|
||||
center={lat && lng ? { lat, lng } : undefined}
|
||||
simplified={true}
|
||||
clickable={true}
|
||||
on:clickedPoint={({ detail: point }) => handleSelect(point)}
|
||||
/>
|
||||
{#await import('../shared-components/map/map.svelte')}
|
||||
{#await delay(timeToLoadTheMap) then}
|
||||
<!-- show the loading spinner only if loading the map takes too much time -->
|
||||
<div class="flex items-center justify-center h-full w-full">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
{/await}
|
||||
{:then component}
|
||||
<svelte:component
|
||||
this={component.default}
|
||||
mapMarkers={lat && lng && asset ? [{ id: asset.id, lat, lon: lng }] : []}
|
||||
{zoom}
|
||||
center={lat && lng ? { lat, lng } : undefined}
|
||||
simplified={true}
|
||||
clickable={true}
|
||||
on:clickedPoint={({ detail: point }) => handleSelect(point)}
|
||||
/>
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
</ConfirmDialogue>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
/>
|
||||
{/await}
|
||||
{:else}
|
||||
<img
|
||||
<enhanced:img
|
||||
src={noThumbnailUrl}
|
||||
alt={'Album without assets'}
|
||||
class="h-[100px] w-[100px] rounded-lg object-cover"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue