mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-28 00:06:53 +01:00
feat: Persist expand collapse (#7169)
This commit is contained in:
parent
67148dbdc9
commit
c8db321b3e
@ -60,6 +60,7 @@ import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
|
|||||||
import { basePath } from 'utils/formatPath';
|
import { basePath } from 'utils/formatPath';
|
||||||
import { useLocalStorageState } from 'hooks/useLocalStorageState';
|
import { useLocalStorageState } from 'hooks/useLocalStorageState';
|
||||||
import type { Theme } from '@mui/material/styles/createTheme';
|
import type { Theme } from '@mui/material/styles/createTheme';
|
||||||
|
import { unique } from 'utils/unique';
|
||||||
|
|
||||||
export const StyledProjectIcon = styled(ProjectIcon)(({ theme }) => ({
|
export const StyledProjectIcon = styled(ProjectIcon)(({ theme }) => ({
|
||||||
fill: theme.palette.neutral.main,
|
fill: theme.palette.neutral.main,
|
||||||
@ -226,7 +227,7 @@ const IconRenderer: FC<{ path: string }> = ({ path }) => {
|
|||||||
|
|
||||||
const ShowHideWrapper = styled(Box, {
|
const ShowHideWrapper = styled(Box, {
|
||||||
shouldForwardProp: (prop) => prop !== 'mode',
|
shouldForwardProp: (prop) => prop !== 'mode',
|
||||||
})<{ mode: 'mini' | 'full' }>(({ theme, mode }) => ({
|
})<{ mode: NavigationMode }>(({ theme, mode }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -234,7 +235,7 @@ const ShowHideWrapper = styled(Box, {
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ShowHide: FC<{ mode: 'full' | 'mini'; onChange: () => void }> = ({
|
const ShowHide: FC<{ mode: NavigationMode; onChange: () => void }> = ({
|
||||||
mode,
|
mode,
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
@ -297,8 +298,10 @@ const useShowBadge = () => {
|
|||||||
return showBadge;
|
return showBadge;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NavigationMode = 'mini' | 'full';
|
||||||
|
|
||||||
const useNavigationMode = () => {
|
const useNavigationMode = () => {
|
||||||
const [mode, setMode] = useLocalStorageState<'mini' | 'full'>(
|
const [mode, setMode] = useLocalStorageState<NavigationMode>(
|
||||||
'navigation-mode:v1',
|
'navigation-mode:v1',
|
||||||
'full',
|
'full',
|
||||||
);
|
);
|
||||||
@ -320,7 +323,7 @@ const useNavigationMode = () => {
|
|||||||
return [mode, setMode] as const;
|
return [mode, setMode] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MainNavigationList: FC<{ mode: 'mini' | 'full'; onClick?: () => void }> =
|
const MainNavigationList: FC<{ mode: NavigationMode; onClick?: () => void }> =
|
||||||
({ mode, onClick }) => {
|
({ mode, onClick }) => {
|
||||||
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
|
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
|
||||||
|
|
||||||
@ -356,7 +359,7 @@ const MainNavigationList: FC<{ mode: 'mini' | 'full'; onClick?: () => void }> =
|
|||||||
|
|
||||||
const ConfigureNavigationList: FC<{
|
const ConfigureNavigationList: FC<{
|
||||||
routes: INavigationMenuItem[];
|
routes: INavigationMenuItem[];
|
||||||
mode: 'mini' | 'full';
|
mode: NavigationMode;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}> = ({ routes, mode, onClick }) => {
|
}> = ({ routes, mode, onClick }) => {
|
||||||
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
|
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
|
||||||
@ -378,7 +381,7 @@ const ConfigureNavigationList: FC<{
|
|||||||
|
|
||||||
const AdminNavigationList: FC<{
|
const AdminNavigationList: FC<{
|
||||||
routes: INavigationMenuItem[];
|
routes: INavigationMenuItem[];
|
||||||
mode: 'mini' | 'full';
|
mode: NavigationMode;
|
||||||
badge?: ReactNode;
|
badge?: ReactNode;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}> = ({ routes, mode, onClick, badge }) => {
|
}> = ({ routes, mode, onClick, badge }) => {
|
||||||
@ -443,15 +446,40 @@ export const MobileNavigationSidebar: FC<{ onClick: () => void }> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useExpanded = <T extends string>() => {
|
||||||
|
const [expanded, setExpanded] = useLocalStorageState<Array<T>>(
|
||||||
|
'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 = () => {
|
export const NavigationSidebar = () => {
|
||||||
const { routes } = useRoutes();
|
const { routes } = useRoutes();
|
||||||
|
|
||||||
const [mode, setMode] = useNavigationMode();
|
const [mode, setMode] = useNavigationMode();
|
||||||
|
const [expanded, changeExpanded] = useExpanded<'configure' | 'admin'>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBox>
|
<StyledBox>
|
||||||
<MainNavigationList mode={mode} />
|
<MainNavigationList mode={mode} />
|
||||||
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
|
<Accordion
|
||||||
|
disableGutters={true}
|
||||||
|
sx={{ boxShadow: 'none' }}
|
||||||
|
expanded={expanded.includes('configure')}
|
||||||
|
onChange={(_, expand) => {
|
||||||
|
changeExpanded('configure', expand);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{mode === 'full' && (
|
{mode === 'full' && (
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMoreIcon />}
|
expandIcon={<ExpandMoreIcon />}
|
||||||
@ -472,7 +500,14 @@ export const NavigationSidebar = () => {
|
|||||||
/>
|
/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
|
<Accordion
|
||||||
|
disableGutters={true}
|
||||||
|
sx={{ boxShadow: 'none' }}
|
||||||
|
expanded={expanded.includes('admin')}
|
||||||
|
onChange={(_, expand) => {
|
||||||
|
changeExpanded('admin', expand);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{mode === 'full' && (
|
{mode === 'full' && (
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMoreIcon />}
|
expandIcon={<ExpandMoreIcon />}
|
||||||
|
7
frontend/src/utils/unique.ts
Normal file
7
frontend/src/utils/unique.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const unique = <T extends string | number>(items: T[]): T[] =>
|
||||||
|
Array.from(new Set(items));
|
||||||
|
|
||||||
|
export const uniqueByKey = <T extends Record<string, unknown>>(
|
||||||
|
items: T[],
|
||||||
|
key: keyof T,
|
||||||
|
): T[] => [...new Map(items.map((item) => [item[key], item])).values()];
|
Loading…
Reference in New Issue
Block a user