From 2d71f2ce30f5141cb915dd56ab32b98e142c64b2 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Mon, 29 Jun 2026 16:10:29 -0400 Subject: [PATCH] refactor(ui): name the global overlay z-index layers (native-cinny nit) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Centralized the global floating-UI stacking values into styles/zIndex.ts (inCallBanner 9990 < seasonalEffect 9997 < nightLight 9998 < toast 10001; folds modals sit at 9999 between). Same values, no behavior change — just removes the magic numbers and documents the layering so future overlays don't collide. Component-internal small z-index stays local. Co-Authored-By: Claude Opus 4.8 --- src/app/components/CallEmbedProvider.tsx | 3 ++- src/app/components/seasonal/SeasonalEffect.tsx | 3 ++- src/app/features/toast/LotusToastContainer.tsx | 3 ++- src/app/pages/App.tsx | 3 ++- src/app/styles/zIndex.ts | 16 ++++++++++++++++ 5 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 src/app/styles/zIndex.ts diff --git a/src/app/components/CallEmbedProvider.tsx b/src/app/components/CallEmbedProvider.tsx index 18e065afc..b1d91b841 100644 --- a/src/app/components/CallEmbedProvider.tsx +++ b/src/app/components/CallEmbedProvider.tsx @@ -64,6 +64,7 @@ import { getRoomPermissionsAPI } from '../hooks/useRoomPermissions'; import { useLivekitSupport } from '../hooks/useLivekitSupport'; import { CallAvatarAnimation } from '../styles/Animations.css'; import { webRTCSupported } from '../utils/rtc'; +import { zIndices } from '../styles/zIndex'; const PIP_MIN_W = 200; const PIP_MIN_H = 112; @@ -323,7 +324,7 @@ function IncomingCallBanner({ dm, info, onIgnore, onAnswer, onReject }: Incoming position: 'fixed', top: config.space.S400, right: config.space.S400, - zIndex: 9990, + zIndex: zIndices.inCallBanner, width: toRem(300), maxWidth: `calc(100vw - 2 * ${config.space.S400})`, padding: config.space.S300, diff --git a/src/app/components/seasonal/SeasonalEffect.tsx b/src/app/components/seasonal/SeasonalEffect.tsx index a5ba93c8f..3617e0a73 100644 --- a/src/app/components/seasonal/SeasonalEffect.tsx +++ b/src/app/components/seasonal/SeasonalEffect.tsx @@ -1,6 +1,7 @@ import React, { useMemo } from 'react'; import { useAtomValue } from 'jotai'; import { settingsAtom } from '../../state/settings'; +import { zIndices } from '../../styles/zIndex'; import { animSeasonFall, animLeafFall, @@ -758,7 +759,7 @@ function SeasonalOverlay({ theme, reduced }: { theme: SeasonTheme; reduced: bool pointerEvents: 'none', // Below the Night Light overlay (9998) so seasonal particles are tinted // by it, and below modals (9999) so dialogs are never obscured. - zIndex: 9997, + zIndex: zIndices.seasonalEffect, overflow: 'hidden', }} > diff --git a/src/app/features/toast/LotusToastContainer.tsx b/src/app/features/toast/LotusToastContainer.tsx index 814753a28..0b035e746 100644 --- a/src/app/features/toast/LotusToastContainer.tsx +++ b/src/app/features/toast/LotusToastContainer.tsx @@ -4,6 +4,7 @@ import { color, config, Icon, IconButton, Icons } from 'folds'; import { toastQueueAtom, dismissToastAtom, ToastNotif } from '../../state/toast'; import { useSetting } from '../../state/hooks/settings'; import { settingsAtom } from '../../state/settings'; +import { zIndices } from '../../styles/zIndex'; // Inject the keyframe animation once const STYLE_ID = 'lotus-toast-keyframes'; @@ -214,7 +215,7 @@ export function LotusToastContainer() { position: 'fixed', bottom: '1.5rem', right: '1.5rem', - zIndex: 10001, + zIndex: zIndices.toast, display: 'flex', flexDirection: 'column', gap: config.space.S200, diff --git a/src/app/pages/App.tsx b/src/app/pages/App.tsx index 5c0be9fe5..7d74f4a1c 100644 --- a/src/app/pages/App.tsx +++ b/src/app/pages/App.tsx @@ -27,6 +27,7 @@ import { LotusToastContainer } from '../features/toast/LotusToastContainer'; import { useTauriNotificationBadge } from '../hooks/useTauriNotificationBadge'; import { SeasonalEffect } from '../components/seasonal/SeasonalEffect'; import { applyCustomAccent, removeCustomAccent } from '../utils/accentColor'; +import { zIndices } from '../styles/zIndex'; const FONT_MAP: Record = { system: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", @@ -95,7 +96,7 @@ function NightLightOverlay() { position: 'fixed', inset: 0, pointerEvents: 'none', - zIndex: 9998, + zIndex: zIndices.nightLight, backgroundColor: `rgba(255, 140, 0, ${(settings.nightLightOpacity ?? 30) / 100})`, }} /> diff --git a/src/app/styles/zIndex.ts b/src/app/styles/zIndex.ts new file mode 100644 index 000000000..9501c690f --- /dev/null +++ b/src/app/styles/zIndex.ts @@ -0,0 +1,16 @@ +/** + * Global overlay stacking layers, centralized so floating Lotus UI doesn't + * collide. (folds `Overlay`/`Dialog` modals resolve to 9999, which sits between + * `nightLight` and `toast`.) Component-internal stacking uses small local + * z-index values and is intentionally not listed here. + */ +export const zIndices = { + /** In-call incoming-call banner — below seasonal/night-light/modals. */ + inCallBanner: 9990, + /** Seasonal particle effect — below the night-light tint so particles tint. */ + seasonalEffect: 9997, + /** Night Light tint overlay — above effects, below modals. */ + nightLight: 9998, + /** Toasts — above everything, including modals. */ + toast: 10001, +} as const;