From c8db321b3e8dee65a0aeeb1ea6fefa7f1d6f1a44 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Mon, 27 May 2024 15:36:24 +0200 Subject: [PATCH] feat: Persist expand collapse (#7169) --- .../NavigationSidebar/NavigationSidebar.tsx | 51 ++++++++++++++++--- frontend/src/utils/unique.ts | 7 +++ 2 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 frontend/src/utils/unique.ts diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NavigationSidebar.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NavigationSidebar.tsx index 8dfd9219b8..8dea9c3d39 100644 --- a/frontend/src/component/layout/MainLayout/NavigationSidebar/NavigationSidebar.tsx +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NavigationSidebar.tsx @@ -60,6 +60,7 @@ import LibraryBooksIcon from '@mui/icons-material/LibraryBooks'; import { basePath } from 'utils/formatPath'; import { useLocalStorageState } from 'hooks/useLocalStorageState'; import type { Theme } from '@mui/material/styles/createTheme'; +import { unique } from 'utils/unique'; export const StyledProjectIcon = styled(ProjectIcon)(({ theme }) => ({ fill: theme.palette.neutral.main, @@ -226,7 +227,7 @@ const IconRenderer: FC<{ path: string }> = ({ path }) => { const ShowHideWrapper = styled(Box, { shouldForwardProp: (prop) => prop !== 'mode', -})<{ mode: 'mini' | 'full' }>(({ theme, mode }) => ({ +})<{ mode: NavigationMode }>(({ theme, mode }) => ({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', @@ -234,7 +235,7 @@ const ShowHideWrapper = styled(Box, { cursor: 'pointer', })); -const ShowHide: FC<{ mode: 'full' | 'mini'; onChange: () => void }> = ({ +const ShowHide: FC<{ mode: NavigationMode; onChange: () => void }> = ({ mode, onChange, }) => { @@ -297,8 +298,10 @@ const useShowBadge = () => { return showBadge; }; +type NavigationMode = 'mini' | 'full'; + const useNavigationMode = () => { - const [mode, setMode] = useLocalStorageState<'mini' | 'full'>( + const [mode, setMode] = useLocalStorageState( 'navigation-mode:v1', 'full', ); @@ -320,7 +323,7 @@ const useNavigationMode = () => { return [mode, setMode] as const; }; -const MainNavigationList: FC<{ mode: 'mini' | 'full'; onClick?: () => void }> = +const MainNavigationList: FC<{ mode: NavigationMode; onClick?: () => void }> = ({ mode, onClick }) => { const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem; @@ -356,7 +359,7 @@ const MainNavigationList: FC<{ mode: 'mini' | 'full'; onClick?: () => void }> = const ConfigureNavigationList: FC<{ routes: INavigationMenuItem[]; - mode: 'mini' | 'full'; + mode: NavigationMode; onClick?: () => void; }> = ({ routes, mode, onClick }) => { const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem; @@ -378,7 +381,7 @@ const ConfigureNavigationList: FC<{ const AdminNavigationList: FC<{ routes: INavigationMenuItem[]; - mode: 'mini' | 'full'; + mode: NavigationMode; badge?: ReactNode; onClick?: () => void; }> = ({ routes, mode, onClick, badge }) => { @@ -443,15 +446,40 @@ export const MobileNavigationSidebar: FC<{ onClick: () => void }> = ({ ); }; +const useExpanded = () => { + const [expanded, setExpanded] = useLocalStorageState>( + 'navigation-expanded:v1', + [], + ); + + const changeExpanded = (key: T, expand: boolean) => { + if (expand) { + setExpanded(unique([...expanded, key])); + } else { + setExpanded(expanded.filter((name) => name !== key)); + } + }; + + return [expanded, changeExpanded] as const; +}; + export const NavigationSidebar = () => { const { routes } = useRoutes(); const [mode, setMode] = useNavigationMode(); + const [expanded, changeExpanded] = useExpanded<'configure' | 'admin'>(); return ( - + { + changeExpanded('configure', expand); + }} + > {mode === 'full' && ( } @@ -472,7 +500,14 @@ export const NavigationSidebar = () => { /> - + { + changeExpanded('admin', expand); + }} + > {mode === 'full' && ( } diff --git a/frontend/src/utils/unique.ts b/frontend/src/utils/unique.ts new file mode 100644 index 0000000000..7a539a8da8 --- /dev/null +++ b/frontend/src/utils/unique.ts @@ -0,0 +1,7 @@ +export const unique = (items: T[]): T[] => + Array.from(new Set(items)); + +export const uniqueByKey = >( + items: T[], + key: keyof T, +): T[] => [...new Map(items.map((item) => [item[key], item])).values()];