-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PKPD-30 collapsible sidebar #568
Changes from 9 commits
7406395
4eec168
569a3fb
1c80400
0f4610e
bf836af
8b99168
478d66f
2bd9dda
4c330b4
7b620d3
7be26bf
8e0e05c
e203f00
74c4700
2501e39
1e5268e
42734a0
15b462e
7edb41d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@keyframes onExpand { | ||
0% {transform: translate(-190px); overflow-X: 'visible';} | ||
100% {transform: translate(0); overflow-x: 'hidden';} | ||
} | ||
|
||
@keyframes onCollapse { | ||
0% {transform: translate(190px); overflow-X: 'visible';} | ||
100% {transform: translate(0); overflow-x: 'hidden';} | ||
} | ||
|
||
.on-expand { | ||
animation-name: onExpand; | ||
animation-duration: .35s; | ||
animation-timing-function: linear; | ||
} | ||
|
||
.on-collapse { | ||
animation-name: onCollapse; | ||
animation-duration: .35s; | ||
animation-timing-function: linear; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,8 +42,12 @@ import ContactSupportIcon from "@mui/icons-material/ContactSupport"; | |
import TableViewIcon from "@mui/icons-material/TableView"; | ||
import "@fontsource/comfortaa"; // Defaults to weight 400 | ||
import useSubjectGroups from "../../hooks/useSubjectGroups"; | ||
import ArrowBackIcon from "@mui/icons-material/ArrowBack"; | ||
import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; | ||
import "./Sidebar.css"; | ||
|
||
const drawerWidth = 240; | ||
const drawerExpandedWidth = 240; | ||
const drawerCollapsedWidth = 50; | ||
|
||
export default function Sidebar() { | ||
const dispatch = useAppDispatch(); | ||
|
@@ -214,7 +218,34 @@ export default function Sidebar() { | |
(step) => step !== projectsPage && step !== helpPage, | ||
); | ||
|
||
const drawer = ( | ||
const [isExpanded, setIsExpanded] = useState(true); | ||
const onCollapse = () => { | ||
const element = document.getElementById("main-content"); | ||
element?.classList.remove("on-expand"); | ||
element?.classList.add("on-collapse"); | ||
|
||
const simulationsNav = document.getElementById("simulations-content"); | ||
if (simulationsNav) { | ||
simulationsNav?.classList.remove("on-expand"); | ||
simulationsNav?.classList.add("on-collapse"); | ||
} | ||
setIsExpanded(false); | ||
}; | ||
|
||
const onExpand = () => { | ||
const element = document.getElementById("main-content"); | ||
element?.classList.remove("on-collapse"); | ||
element?.classList.add("on-expand"); | ||
|
||
const simulationsNav = document.getElementById("simulations-content"); | ||
if (simulationsNav) { | ||
simulationsNav?.classList.remove("on-collapse"); | ||
simulationsNav?.classList.add("on-expand"); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comments here about modifying the DOM outside of the React virtual DOM. |
||
setIsExpanded(true); | ||
}; | ||
|
||
const drawerMobile = ( | ||
<div style={{ marginTop: "7rem" }}> | ||
<List> | ||
<ListItem key={projectsPage?.key} disablePadding> | ||
|
@@ -282,14 +313,102 @@ export default function Sidebar() { | |
</div> | ||
); | ||
|
||
const drawer = ( | ||
<div style={{ marginTop: "7rem", transition: "all .35s linear" }}> | ||
{isExpanded ? ( | ||
<IconButton onClick={onCollapse} sx={{ marginLeft: ".5rem" }}> | ||
<ArrowBackIcon /> | ||
</IconButton> | ||
) : ( | ||
<IconButton onClick={onExpand} sx={{ marginLeft: ".5rem" }}> | ||
<ArrowForwardIcon /> | ||
</IconButton> | ||
)} | ||
|
||
<List> | ||
<ListItem key={projectsPage?.key} disablePadding> | ||
<ListItemButton | ||
onClick={handlePageClick(projectsPage?.key)} | ||
disabled={isPageDisabled(projectsPage?.key)} | ||
disableRipple={true} | ||
selected={isPageSelected(projectsPage?.key)} | ||
> | ||
<ListItemIcon> | ||
{projectsPage?.value in errorComponents | ||
? errorComponents[projectsPage?.value] | ||
: icons[projectsPage?.value]} | ||
</ListItemIcon> | ||
<ListItemText primary={projectsPage?.value} /> | ||
</ListItemButton> | ||
</ListItem> | ||
</List> | ||
{projectIdOrZero !== 0 && ( | ||
<> | ||
{isExpanded ? ( | ||
<Typography | ||
variant="subtitle1" | ||
noWrap | ||
component="div" | ||
sx={{ | ||
flexGrow: 1, | ||
color: "gray", | ||
paddingLeft: "1rem", | ||
paddingTop: "1rem", | ||
}} | ||
> | ||
STEPS | ||
</Typography> | ||
) : ( | ||
<Divider sx={{ paddingTop: "21px", marginBottom: "22px" }} /> | ||
)} | ||
|
||
<List> | ||
{steps.map(({ key, value }) => ( | ||
<ListItem key={key} disablePadding> | ||
<ListItemButton | ||
onClick={handlePageClick(key)} | ||
disabled={isPageDisabled(key)} | ||
disableRipple={true} | ||
selected={isPageSelected(key)} | ||
> | ||
<ListItemIcon> | ||
{value in errorComponents | ||
? errorComponents[value] | ||
: icons[value]} | ||
</ListItemIcon> | ||
<ListItemText sx={{ textWrap: "nowrap" }} primary={value} /> | ||
</ListItemButton> | ||
</ListItem> | ||
))} | ||
</List> | ||
</> | ||
)} | ||
{isExpanded && ( | ||
<Typography | ||
sx={{ | ||
position: "absolute", | ||
bottom: 0, | ||
margin: ".5rem", | ||
color: "gray", | ||
textWrap: "nowrap", | ||
}} | ||
> | ||
pkpdx version {import.meta.env.VITE_APP_VERSION?.slice(0, 7) || "dev"} | ||
</Typography> | ||
)} | ||
</div> | ||
); | ||
|
||
return ( | ||
<Box sx={{ display: "flex" }}> | ||
<Box sx={{ display: "flex", overflowX: "hidden" }}> | ||
<CssBaseline /> | ||
<AppBar | ||
position="fixed" | ||
sx={{ | ||
width: { sm: `100%` }, | ||
ml: { sm: `${drawerWidth}px` }, | ||
ml: { | ||
sm: `${isExpanded ? drawerExpandedWidth : drawerCollapsedWidth}px`, | ||
}, | ||
zIndex: 9998, | ||
backgroundColor: "white", | ||
}} | ||
|
@@ -368,7 +487,12 @@ export default function Sidebar() { | |
</AppBar> | ||
<Box | ||
component="nav" | ||
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }} | ||
sx={{ | ||
width: { | ||
sm: isExpanded ? drawerExpandedWidth : drawerCollapsedWidth, | ||
}, | ||
flexShrink: { sm: 0 }, | ||
}} | ||
aria-label="mailbox folders" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not related to this PR, but I just noticed that these ARIA labels are wrong. |
||
> | ||
{/* The implementation can be swapped with js to avoid SEO duplication of links. */} | ||
|
@@ -383,19 +507,21 @@ export default function Sidebar() { | |
display: { xs: "block", sm: "none" }, | ||
"& .MuiDrawer-paper": { | ||
boxSizing: "border-box", | ||
width: drawerWidth, | ||
width: drawerExpandedWidth, | ||
}, | ||
}} | ||
> | ||
{drawer} | ||
{drawerMobile} | ||
</Drawer> | ||
<Drawer | ||
variant="permanent" | ||
sx={{ | ||
display: { xs: "none", sm: "block" }, | ||
"& .MuiDrawer-paper": { | ||
boxSizing: "border-box", | ||
width: drawerWidth, | ||
transition: "all .35s linear", | ||
width: isExpanded ? drawerExpandedWidth : drawerCollapsedWidth, | ||
overflowX: "hidden", | ||
}, | ||
}} | ||
open | ||
|
@@ -407,23 +533,26 @@ export default function Sidebar() { | |
<Box | ||
component="nav" | ||
sx={{ | ||
width: { sm: drawerWidth }, | ||
width: { | ||
sm: drawerExpandedWidth, | ||
}, | ||
transition: "all .35s linear", | ||
flexShrink: { sm: 0 }, | ||
height: "100vh", | ||
backgroundColor: '#FBFBFA', | ||
borderRight: '1px solid #DBD6D1' | ||
}} | ||
aria-label="mailbox folders" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also not related to this PR, but the wrong ARIA label here too. |
||
id='simulations-portal' | ||
id="simulations-portal" | ||
/> | ||
)} | ||
<Box | ||
component="main" | ||
id="main-content" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be inclined to set the expanded/collapsed className here, rather than modify the DOM directly. |
||
sx={{ | ||
flexGrow: 1, | ||
transition: "all .35s linear", | ||
p: 3, | ||
width: { sm: `calc(100% - ${drawerWidth}px)` }, | ||
paddingBottom: 0 | ||
overflowX: "hidden", | ||
paddingBottom: 0, | ||
}} | ||
> | ||
<Toolbar /> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic could maybe move into a function outside of the component, to make it clear that the DOM is being modified outside of React.
Also, the DOM changes here won't be tracked by React's virtual DOM, so I'm not 100% sure if they'll persist across re-renders.