mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
refactor: nav layout
This commit is contained in:
parent
2c0bf3a8c5
commit
677e4d9ef5
14
package-lock.json
generated
14
package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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>
|
||||
|
||||
@ -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 ? (
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@ -7,6 +7,7 @@ export interface IAppConfig {
|
||||
appName: string;
|
||||
appDescription: string;
|
||||
appVersion: string;
|
||||
appGithubLink: string;
|
||||
};
|
||||
links: LinkType[];
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user