left-side-panel-small-refactor
[arvados-workbench2.git] / src / components / side-panel / side-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { ReactElement } from 'react';
7 import { StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core/styles';
8 import List from "@material-ui/core/List/List";
9 import ListItem from "@material-ui/core/ListItem/ListItem";
10 import ListItemText from "@material-ui/core/ListItemText/ListItemText";
11 import ListItemIcon from '@material-ui/core/ListItemIcon';
12 import Collapse from "@material-ui/core/Collapse/Collapse";
13
14 import { Typography } from '@material-ui/core';
15
16 export interface SidePanelItem {
17     id: string;
18     name: string;
19     icon: string;
20     active?: boolean;
21     open?: boolean;
22 }
23
24 interface SidePanelProps {
25     toggleOpen: (id: string) => void;
26     toggleActive: (id: string) => void;
27     sidePanelItems: SidePanelItem[];
28 }
29
30 class SidePanel extends React.Component<SidePanelProps & WithStyles<CssRules>> {
31     render(): ReactElement<any> {
32         const { classes, toggleOpen, toggleActive, sidePanelItems } = this.props;
33         const { listItemText, leftSidePanelContainer, row, list, icon, projectIcon, active, activeArrow, inactiveArrow, arrowTransition, arrowRotate } = classes;
34         return (
35             <div className={leftSidePanelContainer}>
36                 <List>
37                     {sidePanelItems.map(it => (
38                         <span key={it.name}>
39                             <ListItem button className={list} onClick={() => toggleActive(it.id)}>
40                                 <span className={row}>
41                                     {it.name === "Projects" ? <i onClick={() => toggleOpen(it.id)} className={`${it.active ? activeArrow : inactiveArrow} 
42                                         ${it.open ? `fas fa-caret-down ${arrowTransition}` : `fas fa-caret-down ${arrowRotate}`}`} /> : null}
43                                     <ListItemIcon className={it.active ? active : ''}>
44                                         <i className={`${it.icon} ${icon} ${it.name === "Projects" ? projectIcon : ''}`} />
45                                     </ListItemIcon>
46                                     <ListItemText className={listItemText} primary={<Typography className={it.active ? active : ''}>{it.name}</Typography>} />
47                                 </span>
48                             </ListItem>
49                             {it.name === "Projects" ? (
50                                 <Collapse in={it.open} timeout="auto" unmountOnExit>
51                                     {this.props.children}
52                                 </Collapse>) : null}
53                         </span>
54                     ))}
55                 </List>
56             </div>
57         );
58     }
59 }
60
61 type CssRules = 'active' | 'listItemText' | 'row' | 'leftSidePanelContainer' | 'list' | 'icon' | 'projectIcon' |
62     'activeArrow' | 'inactiveArrow' | 'arrowRotate' | 'arrowTransition';
63
64 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
65     active: {
66         color: '#4285F6',
67     },
68     listItemText: {
69         padding: '0px',
70     },
71     row: {
72         display: 'flex',
73         alignItems: 'center',
74     },
75     activeArrow: {
76         color: '#4285F6',
77         position: 'absolute',
78     },
79     inactiveArrow: {
80         position: 'absolute',
81     },
82     arrowTransition: {
83         transition: 'all 0.1s ease',
84     },
85     arrowRotate: {
86         transition: 'all 0.1s ease',
87         transform: 'rotate(-90deg)',
88     },
89     leftSidePanelContainer: {
90         overflowY: 'auto',
91         minWidth: '240px',
92         whiteSpace: 'nowrap',
93         marginTop: '38px',
94         display: 'flex',
95         flexGrow: 1,
96     },
97     list: {
98         paddingBottom: '5px',
99         paddingTop: '5px',
100         paddingLeft: '14px',
101         minWidth: '240px',
102     },
103     icon: {
104         minWidth: '20px',
105     },
106     projectIcon: {
107         marginLeft: '17px',
108     }
109 });
110
111 export default withStyles(styles)(SidePanel);