From 0cb030420e348d09660986d49698dcfe8e2100c0 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sun, 24 May 2026 07:17:33 -0500 Subject: [PATCH] add collapsible main nav items in settings --- web/src/pages/Settings.tsx | 214 +++++++++++++++++++++++++------------ 1 file changed, 146 insertions(+), 68 deletions(-) diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index b230fbd910..be4a036c0b 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -16,6 +16,11 @@ import { AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; import { Button } from "@/components/ui/button"; import { useCallback, @@ -589,7 +594,7 @@ function MobileMenuItem({ return (
{ @@ -600,7 +605,6 @@ function MobileMenuItem({
{label ??
{t("menu." + item.key)}
}
-
); } @@ -613,6 +617,39 @@ export default function Settings() { const [sectionStatusByKey, setSectionStatusByKey] = useState< Partial> >({}); + const [collapsedGroups, setCollapsedGroups] = useState>( + () => + // all collapsed by default + new Set( + settingsGroups.filter((g) => g.items.length > 1).map((g) => g.label), + ), + ); + + const toggleGroupCollapsed = useCallback((label: string) => { + setCollapsedGroups((prev) => { + const next = new Set(prev); + if (next.has(label)) { + next.delete(label); + } else { + next.add(label); + } + return next; + }); + }, []); + + // Auto-expand the group containing the active page whenever pageToggle changes + useEffect(() => { + const containingGroup = settingsGroups.find((group) => + group.items.some((item) => item.key === pageToggle), + ); + if (!containingGroup) return; + setCollapsedGroups((prev) => { + if (!prev.has(containingGroup.label)) return prev; + const next = new Set(prev); + next.delete(containingGroup.label); + return next; + }); + }, [pageToggle]); const { data: config } = useSWR("config"); const { data: profilesData } = useSWR("profiles"); @@ -1611,34 +1648,49 @@ export default function Settings() { visibleSettingsViews.includes(item.key as SettingsType), ); if (filteredItems.length === 0) return null; + const isMultiItem = filteredItems.length > 1; + const renderedExpanded = + !isMultiItem || !collapsedGroups.has(group.label); + const items = filteredItems.map((item) => ( + { + if ( + !isAdmin && + !ALLOWED_VIEWS_FOR_VIEWER.includes(key as SettingsType) + ) { + setPageToggle("uiSettings"); + } else { + setPageToggle(key as SettingsType); + } + setContentMobileOpen(true); + }} + /> + )); return (
- {filteredItems.length > 1 && ( -

-
{t("menu." + group.label)}
-

+ {isMultiItem ? ( + toggleGroupCollapsed(group.label)} + > + +
{t("menu." + group.label)}
+ +
+ {items} +
+ ) : ( + items )} - {filteredItems.map((item) => ( - { - if ( - !isAdmin && - !ALLOWED_VIEWS_FOR_VIEWER.includes( - key as SettingsType, - ) - ) { - setPageToggle("uiSettings"); - } else { - setPageToggle(key as SettingsType); - } - setContentMobileOpen(true); - }} - /> - ))}
); })} @@ -1940,48 +1992,74 @@ export default function Settings() { ) : ( - <> - pageToggle === item.key, - ) - ? "text-primary" - : "text-sidebar-foreground/80", - )} - > -
{t("menu." + group.label)}
-
- - {filteredItems.map((item) => ( - - { - if ( - !isAdmin && - !ALLOWED_VIEWS_FOR_VIEWER.includes( - item.key as SettingsType, - ) - ) { - setPageToggle("uiSettings"); - } else { - setPageToggle(item.key as SettingsType); - } - }} - > -
- {renderMenuItemLabel( - item.key as SettingsType, + (() => { + const hasActiveItem = filteredItems.some( + (item) => pageToggle === item.key, + ); + const renderedExpanded = !collapsedGroups.has( + group.label, + ); + return ( + + toggleGroupCollapsed(group.label) + } + > + + +
{t("menu." + group.label)}
+ - - - ))} - - + /> +
+
+ + + {filteredItems.map((item) => ( + + { + if ( + !isAdmin && + !ALLOWED_VIEWS_FOR_VIEWER.includes( + item.key as SettingsType, + ) + ) { + setPageToggle("uiSettings"); + } else { + setPageToggle( + item.key as SettingsType, + ); + } + }} + > +
+ {renderMenuItemLabel( + item.key as SettingsType, + )} +
+
+
+ ))} +
+
+
+ ); + })() )} );