mirror of
https://github.com/immich-app/immich.git
synced 2025-12-19 09:13:14 +03:00
* chore(web): another missing translations * unused removed * more keys * lint fix * test fixed * dynamic translation fix * fixes * people search translation * params fixed * keep filter setting fix * lint fix * $t fixes * Update web/src/lib/i18n/en.json Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * another missing * activity translation * link sharing translations * expiration dropdown fix - didn't work localized * notification title * device logout * search results * reset to default * unsaved change * select from computer * selected * select-2 * select-3 * unmerge * pluralize, force icu message * Update web/src/lib/components/asset-viewer/asset-viewer.svelte Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * review fixes * remove user * plural fixes * ffmpeg settings * fixes * error title * plural fixes * onboarding * change password * more more * console log fix * another * api key desc * map marker * format fix * key fix * asset-utils * utils * misc --------- Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
247 lines
8.0 KiB
Svelte
247 lines
8.0 KiB
Svelte
<script lang="ts">
|
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
|
import DeleteButton from './delete-button.svelte';
|
|
import { user } from '$lib/stores/user.store';
|
|
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
|
import { getAssetJobName } from '$lib/utils';
|
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
|
import { AssetJobName, AssetTypeEnum, type AlbumResponseDto, type AssetResponseDto } from '@immich/sdk';
|
|
import {
|
|
mdiAccountCircleOutline,
|
|
mdiAlertOutline,
|
|
mdiArchiveArrowDownOutline,
|
|
mdiArchiveArrowUpOutline,
|
|
mdiArrowLeft,
|
|
mdiCogRefreshOutline,
|
|
mdiContentCopy,
|
|
mdiDatabaseRefreshOutline,
|
|
mdiDotsVertical,
|
|
mdiFolderDownloadOutline,
|
|
mdiHeart,
|
|
mdiHeartOutline,
|
|
mdiHistory,
|
|
mdiImageAlbum,
|
|
mdiImageMinusOutline,
|
|
mdiImageOutline,
|
|
mdiImageRefreshOutline,
|
|
mdiInformationOutline,
|
|
mdiMagnifyMinusOutline,
|
|
mdiMagnifyPlusOutline,
|
|
mdiMotionPauseOutline,
|
|
mdiPlaySpeed,
|
|
mdiPresentationPlay,
|
|
mdiShareVariantOutline,
|
|
mdiUpload,
|
|
} from '@mdi/js';
|
|
import { createEventDispatcher } from 'svelte';
|
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
|
import { t } from 'svelte-i18n';
|
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
|
|
|
export let asset: AssetResponseDto;
|
|
export let album: AlbumResponseDto | null = null;
|
|
export let showCopyButton: boolean;
|
|
export let showZoomButton: boolean;
|
|
export let showMotionPlayButton: boolean;
|
|
export let isMotionPhotoPlaying = false;
|
|
export let showDownloadButton: boolean;
|
|
export let showDetailButton: boolean;
|
|
export let showShareButton: boolean;
|
|
export let showSlideshow = false;
|
|
export let hasStackChildren = false;
|
|
export let onZoomImage: () => void;
|
|
export let onCopyImage: () => void;
|
|
|
|
$: isOwner = $user && asset.ownerId === $user?.id;
|
|
|
|
type EventTypes = {
|
|
back: void;
|
|
stopMotionPhoto: void;
|
|
playMotionPhoto: void;
|
|
download: void;
|
|
showDetail: void;
|
|
favorite: void;
|
|
delete: void;
|
|
permanentlyDelete: void;
|
|
toggleArchive: void;
|
|
addToAlbum: void;
|
|
restoreAsset: void;
|
|
addToSharedAlbum: void;
|
|
asProfileImage: void;
|
|
setAsAlbumCover: void;
|
|
runJob: AssetJobName;
|
|
playSlideShow: void;
|
|
unstack: void;
|
|
showShareModal: void;
|
|
};
|
|
|
|
const dispatch = createEventDispatcher<EventTypes>();
|
|
|
|
const onJobClick = (name: AssetJobName) => {
|
|
dispatch('runJob', name);
|
|
};
|
|
|
|
const onMenuClick = (eventName: keyof EventTypes) => {
|
|
dispatch(eventName);
|
|
};
|
|
</script>
|
|
|
|
<div
|
|
class="z-[1001] flex h-16 place-items-center justify-between bg-gradient-to-b from-black/40 px-3 transition-transform duration-200"
|
|
>
|
|
<div class="text-white">
|
|
<CircleIconButton color="opaque" icon={mdiArrowLeft} title={$t('go_back')} on:click={() => dispatch('back')} />
|
|
</div>
|
|
<div
|
|
class="flex w-[calc(100%-3rem)] justify-end gap-2 overflow-hidden text-white"
|
|
data-testid="asset-viewer-navbar-actions"
|
|
>
|
|
{#if showShareButton}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={mdiShareVariantOutline}
|
|
on:click={() => dispatch('showShareModal')}
|
|
title={$t('share')}
|
|
/>
|
|
{/if}
|
|
{#if asset.isOffline}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={mdiAlertOutline}
|
|
on:click={() => dispatch('showDetail')}
|
|
title={$t('asset_offline')}
|
|
/>
|
|
{/if}
|
|
{#if showMotionPlayButton}
|
|
{#if isMotionPhotoPlaying}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={mdiMotionPauseOutline}
|
|
title={$t('stop_motion_photo')}
|
|
on:click={() => dispatch('stopMotionPhoto')}
|
|
/>
|
|
{:else}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={mdiPlaySpeed}
|
|
title={$t('play_motion_photo')}
|
|
on:click={() => dispatch('playMotionPhoto')}
|
|
/>
|
|
{/if}
|
|
{/if}
|
|
{#if showZoomButton}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
hideMobile={true}
|
|
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
|
|
title={$t('zoom_image')}
|
|
on:click={onZoomImage}
|
|
/>
|
|
{/if}
|
|
{#if showCopyButton}
|
|
<CircleIconButton color="opaque" icon={mdiContentCopy} title={$t('copy_image')} on:click={onCopyImage} />
|
|
{/if}
|
|
|
|
{#if !isOwner && showDownloadButton}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={mdiFolderDownloadOutline}
|
|
on:click={() => dispatch('download')}
|
|
title={$t('download')}
|
|
/>
|
|
{/if}
|
|
|
|
{#if showDetailButton}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={mdiInformationOutline}
|
|
on:click={() => dispatch('showDetail')}
|
|
title={$t('info')}
|
|
/>
|
|
{/if}
|
|
|
|
{#if isOwner}
|
|
<CircleIconButton
|
|
color="opaque"
|
|
icon={asset.isFavorite ? mdiHeart : mdiHeartOutline}
|
|
on:click={() => dispatch('favorite')}
|
|
title={asset.isFavorite ? $t('unfavorite') : $t('to_favorite')}
|
|
/>
|
|
{/if}
|
|
|
|
{#if isOwner}
|
|
<DeleteButton
|
|
{asset}
|
|
on:delete={() => dispatch('delete')}
|
|
on:permanentlyDelete={() => dispatch('permanentlyDelete')}
|
|
/>
|
|
<ButtonContextMenu direction="left" align="top-right" color="opaque" title={$t('more')} icon={mdiDotsVertical}>
|
|
{#if showSlideshow}
|
|
<MenuOption icon={mdiPresentationPlay} onClick={() => onMenuClick('playSlideShow')} text={$t('slideshow')} />
|
|
{/if}
|
|
{#if showDownloadButton}
|
|
<MenuOption icon={mdiFolderDownloadOutline} onClick={() => onMenuClick('download')} text={$t('download')} />
|
|
{/if}
|
|
{#if asset.isTrashed}
|
|
<MenuOption icon={mdiHistory} onClick={() => onMenuClick('restoreAsset')} text={$t('restore')} />
|
|
{:else}
|
|
<MenuOption icon={mdiImageAlbum} onClick={() => onMenuClick('addToAlbum')} text={$t('add_to_album')} />
|
|
<MenuOption
|
|
icon={mdiShareVariantOutline}
|
|
onClick={() => onMenuClick('addToSharedAlbum')}
|
|
text={$t('add_to_shared_album')}
|
|
/>
|
|
{/if}
|
|
|
|
{#if isOwner}
|
|
{#if hasStackChildren}
|
|
<MenuOption icon={mdiImageMinusOutline} onClick={() => onMenuClick('unstack')} text={$t('unstack')} />
|
|
{/if}
|
|
{#if album}
|
|
<MenuOption
|
|
text={$t('set_as_album_cover')}
|
|
icon={mdiImageOutline}
|
|
onClick={() => onMenuClick('setAsAlbumCover')}
|
|
/>
|
|
{/if}
|
|
{#if asset.type === AssetTypeEnum.Image}
|
|
<MenuOption
|
|
icon={mdiAccountCircleOutline}
|
|
onClick={() => onMenuClick('asProfileImage')}
|
|
text={$t('set_as_profile_picture')}
|
|
/>
|
|
{/if}
|
|
<MenuOption
|
|
onClick={() => onMenuClick('toggleArchive')}
|
|
icon={asset.isArchived ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline}
|
|
text={asset.isArchived ? $t('unarchive') : $t('to_archive')}
|
|
/>
|
|
<MenuOption
|
|
icon={mdiUpload}
|
|
onClick={() => openFileUploadDialog({ multiple: false, assetId: asset.id })}
|
|
text={$t('replace_with_upload')}
|
|
/>
|
|
<hr />
|
|
<MenuOption
|
|
icon={mdiDatabaseRefreshOutline}
|
|
onClick={() => onJobClick(AssetJobName.RefreshMetadata)}
|
|
text={$getAssetJobName(AssetJobName.RefreshMetadata)}
|
|
/>
|
|
<MenuOption
|
|
icon={mdiImageRefreshOutline}
|
|
onClick={() => onJobClick(AssetJobName.RegenerateThumbnail)}
|
|
text={$getAssetJobName(AssetJobName.RegenerateThumbnail)}
|
|
/>
|
|
{#if asset.type === AssetTypeEnum.Video}
|
|
<MenuOption
|
|
icon={mdiCogRefreshOutline}
|
|
onClick={() => onJobClick(AssetJobName.TranscodeVideo)}
|
|
text={$getAssetJobName(AssetJobName.TranscodeVideo)}
|
|
/>
|
|
{/if}
|
|
{/if}
|
|
</ButtonContextMenu>
|
|
{/if}
|
|
</div>
|
|
</div>
|