data: T;
id: string;
open: boolean;
+ active: boolean;
items?: Array<TreeItem<T>>;
}
interface TreeProps<T> {
items?: Array<TreeItem<T>>;
- render: (item: T) => ReactElement<{}>;
+ render: (item: TreeItem<T>) => ReactElement<{}>;
toggleItem: (id: string) => any;
level?: number;
}
+function colorArrows(open: boolean, color: string){
+ return <i style={{marginRight: '10px', minWidth: '10px', color}} className={open ? "fas fa-caret-down" : "fas fa-caret-right"} />
+}
+
class Tree<T> extends React.Component<TreeProps<T>, {}> {
render(): ReactElement<any> {
const level = this.props.level ? this.props.level : 0;
{this.props.items && this.props.items.map((it: TreeItem<T>, idx: number) =>
<div key={`item/${level}/${idx}`}>
<ListItem button onClick={() => this.props.toggleItem(it.id)} style={{paddingLeft: (level + 1) * 15, paddingBottom: '3px', paddingTop: '3px'}}>
- <i style={{marginRight: "10px"}} className={it.open ? "fas fa-caret-down" : "fas fa-caret-right"} />
- {this.props.render(it.data)}
+ {it.active ? colorArrows(it.open, "#4285F6") : colorArrows(it.open, "#333")}
+ {this.props.render(it)}
</ListItem>
{it.items && it.items.length > 0 &&
<Collapse in={it.open} timeout="auto" unmountOnExit>
const projects = tree.map((t, idx) => ({
id: `l${level}i${idx}${t[0]}`,
open: false,
+ active: false,
data: {
name: t[0],
- icon: level === 0 ? <i className="icon-th"/> : <i className="fas fa-folder"/>,
+ icon: level === 0 ? <i className="fas fa-th"/> : <i className="fas fa-folder"/>,
createdAt: '2018-05-05',
},
items: t.length > 1 ? buildProjectTree(t[1], level + 1) : []
return item;
}
+function resetTreeActivity<T>(tree: Array<TreeItem<T>>): boolean | undefined {
+ let item;
+ for (const leaf of tree) {
+ item = leaf.active === true
+ ? leaf.active = false
+ : resetTreeActivity(leaf.items ? leaf.items : []);
+ }
+ return item;
+}
+
const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
switch (action.type) {
case getType(actions.createProject): {
case getType(actions.toggleProjectTreeItem): {
const tree = _.cloneDeep(state);
const itemId = action.payload;
+ resetTreeActivity(tree);
const item = findTreeItem(tree, itemId);
if (item) {
item.open = !item.open;
+ item.active = true;
}
return tree;
}
const drawerWidth = 240;
-type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'row' | 'treeContainer' | 'toolbar';
+type CssRules = 'root' | 'appBar' | 'active' | 'drawerPaper' | 'content' | 'row' | 'treeContainer' | 'toolbar';
const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
root: {
zIndex: theme.zIndex.drawer + 1,
backgroundColor: '#692498'
},
+ active: {
+ color: '#4285F6',
+ },
drawerPaper: {
position: 'relative',
width: drawerWidth,
},
row: {
display: 'flex',
- alignItems: 'center'
+ alignItems: 'center',
},
treeContainer: {
position: 'absolute',
overflowX: 'visible',
marginTop: '80px',
minWidth: drawerWidth,
- whiteSpace: 'nowrap'
+ whiteSpace: 'nowrap',
},
toolbar: theme.mixins.toolbar
});
<div className={classes.treeContainer}>
<Tree items={projects}
toggleItem={this.props.toggleProjectTreeItem}
- render={(p: Project) => <span className={classes.row}>
- <div><ListItemIcon>{p.icon}</ListItemIcon></div>
- <div><ListItemText primary={p.name}/></div>
+ render={(project: TreeItem<Project>) => <span className={classes.row}>
+ <div><ListItemIcon className={project.active ? classes.active : ''}>{project.data.icon}</ListItemIcon></div>
+ <div><ListItemText primary={<Typography className={project.active ? classes.active : ''}>{project.data.name}</Typography>} /></div>
</span>}
/>
</div>