SPRINT-18: fixed to dashboards, removed and moved around all the things

This commit is contained in:
Tim Chamberlain
2023-01-04 11:40:21 -06:00
parent e49f178738
commit 267580b44b
460 changed files with 9717 additions and 11057 deletions

View File

@ -0,0 +1,131 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Breadcrumbs as MuiBreadcrumbs} from "@mui/material";
import Box from "@mui/material/Box";
import Icon from "@mui/material/Icon";
import {ReactNode, useContext} from "react";
import {Link} from "react-router-dom";
import QContext from "QContext";
import MDTypography from "qqq/components/legacy/MDTypography";
interface Props
{
icon: ReactNode;
title: string;
route: string | string[];
light?: boolean;
[key: string]: any;
}
const ucFirst = (input: string): string =>
{
if (!input)
{
return (input);
}
return (input.substring(0, 1).toUpperCase() + input.substring(1));
};
export const routeToLabel = (route: string): string =>
{
const label = ucFirst(route
.replace(".", " ")
.replace("-", " ")
.replace("_", " ")
.replace(/([a-z])([A-Z]+)/g, "$1 $2") // transform personUSA => person USA
.replace(/^([A-Z]+)([A-Z])([a-z])/, "$1 $2$3")); // transform USAPerson => USA Person
return (label);
};
function QBreadcrumbs({icon, title, route, light}: Props): JSX.Element
{
const routes: string[] | any = route.slice(0, -1);
const {pageHeader, setPageHeader} = useContext(QContext);
let pageTitle = "Nutrifresh One";
const fullRoutes: string[] = [];
let accumulatedPath = "";
for (let i = 0; i < routes.length; i++)
{
accumulatedPath = `${accumulatedPath}/${routes[i]}`;
fullRoutes.push(accumulatedPath);
pageTitle = `${routeToLabel(routes[i])} | ${pageTitle}`;
}
document.title = `${ucFirst(title)} | ${pageTitle}`;
return (
<Box mr={{xs: 0, xl: 8}}>
<MuiBreadcrumbs
sx={{
"& .MuiBreadcrumbs-separator": {
color: ({palette: {white, grey}}) => (light ? white.main : grey[600]),
},
}}
>
<Link to="/">
<MDTypography
component="span"
variant="body2"
color={light ? "white" : "dark"}
opacity={light ? 0.8 : 0.5}
sx={{lineHeight: 0}}
>
<Icon>{icon}</Icon>
</MDTypography>
</Link>
{fullRoutes.map((fullRoute: string) => (
<Link to={fullRoute} key={fullRoute}>
<MDTypography
component="span"
variant="button"
fontWeight="regular"
textTransform="capitalize"
color={light ? "white" : "dark"}
opacity={light ? 0.8 : 0.5}
sx={{lineHeight: 0}}
>
{routeToLabel(fullRoute.replace(/.*\//, ""))}
</MDTypography>
</Link>
))}
</MuiBreadcrumbs>
<MDTypography
pt={1}
fontWeight="bold"
textTransform="capitalize"
variant="h5"
color={light ? "white" : "dark"}
noWrap
>
{pageHeader}
</MDTypography>
</Box>
);
}
QBreadcrumbs.defaultProps = {
light: false,
};
export default QBreadcrumbs;

View File

@ -0,0 +1,120 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Box from "@mui/material/Box";
import Link from "@mui/material/Link";
import MDTypography from "qqq/components/legacy/MDTypography";
import typography from "qqq/components/legacy/typography";
// Declaring props types for Footer
interface Props
{
company?: {
href: string;
name: string;
};
links?: {
href: string;
name: string;
}[];
[key: string]: any;
}
function Footer({company, links}: Props): JSX.Element
{
const {href, name} = company;
const {size} = typography;
const renderLinks = () => links.map((link) => (
<Box key={link.name} component="li" px={2} lineHeight={1}>
<Link href={link.href} target="_blank">
<MDTypography variant="button" fontWeight="regular" color="text">
{link.name}
</MDTypography>
</Link>
</Box>
));
return (
<Box
width="100%"
display="flex"
flexDirection={{xs: "column", lg: "row"}}
justifyContent="space-between"
alignItems="center"
px={1.5}
style={{
position: "fixed", bottom: "0px", zIndex: -1, marginBottom: "10px",
}}
>
<Box
display="flex"
justifyContent="center"
alignItems="center"
flexWrap="wrap"
color="text"
fontSize={size.sm}
px={1.5}
>
&copy;
{" "}
{new Date().getFullYear()}
,
<Link href={href} target="_blank">
<MDTypography variant="button" fontWeight="medium">
&nbsp;
{name}
&nbsp;
</MDTypography>
</Link>
</Box>
<Box
component="ul"
sx={({breakpoints}) => ({
display: "flex",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "center",
listStyle: "none",
mt: 3,
mb: 0,
p: 0,
[breakpoints.up("lg")]: {
mt: 0,
},
})}
>
{renderLinks()}
</Box>
</Box>
);
}
// Declaring default props for Footer
Footer.defaultProps = {
company: {href: "https://www.nutrifreshservices.com/", name: "Nutrifresh Services"},
links: [],
};
export default Footer;

View File

@ -0,0 +1,255 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Popper} from "@mui/material";
import AppBar from "@mui/material/AppBar";
import Autocomplete from "@mui/material/Autocomplete";
import Badge from "@mui/material/Badge";
import Box from "@mui/material/Box";
import Icon from "@mui/material/Icon";
import IconButton from "@mui/material/IconButton";
import ListItemIcon from "@mui/material/ListItemIcon";
import Menu from "@mui/material/Menu";
import TextField from "@mui/material/TextField";
import Toolbar from "@mui/material/Toolbar";
import React, {useEffect, useState} from "react";
import {useLocation, useNavigate} from "react-router-dom";
import QBreadcrumbs, {routeToLabel} from "qqq/components/horseshoe/Breadcrumbs";
import {navbar, navbarContainer, navbarIconButton, navbarRow,} from "qqq/components/horseshoe/Styles";
import {setTransparentNavbar, useMaterialUIController,} from "qqq/context";
import HistoryUtils from "qqq/utils/HistoryUtils";
// Declaring prop types for NavBar
interface Props
{
absolute?: boolean;
light?: boolean;
isMini?: boolean;
}
interface HistoryEntry {
id: number;
path: string;
label: string;
iconName?: string;
}
function NavBar({absolute, light, isMini}: Props): JSX.Element
{
const [navbarType, setNavbarType] = useState<"fixed" | "absolute" | "relative" | "static" | "sticky">();
const [controller, dispatch] = useMaterialUIController();
const {transparentNavbar, fixedNavbar, darkMode,} = controller;
const [openMenu, setOpenMenu] = useState<any>(false);
const [history, setHistory] = useState<any>([] as HistoryEntry[]);
const [autocompleteValue, setAutocompleteValue] = useState<any>(null);
const route = useLocation().pathname.split("/").slice(1);
const navigate = useNavigate();
useEffect(() =>
{
// Setting the navbar type
if (fixedNavbar)
{
setNavbarType("sticky");
}
else
{
setNavbarType("static");
}
// A function that sets the transparent state of the navbar.
function handleTransparentNavbar()
{
setTransparentNavbar(dispatch, (fixedNavbar && window.scrollY === 0) || !fixedNavbar);
}
/**
The event listener that's calling the handleTransparentNavbar function when
scrolling the window.
*/
window.addEventListener("scroll", handleTransparentNavbar);
// Call the handleTransparentNavbar function to set the state with the initial value.
handleTransparentNavbar();
buildHistoryEntries();
const history = HistoryUtils.get();
setHistory([ {label: "The Godfather", id: 1}, {label: "Pulp Fiction", id: 2}]);
const options = [] as any;
history.entries.reverse().forEach((entry, index) =>
options.push({label: `${entry.label} index`, id: index, key: index, path: entry.path, iconName: entry.iconName})
)
setHistory(options);
// Remove event listener on cleanup
return () => window.removeEventListener("scroll", handleTransparentNavbar);
}, [dispatch, fixedNavbar]);
const goToHistory = (path: string) =>
{
navigate(path);
}
function buildHistoryEntries()
{
const history = HistoryUtils.get();
const options = [] as any;
history.entries.reverse().forEach((entry, index) =>
options.push({label: entry.label, id: index, key: index, path: entry.path, iconName: entry.iconName})
)
setHistory(options);
}
const handleOpenMenu = (event: any) => setOpenMenu(event.currentTarget);
const handleCloseMenu = () => setOpenMenu(false);
const handleAutocompleteOnChange = (event: any, value: any, reason: any, details: any) =>
{
if(value)
{
goToHistory(value.path);
}
setAutocompleteValue(null);
}
const CustomPopper = function (props: any)
{
return (<Popper
{...props}
style={{whiteSpace: "nowrap", width: "auto"}}
placement="bottom-end"
/>)
}
const renderHistory = () =>
{
return (
<Autocomplete
disablePortal
id="recently-viewed-combo-box"
size="small"
value={autocompleteValue}
options={history}
autoHighlight
blurOnSelect
style={{width: "200px"}}
onOpen={buildHistoryEntries}
onChange={handleAutocompleteOnChange}
PopperComponent={CustomPopper}
isOptionEqualToValue={(option, value) => option.id === value.id}
renderInput={(params) => <TextField {...params} label="Recently Viewed Records" />}
renderOption={(props, option: HistoryEntry) => (
<Box {...props} component="li" key={option.id} sx={{width: "auto"}}>
<Box sx={{width: "auto", px: "8px", whiteSpace: "overflow"}} key={option.id}>
<ListItemIcon sx={{minWidth: "24px !important"}}><Icon>{option.iconName}</Icon></ListItemIcon>
{option.label}
</Box>
</Box>
)}
/>
);
}
// Render the notifications menu
const renderMenu = () => (
<Menu
anchorEl={openMenu}
anchorReference={null}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
open={Boolean(openMenu)}
onClose={handleCloseMenu}
sx={{mt: 2}}
/>
);
// Styles for the navbar icons
const iconsStyle = ({
palette: {dark, white, text},
functions: {rgba},
}: {
palette: any;
functions: any;
}) => ({
color: () =>
{
let colorValue = light || darkMode ? white.main : dark.main;
if (transparentNavbar && !light)
{
colorValue = darkMode ? rgba(text.main, 0.6) : text.main;
}
return colorValue;
},
});
const breadcrumbTitle = routeToLabel(route[route.length - 1]);
return (
<AppBar
position={absolute ? "absolute" : navbarType}
color="inherit"
sx={(theme) => navbar(theme, {
transparentNavbar, absolute, light, darkMode,
})}
>
<Toolbar sx={navbarContainer}>
<Box color="inherit" mb={{xs: 1, md: 0}} sx={(theme) => navbarRow(theme, {isMini})}>
<QBreadcrumbs icon="home" title={breadcrumbTitle} route={route} light={light} />
</Box>
{isMini ? null : (
<Box sx={(theme) => navbarRow(theme, {isMini})}>
<Box pr={1}>
{renderHistory()}
</Box>
<Box color={light ? "white" : "inherit"}>
<IconButton
size="small"
color="inherit"
sx={navbarIconButton}
onClick={handleOpenMenu}
>
<Badge badgeContent={0} color="error" variant="dot">
<Icon sx={iconsStyle}>notifications</Icon>
</Badge>
</IconButton>
{renderMenu()}
</Box>
</Box>
)}
</Toolbar>
</AppBar>
);
}
// Declaring default props for NavBar
NavBar.defaultProps = {
absolute: false,
light: false,
isMini: false,
};
export default NavBar;

View File

@ -0,0 +1,172 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Theme} from "@mui/material/styles";
function navbar(theme: Theme | any, ownerState: any)
{
const {
palette, boxShadows, functions, transitions, breakpoints, borders,
} = theme;
const {
transparentNavbar, absolute, light, darkMode,
} = ownerState;
const {
dark, white, text, transparent, background,
} = palette;
const {navbarBoxShadow} = boxShadows;
const {rgba, pxToRem} = functions;
const {borderRadius} = borders;
return {
boxShadow: transparentNavbar || absolute ? "none" : navbarBoxShadow,
backdropFilter: transparentNavbar || absolute ? "none" : `saturate(200%) blur(${pxToRem(30)})`,
backgroundColor:
transparentNavbar || absolute
? `${transparent.main} !important`
: rgba(darkMode ? background.default : white.main, 0.8),
color: () =>
{
let color;
if (light)
{
color = white.main;
}
else if (transparentNavbar)
{
color = text.main;
}
else
{
color = dark.main;
}
return color;
},
top: absolute ? 0 : pxToRem(12),
minHeight: pxToRem(75),
display: "grid",
alignItems: "center",
borderRadius: borderRadius.xl,
paddingTop: pxToRem(8),
paddingBottom: pxToRem(8),
paddingRight: absolute ? pxToRem(8) : 0,
paddingLeft: absolute ? pxToRem(16) : 0,
"& > *": {
transition: transitions.create("all", {
easing: transitions.easing.easeInOut,
duration: transitions.duration.standard,
}),
},
"& .MuiToolbar-root": {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
[breakpoints.up("sm")]: {
minHeight: "auto",
padding: `${pxToRem(4)} ${pxToRem(16)}`,
},
},
};
}
const navbarContainer = ({breakpoints}: Theme): any => ({
flexDirection: "column",
alignItems: "flex-start",
justifyContent: "space-between",
pt: 0.5,
pb: 0.5,
[breakpoints.up("md")]: {
flexDirection: "row",
alignItems: "center",
paddingTop: "0",
paddingBottom: "0",
},
});
const navbarRow = ({breakpoints}: Theme, {isMini}: any) => ({
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "100%",
[breakpoints.up("md")]: {
justifyContent: isMini ? "space-between" : "stretch",
width: isMini ? "100%" : "max-content",
},
[breakpoints.up("xl")]: {
justifyContent: "stretch !important",
width: "max-content !important",
},
});
const navbarIconButton = ({typography: {size}, breakpoints}: Theme) => ({
px: 1,
"& .material-icons, .material-icons-round": {
fontSize: `${size.xl} !important`,
},
"& .MuiTypography-root": {
display: "none",
[breakpoints.up("sm")]: {
display: "inline-block",
lineHeight: 1.2,
ml: 0.5,
},
},
});
const navbarDesktopMenu = ({breakpoints}: Theme) => ({
display: "none !important",
cursor: "pointer",
[breakpoints.up("xl")]: {
display: "inline-block !important",
},
});
const navbarMobileMenu = ({breakpoints}: Theme) => ({
display: "inline-block",
lineHeight: 0,
[breakpoints.up("xl")]: {
display: "none",
},
});
export {
navbar,
navbarContainer,
navbarRow,
navbarIconButton,
navbarDesktopMenu,
navbarMobileMenu,
};

View File

@ -0,0 +1,358 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Box from "@mui/material/Box";
import Divider from "@mui/material/Divider";
import Icon from "@mui/material/Icon";
import Link from "@mui/material/Link";
import List from "@mui/material/List";
import {ReactNode, useEffect, useReducer, useState} from "react";
import {NavLink, useLocation} from "react-router-dom";
import {setMiniSidenav, setTransparentSidenav, setWhiteSidenav, useMaterialUIController,} from "qqq/context";
import AuthenticationButton from "qqq/components/buttons/AuthenticationButton";
import SideNavCollapse from "qqq/components/horseshoe/sidenav/SideNavCollapse";
import SideNavItem from "qqq/components/horseshoe/sidenav/SideNavItem";
import SideNavList from "qqq/components/horseshoe/sidenav/SideNavList";
import SidenavRoot from "qqq/components/horseshoe/sidenav/SideNavRoot";
import sidenavLogoLabel from "qqq/components/horseshoe/sidenav/styles/SideNav";
import MDTypography from "qqq/components/legacy/MDTypography";
interface Props
{
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark";
icon?: string;
logo?: string;
companyName?: string;
routes: {
[key: string]:
| ReactNode
| string
| {
[key: string]:
| ReactNode
| string
| {
[key: string]:
| ReactNode
| string
| {
[key: string]: ReactNode | string;
}[];
}[];
}[];
}[];
[key: string]: any;
}
function Sidenav({color, icon, logo, companyName, routes, ...rest}: Props): JSX.Element
{
const [openCollapse, setOpenCollapse] = useState<boolean | string>(false);
const [openNestedCollapse, setOpenNestedCollapse] = useState<boolean | string>(false);
const [controller, dispatch] = useMaterialUIController();
const {miniSidenav, transparentSidenav, whiteSidenav, darkMode} = controller;
const location = useLocation();
const {pathname} = location;
const collapseName = pathname.split("/").slice(1)[0];
const items = pathname.split("/").slice(1);
const itemParentName = items[1];
const itemName = items[items.length - 1];
const [, forceUpdate] = useReducer((x) => x + 1, 0);
let textColor:
| "primary"
| "secondary"
| "info"
| "success"
| "warning"
| "error"
| "dark"
| "white"
| "inherit"
| "text"
| "light" = "white";
if (transparentSidenav || (whiteSidenav && !darkMode))
{
textColor = "dark";
}
else if (whiteSidenav && darkMode)
{
textColor = "inherit";
}
const closeSidenav = () => setMiniSidenav(dispatch, true);
useEffect(() =>
{
setOpenCollapse(collapseName);
setOpenNestedCollapse(itemParentName);
}, []);
useEffect(() =>
{
// A function that sets the mini state of the sidenav.
function handleMiniSidenav()
{
setMiniSidenav(dispatch, window.innerWidth < 1200);
setTransparentSidenav(dispatch, window.innerWidth < 1200 ? false : transparentSidenav);
setWhiteSidenav(dispatch, window.innerWidth < 1200 ? false : whiteSidenav);
}
/**
The event listener that's calling the handleMiniSidenav function when resizing the window.
*/
window.addEventListener("resize", handleMiniSidenav);
window.onload = () =>
{
forceUpdate();
};
// Call the handleMiniSidenav function to set the state with the initial value.
handleMiniSidenav();
// Remove event listener on cleanup
return () => window.removeEventListener("resize", handleMiniSidenav);
}, [dispatch, location]);
// Render all the nested collapse items from the routes.js
const renderNestedCollapse = (collapse: any) =>
{
const template = collapse.map(({name, route, key, href}: any) =>
href ? (
<Link
key={key}
href={href}
target="_blank"
rel="noreferrer"
sx={{textDecoration: "none"}}
>
<SideNavItem name={name} nested />
</Link>
) : (
<NavLink to={route} key={key} style={{textDecoration: "none"}}>
<SideNavItem name={name} active={route === pathname} nested />
</NavLink>
)
);
return template;
};
// Render the all the collpases from the routes.js
const renderCollapse = (collapses: any) =>
collapses.map(({name, collapse, route, href, key}: any) =>
{
let returnValue;
if (collapse)
{
returnValue = (
<SideNavItem
key={key}
color={color}
name={name}
active={key === itemParentName ? "isParent" : false}
open={openNestedCollapse === key}
onClick={({currentTarget}: any) =>
openNestedCollapse === key && currentTarget.classList.contains("MuiListItem-root")
? setOpenNestedCollapse(false)
: setOpenNestedCollapse(key)
}
>
{renderNestedCollapse(collapse)}
</SideNavItem>
);
}
else
{
returnValue = href ? (
<Link
href={href}
key={key}
target="_blank"
rel="noreferrer"
sx={{textDecoration: "none"}}
>
<SideNavItem color={color} name={name} active={key === itemName} />
</Link>
) : (
<NavLink to={route} key={key} style={{textDecoration: "none"}}>
<SideNavItem color={color} name={name} active={key === itemName} />
</NavLink>
);
}
return <SideNavList key={key}>{returnValue}</SideNavList>;
});
// Render all the routes from the routes.js (All the visible items on the Sidenav)
const renderRoutes = routes.map(
({type, name, icon, title, collapse, noCollapse, key, href, route}: any) =>
{
let returnValue;
if (type === "collapse")
{
if (href)
{
returnValue = (
<Link
href={href}
key={key}
target="_blank"
rel="noreferrer"
sx={{textDecoration: "none"}}
>
<SideNavCollapse
name={name}
icon={icon}
active={key === collapseName}
noCollapse={noCollapse}
/>
</Link>
);
}
else if (noCollapse && route)
{
returnValue = (
<NavLink to={route} key={key}>
<SideNavCollapse
name={name}
icon={icon}
noCollapse={noCollapse}
active={key === collapseName}
>
{collapse ? renderCollapse(collapse) : null}
</SideNavCollapse>
</NavLink>
);
}
else
{
returnValue = (
<SideNavCollapse
key={key}
name={name}
icon={icon}
active={key === collapseName}
open={openCollapse === key}
noCollapse={noCollapse}
onClick={() => (! noCollapse ? (openCollapse === key ? setOpenCollapse(false) : setOpenCollapse(key)) : null) }
>
{collapse ? renderCollapse(collapse) : null}
</SideNavCollapse>
);
}
}
else if (type === "title")
{
returnValue = (
<MDTypography
key={key}
color={textColor}
display="block"
variant="caption"
fontWeight="bold"
textTransform="uppercase"
pl={3}
mt={2}
mb={1}
ml={1}
>
{title}
</MDTypography>
);
}
else if (type === "divider")
{
returnValue = (
<Divider
key={key}
light={
(!darkMode && !whiteSidenav && !transparentSidenav) ||
(darkMode && !transparentSidenav && whiteSidenav)
}
/>
);
}
return returnValue;
}
);
return (
<SidenavRoot
{...rest}
variant="permanent"
ownerState={{transparentSidenav, whiteSidenav, miniSidenav, darkMode}}
>
<Box pt={3} mr={1} pb={0} px={4} textAlign="center">
<Box
display={{xs: "block", xl: "none"}}
position="absolute"
top={0}
right={0}
p={1.625}
onClick={closeSidenav}
sx={{cursor: "pointer"}}
>
<MDTypography variant="h6" color="secondary">
<Icon sx={{fontWeight: "bold"}}>close</Icon>
</MDTypography>
</Box>
<Box component={NavLink} to="/" display="flex" alignItems="center">
{!miniSidenav && logo && <Box component="img" src={logo} alt="Logo" width="100%" />}
{miniSidenav && icon && <Box component="img" src={icon} alt="Icon" width="160%" />}
{!miniSidenav && companyName && <Box width={!companyName && "100%"} sx={(theme: any) => sidenavLogoLabel(theme, {miniSidenav})}>
<MDTypography component="h6" variant="button" fontWeight="medium" color={textColor}>
{companyName}
</MDTypography>
</Box>
}
</Box>
</Box>
<Divider
light={
(!darkMode && !whiteSidenav && !transparentSidenav) ||
(darkMode && !transparentSidenav && whiteSidenav)
}
/>
<List>{renderRoutes}</List>
<Divider
light={
(!darkMode && !whiteSidenav && !transparentSidenav) ||
(darkMode && !transparentSidenav && whiteSidenav)
}
/>
<AuthenticationButton />
</SidenavRoot>
);
}
// Declaring default props for Sidenav
Sidenav.defaultProps = {
color: "info",
icon: "",
logo: "",
companyName: "",
};
export default Sidenav;

View File

@ -0,0 +1,121 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Box from "@mui/material/Box";
import Collapse from "@mui/material/Collapse";
import Icon from "@mui/material/Icon";
import ListItem from "@mui/material/ListItem";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import {ReactNode} from "react";
import {collapseArrow, collapseIcon, collapseIconBox, collapseItem, collapseText,} from "qqq/components/horseshoe/sidenav/styles/SideNavCollapse";
import {useMaterialUIController} from "qqq/context";
// Declaring props types for SideNavCollapse
interface Props {
icon: ReactNode;
name: string;
children?: ReactNode;
active?: Boolean;
noCollapse?: Boolean;
open?: Boolean;
[key: string]: any;
}
function SideNavCollapse({
icon,
name,
children,
active,
noCollapse,
open,
...rest
}: Props): JSX.Element
{
const [controller] = useMaterialUIController();
const {miniSidenav, transparentSidenav, whiteSidenav, darkMode} = controller;
return (
<>
<ListItem component="li">
<Box
{...rest}
sx={(theme: any) =>
collapseItem(theme, {active, transparentSidenav, whiteSidenav, darkMode})
}
>
<ListItemIcon
sx={(theme) => collapseIconBox(theme, {transparentSidenav, whiteSidenav, darkMode})}
>
{typeof icon === "string" ? (
<Icon sx={(theme) => collapseIcon(theme, {active})}>{icon}</Icon>
) : (
icon
)}
</ListItemIcon>
<ListItemText
primary={name}
sx={(theme) =>
collapseText(theme, {
miniSidenav,
transparentSidenav,
whiteSidenav,
active,
})
}
/>
<Icon
sx={(theme) =>
collapseArrow(theme, {
noCollapse,
transparentSidenav,
whiteSidenav,
miniSidenav,
open,
active,
darkMode,
})
}
>
expand_less
</Icon>
</Box>
</ListItem>
{children && (
<Collapse in={Boolean(open)} unmountOnExit>
{children}
</Collapse>
)}
</>
);
}
// Declaring default props for SideNavCollapse
SideNavCollapse.defaultProps = {
active: false,
noCollapse: false,
children: false,
open: false,
};
export default SideNavCollapse;

View File

@ -0,0 +1,100 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Box from "@mui/material/Box";
import Collapse from "@mui/material/Collapse";
import Icon from "@mui/material/Icon";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import {Theme} from "@mui/material/styles";
import {ReactNode} from "react";
import {useMaterialUIController} from "qqq/context";
import {item, itemArrow, itemContent} from "qqq/components/horseshoe/sidenav/styles/SideNavItem";
// Declaring props types for SideNavCollapse
interface Props {
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark";
name: string;
active?: boolean | string;
nested?: boolean;
children?: ReactNode;
open?: boolean;
[key: string]: any;
}
function SideNavItem({color, name, active, nested, children, open, ...rest}: Props): JSX.Element
{
const [controller] = useMaterialUIController();
const {miniSidenav, transparentSidenav, whiteSidenav, darkMode} = controller;
return (
<>
<ListItem
{...rest}
component="li"
sx={(theme) => item(theme, {active, color, transparentSidenav, whiteSidenav, darkMode})}
>
<Box
sx={(theme: Theme): any =>
itemContent(theme, {
active,
miniSidenav,
name,
open,
nested,
transparentSidenav,
whiteSidenav,
darkMode,
})
}
>
<ListItemText primary={name} />
{children && (
<Icon
component="i"
sx={(theme) =>
itemArrow(theme, {open, miniSidenav, transparentSidenav, whiteSidenav, darkMode})
}
>
expand_less
</Icon>
)}
</Box>
</ListItem>
{children && (
<Collapse in={open} timeout="auto" unmountOnExit {...rest}>
{children}
</Collapse>
)}
</>
);
}
// Declaring default props for SideNavItem
SideNavItem.defaultProps = {
color: "info",
active: false,
nested: false,
children: false,
open: false,
};
export default SideNavItem;

View File

@ -0,0 +1,39 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import List from "@mui/material/List";
import {ReactNode} from "react";
function SideNavList({children}: { children: ReactNode }): JSX.Element
{
return (
<List
sx={{
px: 2,
my: 0.3,
}}
>
{children}
</List>
);
}
export default SideNavList;

View File

@ -0,0 +1,101 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Drawer from "@mui/material/Drawer";
import {styled, Theme} from "@mui/material/styles";
export default styled(Drawer)(({theme, ownerState}: { theme?: Theme | any; ownerState: any }) =>
{
const {palette, boxShadows, transitions, breakpoints, functions} = theme;
const {transparentSidenav, whiteSidenav, miniSidenav, darkMode} = ownerState;
const sidebarWidth = 250;
const {transparent, gradients, white, background} = palette;
const {xxl} = boxShadows;
const {pxToRem, linearGradient} = functions;
let backgroundValue = darkMode
? background.sidenav
: linearGradient(gradients.dark.main, gradients.dark.state);
if (transparentSidenav)
{
backgroundValue = transparent.main;
}
else if (whiteSidenav)
{
backgroundValue = white.main;
}
// styles for the sidenav when miniSidenav={false}
const drawerOpenStyles = () => ({
background: backgroundValue,
transform: "translateX(0)",
transition: transitions.create("transform", {
easing: transitions.easing.sharp,
duration: transitions.duration.shorter,
}),
[breakpoints.up("xl")]: {
boxShadow: transparentSidenav ? "none" : xxl,
marginBottom: transparentSidenav ? 0 : "inherit",
left: "0",
width: sidebarWidth,
transform: "translateX(0)",
transition: transitions.create(["width", "background-color"], {
easing: transitions.easing.sharp,
duration: transitions.duration.enteringScreen,
}),
},
});
// styles for the sidenav when miniSidenav={true}
const drawerCloseStyles = () => ({
background: backgroundValue,
transform: `translateX(${pxToRem(-320)})`,
transition: transitions.create("transform", {
easing: transitions.easing.sharp,
duration: transitions.duration.shorter,
}),
[breakpoints.up("xl")]: {
boxShadow: transparentSidenav ? "none" : xxl,
marginBottom: transparentSidenav ? 0 : "inherit",
left: "0",
width: pxToRem(96),
overflowX: "hidden",
transform: "translateX(0)",
transition: transitions.create(["width", "background-color"], {
easing: transitions.easing.sharp,
duration: transitions.duration.shorter,
}),
},
});
return {
"& .MuiDrawer-paper": {
boxShadow: xxl,
border: "none",
...(miniSidenav ? drawerCloseStyles() : drawerOpenStyles()),
},
};
});

View File

@ -0,0 +1,46 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// @mui material components
import {Theme} from "@mui/material/styles";
export default function sidenavLogoLabel(theme: Theme, ownerState: any)
{
const {functions, transitions, typography, breakpoints} = theme;
const {miniSidenav} = ownerState;
const {pxToRem} = functions;
const {fontWeightMedium} = typography;
return {
ml: 0.5,
fontWeight: fontWeightMedium,
wordSpacing: pxToRem(-1),
transition: transitions.create("opacity", {
easing: transitions.easing.easeInOut,
duration: transitions.duration.standard,
}),
[breakpoints.up("xl")]: {
opacity: miniSidenav ? 0 : 1,
},
};
}

View File

@ -0,0 +1,193 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Theme} from "@mui/material/styles";
function collapseItem(theme: Theme, ownerState: any)
{
const {palette, transitions, breakpoints, boxShadows, borders, functions} = theme;
const {active, transparentSidenav, whiteSidenav, darkMode} = ownerState;
const {white, transparent, dark, grey} = palette;
const {md} = boxShadows;
const {borderRadius} = borders;
const {pxToRem, rgba} = functions;
return {
background: () =>
{
let backgroundValue;
if (transparentSidenav && darkMode)
{
backgroundValue = active ? rgba(white.main, 0.2) : transparent.main;
}
else if (transparentSidenav && !darkMode)
{
backgroundValue = active ? grey[300] : transparent.main;
}
else if (whiteSidenav)
{
backgroundValue = active ? grey[200] : transparent.main;
}
else
{
backgroundValue = active ? rgba(white.main, 0.2) : transparent.main;
}
return backgroundValue;
},
color: (transparentSidenav && !darkMode) || whiteSidenav ? dark.main : white.main,
display: "flex",
alignItems: "center",
width: "100%",
padding: `${pxToRem(8)} ${pxToRem(16)}`,
margin: `${pxToRem(1.5)} ${pxToRem(16)}`,
borderRadius: borderRadius.md,
cursor: "pointer",
userSelect: "none",
whiteSpace: "nowrap",
boxShadow: active && !whiteSidenav && !darkMode && !transparentSidenav ? md : "none",
[breakpoints.up("xl")]: {
transition: transitions.create(["box-shadow", "background-color"], {
easing: transitions.easing.easeInOut,
duration: transitions.duration.shorter,
}),
},
"&:hover, &:focus": {
backgroundColor:
transparentSidenav && !darkMode
? grey[300]
: rgba(whiteSidenav ? grey[400] : white.main, 0.2),
},
};
}
function collapseIconBox(theme: Theme, ownerState: any)
{
const {palette, transitions, borders, functions} = theme;
const {transparentSidenav, whiteSidenav, darkMode} = ownerState;
const {white, dark} = palette;
const {borderRadius} = borders;
const {pxToRem} = functions;
return {
minWidth: pxToRem(32),
minHeight: pxToRem(32),
color: (transparentSidenav && !darkMode) || whiteSidenav ? dark.main : white.main,
borderRadius: borderRadius.md,
display: "grid",
placeItems: "center",
transition: transitions.create("margin", {
easing: transitions.easing.easeInOut,
duration: transitions.duration.standard,
}),
"& svg, svg g": {
color: transparentSidenav || whiteSidenav ? dark.main : white.main,
},
};
}
const collapseIcon = ({palette: {white, gradients}}: Theme, {active}: any) => ({
color: active ? white.main : gradients.dark.state,
});
function collapseText(theme: any, ownerState: any)
{
const {typography, transitions, breakpoints, functions} = theme;
const {miniSidenav, transparentSidenav, active} = ownerState;
const {size, fontWeightRegular, fontWeightLight} = typography;
const {pxToRem} = functions;
return {
marginLeft: pxToRem(10),
[breakpoints.up("xl")]: {
opacity: miniSidenav || (miniSidenav && transparentSidenav) ? 0 : 1,
maxWidth: miniSidenav || (miniSidenav && transparentSidenav) ? 0 : "100%",
marginLeft: miniSidenav || (miniSidenav && transparentSidenav) ? 0 : pxToRem(10),
transition: transitions.create(["opacity", "margin"], {
easing: transitions.easing.easeInOut,
duration: transitions.duration.standard,
}),
},
"& span": {
fontWeight: active ? fontWeightRegular : fontWeightLight,
fontSize: size.sm,
lineHeight: 0,
},
};
}
function collapseArrow(theme: Theme, ownerState: any)
{
const {palette, typography, transitions, breakpoints, functions} = theme;
const {noCollapse, transparentSidenav, whiteSidenav, miniSidenav, open, active, darkMode} =
ownerState;
const {white, dark} = palette;
const {size} = typography;
const {pxToRem, rgba} = functions;
return {
fontSize: `${size.lg} !important`,
fontWeight: 700,
marginBottom: pxToRem(-1),
transform: open ? "rotate(0)" : "rotate(-180deg)",
color: () =>
{
let colorValue;
if (transparentSidenav && darkMode)
{
colorValue = open || active ? white.main : rgba(white.main, 0.25);
}
else if (transparentSidenav || whiteSidenav)
{
colorValue = open || active ? dark.main : rgba(dark.main, 0.25);
}
else
{
colorValue = open || active ? white.main : rgba(white.main, 0.5);
}
return colorValue;
},
transition: transitions.create(["color", "transform", "opacity"], {
easing: transitions.easing.easeInOut,
duration: transitions.duration.shorter,
}),
[breakpoints.up("xl")]: {
display:
noCollapse || (transparentSidenav && miniSidenav) || miniSidenav
? "none !important"
: "block !important",
},
};
}
export {collapseItem, collapseIconBox, collapseIcon, collapseText, collapseArrow};

View File

@ -0,0 +1,179 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Theme} from "@mui/material/styles";
function item(theme: Theme | any, ownerState: any)
{
const {palette, borders, functions, transitions} = theme;
const {active, color, transparentSidenav, whiteSidenav, darkMode} = ownerState;
const {transparent, white, grey} = palette;
const {borderRadius} = borders;
const {rgba} = functions;
return {
pl: 3,
mt: 0.375,
mb: 0.3,
width: "100%",
borderRadius: borderRadius.md,
cursor: "pointer",
backgroundColor: () =>
{
let backgroundValue = transparent.main;
if (
(active === "isParent" && !transparentSidenav && !whiteSidenav) ||
(active === "isParent" && transparentSidenav && darkMode)
)
{
backgroundValue = rgba(white.main, 0.2);
}
else if (active === "isParent" && transparentSidenav)
{
backgroundValue = grey[300];
}
else if (active === "isParent" && whiteSidenav)
{
backgroundValue = grey[200];
}
else if (active)
{
backgroundValue = palette[color].main;
}
return backgroundValue;
},
transition: transitions.create("background-color", {
easing: transitions.easing.easeInOut,
duration: transitions.duration.shorter,
}),
"&:hover, &:focus": {
backgroundColor:
!active &&
rgba((transparentSidenav && !darkMode) || whiteSidenav ? grey[400] : white.main, 0.2),
},
};
}
function itemContent(theme: Theme, ownerState: any)
{
const {palette, typography, transitions, functions} = theme;
const {miniSidenav, name, active, transparentSidenav, whiteSidenav, darkMode} = ownerState;
const {white, dark} = palette;
const {size, fontWeightRegular, fontWeightLight} = typography;
const {pxToRem} = functions;
return {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "100%",
padding: `${pxToRem(12)} ${pxToRem(16)}`,
marginLeft: pxToRem(18),
userSelect: "none",
position: "relative",
"& span": {
color:
((transparentSidenav && !darkMode) || whiteSidenav) && (active === "isParent" || !active)
? dark.main
: white.main,
fontWeight: active ? fontWeightRegular : fontWeightLight,
fontSize: size.sm,
opacity: miniSidenav ? 0 : 1,
transition: transitions.create(["opacity", "color"], {
easing: transitions.easing.easeInOut,
duration: transitions.duration.standard,
}),
},
"&::before": {
color:
((transparentSidenav && !darkMode) || whiteSidenav) && (active === "isParent" || !active)
? dark.main
: white.main,
fontWeight: fontWeightRegular,
display: "flex",
alignItems: "center",
position: "absolute",
top: "50%",
transform: "translateY(-50%)",
left: pxToRem(-15),
opacity: 1,
borderRadius: "50%",
fontSize: size.sm,
},
};
}
function itemArrow(theme: Theme, ownerState: any)
{
const {palette, typography, transitions, breakpoints, functions} = theme;
const {noCollapse, transparentSidenav, whiteSidenav, miniSidenav, open, active, darkMode} =
ownerState;
const {white, dark} = palette;
const {size} = typography;
const {pxToRem, rgba} = functions;
return {
fontSize: `${size.lg} !important`,
fontWeight: 700,
marginBottom: pxToRem(-1),
transform: open ? "rotate(0)" : "rotate(-180deg)",
color: () =>
{
let colorValue;
if (transparentSidenav && darkMode)
{
colorValue = open || active ? white.main : rgba(white.main, 0.25);
}
else if (transparentSidenav || whiteSidenav)
{
colorValue = open || active ? dark.main : rgba(dark.main, 0.25);
}
else
{
colorValue = open || active ? white.main : rgba(white.main, 0.5);
}
return colorValue;
},
transition: transitions.create(["color", "transform", "opacity"], {
easing: transitions.easing.easeInOut,
duration: transitions.duration.shorter,
}),
[breakpoints.up("xl")]: {
display:
noCollapse || (transparentSidenav && miniSidenav) || miniSidenav
? "none !important"
: "block !important",
},
};
}
export {item, itemContent, itemArrow};