From 989ac65474cf7c96415744b2c64071e57cd849b2 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 19 Jun 2026 00:04:19 +0200 Subject: [PATCH] fix(settings): size panel to the active tab + drop the native unload prompt - Render only the active settings tab instead of stacking all four in one grid cell. The stack forced the whole panel to the tallest tab's (Account) height, leaving the short tabs (Appearance/Notifications) with dead space and a pointless scrollbar. Now the panel sizes to its actual content. - Remove the beforeunload guard: it could only raise the browser's own native 'Reload site?' prompt (no in-app dialog possible there), which we avoid. Unsaved prefs are local-only and revert to the saved server baseline on the next load, so a reload/close loses nothing. The in-app confirm still guards in-app navigation and browser Back. --- frontend/src/App.tsx | 14 +++---------- frontend/src/components/SettingsPanel.tsx | 24 ++++++++--------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index cc1e2d5..0a6b52b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -374,17 +374,9 @@ export default function App() { confirmRef.current = confirm; pageRef.current = page; }); - - // Warn on a hard navigation (reload / tab close) while preference changes are unsaved. - useEffect(() => { - if (!prefsDirty) return; - const handler = (e: BeforeUnloadEvent) => { - e.preventDefault(); - e.returnValue = ""; - }; - window.addEventListener("beforeunload", handler); - return () => window.removeEventListener("beforeunload", handler); - }, [prefsDirty]); + // No beforeunload guard: a reload/close can only raise the browser's own native prompt + // (we can't show our in-app confirm there), and unsaved prefs are local-only — they + // revert to the saved server baseline on the next load — so there's nothing to lose. if (meQuery.isLoading) return ( diff --git a/frontend/src/components/SettingsPanel.tsx b/frontend/src/components/SettingsPanel.tsx index 9e1b5d1..6e65456 100644 --- a/frontend/src/components/SettingsPanel.tsx +++ b/frontend/src/components/SettingsPanel.tsx @@ -92,22 +92,14 @@ export default function SettingsPanel({ })} - {/* All tabs stacked in one grid cell so the panel sizes to the tallest tab - (stable height, no jump on switch); the active one is shown on top. */} -
- {TABS.map((tabItem) => ( -
- {tabItem.id === "appearance" && } - {tabItem.id === "notifications" && } - {tabItem.id === "sync" && } - {tabItem.id === "account" && } -
- ))} + {/* Render only the active tab so the panel sizes to its actual content. (Stacking + every tab in one grid cell made the whole panel as tall as the tallest tab — + Account — leaving the short tabs with dead space and a needless scrollbar.) */} +
+ {tab === "appearance" && } + {tab === "notifications" && } + {tab === "sync" && } + {tab === "account" && }