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,
+ )}
+
+
+
+ ))}
+
+
+
+ );
+ })()
)}
);