mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat(web): manual face tagging and deletion (#16062)
This commit is contained in:
parent
94c0e8253a
commit
007eaaceb9
35 changed files with 2054 additions and 106 deletions
|
|
@ -13,9 +13,10 @@
|
|||
AssetTypeEnum,
|
||||
type AssetFaceResponseDto,
|
||||
type PersonResponseDto,
|
||||
deleteFace,
|
||||
} from '@immich/sdk';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import { mdiAccountOff, mdiArrowLeftThin, mdiPencil, mdiRestart } from '@mdi/js';
|
||||
import { mdiAccountOff, mdiArrowLeftThin, mdiPencil, mdiRestart, mdiTrashCan } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { linear } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
|
|
@ -24,8 +25,10 @@
|
|||
import AssignFaceSidePanel from './assign-face-side-panel.svelte';
|
||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||
import { zoomImageToBase64 } from '$lib/utils/people-utils';
|
||||
import { photoViewer } from '$lib/stores/assets.store';
|
||||
import { photoViewerImgElement } from '$lib/stores/assets.store';
|
||||
import { t } from 'svelte-i18n';
|
||||
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
|
||||
interface Props {
|
||||
assetId: string;
|
||||
|
|
@ -163,6 +166,30 @@
|
|||
editedFace = face;
|
||||
showSelectedFaces = true;
|
||||
};
|
||||
|
||||
const deleteAssetFace = async (face: AssetFaceResponseDto) => {
|
||||
try {
|
||||
if (!face.person) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isConfirmed = await dialogController.show({
|
||||
prompt: $t('confirm_delete_face', { values: { name: face.person.name } }),
|
||||
});
|
||||
|
||||
if (!isConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
await deleteFace({ id: face.id, assetFaceDeleteDto: { force: false } });
|
||||
|
||||
peopleWithFaces = peopleWithFaces.filter((f) => f.id !== face.id);
|
||||
|
||||
await assetViewingStore.setAssetId(assetId);
|
||||
} catch (error) {
|
||||
handleError(error, $t('error_delete_face'));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<section
|
||||
|
|
@ -242,7 +269,7 @@
|
|||
hidden={face.person.isHidden}
|
||||
/>
|
||||
{:else}
|
||||
{#await zoomImageToBase64(face, assetId, assetType, $photoViewer)}
|
||||
{#await zoomImageToBase64(face, assetId, assetType, $photoViewerImgElement)}
|
||||
<ImageThumbnail
|
||||
curve
|
||||
shadow
|
||||
|
|
@ -308,6 +335,19 @@
|
|||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if face.person != null}
|
||||
<div class="absolute -right-[5px] top-[25px] h-[20px] w-[20px] rounded-full">
|
||||
<CircleIconButton
|
||||
color="red"
|
||||
icon={mdiTrashCan}
|
||||
title={$t('delete_face')}
|
||||
size="18"
|
||||
padding="1"
|
||||
class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"
|
||||
onclick={() => deleteAssetFace(face)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue