fix: always-mounted modal — GPU keeps backdrop-filter composited, no blur delay

This commit is contained in:
Usman Baig
2026-03-25 23:48:57 +01:00
parent b18199aa48
commit 67334f1fd6

View File

@@ -373,29 +373,25 @@ export default function UnifiedSettingsModal() {
}, [guardedAction, closeSettings]) }, [guardedAction, closeSettings])
return ( return (
<AnimatePresence>
{isOpen && (
<> <>
{/* Backdrop — solid scrim, no blur (modal handles its own glass) */} {/* Backdrop — always mounted, visibility toggled via CSS */}
<motion.div <div
initial={{ opacity: 1 }} className={`fixed inset-0 z-[60] bg-black/50 transition-opacity duration-150 ${
animate={{ opacity: 1 }} isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'
exit={{ opacity: 0 }} }`}
transition={{ duration: 0.15 }}
className="fixed inset-0 z-[60] bg-black/50"
onClick={handleBackdropClick} onClick={handleBackdropClick}
/> />
{/* Modal */} {/* Modal — always mounted, blur always composited by GPU */}
<motion.div <div
initial={{ scale: 0.97, y: 8 }} className={`fixed inset-0 z-[61] flex items-center justify-center p-4 transition-all duration-200 ease-out ${
animate={{ opacity: 1, scale: 1, y: 0 }} isOpen
exit={{ opacity: 0, scale: 0.97, y: 8 }} ? 'opacity-100 scale-100 translate-y-0 pointer-events-auto'
transition={{ type: 'spring', bounce: 0.15, duration: 0.35 }} : 'opacity-0 scale-[0.97] translate-y-2 pointer-events-none'
className="fixed inset-0 z-[61] flex items-center justify-center p-4 pointer-events-none" }`}
> >
<div <div
className="pointer-events-auto w-full max-w-3xl h-[85vh] bg-neutral-900/65 backdrop-blur-3xl backdrop-saturate-150 supports-[backdrop-filter]:bg-neutral-900/60 border border-white/[0.08] rounded-2xl shadow-xl shadow-black/20 flex flex-col overflow-hidden" className="w-full max-w-3xl h-[85vh] bg-neutral-900/65 backdrop-blur-3xl backdrop-saturate-150 supports-[backdrop-filter]:bg-neutral-900/60 border border-white/[0.08] rounded-2xl shadow-xl shadow-black/20 flex flex-col overflow-hidden"
onClick={e => e.stopPropagation()} onClick={e => e.stopPropagation()}
> >
{/* Header */} {/* Header */}
@@ -423,8 +419,9 @@ export default function UnifiedSettingsModal() {
</div> </div>
</div> </div>
{/* Content */} {/* Content — only render tab content when open to avoid unnecessary SWR calls */}
<div className="flex-1 overflow-y-auto overflow-x-hidden"> <div className="flex-1 overflow-y-auto overflow-x-hidden">
{isOpen && (
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
<motion.div <motion.div
key={`${context}-${activeTab}`} key={`${context}-${activeTab}`}
@@ -437,9 +434,10 @@ export default function UnifiedSettingsModal() {
<TabContent context={context} activeTab={activeTab} siteId={activeSiteId} onDirtyChange={handleDirtyChange} onRegisterSave={handleRegisterSave} /> <TabContent context={context} activeTab={activeTab} siteId={activeSiteId} onDirtyChange={handleDirtyChange} onRegisterSave={handleRegisterSave} />
</motion.div> </motion.div>
</AnimatePresence> </AnimatePresence>
)}
</div> </div>
{/* Save bar — fixed at modal bottom, outside scroll */} {/* Save bar */}
<AnimatePresence> <AnimatePresence>
{isDirtyVisible && ( {isDirtyVisible && (
<motion.div <motion.div
@@ -472,9 +470,7 @@ export default function UnifiedSettingsModal() {
)} )}
</AnimatePresence> </AnimatePresence>
</div> </div>
</motion.div> </div>
</> </>
)}
</AnimatePresence>
) )
} }