fix(nav): remove backdrop div so the account popover frosts

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.
This commit is contained in:
npeter83 2026-06-16 01:54:01 +02:00
parent a18924bf97
commit ed2d76f92d

View file

@ -1,4 +1,4 @@
import { useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
@ -37,6 +37,7 @@ export default function NavSidebar({
); );
const [acctOpen, setAcctOpen] = useState(false); const [acctOpen, setAcctOpen] = useState(false);
const acctBtnRef = useRef<HTMLButtonElement | null>(null); const acctBtnRef = useRef<HTMLButtonElement | null>(null);
const acctPanelRef = useRef<HTMLDivElement | null>(null);
// Popover position (fixed, viewport coords). It's portaled to <body> so it escapes the // Popover position (fixed, viewport coords). It's portaled to <body> so it escapes the
// nav's backdrop-filter, which would otherwise trap fixed positioning + stacking and let // nav's backdrop-filter, which would otherwise trap fixed positioning + stacking and let
// clicks fall through to the controls behind it. // clicks fall through to the controls behind it.
@ -50,6 +51,27 @@ export default function NavSidebar({
setAcctOpen((o) => !o); 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() { function toggleCollapsed() {
setCollapsed((c) => { setCollapsed((c) => {
const next = !c; const next = !c;
@ -157,9 +179,8 @@ export default function NavSidebar({
{acctOpen && {acctOpen &&
createPortal( createPortal(
<>
<div className="fixed inset-0 z-40" onClick={() => setAcctOpen(false)} />
<div <div
ref={acctPanelRef}
style={{ position: "fixed", left: acctPos.left, bottom: acctPos.bottom }} style={{ position: "fixed", left: acctPos.left, bottom: acctPos.bottom }}
className="glass w-60 rounded-xl p-3 z-50 animate-[popIn_0.16s_ease]" className="glass w-60 rounded-xl p-3 z-50 animate-[popIn_0.16s_ease]"
> >
@ -199,8 +220,7 @@ export default function NavSidebar({
{t("header.account.signOut")} {t("header.account.signOut")}
</button> </button>
</div> </div>
</div> </div>,
</>,
document.body document.body
)} )}
</div> </div>