mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 17:25:35 +03:00
* feat(web): Lazy load thumbnails on the people page Instead of loading all people thumbnails at once, only the first few should be loaded eagerly. This reduces the load on client and server side. * chore: change name --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
92 lines
3.0 KiB
Svelte
92 lines
3.0 KiB
Svelte
<script lang="ts">
|
|
import { PersonResponseDto, api } from '@api';
|
|
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
|
import IconButton from '../elements/buttons/icon-button.svelte';
|
|
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
|
import Portal from '../shared-components/portal/portal.svelte';
|
|
import { createEventDispatcher } from 'svelte';
|
|
import { AppRoute } from '$lib/constants';
|
|
import { mdiDotsVertical } from '@mdi/js';
|
|
import Icon from '$lib/components/elements/icon.svelte';
|
|
|
|
export let person: PersonResponseDto;
|
|
export let preload = false;
|
|
|
|
type MenuItemEvent = 'change-name' | 'set-birth-date' | 'merge-faces' | 'hide-face';
|
|
let dispatch = createEventDispatcher<{
|
|
'change-name': void;
|
|
'set-birth-date': void;
|
|
'merge-faces': void;
|
|
'hide-face': void;
|
|
}>();
|
|
|
|
let showVerticalDots = false;
|
|
let showContextMenu = false;
|
|
let contextMenuPosition = { x: 0, y: 0 };
|
|
const showMenu = (event: MouseEvent) => {
|
|
contextMenuPosition = getContextMenuPosition(event);
|
|
showContextMenu = !showContextMenu;
|
|
};
|
|
const onMenuExit = () => {
|
|
showContextMenu = false;
|
|
};
|
|
const onMenuClick = (event: MenuItemEvent) => {
|
|
onMenuExit();
|
|
dispatch(event);
|
|
};
|
|
</script>
|
|
|
|
<div
|
|
id="people-card"
|
|
class="relative"
|
|
on:mouseenter={() => (showVerticalDots = true)}
|
|
on:mouseleave={() => (showVerticalDots = false)}
|
|
role="group"
|
|
>
|
|
<a href="/people/{person.id}?previousRoute={AppRoute.PEOPLE}" draggable="false">
|
|
<div class="h-48 w-48 rounded-xl brightness-95 filter">
|
|
<ImageThumbnail
|
|
shadow
|
|
{preload}
|
|
url={api.getPeopleThumbnailUrl(person.id)}
|
|
altText={person.name}
|
|
title={person.name}
|
|
widthStyle="100%"
|
|
/>
|
|
</div>
|
|
{#if person.name}
|
|
<span
|
|
class="text-white-shadow absolute bottom-2 left-0 w-full select-text px-1 text-center font-medium text-white"
|
|
title={person.name}
|
|
>
|
|
{person.name}
|
|
</span>
|
|
{/if}
|
|
</a>
|
|
|
|
<button
|
|
class="absolute right-2 top-2"
|
|
on:click|stopPropagation|preventDefault={showMenu}
|
|
class:hidden={!showVerticalDots}
|
|
data-testid="context-button-parent"
|
|
id={`icon-${person.id}`}
|
|
>
|
|
<IconButton color="transparent-primary">
|
|
<Icon path={mdiDotsVertical} size="20" class="icon-white-drop-shadow text-white" />
|
|
</IconButton>
|
|
</button>
|
|
</div>
|
|
|
|
{#if showContextMenu}
|
|
<Portal target="body">
|
|
<ContextMenu {...contextMenuPosition} on:outclick={() => onMenuExit()}>
|
|
<MenuOption on:click={() => onMenuClick('hide-face')} text="Hide face" />
|
|
<MenuOption on:click={() => onMenuClick('change-name')} text="Change name" />
|
|
<MenuOption on:click={() => onMenuClick('set-birth-date')} text="Set date of birth" />
|
|
<MenuOption on:click={() => onMenuClick('merge-faces')} text="Merge faces" />
|
|
</ContextMenu>
|
|
</Portal>
|
|
{/if}
|