Luís Alves 2025-12-11 06:35:52 +07:00 committed by GitHub
commit c29640ec9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 60 additions and 35 deletions

@ -33,6 +33,7 @@
"add_to_albums": "Add to albums", "add_to_albums": "Add to albums",
"add_to_albums_count": "Add to albums ({count})", "add_to_albums_count": "Add to albums ({count})",
"add_to_bottom_bar": "Add to", "add_to_bottom_bar": "Add to",
"add_to_merge": "Add to merge",
"add_to_shared_album": "Add to shared album", "add_to_shared_album": "Add to shared album",
"add_upload_to_stack": "Add upload to stack", "add_upload_to_stack": "Add upload to stack",
"add_url": "Add URL", "add_url": "Add URL",
@ -1516,6 +1517,7 @@
"only_favorites": "Only favorites", "only_favorites": "Only favorites",
"open": "Open", "open": "Open",
"open_in_map_view": "Open in map view", "open_in_map_view": "Open in map view",
"open_in_new_tab": "Open in new tab",
"open_in_openstreetmap": "Open in OpenStreetMap", "open_in_openstreetmap": "Open in OpenStreetMap",
"open_the_search_filters": "Open the search filters", "open_the_search_filters": "Open the search filters",
"options": "Options", "options": "Options",
@ -1713,6 +1715,7 @@
"remove_from_lock_folder_action_prompt": "{count} removed from the locked folder", "remove_from_lock_folder_action_prompt": "{count} removed from the locked folder",
"remove_from_locked_folder": "Remove from locked folder", "remove_from_locked_folder": "Remove from locked folder",
"remove_from_locked_folder_confirmation": "Are you sure you want to move these photos and videos out of the locked folder? They will be visible in your library.", "remove_from_locked_folder_confirmation": "Are you sure you want to move these photos and videos out of the locked folder? They will be visible in your library.",
"remove_from_merge": "Remove from merge",
"remove_from_shared_link": "Remove from shared link", "remove_from_shared_link": "Remove from shared link",
"remove_memory": "Remove memory", "remove_memory": "Remove memory",
"remove_photo_from_memory": "Remove photo from this memory", "remove_photo_from_memory": "Remove photo from this memory",

@ -1,6 +1,9 @@
<script lang="ts"> <script lang="ts">
import { getPeopleThumbnailUrl } from '$lib/utils'; import { getPeopleThumbnailUrl } from '$lib/utils';
import { type PersonResponseDto } from '@immich/sdk'; import { type PersonResponseDto } from '@immich/sdk';
import { IconButton } from '@immich/ui';
import { mdiMinus, mdiOpenInNew, mdiPlus } from '@mdi/js';
import { t } from 'svelte-i18n';
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte'; import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
interface Props { interface Props {
@ -22,47 +25,57 @@
border = false, border = false,
onClick = () => {}, onClick = () => {},
}: Props = $props(); }: Props = $props();
const handleAddToMerge = () => {
onClick(person);
};
</script> </script>
<button <div class="group relative" tabindex={selectable ? 0 : -1} role={selectable ? 'group' : undefined}>
type="button"
class="relative rounded-lg transition-all"
onclick={() => onClick(person)}
disabled={!selectable}
style:width={thumbnailSize ? thumbnailSize + 'px' : '100%'}
style:height={thumbnailSize ? thumbnailSize + 'px' : '100%'}
>
<div <div
class="h-full w-full border-2 brightness-90 filter" class="relative rounded-lg transition-all"
class:rounded-full={circle} style:width={thumbnailSize ? thumbnailSize + 'px' : '100%'}
class:rounded-lg={!circle} style:height={thumbnailSize ? thumbnailSize + 'px' : '100%'}
class:border-transparent={!border}
class:dark:border-immich-dark-primary={border}
class:border-immich-primary={border}
> >
<ImageThumbnail {circle} url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" shadow />
</div>
<div
class="absolute start-0 top-0 h-full w-full bg-immich-primary/30 opacity-0"
class:hover:opacity-100={selectable}
class:rounded-full={circle}
class:rounded-lg={!circle}
></div>
{#if selected}
<div <div
class="absolute start-0 top-0 h-full w-full bg-blue-500/80" class="h-full w-full border-2 brightness-90 filter"
class:rounded-full={circle} class:rounded-full={circle}
class:rounded-lg={!circle} class:rounded-lg={!circle}
></div> class:border-transparent={!border}
{/if} class:dark:border-immich-dark-primary={border}
class:border-immich-primary={border}
>
<ImageThumbnail {circle} url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" shadow />
</div>
{#if person.name} {#if person.name}
<span <span
class="w-100 text-white-shadow absolute bottom-2 start-0 w-full text-ellipsis px-1 text-center font-medium text-white hover:cursor-pointer" class="w-100 text-white-shadow absolute bottom-2 start-0 w-full text-ellipsis px-1 text-center font-medium text-white"
>
{person.name}
</span>
{/if}
</div>
{#if selectable}
<div
class="absolute left-1/2 -bottom-6 hidden -translate-x-1/2 gap-2 group-hover:flex group-focus-within:flex [@media(hover:none)]:flex"
> >
{person.name} <IconButton
</span> icon={mdiOpenInNew}
href="/people/{person.id}"
target="_blank"
aria-label={$t('open_in_new_tab')}
size="small"
color="primary"
/>
<IconButton
icon={selected ? mdiMinus : mdiPlus}
onclick={handleAddToMerge}
aria-label={selected ? $t('remove_from_merge') : $t('add_to_merge')}
size="small"
color="primary"
/>
</div>
{/if} {/if}
</button> </div>

@ -111,7 +111,15 @@
<div class="grid grid-flow-col-dense place-content-center place-items-center gap-4"> <div class="grid grid-flow-col-dense place-content-center place-items-center gap-4">
{#each selectedPeople as person (person.id)} {#each selectedPeople as person (person.id)}
<div animate:flip={{ duration: 250, easing: quintOut }}> <div animate:flip={{ duration: 250, easing: quintOut }}>
<FaceThumbnail border circle {person} selectable thumbnailSize={120} onClick={() => onSelect(person)} /> <FaceThumbnail
border
circle
{person}
selectable
selected
thumbnailSize={120}
onClick={() => onSelect(person)}
/>
</div> </div>
{/each} {/each}

@ -159,6 +159,7 @@
border border
circle circle
selectable selectable
selected
thumbnailSize={180} thumbnailSize={180}
onClick={handleRemoveSelectedPerson} onClick={handleRemoveSelectedPerson}
/> />