"introduce horizontal main navigation component with dynamic styling and interactive elements"

This commit is contained in:
louiscklaw
2025-05-11 10:39:09 +08:00
parent 3321eafffa
commit abca91c26a

View File

@@ -92,7 +92,11 @@ export function MainNav({ color = 'evident', items = [] }: MainNavProps): React.
py: 1, py: 1,
}} }}
> >
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', flex: '1 1 auto' }}> <Stack
direction="row"
spacing={2}
sx={{ alignItems: 'center', flex: '1 1 auto' }}
>
<IconButton <IconButton
onClick={(): void => { onClick={(): void => {
setOpenNav(true); setOpenNav(true);
@@ -101,8 +105,16 @@ export function MainNav({ color = 'evident', items = [] }: MainNavProps): React.
> >
<ListIcon color="var(--NavItem-icon-color)" /> <ListIcon color="var(--NavItem-icon-color)" />
</IconButton> </IconButton>
<Box component={RouterLink} href={paths.home} sx={{ display: { xs: 'none', md: 'inline-block' } }}> <Box
<Logo color={logoColor} height={32} width={122} /> component={RouterLink}
href={paths.home}
sx={{ display: { xs: 'none', md: 'inline-block' } }}
>
<Logo
color={logoColor}
height={32}
width={122}
/>
</Box> </Box>
<Box sx={{ display: { xs: 'none', md: 'block' } }}> <Box sx={{ display: { xs: 'none', md: 'block' } }}>
<WorkspacesSwitch /> <WorkspacesSwitch />
@@ -154,11 +166,17 @@ function SearchButton(): React.JSX.Element {
return ( return (
<React.Fragment> <React.Fragment>
<Tooltip title="Search"> <Tooltip title="Search">
<IconButton onClick={dialog.handleOpen} sx={{ display: { xs: 'none', md: 'inline-flex' } }}> <IconButton
onClick={dialog.handleOpen}
sx={{ display: { xs: 'none', md: 'inline-flex' } }}
>
<MagnifyingGlassIcon color="var(--NavItem-icon-color)" /> <MagnifyingGlassIcon color="var(--NavItem-icon-color)" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<SearchDialog onClose={dialog.handleClose} open={dialog.open} /> <SearchDialog
onClose={dialog.handleClose}
open={dialog.open}
/>
</React.Fragment> </React.Fragment>
); );
} }
@@ -174,12 +192,19 @@ function NotificationsButton(): React.JSX.Element {
sx={{ '& .MuiBadge-dot': { borderRadius: '50%', height: '10px', right: '6px', top: '6px', width: '10px' } }} sx={{ '& .MuiBadge-dot': { borderRadius: '50%', height: '10px', right: '6px', top: '6px', width: '10px' } }}
variant="dot" variant="dot"
> >
<IconButton onClick={popover.handleOpen} ref={popover.anchorRef}> <IconButton
onClick={popover.handleOpen}
ref={popover.anchorRef}
>
<BellIcon color="var(--NavItem-icon-color)" /> <BellIcon color="var(--NavItem-icon-color)" />
</IconButton> </IconButton>
</Badge> </Badge>
</Tooltip> </Tooltip>
<NotificationsPopover anchorEl={popover.anchorRef.current} onClose={popover.handleClose} open={popover.open} /> <NotificationsPopover
anchorEl={popover.anchorRef.current}
onClose={popover.handleClose}
open={popover.open}
/>
</React.Fragment> </React.Fragment>
); );
} }
@@ -190,11 +215,18 @@ function ContactsButton(): React.JSX.Element {
return ( return (
<React.Fragment> <React.Fragment>
<Tooltip title="Contacts"> <Tooltip title="Contacts">
<IconButton onClick={popover.handleOpen} ref={popover.anchorRef}> <IconButton
onClick={popover.handleOpen}
ref={popover.anchorRef}
>
<UsersIcon color="var(--NavItem-icon-color)" /> <UsersIcon color="var(--NavItem-icon-color)" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<ContactsPopover anchorEl={popover.anchorRef.current} onClose={popover.handleClose} open={popover.open} /> <ContactsPopover
anchorEl={popover.anchorRef.current}
onClose={popover.handleClose}
open={popover.open}
/>
</React.Fragment> </React.Fragment>
); );
} }
@@ -214,11 +246,20 @@ function LanguageSwitch(): React.JSX.Element {
sx={{ display: { xs: 'none', md: 'inline-flex' } }} sx={{ display: { xs: 'none', md: 'inline-flex' } }}
> >
<Box sx={{ height: '24px', width: '24px' }}> <Box sx={{ height: '24px', width: '24px' }}>
<Box alt={language} component="img" src={flag} sx={{ height: 'auto', width: '100%' }} /> <Box
alt={language}
component="img"
src={flag}
sx={{ height: 'auto', width: '100%' }}
/>
</Box> </Box>
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<LanguagePopover anchorEl={popover.anchorRef.current} onClose={popover.handleClose} open={popover.open} /> <LanguagePopover
anchorEl={popover.anchorRef.current}
onClose={popover.handleClose}
open={popover.open}
/>
</React.Fragment> </React.Fragment>
); );
} }
@@ -259,7 +300,11 @@ function UserButton(): React.JSX.Element {
<Avatar src={user.avatar} /> <Avatar src={user.avatar} />
</Badge> </Badge>
</Box> </Box>
<UserPopover anchorEl={popover.anchorRef.current} onClose={popover.handleClose} open={popover.open} /> <UserPopover
anchorEl={popover.anchorRef.current}
onClose={popover.handleClose}
open={popover.open}
/>
</React.Fragment> </React.Fragment>
); );
} }
@@ -267,7 +312,11 @@ function UserButton(): React.JSX.Element {
function renderNavGroups({ items = [], pathname }: { items?: NavItemConfig[]; pathname: string }): React.JSX.Element { function renderNavGroups({ items = [], pathname }: { items?: NavItemConfig[]; pathname: string }): React.JSX.Element {
const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => { const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => {
acc.push( acc.push(
<Box component="li" key={curr.key} sx={{ flex: '0 0 auto' }}> <Box
component="li"
key={curr.key}
sx={{ flex: '0 0 auto' }}
>
{renderNavItems({ pathname, items: curr.items })} {renderNavItems({ pathname, items: curr.items })}
</Box> </Box>
); );
@@ -276,7 +325,12 @@ function renderNavGroups({ items = [], pathname }: { items?: NavItemConfig[]; pa
}, []); }, []);
return ( return (
<Stack component="ul" direction="row" spacing={2} sx={{ listStyle: 'none', m: 0, p: '8px 12px' }}> <Stack
component="ul"
direction="row"
spacing={2}
sx={{ listStyle: 'none', m: 0, p: '8px 12px' }}
>
{children} {children}
</Stack> </Stack>
); );
@@ -286,13 +340,24 @@ function renderNavItems({ items = [], pathname }: { items?: NavItemConfig[]; pat
const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => { const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => {
const { key, ...item } = curr; const { key, ...item } = curr;
acc.push(<NavItem key={key} pathname={pathname} {...item} />); acc.push(
<NavItem
key={key}
pathname={pathname}
{...item}
/>
);
return acc; return acc;
}, []); }, []);
return ( return (
<Stack component="ul" direction="row" spacing={2} sx={{ listStyle: 'none', m: 0, p: 0 }}> <Stack
component="ul"
direction="row"
spacing={2}
sx={{ listStyle: 'none', m: 0, p: 0 }}
>
{children} {children}
</Stack> </Stack>
); );
@@ -318,7 +383,10 @@ function NavItem({
const isBranch = Boolean(items); const isBranch = Boolean(items);
const element = ( const element = (
<Box component="li" sx={{ userSelect: 'none' }}> <Box
component="li"
sx={{ userSelect: 'none' }}
>
<Box <Box
{...(isBranch {...(isBranch
? { role: 'button' } ? { role: 'button' }
@@ -373,10 +441,19 @@ function NavItem({
{title} {title}
</Typography> </Typography>
</Box> </Box>
{label ? <Chip color="primary" label={label} size="small" /> : null} {label ? (
<Chip
color="primary"
label={label}
size="small"
/>
) : null}
{external ? ( {external ? (
<Box sx={{ alignItems: 'center', display: 'flex', flex: '0 0 auto' }}> <Box sx={{ alignItems: 'center', display: 'flex', flex: '0 0 auto' }}>
<ArrowSquareOutIcon color="var(--NavItem-icon-color)" fontSize="var(--icon-fontSize-sm)" /> <ArrowSquareOutIcon
color="var(--NavItem-icon-color)"
fontSize="var(--icon-fontSize-sm)"
/>
</Box> </Box>
) : null} ) : null}
{isBranch ? ( {isBranch ? (
@@ -415,13 +492,23 @@ function renderDropdownItems({
const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => { const children = items.reduce((acc: React.ReactNode[], curr: NavItemConfig): React.ReactNode[] => {
const { key, ...item } = curr; const { key, ...item } = curr;
acc.push(<DropdownItem key={key} pathname={pathname} {...item} />); acc.push(
<DropdownItem
key={key}
pathname={pathname}
{...item}
/>
);
return acc; return acc;
}, []); }, []);
return ( return (
<Stack component="ul" spacing={1} sx={{ listStyle: 'none', m: 0, p: 0 }}> <Stack
component="ul"
spacing={1}
sx={{ listStyle: 'none', m: 0, p: 0 }}
>
{children} {children}
</Stack> </Stack>
); );
@@ -444,7 +531,10 @@ function DropdownItem({
const isBranch = Boolean(items); const isBranch = Boolean(items);
const element = ( const element = (
<Box component="li" sx={{ userSelect: 'none' }}> <Box
component="li"
sx={{ userSelect: 'none' }}
>
<Box <Box
{...(isBranch {...(isBranch
? { role: 'button' } ? { role: 'button' }