fix: z-index war in the asset viewer ()

This commit is contained in:
Daniel Dietzler 2025-05-09 16:17:26 +02:00 committed by GitHub
parent cb6c541ae1
commit 89551edee5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 47 additions and 49 deletions

View file

@ -7,6 +7,7 @@
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
import DownloadAction from '$lib/components/asset-viewer/actions/download-action.svelte';
import FavoriteAction from '$lib/components/asset-viewer/actions/favorite-action.svelte';
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
import RestoreAction from '$lib/components/asset-viewer/actions/restore-action.svelte';
import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/set-album-cover-action.svelte';
import SetFeaturedPhotoAction from '$lib/components/asset-viewer/actions/set-person-featured-action.svelte';
@ -14,7 +15,6 @@
import ShareAction from '$lib/components/asset-viewer/actions/share-action.svelte';
import ShowDetailAction from '$lib/components/asset-viewer/actions/show-detail-action.svelte';
import UnstackAction from '$lib/components/asset-viewer/actions/unstack-action.svelte';
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
@ -22,6 +22,7 @@
import { user } from '$lib/stores/user.store';
import { photoZoomState } from '$lib/stores/zoom-image.store';
import { getAssetJobName, getSharedLink } from '$lib/utils';
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import {
AssetJobName,
@ -45,9 +46,8 @@
mdiPresentationPlay,
mdiUpload,
} from '@mdi/js';
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
import { t } from 'svelte-i18n';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
interface Props {
asset: AssetResponseDto;
@ -104,7 +104,7 @@
</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"
class="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">
{#if showCloseButton}

View file

@ -4,6 +4,7 @@
import MotionPhotoAction from '$lib/components/asset-viewer/actions/motion-photo-action.svelte';
import NextAssetAction from '$lib/components/asset-viewer/actions/next-asset-action.svelte';
import PreviousAssetAction from '$lib/components/asset-viewer/actions/previous-asset-action.svelte';
import AssetViewerNavBar from '$lib/components/asset-viewer/asset-viewer-nav-bar.svelte';
import { AssetAction, ProjectionType } from '$lib/constants';
import { activityManager } from '$lib/managers/activity-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
@ -34,7 +35,6 @@
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import ActivityStatus from './activity-status.svelte';
import ActivityViewer from './activity-viewer.svelte';
import AssetViewerNavBar from './asset-viewer-nav-bar.svelte';
import DetailPanel from './detail-panel.svelte';
import CropArea from './editor/crop-tool/crop-area.svelte';
import EditorPanel from './editor/editor-panel.svelte';
@ -379,12 +379,13 @@
<section
id="immich-asset-viewer"
class="fixed start-0 top-0 z-[1001] grid size-full grid-cols-4 grid-rows-[64px_1fr] overflow-hidden bg-black"
class="fixed start-0 top-0 grid size-full grid-cols-4 grid-rows-[64px_1fr] overflow-hidden bg-black"
use:focusTrap
bind:this={assetViewerHtmlElement}
>
<!-- Top navigation bar -->
{#if $slideshowState === SlideshowState.None && !isShowEditor}
<div class="z-[1002] col-span-4 col-start-1 row-span-1 row-start-1 transition-transform">
<div class="col-span-4 col-start-1 row-span-1 row-start-1 transition-transform">
<AssetViewerNavBar
{asset}
{album}
@ -412,26 +413,26 @@
</div>
{/if}
{#if $slideshowState != SlideshowState.None}
<div class="absolute w-full flex">
<SlideshowBar
{isFullScreen}
onSetToFullScreen={() => assetViewerHtmlElement?.requestFullscreen?.()}
onPrevious={() => navigateAsset('previous')}
onNext={() => navigateAsset('next')}
onClose={() => ($slideshowState = SlideshowState.StopSlideshow)}
/>
</div>
{/if}
{#if $slideshowState === SlideshowState.None && showNavigation && !isShowEditor}
<div class="z-[1001] my-auto column-span-1 col-start-1 row-span-full row-start-1 justify-self-start">
<div class="my-auto column-span-1 col-start-1 row-span-full row-start-1 justify-self-start">
<PreviousAssetAction onPreviousAsset={() => navigateAsset('previous')} />
</div>
{/if}
<!-- Asset Viewer -->
<div class="z-[1000] relative col-start-1 col-span-4 row-start-1 row-span-full" bind:this={assetViewerHtmlElement}>
{#if $slideshowState != SlideshowState.None}
<div class="z-[1000] absolute w-full flex">
<SlideshowBar
{isFullScreen}
onSetToFullScreen={() => assetViewerHtmlElement?.requestFullscreen?.()}
onPrevious={() => navigateAsset('previous')}
onNext={() => navigateAsset('next')}
onClose={() => ($slideshowState = SlideshowState.StopSlideshow)}
/>
</div>
{/if}
<div class="z-[-1] relative col-start-1 col-span-4 row-start-1 row-span-full">
{#if previewStackedAsset}
{#key previewStackedAsset.id}
{#if previewStackedAsset.type === AssetTypeEnum.Image}
@ -504,7 +505,7 @@
/>
{/if}
{#if $slideshowState === SlideshowState.None && isShared && ((album && album.isActivityEnabled) || activityManager.commentCount > 0)}
<div class="z-[9999] absolute bottom-0 end-0 mb-20 me-8">
<div class="absolute bottom-0 end-0 mb-20 me-8">
<ActivityStatus
disabled={!album?.isActivityEnabled}
isLiked={activityManager.isLiked}
@ -519,7 +520,7 @@
</div>
{#if $slideshowState === SlideshowState.None && showNavigation && !isShowEditor}
<div class="z-[1001] my-auto col-span-1 col-start-4 row-span-full row-start-1 justify-self-end">
<div class="my-auto col-span-1 col-start-4 row-span-full row-start-1 justify-self-end">
<NextAssetAction onNextAsset={() => navigateAsset('next')} />
</div>
{/if}
@ -528,7 +529,7 @@
<div
transition:fly={{ duration: 150 }}
id="detail-panel"
class="z-[1002] row-start-1 row-span-4 w-[360px] overflow-y-auto bg-immich-bg transition-all dark:border-l dark:border-s-immich-dark-gray dark:bg-immich-dark-bg"
class="row-start-1 row-span-4 w-[360px] overflow-y-auto bg-immich-bg transition-all dark:border-l dark:border-s-immich-dark-gray dark:bg-immich-dark-bg"
translate="yes"
>
<DetailPanel {asset} currentAlbum={album} albums={appearsInAlbums} onClose={() => ($isShowDetail = false)} />
@ -539,7 +540,7 @@
<div
transition:fly={{ duration: 150 }}
id="editor-panel"
class="z-[1002] row-start-1 row-span-4 w-[400px] overflow-y-auto bg-immich-bg transition-all dark:border-l dark:border-s-immich-dark-gray dark:bg-immich-dark-bg"
class="row-start-1 row-span-4 w-[400px] overflow-y-auto bg-immich-bg transition-all dark:border-l dark:border-s-immich-dark-gray dark:bg-immich-dark-bg"
translate="yes"
>
<EditorPanel {asset} onUpdateSelectedType={handleUpdateSelectedEditType} onClose={closeEditor} />
@ -550,7 +551,7 @@
{@const stackedAssets = stack.assets}
<div
id="stack-slideshow"
class="z-[1002] flex place-item-center place-content-center absolute bottom-0 w-full col-span-4 col-start-1 overflow-x-auto horizontal-scrollbar"
class="flex place-item-center place-content-center absolute bottom-0 w-full col-span-4 col-start-1 overflow-x-auto horizontal-scrollbar"
>
<div class="relative w-full">
{#each stackedAssets as stackedAsset (stackedAsset.id)}
@ -588,7 +589,7 @@
<div
transition:fly={{ duration: 150 }}
id="activity-panel"
class="z-[1002] row-start-1 row-span-5 w-[360px] md:w-[460px] overflow-y-auto bg-immich-bg transition-all dark:border-l dark:border-s-immich-dark-gray dark:bg-immich-dark-bg"
class="row-start-1 row-span-5 w-[360px] md:w-[460px] overflow-y-auto bg-immich-bg transition-all dark:border-l dark:border-s-immich-dark-gray dark:bg-immich-dark-bg"
translate="yes"
>
<ActivityViewer

View file

@ -6,7 +6,6 @@
import DetailPanelTags from '$lib/components/asset-viewer/detail-panel-tags.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import { AppRoute, QueryParameter, timeToLoadTheMap } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
@ -355,14 +354,12 @@
{/if}
{#if isShowChangeDate}
<Portal>
<ChangeDate
initialDate={dateTime}
initialTimeZone={timeZone ?? ''}
onConfirm={handleConfirmChangeDate}
onCancel={() => (isShowChangeDate = false)}
/>
</Portal>
<ChangeDate
initialDate={dateTime}
initialTimeZone={timeZone ?? ''}
onConfirm={handleConfirmChangeDate}
onCancel={() => (isShowChangeDate = false)}
/>
{/if}
<div class="flex gap-4 py-4">

View file

@ -1,27 +1,27 @@
<script lang="ts">
import { shortcuts } from '$lib/actions/shortcut';
import { zoomImageAction, zoomed } from '$lib/actions/zoom-image';
import FaceEditor from '$lib/components/asset-viewer/face-editor/face-editor.svelte';
import BrokenAsset from '$lib/components/assets/broken-asset.svelte';
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { boundingBoxesArray } from '$lib/stores/people.store';
import { alwaysLoadOriginalFile } from '$lib/stores/preferences.store';
import { SlideshowLook, SlideshowState, slideshowLookCssMapping, slideshowStore } from '$lib/stores/slideshow.store';
import { photoZoomState } from '$lib/stores/zoom-image.store';
import { getAssetOriginalUrl, getAssetThumbnailUrl, handlePromiseError } from '$lib/utils';
import { canCopyImageToClipboard, copyImageToClipboard, isWebCompatibleImage } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { getBoundingBox } from '$lib/utils/people-utils';
import { cancelImageUrl, preloadImageUrl } from '$lib/utils/sw-messaging';
import { getAltText } from '$lib/utils/thumbnail-util';
import { AssetMediaSize, AssetTypeEnum, type AssetResponseDto, type SharedLinkResponseDto } from '@immich/sdk';
import { onDestroy, onMount } from 'svelte';
import { swipe, type SwipeCustomEvent } from 'svelte-gestures';
import { t } from 'svelte-i18n';
import { type SwipeCustomEvent, swipe } from 'svelte-gestures';
import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import FaceEditor from '$lib/components/asset-viewer/face-editor/face-editor.svelte';
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { cancelImageUrl, preloadImageUrl } from '$lib/utils/sw-messaging';
interface Props {
asset: AssetResponseDto;

View file

@ -1,16 +1,16 @@
<script lang="ts">
import FaceEditor from '$lib/components/asset-viewer/face-editor/face-editor.svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { loopVideo as loopVideoPreference, videoViewerMuted, videoViewerVolume } from '$lib/stores/preferences.store';
import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { AssetMediaSize } from '@immich/sdk';
import { onDestroy, onMount } from 'svelte';
import { swipe } from 'svelte-gestures';
import type { SwipeCustomEvent } from 'svelte-gestures';
import { fade } from 'svelte/transition';
import { swipe } from 'svelte-gestures';
import { t } from 'svelte-i18n';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import FaceEditor from '$lib/components/asset-viewer/face-editor/face-editor.svelte';
import { fade } from 'svelte/transition';
interface Props {
assetId: string;

View file

@ -1,8 +1,8 @@
<script lang="ts">
import { getAssetPlaybackUrl, getAssetOriginalUrl } from '$lib/utils';
import { getAssetOriginalUrl, getAssetPlaybackUrl } from '$lib/utils';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { t } from 'svelte-i18n';
interface Props {
assetId: string;

View file

@ -44,7 +44,7 @@
</ModalBody>
<ModalFooter>
<div class="flex gap-3 w-full">
<div class="flex gap-3 w-full my-3">
{#if !hideCancelButton}
<Button shape="round" color={cancelColor} fullWidth onclick={() => onClose(false)}>
{cancelText}