fix: z-index overuse (#18192)

This commit is contained in:
Daniel Dietzler 2025-05-13 16:10:05 +02:00 committed by GitHub
parent 48112d84a3
commit 989d9dbe51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 330 additions and 332 deletions

View file

@ -135,7 +135,7 @@
{/if}
<div
class="absolute z-[99] w-full"
class="absolute w-full"
id="suggestion"
bind:this={suggestionContainer}
use:clickOutside={{ onOutclick: () => (hideSuggestion = true) }}

View file

@ -20,16 +20,16 @@
</script>
<script lang="ts">
import { fly } from 'svelte/transition';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiMagnify, mdiUnfoldMoreHorizontal, mdiClose } from '@mdi/js';
import { onMount, tick } from 'svelte';
import type { FormEventHandler } from 'svelte/elements';
import { shortcuts } from '$lib/actions/shortcut';
import { focusOutside } from '$lib/actions/focus-outside';
import { generateId } from '$lib/utils/generate-id';
import { shortcuts } from '$lib/actions/shortcut';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import { generateId } from '$lib/utils/generate-id';
import { mdiClose, mdiMagnify, mdiUnfoldMoreHorizontal } from '@mdi/js';
import { onMount, tick } from 'svelte';
import { t } from 'svelte-i18n';
import type { FormEventHandler } from 'svelte/elements';
import { fly } from 'svelte/transition';
interface Props {
label: string;
@ -341,7 +341,7 @@
role="listbox"
id={listboxId}
transition:fly={{ duration: 250 }}
class="fixed text-start text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900 z-[10000]"
class="fixed z-[1] text-start text-sm w-full overflow-y-auto bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-900"
class:rounded-b-xl={dropdownDirection === 'bottom'}
class:rounded-t-xl={dropdownDirection === 'top'}
class:shadow={dropdownDirection === 'bottom'}

View file

@ -59,7 +59,7 @@
<div
bind:clientHeight={height}
class="fixed z-10 min-w-[200px] w-max max-w-[300px] overflow-hidden rounded-lg shadow-lg"
class="fixed min-w-[200px] w-max max-w-[300px] overflow-hidden rounded-lg shadow-lg"
style:left="{left}px"
style:top="{top}px"
transition:slide={{ duration: 250, easing: quintOut }}

View file

@ -1,10 +1,10 @@
<script lang="ts">
import { tick, type Snippet } from 'svelte';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import { shortcuts } from '$lib/actions/shortcut';
import { generateId } from '$lib/utils/generate-id';
import { contextMenuNavigation } from '$lib/actions/context-menu-navigation';
import { shortcuts } from '$lib/actions/shortcut';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
import { generateId } from '$lib/utils/generate-id';
import { tick, type Snippet } from 'svelte';
interface Props {
title: string;
@ -91,7 +91,7 @@
},
]}
>
<section class="fixed start-0 top-0 z-10 flex h-dvh w-dvw" {oncontextmenu} role="presentation">
<section class="fixed start-0 top-0 flex h-dvh w-dvw" {oncontextmenu} role="presentation">
<ContextMenu
{direction}
{x}

View file

@ -66,7 +66,7 @@
let buttonClass = $derived(forceDark ? 'hover:text-immich-dark-gray' : undefined);
</script>
<div in:fly={{ y: 10, duration: 200 }} class="absolute top-0 w-full z-[100] bg-transparent">
<div in:fly={{ y: 10, duration: 200 }} class="absolute top-0 w-full bg-transparent z-[1]">
<nav
id="asset-selection-app-bar"
class={[

View file

@ -161,7 +161,7 @@
{#if dragStartTarget}
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
class="fixed inset-0 z-[1000] flex h-full w-full flex-col items-center justify-center bg-gray-100/90 text-immich-dark-gray dark:bg-immich-dark-bg/90 dark:text-immich-gray"
class="fixed inset-0 flex h-full w-full flex-col items-center justify-center bg-gray-100/90 text-immich-dark-gray dark:bg-immich-dark-bg/90 dark:text-immich-gray"
transition:fade={{ duration: 250 }}
ondragover={onDragOver}
>

View file

@ -1,10 +1,10 @@
<script lang="ts">
import { clickOutside } from '$lib/actions/click-outside';
import { focusTrap } from '$lib/actions/focus-trap';
import { fade } from 'svelte/transition';
import ModalHeader from '$lib/components/shared-components/modal-header.svelte';
import { generateId } from '$lib/utils/generate-id';
import type { Snippet } from 'svelte';
import { fade } from 'svelte/transition';
interface Props {
onClose: () => void;
@ -77,14 +77,14 @@
role="presentation"
in:fade={{ duration: 100 }}
out:fade={{ duration: 100 }}
class="fixed start-0 top-0 z-[9999] flex h-dvh w-dvw place-content-center place-items-center bg-black/40"
class="fixed start-0 top-0 flex h-dvh w-dvw place-content-center place-items-center bg-black/40"
onkeydown={(event) => {
event.stopPropagation();
}}
use:focusTrap
>
<div
class="flex flex-col max-h-[min(95dvh,60rem)] z-[9999] max-w-[95vw] {modalWidth} overflow-hidden rounded-3xl bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg pt-3 pb-4"
class="flex flex-col max-h-[min(95dvh,60rem)] max-w-[95vw] {modalWidth} overflow-hidden rounded-3xl bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg pt-3 pb-4"
use:clickOutside={{ onOutclick: onClose, onEscape: onClose }}
tabindex="-1"
aria-modal="true"

View file

@ -25,7 +25,7 @@
in:fade={{ duration: 100 }}
out:fade={{ duration: 100 }}
id="account-info-panel"
class="absolute end-[25px] top-[75px] z-[100] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray"
class="absolute z-[1] end-[25px] top-[75px] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray"
use:focusTrap
>
<div
@ -33,7 +33,7 @@
>
<div class="relative">
<UserAvatar user={$user} size="xl" />
<div class="absolute z-10 bottom-0 end-0 rounded-full w-6 h-6">
<div class="absolute bottom-0 end-0 rounded-full w-6 h-6">
<CircleIconButton
color="primary"
icon={mdiPencil}

View file

@ -51,7 +51,7 @@
<nav
id="dashboard-navbar"
class="z-auto max-md:h-[var(--navbar-height-md)] h-[var(--navbar-height)] w-dvw text-sm overflow-hidden"
class="max-md:h-[var(--navbar-height-md)] h-[var(--navbar-height)] w-dvw text-sm overflow-hidden"
>
<SkipLink text={$t('skip_to_content')} />
<div

View file

@ -12,8 +12,8 @@
import { Button, Scrollable, Stack, Text } from '@immich/ui';
import { mdiBellOutline, mdiCheckAll } from '@mdi/js';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
import { flip } from 'svelte/animate';
import { fade } from 'svelte/transition';
const noUnreadNotifications = $derived(notificationManager.notifications.length === 0);
@ -39,7 +39,7 @@
in:fade={{ duration: 100 }}
out:fade={{ duration: 100 }}
id="notification-panel"
class="absolute right-[25px] top-[70px] z-[100] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-100 border border-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray text-light"
class="absolute right-[25px] top-[70px] z-[1] w-[min(360px,100vw-50px)] rounded-3xl bg-gray-100 border border-gray-200 shadow-lg dark:border dark:border-immich-dark-gray dark:bg-immich-dark-gray text-light"
use:focusTrap
>
<Stack class="max-h-[500px]">

View file

@ -26,7 +26,7 @@
</script>
{#if showing}
<div class="absolute start-0 top-0 z-[999999999] h-[3px] w-dvw bg-white">
<div class="absolute start-0 top-0 h-[3px] w-dvw bg-white">
<span class="absolute h-[3px] bg-immich-primary" style:width={`${$progress}%`}></span>
</div>
{/if}

View file

@ -5,8 +5,8 @@ import { get } from 'svelte/store';
import { NotificationType, notificationController } from '../notification';
import NotificationList from '../notification-list.svelte';
function _getNotificationListElement(sut: RenderResult<NotificationList>): HTMLAnchorElement | null {
return sut.container.querySelector('#notification-list');
function _getNotificationListElement(): HTMLAnchorElement | null {
return document.body.querySelector('#notification-list');
}
describe('NotificationList component', () => {
@ -23,7 +23,7 @@ describe('NotificationList component', () => {
const status = await sut.findAllByRole('status');
expect(status).toHaveLength(1);
expect(_getNotificationListElement(sut)).not.toBeInTheDocument();
expect(_getNotificationListElement()).not.toBeInTheDocument();
notificationController.show({
message: 'Notification',
@ -31,11 +31,11 @@ describe('NotificationList component', () => {
timeout: 1,
});
await waitFor(() => expect(_getNotificationListElement(sut)).toBeInTheDocument());
await waitFor(() => expect(_getNotificationListElement(sut)?.children).toHaveLength(1));
await waitFor(() => expect(_getNotificationListElement()).toBeInTheDocument());
await waitFor(() => expect(_getNotificationListElement()?.children).toHaveLength(1));
expect(get(notificationController.notificationList)).toHaveLength(1);
await waitFor(() => expect(_getNotificationListElement(sut)).not.toBeInTheDocument());
await waitFor(() => expect(_getNotificationListElement()).not.toBeInTheDocument());
expect(get(notificationController.notificationList)).toHaveLength(0);
});
});

View file

@ -75,7 +75,7 @@
transition:fade={{ duration: 250 }}
style:background-color={backgroundColor[notification.type]}
style:border-color={borderColor[notification.type]}
class="border z-[999999] mb-4 min-h-[80px] w-[300px] rounded-2xl p-4 shadow-md {hoverStyle}"
class="border mb-4 min-h-[80px] w-[300px] rounded-2xl p-4 shadow-md {hoverStyle}"
onclick={handleClick}
onkeydown={handleClick}
>

View file

@ -1,22 +1,25 @@
<script lang="ts">
import { notificationController } from './notification';
import { fade } from 'svelte/transition';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import { t } from 'svelte-i18n';
import NotificationCard from './notification-card.svelte';
import { flip } from 'svelte/animate';
import { quintOut } from 'svelte/easing';
import { fade } from 'svelte/transition';
import { notificationController } from './notification';
import NotificationCard from './notification-card.svelte';
const { notificationList } = notificationController;
</script>
<div role="status" aria-relevant="additions" aria-label={$t('notifications')}>
{#if $notificationList.length > 0}
<section transition:fade={{ duration: 250 }} id="notification-list" class="fixed end-5 top-[80px] z-[99999999]">
{#each $notificationList as notification (notification.id)}
<div animate:flip={{ duration: 250, easing: quintOut }}>
<NotificationCard {notification} />
</div>
{/each}
</section>
{/if}
</div>
<Portal>
<div role="status" aria-relevant="additions" aria-label={$t('notifications')}>
{#if $notificationList.length > 0}
<section transition:fade={{ duration: 250 }} id="notification-list" class="fixed end-5 top-[80px]">
{#each $notificationList as notification (notification.id)}
<div animate:flip={{ duration: 250, easing: quintOut }}>
<NotificationCard {notification} />
</div>
{/each}
</section>
{/if}
</div>
</Portal>

View file

@ -464,7 +464,7 @@
class={[
{ 'border-b-2': isDragging },
{ 'rounded-bl-md': !isDragging },
'bg-light truncate opacity-85 pointer-events-none absolute end-0 z-[100] min-w-20 max-w-64 w-fit rounded-ss-md border-immich-primary py-1 px-1 text-sm font-medium shadow-[0_0_8px_rgba(0,0,0,0.25)] dark:border-immich-dark-primary dark:text-immich-dark-fg',
'bg-light truncate opacity-85 pointer-events-none absolute end-0 min-w-20 max-w-64 w-fit rounded-ss-md border-immich-primary py-1 px-1 text-sm font-medium shadow-[0_0_8px_rgba(0,0,0,0.25)] dark:border-immich-dark-primary dark:text-immich-dark-fg',
]}
style:top="{hoverY + 2}px"
>
@ -506,7 +506,7 @@
{#if assetStore.scrolling && scrollHoverLabel && !isHover}
<p
transition:fade={{ duration: 200 }}
class="truncate pointer-events-none absolute end-0 bottom-0 z-[100] min-w-20 max-w-64 w-fit rounded-tl-md border-b-2 border-immich-primary bg-subtle/70 py-1 px-1 text-sm font-medium shadow-[0_0_8px_rgba(0,0,0,0.25)] dark:border-immich-dark-primary dark:text-immich-dark-fg"
class="truncate pointer-events-none absolute end-0 bottom-0 min-w-20 max-w-64 w-fit rounded-tl-md border-b-2 border-immich-primary bg-subtle/70 py-1 px-1 text-sm font-medium shadow-[0_0_8px_rgba(0,0,0,0.25)] dark:border-immich-dark-primary dark:text-immich-dark-fg"
>
{scrollHoverLabel}
</p>
@ -514,7 +514,7 @@
</div>
{/if}
<div
class="relative z-10"
class="relative"
style:height={relativeTopOffset + 'px'}
data-id="lead-in"
data-time-segment-bucket-date={segments.at(0)?.date}
@ -535,7 +535,7 @@
>
{#if !usingMobileDevice}
{#if segment.hasLabel}
<div class="absolute end-[1.25rem] top-[-16px] z-10 text-[12px] dark:text-immich-dark-fg font-immich-mono">
<div class="absolute end-[1.25rem] top-[-16px] text-[12px] dark:text-immich-dark-fg font-immich-mono">
{segment.date.year}
</div>
{/if}
@ -547,6 +547,3 @@
{/each}
<div data-id="lead-out" class="relative" style:height={relativeBottomOffset + 'px'}></div>
</div>
<style>
</style>

View file

@ -282,7 +282,7 @@
class:end-28={isFocus && value.length > 0}
>
<p
class="bg-immich-primary text-white dark:bg-immich-dark-primary/90 dark:text-black/75 rounded-full px-3 py-1 text-xs z-10"
class="bg-immich-primary text-white dark:bg-immich-dark-primary/90 dark:text-black/75 rounded-full px-3 py-1 text-xs"
>
{getSearchTypeText()}
</p>

View file

@ -119,7 +119,7 @@
{#if showMessage}
<dialog
open
class="hidden sidebar:block w-[500px] absolute bottom-[75px] start-[255px] bg-gray-50 dark:border-gray-800 border border-gray-200 dark:bg-immich-dark-gray dark:text-white text-black rounded-3xl z-10 shadow-2xl px-8 py-6"
class="hidden sidebar:block w-[500px] absolute bottom-[75px] start-[255px] bg-gray-50 dark:border-gray-800 border border-gray-200 dark:bg-immich-dark-gray dark:text-white text-black rounded-3xl shadow-2xl px-8 py-6"
transition:fade={{ duration: 150 }}
onmouseover={() => (hoverMessage = true)}
onmouseleave={() => (hoverMessage = false)}

View file

@ -37,7 +37,7 @@
<div class="relative">
{#if hasDropdown}
<span class="hidden md:block absolute start-1 z-50 h-full">
<span class="hidden md:block absolute start-1 h-full">
<button
type="button"
aria-label={$t('recent-albums')}

View file

@ -35,7 +35,7 @@
id="sidebar"
aria-label={ariaLabel}
tabindex="-1"
class="immich-scrollbar relative z-auto w-0 sidebar:w-[16rem] overflow-y-auto overflow-x-hidden pt-8 transition-all duration-200"
class="immich-scrollbar relative z-[1] w-0 sidebar:w-[16rem] overflow-y-auto overflow-x-hidden pt-8 transition-all duration-200"
class:shadow-2xl={isExpanded}
class:dark:border-e-immich-dark-gray={isExpanded}
class:border-r={isExpanded}

View file

@ -1,15 +1,15 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { uploadAssetsStore } from '$lib/stores/upload';
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
import { mdiCancel, mdiCloudUploadOutline, mdiCog, mdiWindowMinimize } from '@mdi/js';
import { t } from 'svelte-i18n';
import { quartInOut } from 'svelte/easing';
import { fade, scale } from 'svelte/transition';
import { uploadAssetsStore } from '$lib/stores/upload';
import Icon from '$lib/components/elements/icon.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { notificationController, NotificationType } from './notification/notification';
import UploadAssetPreview from './upload-asset-preview.svelte';
import { uploadExecutionQueue } from '$lib/utils/file-uploader';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { mdiCog, mdiWindowMinimize, mdiCancel, mdiCloudUploadOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import { locale } from '$lib/stores/preferences.store';
let showDetail = $state(false);
let showOptions = $state(false);
@ -48,7 +48,7 @@
}
uploadAssetsStore.reset();
}}
class="fixed bottom-6 end-16 z-[10000]"
class="fixed bottom-6 end-16"
>
{#if showDetail}
<div