Add menu skeleton

This commit is contained in:
dominik-zeglen 2020-09-07 13:28:59 +02:00
parent 14da39ebfa
commit 2711292315
10 changed files with 223 additions and 93 deletions

View file

@ -0,0 +1,5 @@
<svg width="36" height="33" viewBox="0 0 36 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6072 33C22.4977 33 23.9789 30.6214 23.9789 27.3629C23.9789 23.3549 20.3772 22.6056 17.3814 22.1167C15.0924 21.7258 14.0489 21.5304 14.0489 20.1292C14.0489 19.0867 14.9577 18.6954 16.4389 18.6954C18.2566 18.6954 18.7614 19.2168 18.9298 20.7482L23.7097 20.0314C23.3055 16.7404 21.4542 15.0787 16.5735 15.0787C11.2216 15.0787 9.33654 17.2293 9.33654 20.6504C9.30299 25.082 13.4768 25.5382 16.5735 26.0594C18.492 26.418 19.2328 26.7437 19.2328 28.0146C19.2328 29.0573 18.5933 29.5135 16.6745 29.5135C14.5539 29.5135 13.9144 29.1551 13.6451 27.4281L9 28.1124C9.43753 31.599 11.4908 33 16.6072 33Z" fill="#28234A"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.7838 0L13.4043 6.64709H29.1638L35.5433 0H19.7838Z" fill="#8AC4EB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.15911 2.31187C6.27552 2.1958 6.4332 2.13062 6.59759 2.13062H27.3248C27.5761 2.13062 27.8026 2.28211 27.8987 2.51437C27.9947 2.74664 27.9412 3.01388 27.7632 3.19134L21.7867 9.1508C21.6703 9.26687 21.5126 9.33205 21.3482 9.33205H0.621008C0.369679 9.33205 0.143131 9.18056 0.0471181 8.94829C-0.0488948 8.71603 0.00456112 8.44879 0.182532 8.27133L6.15911 2.31187ZM6.85429 3.37259L2.12325 8.09007H21.0915L25.8225 3.37259H6.85429Z" fill="#28234A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1 +0,0 @@
<svg viewBox="0 0 538 182" xmlns="http://www.w3.org/2000/svg" xmlns:serif="http://www.serif.com/" fill-rule="evenodd" clip-rule="evenodd"><g serif:id="Saleor OS"><path fill="none" d="M0 0h537.903v181.963H0z"/><clipPath id="a"><path d="M0 0h537.903v181.963H0z"/></clipPath><g serif:id="Layer 1" clip-path="url(#a)"><path d="M28.649 0L-.001 28.949l145.042-.001 28.65-28.949L28.649 0z" fill="#fff"/><path d="M83.256 181.766c35.637 0 44.598-14.329 44.598-33.957 0-24.144-21.79-28.658-39.914-31.603-13.848-2.356-20.161-3.533-20.161-11.973 0-6.281 5.498-8.637 14.459-8.637 10.997 0 14.051 3.141 15.07 12.366l28.917-4.318c-2.445-19.825-13.645-29.836-43.173-29.836-32.378 0-43.782 12.955-43.782 33.565-.203 26.696 25.048 29.443 43.782 32.583 11.607 2.161 16.089 4.122 16.089 11.778 0 6.282-3.869 9.03-15.478 9.03-12.829 0-16.698-2.159-18.327-12.563l-28.102 4.122c2.647 21.003 15.069 29.443 46.022 29.443m93.212-21.59c-13.645 0-18.531-2.945-18.531-12.759 0-8.833 4.886-12.366 19.549-12.366h14.662v10.207c0 9.814-4.887 14.918-15.68 14.918m-12.626 21.591c15.884 0 23.012-5.104 28.103-12.563v11.189h28.712v-71.056c0-23.751-9.164-35.724-40.931-35.724-30.75 0-41.542 8.636-45.819 29.835l28.51 4.319c1.832-9.029 4.48-11.778 16.291-11.778 11.404 0 13.237 4.711 13.237 12.563v7.263h-13.441c-36.451 0-48.874 10.992-48.874 33.368 0 21.984 11.201 32.584 34.212 32.584M227.989 180.392h29.325V28.949l-29.325 28.948v122.495zm65.165-63.99v-5.299c0-9.225 4.277-15.507 17.106-15.507 12.422 0 16.496 5.3 16.496 15.507v5.299h-33.602zm17.106 65.561c33.805 0 42.765-15.703 44.801-31.406l-27.898-4.122c-1.222 9.421-3.055 14.329-16.903 14.329-14.05 0-17.106-6.871-17.106-15.899v-8.637h61.907v-18.844c0-26.302-10.386-43.772-44.801-43.772-34.007 0-45.615 17.666-45.615 40.043v28.265c0 21.789 11.811 40.043 45.615 40.043m99.173 0c33.6 0 47.447-17.077 47.447-40.043v-28.265c0-23.358-13.847-40.043-47.447-40.043-33.602 0-47.041 16.685-47.041 40.043v28.265c0 22.966 13.236 40.043 47.041 40.043m0-22.769c-11.812 0-17.717-6.085-17.717-15.899v-30.228c0-10.011 5.905-16.096 17.717-16.096 11.811 0 18.123 6.085 18.123 16.096v30.228c0 9.814-6.312 15.899-18.123 15.899M509.253 103.568h-15.718v76.21h-29.324v-76.21l28.65-28.949h45.042l-28.65 28.949z" fill="#fff"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -30,6 +30,7 @@ import Container from "../Container";
import ErrorPage from "../ErrorPage"; import ErrorPage from "../ErrorPage";
import Navigator from "../Navigator"; import Navigator from "../Navigator";
import NavigatorButton from "../NavigatorButton/NavigatorButton"; import NavigatorButton from "../NavigatorButton/NavigatorButton";
import SideBar from "../SideBar";
import AppActionContext from "./AppActionContext"; import AppActionContext from "./AppActionContext";
import AppHeaderContext from "./AppHeaderContext"; import AppHeaderContext from "./AppHeaderContext";
import { appLoaderHeight, drawerWidth, drawerWidthExpanded } from "./consts"; import { appLoaderHeight, drawerWidth, drawerWidthExpanded } from "./consts";
@ -52,12 +53,12 @@ const useStyles = makeStyles(
}, },
appLoader: { appLoader: {
height: appLoaderHeight, height: appLoaderHeight,
marginBottom: theme.spacing(2), marginBottom: theme.spacing(4),
zIndex: 1201 zIndex: 1201
}, },
appLoaderPlaceholder: { appLoaderPlaceholder: {
height: appLoaderHeight, height: appLoaderHeight,
marginBottom: theme.spacing(2) marginBottom: theme.spacing(4)
}, },
arrow: { arrow: {
marginLeft: theme.spacing(2), marginLeft: theme.spacing(2),
@ -70,18 +71,7 @@ const useStyles = makeStyles(
} }
}, },
content: { content: {
[theme.breakpoints.down("sm")]: { flex: 1
paddingLeft: 0
},
paddingLeft: drawerWidthExpanded,
transition: "padding-left 0.5s ease",
width: "100%"
},
contentToggle: {
[theme.breakpoints.down("sm")]: {
paddingLeft: 0
},
paddingLeft: drawerWidth
}, },
darkThemeSwitch: { darkThemeSwitch: {
[theme.breakpoints.down("sm")]: { [theme.breakpoints.down("sm")]: {
@ -98,70 +88,6 @@ const useStyles = makeStyles(
height: 40, height: 40,
marginBottom: theme.spacing(3) marginBottom: theme.spacing(3)
}, },
isMenuSmall: {
"& path": {
fill: theme.palette.primary.main
},
"& span": {
margin: "0 8px"
},
"& svg": {
marginTop: 8,
transform: "rotate(180deg)"
},
"&:hover": {
background: "#E6F3F3"
},
background: theme.palette.background.paper,
border: `solid 1px #EAEAEA`,
borderRadius: "50%",
cursor: "pointer",
height: 32,
position: "absolute",
right: -16,
top: 65,
transition: `background ${theme.transitions.duration.shorter}ms`,
width: 32,
zIndex: 99
},
isMenuSmallDark: {
"&:hover": {
background: `linear-gradient(0deg, rgba(25, 195, 190, 0.1), rgba(25, 195, 190, 0.1)), ${theme.palette.background.paper}`
},
border: `solid 1px #252728`,
transition: `background ${theme.transitions.duration.shorter}ms`
},
isMenuSmallHide: {
"& svg": {
marginLeft: "3px",
transform: "rotate(0deg)"
}
},
logo: {
"& svg": {
left: "50%",
position: "absolute",
top: "50%",
transform: "translate(-50%,-50%)"
},
background: theme.palette.secondary.main,
display: "block",
height: 80,
position: "relative"
},
logoDark: {
"& path": {
fill: theme.palette.common.white
},
background: theme.palette.primary.main
},
logoSmall: {
"& svg": {
margin: 0,
padding: 0,
width: "80px"
}
},
menu: { menu: {
background: theme.palette.background.paper, background: theme.palette.background.paper,
height: "100vh", height: "100vh",
@ -238,6 +164,7 @@ const useStyles = makeStyles(
zIndex: 1 zIndex: 1
}, },
root: { root: {
display: "flex",
width: `100%` width: `100%`
}, },
rotate: { rotate: {
@ -286,7 +213,7 @@ const useStyles = makeStyles(
} }
}, },
viewContainer: { viewContainer: {
minHeight: `calc(100vh - ${theme.spacing(2) + appLoaderHeight + 70}px)` minHeight: `calc(100vh - ${theme.spacing(4) + appLoaderHeight + 120}px)`
} }
}), }),
{ {
@ -301,7 +228,6 @@ interface AppLayoutProps {
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => { const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
const classes = useStyles({}); const classes = useStyles({});
const { isDark, toggleTheme } = useTheme(); const { isDark, toggleTheme } = useTheme();
const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false);
const [isDrawerOpened, setDrawerState] = React.useState(false); const [isDrawerOpened, setDrawerState] = React.useState(false);
const [isMenuOpened, setMenuState] = React.useState(false); const [isMenuOpened, setMenuState] = React.useState(false);
const appActionAnchor = React.useRef<HTMLDivElement>(); const appActionAnchor = React.useRef<HTMLDivElement>();
@ -344,10 +270,6 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
navigate(url); navigate(url);
}; };
const handleIsMenuSmall = () => {
setMenuSmall(!isMenuSmall);
};
const handleErrorBack = () => { const handleErrorBack = () => {
navigate("/"); navigate("/");
dispatchAppState({ dispatchAppState({
@ -367,7 +289,7 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
<AppHeaderContext.Provider value={appHeaderAnchor}> <AppHeaderContext.Provider value={appHeaderAnchor}>
<AppActionContext.Provider value={appActionAnchor}> <AppActionContext.Provider value={appActionAnchor}>
<div className={classes.root}> <div className={classes.root}>
<div className={classes.sideBar}> {/* <div className={classes.sideBar}>
<ResponsiveDrawer <ResponsiveDrawer
onClose={() => setDrawerState(false)} onClose={() => setDrawerState(false)}
open={isDrawerOpened} open={isDrawerOpened}
@ -404,12 +326,15 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
onMenuItemClick={handleMenuItemClick} onMenuItemClick={handleMenuItemClick}
/> />
</ResponsiveDrawer> </ResponsiveDrawer>
</div> </div> */}
<div <SideBar
className={classNames(classes.content, { menuItems={menuStructure}
[classes.contentToggle]: isMenuSmall location={location.pathname}
})} user={user}
> renderConfigure={renderConfigure}
onMenuItemClick={handleMenuItemClick}
/>
<div className={classes.content}>
{appState.loading ? ( {appState.loading ? (
<LinearProgress className={classes.appLoader} color="primary" /> <LinearProgress className={classes.appLoader} color="primary" />
) : ( ) : (

View file

@ -79,7 +79,7 @@ export const SaveButtonBar: React.FC<SaveButtonBarProps> = props => {
const intl = useIntl(); const intl = useIntl();
const scrollPosition = useWindowScroll(); const scrollPosition = useWindowScroll();
const scrolledToBottom = const scrolledToBottom =
scrollPosition.y + window.innerHeight >= document.body.scrollHeight; scrollPosition.y + window.innerHeight - document.body.scrollHeight >= -5;
return ( return (
<AppActionContext.Consumer> <AppActionContext.Consumer>

View file

View file

@ -0,0 +1,80 @@
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper";
import { fade } from "@material-ui/core/styles/colorManipulator";
import makeStyles from "@material-ui/core/styles/makeStyles";
import React from "react";
import { IMenuItem } from "../AppLayout/menuStructure";
export interface MenuItemProps {
menuItem: IMenuItem;
onClick: (url: string, event: React.MouseEvent) => void;
}
const useStyles = makeStyles(
theme => ({
paper: {
borderRadius: 16,
padding: theme.spacing(3)
},
popper: {
marginLeft: theme.spacing(3),
zIndex: 2
}
}),
{
name: "MenuItem"
}
);
const MenuItem: React.FC<MenuItemProps> = ({ menuItem, onClick }) => {
const classes = useStyles({});
const [open, setOpen] = React.useState(false);
const anchor = React.useRef<HTMLDivElement>(null);
const handleClick = (event: React.MouseEvent, menuItem: IMenuItem) => {
if (menuItem.children) {
setOpen(true);
} else {
onClick(menuItem.url, event);
setOpen(false);
}
};
return (
<div ref={anchor} onClick={event => handleClick(event, menuItem)}>
{menuItem.label}
{menuItem.children && (
<Popper
className={classes.popper}
open={open}
anchorEl={anchor.current}
transition
disablePortal
placement="right-start"
>
<ClickAwayListener
onClickAway={() => setOpen(false)}
mouseEvent="onClick"
>
<Paper elevation={6} className={classes.paper}>
{menuItem.children.map(subMenuItem => (
<div
key={subMenuItem.url}
onClick={event => handleClick(event, subMenuItem)}
data-test="select-option"
>
{subMenuItem.label}
</div>
))}
</Paper>
</ClickAwayListener>
</Popper>
)}
</div>
);
};
MenuItem.displayName = "MenuItem";
export default MenuItem;

View file

@ -0,0 +1,105 @@
import logoLight from "@assets/images/logo-sidebar-light.svg";
import makeStyles from "@material-ui/core/styles/makeStyles";
import {
configurationMenuUrl,
createConfigurationMenu
} from "@saleor/configuration";
import { User } from "@saleor/fragments/types/User";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import { sectionNames } from "@saleor/intl";
import classNames from "classnames";
import React from "react";
import SVG from "react-inlinesvg";
import { useIntl } from "react-intl";
import { IMenuItem } from "../AppLayout/menuStructure";
import MenuItem from "./MenuItem";
import { isMenuActive } from "./utils";
const useStyles = makeStyles(
theme => ({
logo: {
margin: "36px 0 0 19px"
},
root: {
transition: "width 0.5s ease",
width: 210
},
shrunk: {
"&$root": {
width: 72
}
}
}),
{
name: "SideBar"
}
);
export interface SideBarProps {
className?: string;
menuItems: IMenuItem[];
location: string;
user: User;
renderConfigure: boolean;
onMenuItemClick: (url: string, event: React.MouseEvent) => void;
}
export interface IActiveSubMenu {
isActive: boolean;
label: string | null;
}
const SideBar: React.FC<SideBarProps> = ({
location,
menuItems,
renderConfigure,
user,
onMenuItemClick
}) => {
const classes = useStyles({});
const [isShrunk, setShrink] = useLocalStorage("isMenuSmall", false);
const intl = useIntl();
return (
<div
className={classNames(classes.root, {
[classes.shrunk]: isShrunk
})}
>
<div className={classes.logo}>
<SVG src={logoLight} />
</div>
{menuItems.map(menuItem => {
// const isActive = isMenuActive(location, menuItem);
if (
menuItem.permission &&
!user.userPermissions
.map(perm => perm.code)
.includes(menuItem.permission)
) {
return null;
}
return <MenuItem menuItem={menuItem} onClick={onMenuItemClick} />;
})}
{renderConfigure && (
<MenuItem
menuItem={{
ariaLabel: "configure",
icon: null,
label: intl.formatMessage(sectionNames.configuration),
testingContextId: "configure",
url: configurationMenuUrl
}}
onClick={onMenuItemClick}
/>
)}
<button onClick={() => setShrink(!isShrunk)}>toggl</button>
</div>
);
};
SideBar.displayName = "SideBar";
export default SideBar;

View file

View file

@ -0,0 +1,2 @@
export * from "./SideBar";
export { default } from "./SideBar";

View file

@ -0,0 +1,14 @@
import { orderDraftListUrl, orderListUrl } from "@saleor/orders/urls";
import { matchPath } from "react-router";
import { IMenuItem } from "../AppLayout/menuStructure";
export function isMenuActive(location: string, menuItem: IMenuItem) {
return location.split("?")[0] === orderDraftListUrl().split("?")[0] &&
menuItem.url.split("?")[0] === orderListUrl().split("?")[0]
? false
: !!matchPath(location.split("?")[0], {
exact: menuItem.url.split("?")[0] === "/",
path: menuItem.url.split("?")[0]
});
}