UNPKG

react-garden

Version:

React + TypeScript + ThreeJS app using Material UI on NextJS, Apollo Client, GraphQL + WordPress REST APIs, for ThreeD web development.. a part of the threed.ai code family.

323 lines (298 loc) 11.1 kB
// ** React Imports import { useEffect, Fragment } from 'react' // ** Next Import import { useRouter } from 'next/router' // ** MUI Imports import Chip from '@mui/material/Chip' import Collapse from '@mui/material/Collapse' import ListItem from '@mui/material/ListItem' import Typography from '@mui/material/Typography' import Box from '@mui/material/Box' import ListItemIcon from '@mui/material/ListItemIcon' import { styled, useTheme } from '@mui/material/styles' import ListItemButton from '@mui/material/ListItemButton' // ** Third Party Imports import clsx from 'clsx' // ** Icons Imports import ChevronLeft from 'mdi-material-ui/ChevronLeft' import ChevronRight from 'mdi-material-ui/ChevronRight' // ** Configs Import import themeConfig from '~/configs/themeConfig' // ** Utils import { hasActiveChild, removeChildren } from '~/@core/layouts/utils' // ** Custom Components Imports import VerticalNavItems from './VerticalNavItems' import UserIcon from '~/layouts/components/UserIcon' import Translations from '~/layouts/components/Translations' import CanViewNavGroup from '~/layouts/components/acl/CanViewNavGroup' const MenuItemTextWrapper = styled(Box)(() => ({ width: '100%', display: 'flex', justifyContent: 'space-between', transition: 'opacity .25s ease-in-out', ...(themeConfig.menuTextTruncate && { overflow: 'hidden' }) })) const MenuGroupToggleRightIcon = styled(ChevronRight)(({ theme }) => ({ color: theme.palette.text.primary, transition: 'transform .25s ease-in-out' })) const MenuGroupToggleLeftIcon = styled(ChevronLeft)(({ theme }) => ({ color: theme.palette.text.primary, transition: 'transform .25s ease-in-out' })) const VerticalNavGroup = props => { // ** Props const { item, parent, settings, navHover, navVisible, isSubToSub, groupActive, setGroupActive, collapsedNavWidth, currentActiveGroup, setCurrentActiveGroup, navigationBorderWidth } = props // ** Hooks & Vars const theme = useTheme() const router = useRouter() const currentURL = router.pathname const { skin, direction, navCollapsed, verticalNavToggleType } = settings // ** Accordion menu group open toggle const toggleActiveGroup = (item, parent) => { let openGroup = groupActive // ** If Group is already open and clicked, close the group if (openGroup.includes(item.title)) { openGroup.splice(openGroup.indexOf(item.title), 1) // If clicked Group has open group children, Also remove those children to close those groups if (item.children) { removeChildren(item.children, openGroup, currentActiveGroup) } } else if (parent) { // ** If Group clicked is the child of an open group, first remove all the open groups under that parent if (parent.children) { removeChildren(parent.children, openGroup, currentActiveGroup) } // ** After removing all the open groups under that parent, add the clicked group to open group array if (!openGroup.includes(item.title)) { openGroup.push(item.title) } } else { // ** If clicked on another group that is not active or open, create openGroup array from scratch // ** Empty Open Group array openGroup = [] // ** push Current Active Group To Open Group array if (currentActiveGroup.every(elem => groupActive.includes(elem))) { openGroup.push(...currentActiveGroup) } // ** Push current clicked group item to Open Group array if (!openGroup.includes(item.title)) { openGroup.push(item.title) } } setGroupActive([...openGroup]) } // ** Menu Group Click const handleGroupClick = () => { const openGroup = groupActive if (verticalNavToggleType === 'collapse') { if (openGroup.includes(item.title)) { openGroup.splice(openGroup.indexOf(item.title), 1) } else { openGroup.push(item.title) } setGroupActive([...openGroup]) } else { toggleActiveGroup(item, parent) } } useEffect(() => { if (hasActiveChild(item, currentURL)) { if (!groupActive.includes(item.title)) groupActive.push(item.title) } else { const index = groupActive.indexOf(item.title) if (index > -1) groupActive.splice(index, 1) } setGroupActive([...groupActive]) setCurrentActiveGroup([...groupActive]) // Empty Active Group When Menu is collapsed and not hovered, to fix issue route change if (navCollapsed && !navHover) { setGroupActive([]) } }, [router.asPath]) useEffect(() => { if (navCollapsed && !navHover) { setGroupActive([]) } if ((navCollapsed && navHover) || (groupActive.length === 0 && !navCollapsed)) { setGroupActive([...currentActiveGroup]) } }, [navCollapsed, navHover]) useEffect(() => { if (groupActive.length === 0 && !navCollapsed) { setGroupActive([]) } }, [navHover]) const IconTag = parent && !item.icon ? themeConfig.navSubItemIcon : item.icon const menuGroupCollapsedStyles = navCollapsed && !navHover ? { opacity: 0 } : { opacity: 1 } const conditionalColor = () => { if (skin === 'semi-dark' && theme.palette.mode === 'light') { return { color: `rgba(${theme.palette.customColors.dark}, 0.68) !important` } } else if (skin === 'semi-dark' && theme.palette.mode === 'dark') { return { color: `rgba(${theme.palette.customColors.light}, 0.68) !important` } } else { return { color: `${theme.palette.text.secondary} !important` } } } const conditionalBgColor = () => { if (skin === 'semi-dark' && theme.palette.mode === 'light') { return { color: `rgba(${theme.palette.customColors.dark}, 0.87)`, '&:hover': { backgroundColor: `rgba(${theme.palette.customColors.dark}, 0.04)` }, '&.Mui-selected': { backgroundColor: `rgba(${theme.palette.customColors.dark}, 0.08)`, '&:hover': { backgroundColor: `rgba(${theme.palette.customColors.dark}, 0.12)` } } } } else if (skin === 'semi-dark' && theme.palette.mode === 'dark') { return { color: `rgba(${theme.palette.customColors.light}, 0.87)`, '&:hover': { backgroundColor: `rgba(${theme.palette.customColors.light}, 0.04)` }, '&.Mui-selected': { backgroundColor: `rgba(${theme.palette.customColors.light}, 0.08)`, '&:hover': { backgroundColor: `rgba(${theme.palette.customColors.light}, 0.12)` } } } } else { return { '&.Mui-selected': { backgroundColor: theme.palette.action.hover, '&:hover': { backgroundColor: theme.palette.action.hover } } } } } return ( <CanViewNavGroup navGroup={item}> <> <ListItem disablePadding className='nav-group' onClick={handleGroupClick} sx={{ mt: 1.5, px: '0 !important', flexDirection: 'column' }} > <ListItemButton className={clsx({ 'Mui-selected': groupActive.includes(item.title) || currentActiveGroup.includes(item.title) })} sx={{ py: 2.25, width: '100%', ...conditionalBgColor(), borderTopRightRadius: 100, borderBottomRightRadius: 100, transition: 'padding-left .25s ease-in-out', pl: navCollapsed && !navHover ? (collapsedNavWidth - navigationBorderWidth - 24) / 8 : 5.5, pr: navCollapsed && !navHover ? ((collapsedNavWidth - navigationBorderWidth - 24) / 2 - 5) / 4 : 3.5 }} > {isSubToSub ? null : ( <ListItemIcon sx={{ color: 'text.primary', transition: 'margin .25s ease-in-out', ...(parent && navCollapsed && !navHover ? {} : { mr: 2.5 }), ...(navCollapsed && !navHover ? { mr: 0 } : {}), ...(parent && item.children ? { ml: 1.25, mr: 3.75 } : {}) }} > <UserIcon icon={IconTag} componentType='vertical-menu' iconProps={{ sx: { ...(parent ? { fontSize: '0.875rem' } : {}) } }} /> </ListItemIcon> )} <MenuItemTextWrapper sx={{ ...menuGroupCollapsedStyles, ...(isSubToSub ? { ml: 9 } : {}) }}> <Typography {...((themeConfig.menuTextTruncate || (!themeConfig.menuTextTruncate && navCollapsed && !navHover)) && { noWrap: true })} > <Translations text={item.title} /> </Typography> <Box className='menu-item-meta' sx={{ ml: 0.8, display: 'flex', alignItems: 'center' }}> {item.badgeContent ? ( <Chip label={item.badgeContent} color={item.badgeColor || 'primary'} sx={{ mr: 0.8, height: 20, fontWeight: 500, '& .MuiChip-label': { px: 1.5, textTransform: 'capitalize' } }} /> ) : null} {direction === 'ltr' ? ( <MenuGroupToggleRightIcon sx={{ ...conditionalColor(), ...(groupActive.includes(item.title) ? { transform: 'rotate(90deg)' } : {}) }} /> ) : ( <MenuGroupToggleLeftIcon sx={{ ...conditionalColor(), ...(groupActive.includes(item.title) ? { transform: 'rotate(-90deg)' } : {}) }} /> )} </Box> </MenuItemTextWrapper> </ListItemButton> <Collapse component='ul' onClick={e => e.stopPropagation()} in={groupActive.includes(item.title)} sx={{ pl: 0, width: '100%', ...menuGroupCollapsedStyles, transition: 'all .25s ease-in-out' }} > <VerticalNavItems {...props} parent={item} navVisible={navVisible} verticalNavItems={item.children} isSubToSub={parent && item.children ? item : undefined} /> </Collapse> </ListItem> </> </CanViewNavGroup> ) } export default VerticalNavGroup