refactor: nav layout

This commit is contained in:
Sergey Yarkov 2021-12-06 22:25:01 +03:00
parent 2c0bf3a8c5
commit 677e4d9ef5
10 changed files with 79 additions and 89 deletions

14
package-lock.json generated
View File

@ -1337,11 +1337,6 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"caniuse-lite": {
"version": "1.0.30001267",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001267.tgz",
@ -2155,12 +2150,9 @@
"integrity": "sha512-7XhbCr7d9fDC1TgcK/BUbt7D3q0VJMu7jPErfsa0JrxVjv/nni41xWdJcy0Zb7R+Np8OsCkQ2lMyloAtE3DLiQ=="
},
"react-icons": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.11.0.tgz",
"integrity": "sha512-JRgiI/vdF6uyBgyZhVyYJUZAop95Sy4XDe/jmT3R/bKliFWpO/uZBwvSjWEdxwzec7SYbEPNPck0Kff2tUGM2Q==",
"requires": {
"camelcase": "^5.0.0"
}
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ=="
},
"react-is": {
"version": "16.13.1",

View File

@ -27,7 +27,7 @@
"react-error-boundary": "^3.1.3",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.12.2",
"react-icons": "^3.11.0",
"react-icons": "^4.3.1",
"react-router-dom": "^5.2.0",
"react-spinners": "^0.11.0",
"react-virtuoso": "^2.2.8",

View File

@ -1,25 +1,24 @@
import React from 'react';
import { observer } from 'mobx-react';
import { Flex, Box, Heading, useColorMode } from '@chakra-ui/react';
import { MdSchool } from 'react-icons/md';
import config from '@educt/config';
import { Flex, Box } from '@chakra-ui/react';
/**
* Components
*/
import Logo from '@educt/components/Logo';
import NavMobile from '@educt/components/Nav/Mobile';
import ColorModeSwitcher from '@educt/components/ColorModeSwitcher';
import UserInfo from './UserInfo';
import UserNotifications from './UserNotifications';
import ProfileMenu from './ProfileMenu';
import NotificationsMenu from './NotificationsMenu';
/**
* Hooks
*/
import { useMediaQuery } from '@chakra-ui/media-query';
import { useColorModeValue } from '@chakra-ui/color-mode';
const Header: React.FC = () => {
const [isDesktop] = useMediaQuery('(min-width: 992px)');
const { colorMode } = useColorMode();
return (
<Box
@ -28,10 +27,8 @@ const Header: React.FC = () => {
top={0}
left={0}
right={0}
// borderBottomWidth={1}
// h='43px'
boxShadow='md'
backgroundColor={colorMode === 'dark' ? 'gray.800' : 'white'}
borderBottomWidth='1px'
backgroundColor={useColorModeValue('white', 'gray.800')}
zIndex={4}
>
<Flex
@ -41,25 +38,15 @@ const Header: React.FC = () => {
alignItems='center'
padding='5px 1.5rem 5px 1.5rem'
>
<Flex alignItems='center'>
<Box mr='4'>
<Box as={MdSchool} color='blue.500' size='36px' />
</Box>
<Box>
<Heading as='p' fontSize='2xl' lineHeight='1'>
{config.metaData.appName}
</Heading>
</Box>
</Flex>
{isDesktop ? (
<Logo h='10' />
{isDesktop && (
<Flex>
<ColorModeSwitcher />
<UserNotifications />
<UserInfo />
<NotificationsMenu />
<ProfileMenu />
</Flex>
) : (
<NavMobile />
)}
{!isDesktop && <NavMobile />}
</Flex>
</Box>
);

View File

@ -6,7 +6,7 @@ import { MdNotifications } from 'react-icons/md';
import { useRootStore } from '@educt/hooks/useRootStore';
import { observer } from 'mobx-react';
const UserNotifications: React.FC = () => {
const NotificationsMenu: React.FC = () => {
const { userStore } = useRootStore();
if (userStore.me === null) {
@ -39,4 +39,4 @@ const UserNotifications: React.FC = () => {
);
};
export default observer(UserNotifications);
export default observer(NotificationsMenu);

View File

@ -24,7 +24,7 @@ import UserBadge from '@educt/components/UserBadge';
*/
import { useLogout } from '@educt/hooks/queries';
const UserInfo: React.FC = () => {
const ProfileMenu: React.FC = () => {
const { userStore } = useRootStore();
const { logout } = useLogout();
@ -64,4 +64,4 @@ const UserInfo: React.FC = () => {
);
};
export default observer(UserInfo);
export default observer(ProfileMenu);

View File

@ -37,17 +37,10 @@ const Nav: React.FC = () => {
zIndex='1'
backgroundColor={colorMode === 'dark' ? 'gray.800' : 'white'}
>
<Flex
as='nav'
flexDirection='column'
alignItems='flex-start'
textDecoration='none'
pt='4rem'
pr='5'
pl='5'
pb='5'
>
<NavList links={config.links} />
<Flex as='nav' flexDirection='column' alignItems='flex-start' textDecoration='none' p='32px 24px'>
<Flex flexDir='column' pt='3rem' w='full'>
<NavList links={config.links} />
</Flex>
</Flex>
<Box textAlign='center' mt='auto' mb='5'>
<Text fontSize='xs' color='gray.500' lineHeight='1.6'>
@ -55,7 +48,7 @@ const Nav: React.FC = () => {
</Text>
<Box textAlign='center' mt='2'>
<IconButton variant='link' aria-label='GitHub repository'>
<Link isExternal href='https://github.com/sergeyyarkov/educt-client'>
<Link isExternal href={config.metaData.appGithubLink}>
<Box as={FaGithub} />
</Link>
</IconButton>

View File

@ -13,6 +13,7 @@ import config from '@educt/config';
* Components
*/
import NavList from '../NavList';
import Logo from '@educt/components/Logo';
/**
* Hooks
@ -37,7 +38,10 @@ const NavMobile: React.FC = () => {
<DrawerContent backgroundColor={colorMode === 'dark' ? 'gray.800' : 'white'}>
<DrawerBody>
<Flex flexDirection='column' height='100%'>
<Flex as='nav' flexDirection='column' alignItems='flex-start' textDecoration='none' mb='20px'>
<Box mt='2'>
<Logo h='10' ml='2' />
</Box>
<Flex flexDir='column' mt='3' w='full'>
<NavList links={config.links} onCloseDrawer={onClose} />
</Flex>
{me !== null ? (

View File

@ -1,62 +1,67 @@
import React from 'react';
import { observer } from 'mobx-react';
import { userContainRoles } from '@educt/helpers';
import { Box, useColorMode } from '@chakra-ui/react';
import * as helpers from '@educt/helpers';
import { Flex, Box, Icon, Text } from '@chakra-ui/react';
/**
* Types
*/
import type { LinkType } from '@educt/types';
/**
* Hooks
*/
import { useRootStore } from '@educt/hooks/useRootStore';
import { useColorMode } from '@chakra-ui/react';
type NavLinkPropsType = {
link: LinkType;
onClickLink: (link: LinkType) => void;
};
/**
* Returns the link component for navigation.
*/
const NavLink: React.FC<NavLinkPropsType> = ({ link, onClickLink }) => {
const { uiStore, userStore } = useRootStore();
const { colorMode } = useColorMode();
const isActive = uiStore.location === link.location;
const onClick = () => onClickLink(link);
if (!link.public && link.roles !== undefined) {
const { me } = userStore;
if (me === null) return null;
if (!userContainRoles(me.roles, link.roles)) return null;
if (!helpers.userContainRoles(me.roles, link.roles)) return null;
}
return (
<Box
as='a'
onClick={onClick}
display='flex'
margin='3px 0'
width='100%'
border='none'
display='block'
aria-label={link.title}
role='link'
fontWeight='medium'
borderRadius='md'
mt='0.5rem'
pt='2'
pb='2'
paddingInlineStart='3'
paddingInlineEnd='3'
transition='all 0.3s ease 0s'
lineHeight='1.5rem'
textDecoration='none'
cursor='pointer'
outline='transparent solid 2px'
outlineOffset='2px'
color={isActive ? 'white' : ''}
backgroundColor={isActive ? `${colorMode === 'dark' ? 'gray.700' : 'blue.500'}` : ''}
_hover={{
bg: `${colorMode === 'dark' ? 'gray.700' : `${!isActive ? 'gray.100' : ''}`}`,
}}
>
<Box
color={uiStore.location === link.location ? 'blue.400' : ''}
backgroundColor={uiStore.location === link.location ? `${colorMode === 'dark' ? 'gray.700' : 'gray.100'}` : ''}
alignItems='center'
borderRadius='3xl'
display='flex'
padding='10px 15px'
fontWeight='500'
transition='all .1s'
_hover={{
bg: `${colorMode === 'dark' ? 'gray.700' : 'gray.100'}`,
color: `blue.400`,
}}
>
<Box as={link.icon} boxSize='26px' mr={3} />
{link.title}
</Box>
<Flex flexDir='row' alignItems='center'>
<Icon as={link.icon} boxSize='21px' />
<Text as='span' ml='16px'>
{link.title}
</Text>
</Flex>
</Box>
);
};

View File

@ -1,5 +1,12 @@
import { UserRoleEnum } from '@educt/enums';
import { MdAccountCircle, MdCollectionsBookmark, MdGroup, MdHome, MdMessage, MdList } from 'react-icons/md';
import {
MdOutlineHome,
MdOutlineMessage,
MdOutlineCollectionsBookmark,
MdOutlineVideoLibrary,
MdOutlineGroup,
MdOutlineAccountCircle,
} from 'react-icons/md';
import { IAppConfig } from './interfaces';
import packageJson from '../package.json';
@ -11,28 +18,29 @@ const config: IAppConfig = {
appName: 'Educt',
appDescription: 'Learning management system',
appVersion: packageJson.version,
appGithubLink: 'https://github.com/sergeyyarkov/educt-client',
},
/**
* Links that are rendered in the navigation
*/
links: [
{ location: '/', title: 'Main', public: true, icon: MdHome },
{ location: '/courses', title: 'Courses', public: true, icon: MdCollectionsBookmark },
{ location: '/', title: 'Main', public: true, icon: MdOutlineHome },
{ location: '/courses', title: 'Courses', public: true, icon: MdOutlineCollectionsBookmark },
{
location: '/lessons',
title: 'Lessons',
public: false,
icon: MdList,
icon: MdOutlineVideoLibrary,
roles: [UserRoleEnum.ADMIN, UserRoleEnum.TEACHER],
},
{ location: '/messages', title: 'Messages', public: true, icon: MdMessage },
{ location: '/profile', title: 'Profile', public: true, icon: MdAccountCircle },
{ location: '/messages', title: 'Messages', public: true, icon: MdOutlineMessage },
{ location: '/profile', title: 'Profile', public: true, icon: MdOutlineAccountCircle },
{
location: '/users',
title: 'Users',
public: false,
roles: [UserRoleEnum.ADMIN, UserRoleEnum.TEACHER],
icon: MdGroup,
icon: MdOutlineGroup,
},
],
};

View File

@ -7,6 +7,7 @@ export interface IAppConfig {
appName: string;
appDescription: string;
appVersion: string;
appGithubLink: string;
};
links: LinkType[];
}