update main-nav refactoring, working,

This commit is contained in:
louiscklaw
2025-05-11 13:06:58 +08:00
parent 031dbed6a9
commit e5b136b8b5
8 changed files with 279 additions and 36 deletions

View File

@@ -0,0 +1,3 @@
# GUIDELINE
- please keep one default `export` per file

View File

@@ -0,0 +1,73 @@
'use client';
import * as React from 'react';
import IconButton from '@mui/material/IconButton';
import Popover from '@mui/material/Popover';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Tooltip from '@mui/material/Tooltip';
import { ChatCenteredDots as ChatCenteredDotsIcon } from '@phosphor-icons/react/dist/ssr/ChatCenteredDots';
import { EnvelopeSimple as EnvelopeSimpleIcon } from '@phosphor-icons/react/dist/ssr/EnvelopeSimple';
import { User as UserIcon } from '@phosphor-icons/react/dist/ssr/User';
export function ContactsButton(): React.JSX.Element {
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? 'contacts-popover' : undefined;
return (
<React.Fragment>
<Tooltip title="Contacts">
<IconButton onClick={handleClick}>
<ChatCenteredDotsIcon />
</IconButton>
</Tooltip>
<Popover
anchorEl={anchorEl}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
id={id}
onClose={handleClose}
open={open}
slotProps={{ paper: { sx: { width: '280px' } } }}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
>
<List sx={{ p: 0 }}>
<ListItem disablePadding>
<ListItemButton
component="a"
href="#"
>
<ListItemIcon>
<UserIcon />
</ListItemIcon>
<ListItemText primary="Profile" />
</ListItemButton>
</ListItem>
<ListItem disablePadding>
<ListItemButton
component="a"
href="#"
>
<ListItemIcon>
<EnvelopeSimpleIcon />
</ListItemIcon>
<ListItemText primary="Messages" />
</ListItemButton>
</ListItem>
</List>
</Popover>
</React.Fragment>
);
}

View File

@@ -19,13 +19,15 @@ import type { User } from '@/types/user';
import { useDialog } from '@/hooks/use-dialog'; import { useDialog } from '@/hooks/use-dialog';
import { usePopover } from '@/hooks/use-popover'; import { usePopover } from '@/hooks/use-popover';
import { ContactsPopover } from '../contacts-popover'; import { ContactsPopover } from '../../contacts-popover';
import { languageFlags, LanguagePopover } from '../language-popover'; import { languageFlags, LanguagePopover } from '../../language-popover';
import type { Language } from '../language-popover'; import type { Language } from '../../language-popover';
import { MobileNav } from '../mobile-nav'; import { MobileNav } from '../../mobile-nav';
import { NotificationsPopover } from '../notifications-popover'; import { NotificationsPopover } from '../../notifications-popover';
import { SearchDialog } from '../search-dialog'; import { SearchDialog } from '../../search-dialog';
import { UserPopover } from '../user-popover/user-popover'; import { UserPopover } from '../../user-popover/user-popover';
import { NotificationsButton } from './notifications-button';
import { LanguageSwitch } from './language-switch';
export interface MainNavProps { export interface MainNavProps {
items: NavItemConfig[]; items: NavItemConfig[];
@@ -146,35 +148,7 @@ function ContactsButton(): React.JSX.Element {
); );
} }
function NotificationsButton(): React.JSX.Element { function LanguageSwitch1(): React.JSX.Element {
const popover = usePopover<HTMLButtonElement>();
return (
<React.Fragment>
<Tooltip title="Notifications">
<Badge
color="error"
sx={{ '& .MuiBadge-dot': { borderRadius: '50%', height: '10px', right: '6px', top: '6px', width: '10px' } }}
variant="dot"
>
<IconButton
onClick={popover.handleOpen}
ref={popover.anchorRef}
>
<BellIcon />
</IconButton>
</Badge>
</Tooltip>
<NotificationsPopover
anchorEl={popover.anchorRef.current}
onClose={popover.handleClose}
open={popover.open}
/>
</React.Fragment>
);
}
function LanguageSwitch(): React.JSX.Element {
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const popover = usePopover<HTMLButtonElement>(); const popover = usePopover<HTMLButtonElement>();
const language = (i18n.language || 'en') as Language; const language = (i18n.language || 'en') as Language;

View File

@@ -0,0 +1,62 @@
'use client';
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import Badge from '@mui/material/Badge';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import IconButton from '@mui/material/IconButton';
import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip';
import { Bell as BellIcon } from '@phosphor-icons/react/dist/ssr/Bell';
import { List as ListIcon } from '@phosphor-icons/react/dist/ssr/List';
import { MagnifyingGlass as MagnifyingGlassIcon } from '@phosphor-icons/react/dist/ssr/MagnifyingGlass';
import { Users as UsersIcon } from '@phosphor-icons/react/dist/ssr/Users';
import { useTranslation } from 'next-i18next';
import type { NavItemConfig } from '@/types/nav';
import type { User } from '@/types/user';
import { useDialog } from '@/hooks/use-dialog';
import { usePopover } from '@/hooks/use-popover';
import { ContactsPopover } from '../../contacts-popover';
import { languageFlags, LanguagePopover } from '../../language-popover';
import type { Language } from '../../language-popover';
import { MobileNav } from '../../mobile-nav';
import { NotificationsPopover } from '../../notifications-popover';
import { SearchDialog } from '../../search-dialog';
import { UserPopover } from '../../user-popover/user-popover';
import { NotificationsButton } from './notifications-button';
export function LanguageSwitch(): React.JSX.Element {
const { i18n } = useTranslation();
const popover = usePopover<HTMLButtonElement>();
const language = (i18n.language || 'en') as Language;
const flag = languageFlags[language];
return (
<React.Fragment>
<Tooltip title="Language">
<IconButton
onClick={popover.handleOpen}
ref={popover.anchorRef}
sx={{ display: { xs: 'none', lg: 'inline-flex' } }}
>
<Box sx={{ height: '24px', width: '24px' }}>
<Box
alt={language}
component="img"
src={flag}
sx={{ height: 'auto', width: '100%' }}
/>
</Box>
</IconButton>
</Tooltip>
<LanguagePopover
anchorEl={popover.anchorRef.current}
onClose={popover.handleClose}
open={popover.open}
/>
</React.Fragment>
);
}

View File

@@ -0,0 +1,49 @@
'use client';
import * as React from 'react';
import Badge from '@mui/material/Badge';
import IconButton from '@mui/material/IconButton';
import Popover from '@mui/material/Popover';
import Tooltip from '@mui/material/Tooltip';
import { Bell as BellIcon } from '@phosphor-icons/react/dist/ssr/Bell';
export function NotificationsButton(): React.JSX.Element {
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? 'notifications-popover' : undefined;
return (
<React.Fragment>
<Tooltip title="Notifications">
<IconButton onClick={handleClick}>
<Badge
badgeContent={4}
color="error"
>
<BellIcon />
</Badge>
</IconButton>
</Tooltip>
<Popover
anchorEl={anchorEl}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
id={id}
onClose={handleClose}
open={open}
slotProps={{ paper: { sx: { width: '280px' } } }}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
>
{/* Notification content would go here */}
</Popover>
</React.Fragment>
);
}

View File

@@ -0,0 +1,29 @@
'use client';
import * as React from 'react';
import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip';
import { MagnifyingGlass as MagnifyingGlassIcon } from '@phosphor-icons/react/dist/ssr/MagnifyingGlass';
import { useDialog } from '@/hooks/use-dialog';
import { SearchDialog } from '../../search-dialog';
export function SearchButton(): React.JSX.Element {
const dialog = useDialog();
return (
<React.Fragment>
<Tooltip title="Search">
<IconButton
onClick={dialog.handleOpen}
sx={{ display: { xs: 'none', lg: 'inline-flex' } }}
>
<MagnifyingGlassIcon />
</IconButton>
</Tooltip>
<SearchDialog
onClose={dialog.handleClose}
open={dialog.open}
/>
</React.Fragment>
);
}

View File

@@ -0,0 +1,44 @@
'use client';
import * as React from 'react';
import { User as UserIcon } from '@phosphor-icons/react/dist/ssr/User';
import { Avatar, Popover, Tooltip } from '@mui/material';
export function UserButton(): React.JSX.Element {
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? 'user-popover' : undefined;
return (
<React.Fragment>
<Tooltip title="User">
<Avatar
onClick={handleClick}
sx={{ cursor: 'pointer', height: 32, width: 32 }}
>
<UserIcon fontSize="var(--Icon-fontSize)" />
</Avatar>
</Tooltip>
<Popover
anchorEl={anchorEl}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
id={id}
onClose={handleClose}
open={open}
slotProps={{ paper: { sx: { width: '240px' } } }}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
>
{/* User menu content would go here */}
</Popover>
</React.Fragment>
);
}

View File

@@ -0,0 +1,9 @@
'use client';
import type { User } from '@/types/user';
export const user = {
id: 'USR-000',
name: 'Sofia Rivers',
avatar: '/assets/avatar.png',
email: 'sofia@devias.io',
} satisfies User;