feat: Add sidebar and panel (#866)

* feat: Add sidebar and panel

* fix: fix sidebar values
This commit is contained in:
Bruno Quaresma
2022-04-05 14:01:45 -03:00
committed by GitHub
parent abf6934ebb
commit abddd64497
8 changed files with 916 additions and 0 deletions
@@ -0,0 +1,21 @@
import { Story } from "@storybook/react"
import React from "react"
import { Panel, PanelProps } from "./"
export default {
title: "Page/Panel",
component: Panel,
}
const Template: Story<PanelProps> = (args: PanelProps) => <Panel {...args} />
export const Example = Template.bind({})
Example.args = {
title: "Panel title",
activeTab: "oauthSettings",
menuItems: [
{ label: "OAuth Settings", value: "oauthSettings" },
{ label: "Security", value: "oauthSettings", hasChanges: true },
{ label: "Hardware", value: "oauthSettings" },
],
}
+102
View File
@@ -0,0 +1,102 @@
import { makeStyles } from "@material-ui/core/styles"
import { fade } from "@material-ui/core/styles/colorManipulator"
import React from "react"
import { Sidebar, SidebarItem } from "../Sidebar"
export type AdminMenuItemCallback = (menuItem: string) => void
export interface PanelProps {
title: string
menuItems: SidebarItem[]
activeTab: string
onSelect: AdminMenuItemCallback
}
export const Panel: React.FC<PanelProps> = ({ children, title, menuItems, activeTab, onSelect }) => {
const styles = useStyles()
return (
<div className={styles.root}>
<div className={styles.inner}>
<div className={styles.menuPanel}>
<div className={styles.title}>{title}</div>
<Sidebar menuItems={menuItems} activeItem={activeTab} onSelect={onSelect} />
</div>
<div className={styles.contentPanel}>{children}</div>
</div>
</div>
)
}
const useStyles = makeStyles((theme) => ({
root: {
minHeight: 400,
marginBottom: theme.spacing(2),
// Prevents scrollbar jitter from long content
marginRight: "calc(-1 * (100vw - 100%))",
},
inner: {
display: "flex",
maxWidth: 1920,
padding: theme.spacing(5, 3.5, 0, 4),
},
icon: {
fontSize: 100,
position: "absolute",
left: -50,
top: 31,
color: fade(theme.palette.common.black, 0.1),
transition: "transform 0.3s ease",
zIndex: -1,
},
menuPanel: {
paddingRight: 40,
},
title: {
marginTop: theme.spacing(4),
fontSize: 32,
letterSpacing: -theme.spacing(0.0375),
},
contentPanel: {
display: "flex",
flexDirection: "column",
width: "100%",
maxWidth: 930,
},
[theme.breakpoints.up("lg")]: {
icon: {
position: "relative",
top: -11,
left: 30,
},
contentPanel: {
width: 930,
},
},
[theme.breakpoints.down("lg")]: {
contentPanel: {
width: 890,
},
},
[theme.breakpoints.down("md")]: {
contentPanel: {
width: 700,
},
},
[theme.breakpoints.down("sm")]: {
contentPanel: {
width: 550,
},
root: {
marginRight: 0, //disabled scrollbar jump trick to avoid small screen bug with menu
},
},
}))
@@ -0,0 +1,20 @@
import { Story } from "@storybook/react"
import React from "react"
import { Sidebar, SidebarProps } from "./"
export default {
title: "Page/Sidebar",
component: Sidebar,
}
const Template: Story<SidebarProps> = (args: SidebarProps) => <Sidebar {...args} />
export const Example = Template.bind({})
Example.args = {
activeItem: "oauthSettings",
menuItems: [
{ label: "OAuth Settings", value: "oauthSettings" },
{ label: "Security", value: "security", hasChanges: true },
{ label: "Hardware", value: "hardware" },
],
}
+104
View File
@@ -0,0 +1,104 @@
import List from "@material-ui/core/List"
import ListItem from "@material-ui/core/ListItem"
import { makeStyles } from "@material-ui/core/styles"
import React from "react"
import { combineClasses } from "../../util/combine-classes"
export interface SidebarItem {
value: string
label: string
hasChanges?: boolean
}
export interface SidebarProps {
menuItems: SidebarItem[]
activeItem?: string
onSelect?: (value: string) => void
}
export const Sidebar: React.FC<SidebarProps> = ({ menuItems, activeItem, onSelect }) => {
const styles = useStyles()
return (
<List className={styles.menu}>
{menuItems.map(({ hasChanges, ...tab }) => {
const isActive = activeItem === tab.value
return (
<ListItem
key={tab.value}
button
onClick={onSelect ? () => onSelect(tab.value) : undefined}
className={styles.menuItem}
disableRipple
focusRipple={false}
component="li"
>
<span className={combineClasses({ [styles.menuItemSpan]: true, active: isActive })}>
{hasChanges ? `${tab.label}*` : tab.label}
</span>
</ListItem>
)
})}
</List>
)
}
const useStyles = makeStyles((theme) => ({
menu: {
minWidth: 160,
marginTop: theme.spacing(5),
},
menuItem: {
letterSpacing: -theme.spacing(0.0375),
padding: 0,
fontSize: 18,
color: theme.palette.text.secondary,
"&.MuiListItem-button:hover": {
backgroundColor: "transparent",
},
},
menuItemSpan: {
paddingTop: theme.spacing(1.5),
paddingBottom: theme.spacing(1),
transition: "300ms all ease",
position: "relative",
"&:hover": {
color: theme.palette.text.primary,
},
"&.active": {
color: theme.palette.primary.dark,
},
"&.active, &:hover": {
"&::before": {
opacity: 1,
},
"&::after": {
opacity: 1,
},
},
},
[theme.breakpoints.up("lg")]: {
menuItemSpan: {
"&::before": {
content: "'{'",
position: "absolute",
left: -15,
opacity: 0,
transition: "inherit",
},
"&::after": {
content: "'}'",
position: "absolute",
right: -15,
opacity: 0,
transition: "inherit",
},
},
},
}))