mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
fix: z-index overuse (#18192)
This commit is contained in:
parent
48112d84a3
commit
989d9dbe51
49 changed files with 330 additions and 332 deletions
|
|
@ -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) }}
|
||||
|
|
|
|||
|
|
@ -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'}
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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={[
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]">
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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')}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue