diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index d69be26..b6b4af5 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -4,7 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import * as LucideIcons from 'lucide-react'; const { ChevronDown, Lock } = LucideIcons; @@ -74,6 +74,27 @@ function subtreeHasVisibleLink(items: LayoutSubItem[], edition: string): boolean return false; } +interface AutoOpenCollapsibleProps { + containsActive: boolean; + children: React.ReactNode; +} + +// A collapsible that opens itself whenever the active page lands inside it, +// while still allowing the user to toggle it manually afterwards. +function AutoOpenCollapsible({ containsActive, children }: AutoOpenCollapsibleProps) { + const [open, setOpen] = useState(containsActive); + const [prevContainsActive, setPrevContainsActive] = useState(containsActive); + if (containsActive !== prevContainsActive) { + setPrevContainsActive(containsActive); + if (containsActive) setOpen(true); + } + return ( + + {children} + + ); +} + function checkLinkVisible(viewName: string): boolean { const schema = useSchemaStore.getState().schema; if (!schema) return true; @@ -120,6 +141,7 @@ function SidebarSubItem({ item, depth, sectionName, currentPath, navigate, editi return (