From ed2d76f92d947ed6a3eb3bcb742c875b71c5eac6 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Tue, 16 Jun 2026 01:54:01 +0200 Subject: [PATCH] fix(nav): remove backdrop div so the account popover frosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The full-screen transparent dismiss backdrop sat directly behind the popover and acted as a compositing layer, so the popover's backdrop-filter sampled it (empty) instead of the page — making the glass look fully solid. Drop the backdrop and dismiss via document mousedown/Escape listeners (like the other menus). Now backdrop-filter samples real content and the frost shows. --- frontend/src/components/NavSidebar.tsx | 38 ++++++++++++++++++++------ 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/NavSidebar.tsx b/frontend/src/components/NavSidebar.tsx index 5a10f90..533f100 100644 --- a/frontend/src/components/NavSidebar.tsx +++ b/frontend/src/components/NavSidebar.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { useTranslation } from "react-i18next"; import { @@ -37,6 +37,7 @@ export default function NavSidebar({ ); const [acctOpen, setAcctOpen] = useState(false); const acctBtnRef = useRef(null); + const acctPanelRef = useRef(null); // Popover position (fixed, viewport coords). It's portaled to so it escapes the // nav's backdrop-filter, which would otherwise trap fixed positioning + stacking and let // clicks fall through to the controls behind it. @@ -50,6 +51,27 @@ export default function NavSidebar({ setAcctOpen((o) => !o); } + // Dismiss on outside click / Escape via document listeners — NOT a full-screen backdrop + // div, which (sitting between the popover and the page) would break the popover's + // backdrop-filter and make it look solid. + useEffect(() => { + if (!acctOpen) return; + function onDoc(e: MouseEvent) { + const t = e.target as Node; + if (acctPanelRef.current?.contains(t) || acctBtnRef.current?.contains(t)) return; + setAcctOpen(false); + } + function onKey(e: KeyboardEvent) { + if (e.key === "Escape") setAcctOpen(false); + } + document.addEventListener("mousedown", onDoc); + document.addEventListener("keydown", onKey); + return () => { + document.removeEventListener("mousedown", onDoc); + document.removeEventListener("keydown", onKey); + }; + }, [acctOpen]); + function toggleCollapsed() { setCollapsed((c) => { const next = !c; @@ -157,12 +179,11 @@ export default function NavSidebar({ {acctOpen && createPortal( - <> -
setAcctOpen(false)} /> -
+
-
- , +
, document.body )}