fix(dashboard): layout
This commit is contained in:
215
dashboard/src/components/Menu.tsx
Normal file
215
dashboard/src/components/Menu.tsx
Normal file
@@ -0,0 +1,215 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import {
|
||||
IconButton,
|
||||
Avatar,
|
||||
Box,
|
||||
CloseButton,
|
||||
Flex,
|
||||
Image,
|
||||
HStack,
|
||||
VStack,
|
||||
Icon,
|
||||
useColorModeValue,
|
||||
Link,
|
||||
Text,
|
||||
BoxProps,
|
||||
FlexProps,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FiHome,
|
||||
FiTrendingUp,
|
||||
FiCompass,
|
||||
FiStar,
|
||||
FiSettings,
|
||||
FiMenu,
|
||||
FiUser,
|
||||
FiUsers,
|
||||
FiChevronDown,
|
||||
} from 'react-icons/fi';
|
||||
import { IconType } from 'react-icons';
|
||||
import { ReactText } from 'react';
|
||||
import { useMutation } from 'urql';
|
||||
import { NavLink, useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useAuthContext } from '../contexts/AuthContext';
|
||||
import { AdminLogout } from '../graphql/mutation';
|
||||
|
||||
interface LinkItemProps {
|
||||
name: string;
|
||||
icon: IconType;
|
||||
route: string;
|
||||
}
|
||||
const LinkItems: Array<LinkItemProps> = [
|
||||
{ name: 'Home', icon: FiHome, route: '/' },
|
||||
{ name: 'Users', icon: FiUsers, route: '/users' },
|
||||
{ name: 'Environment Variables', icon: FiSettings, route: '/environment' },
|
||||
];
|
||||
|
||||
interface SidebarProps extends BoxProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
|
||||
const { pathname } = useLocation();
|
||||
return (
|
||||
<Box
|
||||
transition="3s ease"
|
||||
bg={useColorModeValue('white', 'gray.900')}
|
||||
borderRight="1px"
|
||||
borderRightColor={useColorModeValue('gray.200', 'gray.700')}
|
||||
w={{ base: 'full', md: 60 }}
|
||||
pos="fixed"
|
||||
h="full"
|
||||
{...rest}
|
||||
>
|
||||
<Flex h="20" alignItems="center" mx="8" justifyContent="space-between">
|
||||
<NavLink to="/">
|
||||
<Flex alignItems="center">
|
||||
<Image
|
||||
src="https://authorizer.dev/images/logo.png"
|
||||
alt="logo"
|
||||
height="36px"
|
||||
/>
|
||||
<Text fontSize="large" ml="2" letterSpacing="3">
|
||||
AUTHORIZER
|
||||
</Text>
|
||||
</Flex>
|
||||
</NavLink>
|
||||
<CloseButton display={{ base: 'flex', md: 'none' }} onClick={onClose} />
|
||||
</Flex>
|
||||
{LinkItems.map((link) => (
|
||||
<NavLink key={link.name} to={link.route}>
|
||||
<NavItem
|
||||
icon={link.icon}
|
||||
color={pathname === link.route ? 'blue.500' : ''}
|
||||
>
|
||||
{link.name}
|
||||
</NavItem>
|
||||
</NavLink>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
interface NavItemProps extends FlexProps {
|
||||
icon: IconType;
|
||||
children: ReactText;
|
||||
}
|
||||
export const NavItem = ({ icon, children, ...rest }: NavItemProps) => {
|
||||
return (
|
||||
<Link
|
||||
href="#"
|
||||
style={{ textDecoration: 'none' }}
|
||||
_focus={{ boxShadow: 'none' }}
|
||||
>
|
||||
<Flex
|
||||
align="center"
|
||||
p="3"
|
||||
mx="3"
|
||||
borderRadius="md"
|
||||
role="group"
|
||||
cursor="pointer"
|
||||
_hover={{
|
||||
bg: 'blue.500',
|
||||
color: 'white',
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{icon && (
|
||||
<Icon
|
||||
mr="4"
|
||||
fontSize="16"
|
||||
_groupHover={{
|
||||
color: 'white',
|
||||
}}
|
||||
as={icon}
|
||||
/>
|
||||
)}
|
||||
{children}
|
||||
</Flex>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
interface MobileProps extends FlexProps {
|
||||
onOpen: () => void;
|
||||
}
|
||||
export const MobileNav = ({ onOpen, ...rest }: MobileProps) => {
|
||||
const [_, logout] = useMutation(AdminLogout);
|
||||
const { setIsLoggedIn } = useAuthContext();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleLogout = async () => {
|
||||
await logout();
|
||||
setIsLoggedIn(false);
|
||||
navigate('/', { replace: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex
|
||||
ml={{ base: 0, md: 60 }}
|
||||
px={{ base: 4, md: 4 }}
|
||||
height="20"
|
||||
position="fixed"
|
||||
right="0"
|
||||
left="0"
|
||||
alignItems="center"
|
||||
bg={useColorModeValue('white', 'gray.900')}
|
||||
borderBottomWidth="1px"
|
||||
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
|
||||
justifyContent={{ base: 'space-between', md: 'flex-end' }}
|
||||
{...rest}
|
||||
>
|
||||
<IconButton
|
||||
display={{ base: 'flex', md: 'none' }}
|
||||
onClick={onOpen}
|
||||
variant="outline"
|
||||
aria-label="open menu"
|
||||
icon={<FiMenu />}
|
||||
/>
|
||||
|
||||
<Image
|
||||
src="https://authorizer.dev/images/logo.png"
|
||||
alt="logo"
|
||||
height="36px"
|
||||
display={{ base: 'flex', md: 'none' }}
|
||||
/>
|
||||
|
||||
<HStack spacing={{ base: '0', md: '6' }}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Menu>
|
||||
<MenuButton
|
||||
py={2}
|
||||
transition="all 0.3s"
|
||||
_focus={{ boxShadow: 'none' }}
|
||||
>
|
||||
<HStack>
|
||||
<FiUser />
|
||||
<VStack
|
||||
display={{ base: 'none', md: 'flex' }}
|
||||
alignItems="flex-start"
|
||||
spacing="1px"
|
||||
ml="2"
|
||||
>
|
||||
<Text fontSize="sm">Admin</Text>
|
||||
</VStack>
|
||||
<Box display={{ base: 'none', md: 'flex' }}>
|
||||
<FiChevronDown />
|
||||
</Box>
|
||||
</HStack>
|
||||
</MenuButton>
|
||||
<MenuList
|
||||
bg={useColorModeValue('white', 'gray.900')}
|
||||
borderColor={useColorModeValue('gray.200', 'gray.700')}
|
||||
>
|
||||
<MenuItem onClick={handleLogout}>Sign out</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Flex>
|
||||
</HStack>
|
||||
</Flex>
|
||||
);
|
||||
};
|
@@ -1,78 +0,0 @@
|
||||
import { Box, Image, Link, Text, Button } from '@chakra-ui/react';
|
||||
import { NavLink, useLocation, useNavigate } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { LOGO_URL } from '../constants';
|
||||
import { useMutation } from 'urql';
|
||||
import { AdminLogout } from '../graphql/mutation';
|
||||
import { useAuthContext } from '../contexts/AuthContext';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
route: '/users',
|
||||
name: 'Users',
|
||||
},
|
||||
{
|
||||
route: '/',
|
||||
name: 'Environment Variable',
|
||||
},
|
||||
];
|
||||
|
||||
export const Sidebar = () => {
|
||||
const { pathname } = useLocation();
|
||||
const [_, logout] = useMutation(AdminLogout);
|
||||
const { setIsLoggedIn } = useAuthContext();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleLogout = async () => {
|
||||
await logout();
|
||||
setIsLoggedIn(false);
|
||||
navigate('/', { replace: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<Box as="nav" h="100%">
|
||||
<NavLink to="/">
|
||||
<Box d="flex" alignItems="center" p="4" mt="4" mb="10">
|
||||
<Image w="8" src={LOGO_URL} alt="" />
|
||||
<Text
|
||||
color="white"
|
||||
casing="uppercase"
|
||||
fontSize="1xl"
|
||||
ml="3"
|
||||
letterSpacing="1.5px"
|
||||
>
|
||||
Authorizer
|
||||
</Text>
|
||||
</Box>
|
||||
</NavLink>
|
||||
{routes.map(({ route, name }: any) => (
|
||||
<Link
|
||||
color={pathname === route ? 'blue.500' : 'white'}
|
||||
transition="all ease-in 0.2s"
|
||||
_hover={{ color: pathname === route ? 'blue.200' : 'whiteAlpha.700' }}
|
||||
px="4"
|
||||
py="2"
|
||||
bg={pathname === route ? 'white' : ''}
|
||||
fontWeight="bold"
|
||||
display="block"
|
||||
as={NavLink}
|
||||
key={name}
|
||||
to={route}
|
||||
>
|
||||
{name}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<Box
|
||||
as="div"
|
||||
w="100%"
|
||||
position="absolute"
|
||||
bottom="5"
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
>
|
||||
<Button onClick={handleLogout}>Logout</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user