feat: shared person indicator (#32223)

* feat: shared person indicator

* fix: styles

---------

Co-authored-by: Jason Rasmussen <[email protected]>
This commit is contained in:
Daniel Dietzler
2026-10-08 14:47:33 -04:00
committed by GitHub
co-authored by Jason Rasmussen
parent 9640d9f5d2
commit a3c52d1396
3 changed files with 45 additions and 24 deletions
@@ -0,0 +1,26 @@
<script lang="ts">
import type { PersonResponseDto } from '@immich/sdk';
import { Icon } from '@immich/ui';
import { mdiAccountMultiple, mdiHeart } from '@mdi/js';
import { t } from 'svelte-i18n';
type Props = {
person: PersonResponseDto;
};
let { person }: Props = $props();
</script>
{#if person.isFavorite || person.otherPeople.length > 0}
<div
class="absolute inset-e-[14.6%] bottom-[14.6%] flex translate-1/2 items-center gap-[0.25em] rounded-full border-primary bg-light-200 p-[0.25em] text-[max(10cqw,12px)] text-dark rtl:-translate-x-1/2 dark:bg-immich-dark-gray"
>
{#if person.isFavorite}
<Icon icon={mdiHeart} size="1em" title={$t('favorite')} />
{/if}
{#if person.otherPeople.length > 0}
<Icon icon={mdiAccountMultiple} size="1em" title={$t('shared_with_me')} />
{/if}
</div>
{/if}
+13 -15
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import ImageThumbnail from '$lib/components/assets/thumbnail/ImageThumbnail.svelte';
import PersonIndicator from '$lib/components/faces-page/PersonIndicator.svelte';
import UserPageLayout from '$lib/components/layouts/UserPageLayout.svelte';
import OnEvents from '$lib/components/OnEvents.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/EmptyPlaceholder.svelte';
@@ -10,8 +11,7 @@
import { getAssetInfo, AssetMediaSize, type SearchExploreResponseDto } from '@immich/sdk';
import { authManager } from '$lib/managers/auth-manager.svelte';
import MemoryCard from '$lib/components/memories/MemoryCard.svelte';
import { Icon, ImageCarousel } from '@immich/ui';
import { mdiHeart } from '@mdi/js';
import { ImageCarousel } from '@immich/ui';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
import { toTimelineAsset } from '$lib/utils/timeline-util';
@@ -81,19 +81,17 @@
<SingleGridRow class="grid grid-flow-col grid-auto-fill-20 gap-x-4 md:grid-auto-fill-28">
{#snippet children({ itemCount })}
{#each people.slice(0, itemCount) as person (person.id)}
<a href={Route.viewPerson(person)} class="relative text-center">
<ImageThumbnail
circle
shadow
url={getPeopleThumbnailUrl(person)}
altText={person.name}
widthStyle="100%"
/>
{#if person.isFavorite}
<div class="absolute inset-s-2 top-2">
<Icon icon={mdiHeart} size="24" class="text-white" />
</div>
{/if}
<a href={Route.viewPerson(person)} class="text-center">
<div class="@container relative">
<ImageThumbnail
circle
shadow
url={getPeopleThumbnailUrl(person)}
altText={person.name}
widthStyle="100%"
/>
<PersonIndicator {person} />
</div>
<p class="mt-2 text-sm font-medium text-ellipsis dark:text-white">{person.name}</p>
</a>
{/each}
@@ -1,12 +1,13 @@
<script lang="ts">
import ImageThumbnail from '$lib/components/assets/thumbnail/ImageThumbnail.svelte';
import PersonIndicator from '$lib/components/faces-page/PersonIndicator.svelte';
import { Route } from '$lib/route';
import { getPersonActions } from '$lib/services/person.service';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { type PersonResponseDto } from '@immich/sdk';
import { ContextMenuButton, Icon } from '@immich/ui';
import { mdiAccountMultipleCheckOutline, mdiHeart } from '@mdi/js';
import { ContextMenuButton } from '@immich/ui';
import { mdiAccountMultipleCheckOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import ImageThumbnail from '$lib/components/assets/thumbnail/ImageThumbnail.svelte';
type Props = {
person: PersonResponseDto;
@@ -33,7 +34,7 @@
<div id="people-card" class="relative" role="group">
<a href={Route.viewPerson(person, { previousRoute: Route.people() })} draggable="false" class="group">
<div class="size-full rounded-xl brightness-95 filter">
<div class="@container relative size-full rounded-xl brightness-95 filter">
<ImageThumbnail
shadow
url={getPeopleThumbnailUrl(person)}
@@ -43,11 +44,7 @@
circle
preload={false}
/>
{#if person.isFavorite}
<div class="absolute inset-s-4 top-4">
<Icon icon={mdiHeart} size="24" class="text-white" />
</div>
{/if}
<PersonIndicator {person} />
</div>
<div class="absolute inset-e-2 top-2 opacity-0 group-hover:opacity-100 focus-within:opacity-100">