Make Menu Collapsable (#1025)

This commit is contained in:
Daniel Valdivia
2021-09-10 18:33:50 -07:00
committed by GitHub
parent e104c4a48e
commit 67b0261b0b
6 changed files with 296 additions and 118 deletions

View File

@@ -15,21 +15,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
interface IConsoleLogo {
width?: number;
}
const ConsoleLogo = ({ width = 120 }: IConsoleLogo) => {
const ConsoleLogo = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
viewBox="0 0 121.755 29.822"
>
<defs>
<style>{".prefix__a{fill:#fff}"}</style>
</defs>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 121.755 29.822">
<path
className="prefix__a"
d="M15.647 15.935l-1.772 1.194a6.088 6.088 0 00-5.135-2.652 6.348 6.348 0 00-6.522 6.654 6.348 6.348 0 006.522 6.654 6.031 6.031 0 005.124-2.64l1.735 1.266a8.126 8.126 0 01-6.859 3.411A8.422 8.422 0 010 21.131a8.422 8.422 0 018.74-8.691 7.963 7.963 0 016.907 3.495zM35.641 21.131a8.422 8.422 0 01-8.74 8.691 8.422 8.422 0 01-8.739-8.691 8.421 8.421 0 018.739-8.691 8.422 8.422 0 018.74 8.691zm-15.261 0a6.347 6.347 0 006.521 6.654 6.347 6.347 0 006.521-6.654 6.347 6.347 0 00-6.521-6.654 6.347 6.347 0 00-6.521 6.654zM53.729 29.581h-1.917l-10.2-13.26-.012 13.248h-2.122V12.681h1.917l10.21 13.26V12.693h2.122zM69.551 16.02a8.835 8.835 0 00-5-1.555c-2.471 0-4.231 1.109-4.231 2.929 0 1.531 1.29 2.315 3.821 2.628l1.484.181c2.856.35 5.3 1.507 5.3 4.484 0 3.364-3.05 5.123-6.7 5.123a10.935 10.935 0 01-6.654-2.194l1.157-1.687a9.018 9.018 0 005.5 1.868c2.519 0 4.5-1.025 4.5-2.929 0-1.567-1.41-2.314-4.038-2.64l-1.567-.193c-2.784-.337-5-1.627-5-4.508 0-3.255 2.893-5.075 6.449-5.075a10.336 10.336 0 016.076 1.844zM91.268 21.131a8.422 8.422 0 01-8.74 8.691 8.422 8.422 0 01-8.739-8.691 8.421 8.421 0 018.739-8.691 8.422 8.422 0 018.74 8.691zm-15.261 0a6.348 6.348 0 006.521 6.654 6.347 6.347 0 006.521-6.654 6.347 6.347 0 00-6.521-6.654 6.348 6.348 0 00-6.521 6.654zM106.897 29.569h-11.79V12.693h2.122v14.863h9.668zM121.76 29.569h-11.982V12.693h11.862v1.988h-9.74v5.389h9.427v2H111.9v5.509h9.86zM14.9.167h2.576v7.547H14.9zM11.801.238l-5.23 3.194a.229.229 0 01-.242 0L1.099.238a.726.726 0 00-.374-.1H.719a.717.717 0 00-.717.717v6.864h2.574V4.462a.258.258 0 01.392-.22l2.931 1.793a.919.919 0 00.944.009L9.935 4.23a.258.258 0 01.388.222v3.267h2.575V.855a.717.717 0 00-.717-.717h-.006a.723.723 0 00-.374.1zM30.348.165h-2.613v3.463a.258.258 0 01-.379.228L20.585.249a.723.723 0 00-.337-.084.717.717 0 00-.717.717v6.832h2.592V4.306a.258.258 0 01.379-.227l6.8 3.606a.714.714 0 00.336.083.716.716 0 00.717-.717V.165zM32.439 7.712V.165h1.2v7.547zM40.536 7.878c-3.189 0-5.451-1.513-5.451-3.939S37.361 0 40.536 0s5.466 1.513 5.466 3.939-2.236 3.939-5.466 3.939zm0-6.87c-2.371 0-4.2 1.036-4.2 2.931s1.826 2.93 4.2 2.93 4.212-1.022 4.212-2.93-1.84-2.931-4.212-2.931z"

View File

@@ -31,12 +31,17 @@ import {
GLOBAL_SET_DISTRIBUTED_SETUP,
} from "./types";
// determine whether we have the sidebar state stored on localstorage
const initSideBarOpen = localStorage.getItem("sidebarOpen")
? JSON.parse(localStorage.getItem("sidebarOpen")!)["open"]
: true;
const initialState: SystemState = {
loggedIn: false,
operatorMode: false,
session: "",
userName: "",
sidebarOpen: true,
sidebarOpen: initSideBarOpen,
serverNeedsRestart: false,
serverIsLoading: false,
loadingProgress: 100,
@@ -70,6 +75,11 @@ export function systemReducer(
operatorMode: action.operatorMode,
};
case MENU_OPEN:
// persist preference to local storage
localStorage.setItem(
"sidebarOpen",
JSON.stringify({ open: action.open })
);
return {
...state,
sidebarOpen: action.open,

View File

@@ -1,13 +1,12 @@
import React from "react";
import React, { Fragment } from "react";
import Grid from "@material-ui/core/Grid";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
interface IPageHeader {
classes: any;
label: any;
actions?: any;
}
import { AppState } from "../../../../store";
import { connect } from "react-redux";
import { setMenuOpen, userLoggedIn } from "../../../../actions";
import OperatorLogo from "../../../../icons/OperatorLogo";
import ConsoleLogo from "../../../../icons/ConsoleLogo";
const styles = (theme: Theme) =>
createStyles({
@@ -37,9 +36,28 @@ const styles = (theme: Theme) =>
marginTop: 16,
marginRight: 8,
},
logo: {
marginLeft: 34,
fill: theme.palette.primary.main,
width: 120,
},
});
const PageHeader = ({ classes, label, actions }: IPageHeader) => {
interface IPageHeader {
classes: any;
sidebarOpen?: boolean;
operatorMode?: boolean;
label: any;
actions?: any;
}
const PageHeader = ({
classes,
label,
actions,
sidebarOpen,
operatorMode,
}: IPageHeader) => {
return (
<Grid
container
@@ -47,6 +65,11 @@ const PageHeader = ({ classes, label, actions }: IPageHeader) => {
justify={"space-between"}
>
<Grid item className={classes.label}>
{!sidebarOpen && (
<div className={classes.logo}>
{operatorMode ? <OperatorLogo /> : <ConsoleLogo />}
</div>
)}
<Typography variant="h4" className={classes.labelStyle}>
{label}
</Typography>
@@ -60,4 +83,11 @@ const PageHeader = ({ classes, label, actions }: IPageHeader) => {
);
};
export default withStyles(styles)(PageHeader);
const mapState = (state: AppState) => ({
sidebarOpen: state.system.sidebarOpen,
operatorMode: state.system.operatorMode,
});
const connector = connect(mapState, null);
export default connector(withStyles(styles)(PageHeader));

View File

@@ -384,20 +384,7 @@ const Console = ({
{session.status === "ok" ? (
<div className={classes.root}>
<CssBaseline />
{!hideMenu && (
<Drawer
variant="permanent"
classes={{
paper: clsx(
classes.drawerPaper,
!open && classes.drawerPaperClose
),
}}
open={open}
>
<Menu pages={session.pages} />
</Drawer>
)}
{!hideMenu && <Menu pages={session.pages} />}
<main className={classes.content}>
{needsRestart && (

View File

@@ -14,19 +14,25 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React, { Fragment, useState } from "react";
import { connect } from "react-redux";
import { NavLink } from "react-router-dom";
import { Divider, withStyles } from "@material-ui/core";
import {
Divider,
Drawer,
IconButton,
Tooltip,
withStyles,
} from "@material-ui/core";
import { createStyles, Theme } from "@material-ui/core/styles";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import List from "@material-ui/core/List";
import { AppState } from "../../../store";
import { userLoggedIn } from "../../../actions";
import { setMenuOpen, userLoggedIn } from "../../../actions";
import { menuGroups } from "./utils";
import { IMenuItem, IMenuProps } from "./types";
import { IMenuItem } from "./types";
import {
BucketsIcon,
DashboardIcon,
@@ -52,6 +58,12 @@ import LogsIcon from "../../../icons/LogsIcon";
import SettingsIcon from "../../../icons/SettingsIcon";
import StorageIcon from "../../../icons/StorageIcon";
import TenantsOutlinedIcon from "../../../icons/TenantsOutlineIcon";
import MenuIcon from "@material-ui/icons/Menu";
import clsx from "clsx";
import { ChevronLeft } from "@material-ui/icons";
const drawerWidth = 245;
const styles = (theme: Theme) =>
createStyles({
@@ -59,9 +71,39 @@ const styles = (theme: Theme) =>
paddingTop: 25,
marginBottom: 30,
paddingLeft: 45,
transition: theme.transitions.create("paddingLeft", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
"& img": {
width: 120,
},
"& .MuiIconButton-root": {
color: "#ffffff",
float: "right",
},
},
logoClosed: {
paddingTop: 25,
marginBottom: 30,
paddingLeft: 34,
transition: theme.transitions.create("paddingLeft", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
"& .MuiIconButton-root": {
color: "#ffffff",
},
},
logoSvg: {
width: 40,
},
logoSvgClosed: {
width: 0,
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
menuList: {
"& .active": {
@@ -147,6 +189,80 @@ const styles = (theme: Theme) =>
selectorArrowOpen: {
transform: "rotateZ(180deg)",
},
//new
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(["width", "margin"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(["width", "margin"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
menuButton: {
marginRight: 36,
},
hide: {
display: "none",
},
drawer: {
width: drawerWidth,
flexShrink: 0,
whiteSpace: "nowrap",
background:
"transparent linear-gradient(90deg, #073052 0%, #081C42 100%) 0% 0% no-repeat padding-box !important",
boxShadow: "0px 3px 7px #00000014",
"& .MuiPaper-root": {
backgroundColor: "inherit",
},
},
drawerOpen: {
width: drawerWidth,
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerClose: {
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: "hidden",
width: 115,
[theme.breakpoints.up("sm")]: {
width: 115,
},
"& .logo": {
background: "red",
},
"& .MuiListItem-root": {
padding: "2px 0 2px 16px",
marginLeft: 36,
height: 50,
width: "48px",
transition: theme.transitions.create("marginLeft", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
"& .MuiListItemText-root": {
display: "none",
},
},
},
logoIcon: {
float: "left",
"& svg": {
fill: "white",
width: 120,
},
},
});
// Menu State builder for groups
@@ -161,15 +277,25 @@ const menuStateBuilder = () => {
return elements;
};
interface IMenuProps {
classes: any;
userLoggedIn: typeof userLoggedIn;
pages: string[];
operatorMode: boolean;
distributedSetup: boolean;
sidebarOpen: boolean;
setMenuOpen: typeof setMenuOpen;
}
const Menu = ({
userLoggedIn,
classes,
pages,
operatorMode,
distributedSetup,
sidebarOpen,
setMenuOpen,
}: IMenuProps) => {
const [menuOpen, setMenuOpen] = useState<any>(menuStateBuilder());
const logout = () => {
const deleteSession = () => {
clearSession();
@@ -385,18 +511,52 @@ const Menu = ({
item.fsHidden !== false
);
const setMenuCollapse = (menuClicked: string) => {
let newMenu: any = { ...menuOpen };
const handleDrawerOpen = () => {
setMenuOpen(true);
};
newMenu[menuClicked] = !newMenu[menuClicked];
setMenuOpen(newMenu);
const handleDrawerClose = () => {
setMenuOpen(false);
};
return (
<React.Fragment>
<div className={classes.logo}>
<Drawer
variant="permanent"
className={clsx(classes.drawer, {
[classes.drawerOpen]: sidebarOpen,
[classes.drawerClose]: !sidebarOpen,
})}
classes={{
paper: clsx({
[classes.drawerOpen]: sidebarOpen,
[classes.drawerClose]: !sidebarOpen,
}),
}}
>
<div
className={clsx({
[classes.logo]: sidebarOpen,
[classes.logoClosed]: !sidebarOpen,
})}
>
{sidebarOpen && (
<span className={classes.logoIcon}>
{operatorMode ? <OperatorLogo /> : <ConsoleLogo />}
</span>
)}
<IconButton
onClick={() => {
if (sidebarOpen) {
setMenuOpen(false);
} else {
setMenuOpen(true);
}
}}
>
{sidebarOpen ? <ChevronLeft /> : <MenuIcon />}
</IconButton>
</div>
<List className={classes.menuList}>
{menuGroups.map((groupMember, index) => {
@@ -429,7 +589,11 @@ const Menu = ({
page.extraMargin ? classes.extraMargin : null
}
>
{page.icon && <ListItemIcon>{page.icon}</ListItemIcon>}
{page.icon && (
<Tooltip title={page.name}>
<ListItemIcon>{page.icon}</ListItemIcon>
</Tooltip>
)}
{page.name && <ListItemText primary={page.name} />}
</ListItem>
);
@@ -460,16 +624,17 @@ const Menu = ({
<ListItemText primary="Logout" />
</ListItem>
</List>
</Drawer>
</React.Fragment>
);
};
const mapState = (state: AppState) => ({
open: state.system.loggedIn,
sidebarOpen: state.system.sidebarOpen,
operatorMode: state.system.operatorMode,
distributedSetup: state.system.distributedSetup,
});
const connector = connect(mapState, { userLoggedIn });
const connector = connect(mapState, { userLoggedIn, setMenuOpen });
export default connector(withStyles(styles)(Menu));

View File

@@ -16,14 +16,6 @@
import { userLoggedIn } from "../../../actions";
export interface IMenuProps {
classes: any;
userLoggedIn: typeof userLoggedIn;
pages: string[];
operatorMode: boolean;
distributedSetup: boolean;
}
export interface IMenuItem {
group: string;
type: string;