mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
feat: Mini navigation sidebar (#7131)
This commit is contained in:
parent
4b68a0b3fd
commit
79ed56ecfc
@ -43,7 +43,13 @@ import EmptyIcon from '@mui/icons-material/CheckBoxOutlineBlankOutlined';
|
|||||||
import CorsIcon from '@mui/icons-material/StorageOutlined';
|
import CorsIcon from '@mui/icons-material/StorageOutlined';
|
||||||
import BillingIcon from '@mui/icons-material/CreditCardOutlined';
|
import BillingIcon from '@mui/icons-material/CreditCardOutlined';
|
||||||
import { ReactComponent as ProjectIcon } from 'assets/icons/projectIconSmall.svg';
|
import { ReactComponent as ProjectIcon } from 'assets/icons/projectIconSmall.svg';
|
||||||
import { type FC, type ReactNode, useCallback } from 'react';
|
import {
|
||||||
|
type FC,
|
||||||
|
type ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { getCondensedRoutes, getRoutes } from '../../../menu/routes';
|
import { getCondensedRoutes, getRoutes } from '../../../menu/routes';
|
||||||
import { useAdminRoutes } from '../../../admin/useAdminRoutes';
|
import { useAdminRoutes } from '../../../admin/useAdminRoutes';
|
||||||
import { filterByConfig, mapRouteLink } from 'component/common/util';
|
import { filterByConfig, mapRouteLink } from 'component/common/util';
|
||||||
@ -74,7 +80,7 @@ const EnterprisePlanBadge = () => (
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
const StyledListItem: FC<{ href: string; text: string; badge?: ReactNode }> = ({
|
const FullListItem: FC<{ href: string; text: string; badge?: ReactNode }> = ({
|
||||||
href,
|
href,
|
||||||
text,
|
text,
|
||||||
badge,
|
badge,
|
||||||
@ -93,6 +99,26 @@ const StyledListItem: FC<{ href: string; text: string; badge?: ReactNode }> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MiniListItem: FC<{ href: string; text: string }> = ({
|
||||||
|
href,
|
||||||
|
text,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<ListItem disablePadding>
|
||||||
|
<ListItemButton dense={true} component={Link} to={href}>
|
||||||
|
<Tooltip title={text} placement='right'>
|
||||||
|
<ListItemIcon
|
||||||
|
sx={(theme) => ({ minWidth: theme.spacing(4) })}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ListItemIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const StyledBox = styled(Box)(({ theme }) => ({
|
export const StyledBox = styled(Box)(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
pt: theme.spacing(3),
|
pt: theme.spacing(3),
|
||||||
@ -166,62 +192,95 @@ const useRoutes = () => {
|
|||||||
return { routes: filteredMainRoutes, showBadge };
|
return { routes: filteredMainRoutes, showBadge };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useNavigationMode = () => {
|
||||||
|
const [mode, setMode] = useState<'mini' | 'full'>('full');
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'b' && (event.metaKey || event.ctrlKey)) {
|
||||||
|
event.preventDefault();
|
||||||
|
setMode(mode === 'mini' ? 'full' : 'mini');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [mode]);
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
};
|
||||||
|
|
||||||
export const NavigationSidebar = () => {
|
export const NavigationSidebar = () => {
|
||||||
const { routes, showBadge } = useRoutes();
|
const { routes, showBadge } = useRoutes();
|
||||||
|
|
||||||
|
const mode = useNavigationMode();
|
||||||
|
|
||||||
|
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBox>
|
<StyledBox>
|
||||||
<List>
|
<List>
|
||||||
<StyledListItem href='/projects' text='Projects'>
|
<DynamicListItem href='/projects' text='Projects'>
|
||||||
<StyledProjectIcon />
|
<StyledProjectIcon />
|
||||||
</StyledListItem>
|
</DynamicListItem>
|
||||||
<StyledListItem href='/search' text='Search'>
|
<DynamicListItem href='/search' text='Search'>
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
</StyledListItem>
|
</DynamicListItem>
|
||||||
<StyledListItem href='/playground' text='Playground'>
|
<DynamicListItem href='/playground' text='Playground'>
|
||||||
<PlaygroundIcon />
|
<PlaygroundIcon />
|
||||||
</StyledListItem>
|
</DynamicListItem>
|
||||||
<StyledListItem href='/insights' text='Insights'>
|
<DynamicListItem href='/insights' text='Insights'>
|
||||||
<InsightsIcon />
|
<InsightsIcon />
|
||||||
</StyledListItem>
|
</DynamicListItem>
|
||||||
</List>
|
</List>
|
||||||
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
|
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
|
||||||
<AccordionSummary
|
{mode === 'full' && (
|
||||||
expandIcon={<ExpandMoreIcon />}
|
<AccordionSummary
|
||||||
aria-controls='configure-content'
|
expandIcon={<ExpandMoreIcon />}
|
||||||
id='configure-header'
|
aria-controls='configure-content'
|
||||||
>
|
id='configure-header'
|
||||||
<Typography sx={{ fontWeight: 'bold', fontSize: 'small' }}>
|
>
|
||||||
Configure
|
<Typography
|
||||||
</Typography>
|
sx={{ fontWeight: 'bold', fontSize: 'small' }}
|
||||||
</AccordionSummary>
|
>
|
||||||
|
Configure
|
||||||
|
</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
)}
|
||||||
<AccordionDetails sx={{ p: 0 }}>
|
<AccordionDetails sx={{ p: 0 }}>
|
||||||
<List>
|
<List>
|
||||||
{routes.mainNavRoutes.map((route) => (
|
{routes.mainNavRoutes.map((route) => (
|
||||||
<StyledListItem
|
<DynamicListItem
|
||||||
href={route.path}
|
href={route.path}
|
||||||
text={route.title}
|
text={route.title}
|
||||||
>
|
>
|
||||||
<IconRenderer path={route.path} />
|
<IconRenderer path={route.path} />
|
||||||
</StyledListItem>
|
</DynamicListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
|
<Accordion disableGutters={true} sx={{ boxShadow: 'none' }}>
|
||||||
<AccordionSummary
|
{mode === 'full' && (
|
||||||
expandIcon={<ExpandMoreIcon />}
|
<AccordionSummary
|
||||||
aria-controls='admin-content'
|
expandIcon={<ExpandMoreIcon />}
|
||||||
id='admin-header'
|
aria-controls='admin-content'
|
||||||
>
|
id='admin-header'
|
||||||
<Typography sx={{ fontWeight: 'bold', fontSize: 'small' }}>
|
>
|
||||||
Admin
|
<Typography
|
||||||
</Typography>
|
sx={{ fontWeight: 'bold', fontSize: 'small' }}
|
||||||
</AccordionSummary>
|
>
|
||||||
|
Admin
|
||||||
|
</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
)}
|
||||||
|
|
||||||
<AccordionDetails sx={{ p: 0 }}>
|
<AccordionDetails sx={{ p: 0 }}>
|
||||||
<List>
|
<List>
|
||||||
{routes.adminRoutes.map((route) => (
|
{routes.adminRoutes.map((route) => (
|
||||||
<StyledListItem
|
<DynamicListItem
|
||||||
href={route.path}
|
href={route.path}
|
||||||
text={route.title}
|
text={route.title}
|
||||||
badge={
|
badge={
|
||||||
@ -231,7 +290,7 @@ export const NavigationSidebar = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<IconRenderer path={route.path} />
|
<IconRenderer path={route.path} />
|
||||||
</StyledListItem>
|
</DynamicListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
|
Loading…
Reference in New Issue
Block a user