embark/embark-ui/src/components/FileExplorer.js

236 lines
5.4 KiB
JavaScript
Raw Normal View History

import {AppSwitch} from '@coreui/react';
import {Label} from 'reactstrap';
2018-08-30 12:13:37 +00:00
import React from 'react';
import PropTypes from 'prop-types';
import {Treebeard, decorators} from 'react-treebeard';
2018-10-25 07:06:37 +00:00
import classNames from 'classnames';
2018-10-25 13:51:54 +00:00
import {DARK_THEME} from '../constants';
2018-08-30 12:13:37 +00:00
2018-10-25 11:02:13 +00:00
const isDarkTheme= (theme) => theme === DARK_THEME;
const style = (theme) => ({
2018-10-11 11:08:47 +00:00
tree: {
base: {
listStyle: 'none',
2018-10-25 11:02:13 +00:00
backgroundColor: isDarkTheme(theme) ? '#1C1C1C' : '#FFFFFF',
color: isDarkTheme(theme) ? '#FFFFFF' : '#000000',
2018-10-25 07:06:37 +00:00
padding: '10px 0 0 10px',
2018-10-11 11:08:47 +00:00
margin: 0,
2018-10-25 13:51:54 +00:00
overflow: 'auto',
position: 'absolute',
top: 0,
bottom: '40px',
left: 0,
2018-11-08 19:48:17 +00:00
right: 0,
minWidth: '175px'
2018-10-11 11:08:47 +00:00
},
node: {
base: {
2018-10-25 07:06:37 +00:00
position: 'relative',
2018-10-25 13:51:54 +00:00
verticalAlign: 'middle'
2018-10-11 11:08:47 +00:00
},
link: {
cursor: 'pointer',
position: 'relative',
padding: '0px 5px',
display: 'block'
},
toggle: {
base: {
display: 'inline-block',
2018-10-25 07:06:37 +00:00
marginRight: '10px'
2018-10-11 11:08:47 +00:00
},
wrapper: {
2018-10-25 13:51:54 +00:00
margin: '-7px 0 0 0'
2018-10-11 11:08:47 +00:00
},
2018-10-25 07:06:37 +00:00
height: 7,
width: 7,
2018-10-11 11:08:47 +00:00
arrow: {
2018-10-25 11:02:13 +00:00
fill: isDarkTheme(theme) ? '#FFFFFF' : '#000000',
2018-10-11 11:08:47 +00:00
strokeWidth: 0
}
},
header: {
base: {
2018-10-25 13:51:54 +00:00
display: 'inline-block'
2018-10-11 11:08:47 +00:00
},
connector: {
width: '2px',
height: '12px',
borderLeft: 'solid 2px black',
borderBottom: 'solid 2px black',
position: 'absolute',
top: '0px',
left: '-21px'
},
title: {
2018-10-25 13:51:54 +00:00
lineHeight: '24px'
2018-10-11 11:08:47 +00:00
}
},
subtree: {
listStyle: 'none',
2018-10-25 07:06:37 +00:00
paddingLeft: '22px'
2018-10-11 11:08:47 +00:00
},
loading: {
color: '#E2C089'
}
}
}
2018-10-25 11:02:13 +00:00
});
2018-10-11 11:08:47 +00:00
2018-10-25 07:06:37 +00:00
2018-08-30 12:13:37 +00:00
const Header = ({style, node}) => {
2018-10-25 07:06:37 +00:00
let icon;
if (!node.children) {
const extension = node.path.split('.').pop();
switch(extension) {
case 'html':
icon = 'text-danger fa fa-html5';
break;
case 'css':
icon = 'text-warning fa fa-css3';
break;
case 'js':
case 'jsx':
icon = 'text-primary icon js-icon';
break;
case 'json':
icon = 'text-success icon hjson-icon';
break;
case 'sol':
icon = 'text-warning icon solidity-icon';
break;
default:
icon = 'fa fa-file-o';
}
} else {
switch(node.name) {
case 'dist':
icon = 'text-danger icon easybuild-icon';
break;
case 'config':
icon = 'text-warning fa fa-cogs';
break;
case 'contracts':
icon = 'text-success fa fa-file-text';
2018-10-25 07:06:37 +00:00
break;
case 'app':
icon = 'text-primary fa fa-code';
break;
case 'test':
icon = 'icon test-dir-icon';
break;
case 'node_modules':
icon = 'fa fa-folder-o';
break;
default:
2018-10-25 13:51:54 +00:00
icon = 'fa fa-folder';
2018-10-25 07:06:37 +00:00
}
}
2018-08-30 12:13:37 +00:00
return (
2018-10-25 07:06:37 +00:00
<div className="mb-1" style={style.base}>
<div style={style.title}>
2018-10-25 07:06:37 +00:00
<i className={classNames('mr-1', icon)} />
{node.name}
2018-08-30 12:13:37 +00:00
</div>
</div>
2018-08-30 12:13:37 +00:00
);
};
Header.propTypes = {
style: PropTypes.object,
node: PropTypes.object
};
decorators.Header = Header;
class FileExplorer extends React.Component {
constructor(props) {
2018-08-30 12:13:37 +00:00
super(props);
2018-10-26 15:06:14 +00:00
this.state = {activeNodes: []};
2018-08-30 12:13:37 +00:00
}
2018-08-30 12:13:37 +00:00
onToggle(node, toggled) {
2018-10-26 15:06:14 +00:00
node.active = toggled;
if (node.children) {
2018-08-30 12:13:37 +00:00
node.toggled = toggled;
2018-08-30 12:13:37 +00:00
} else {
this.props.fetchFile(node);
2018-08-30 12:13:37 +00:00
}
2018-10-26 15:06:14 +00:00
let newNodes;
if (toggled) {
newNodes = this.state.activeNodes;
2018-10-29 11:29:20 +00:00
newNodes.push(node);
2018-10-26 15:06:14 +00:00
} else {
2018-10-29 11:29:20 +00:00
newNodes = this.state.activeNodes.filter(n => !this.nodeEquals(node, n));
2018-10-26 15:06:14 +00:00
}
this.setState({activeNodes: newNodes});
}
nodeEquals(a, b) {
return a && b && a.path && b.path && a.name && b.name &&
a.path === b.path &&
a.name === b.name;
2018-08-30 12:13:37 +00:00
}
2018-08-30 12:13:37 +00:00
data(nodes) {
let filtered = [];
if (!Array.isArray(nodes)) return filtered;
2018-10-26 15:06:14 +00:00
const activeNodes = this.state.activeNodes;
const showHidden = this.props.showHiddenFiles;
2018-10-26 15:06:14 +00:00
return nodes.reduce((filtered, node) => {
if (!showHidden && node.isHidden) return filtered;
let updatedNode = {...node};
if (node.children) {
const children = this.data(node.children);
if (children.length) {
updatedNode.children = children;
}
}
2018-10-26 15:06:14 +00:00
if (activeNodes.find(n => this.nodeEquals(node, n))) {
updatedNode.active = true;
if (node.children) updatedNode.toggled = true;
}
2018-10-26 15:06:14 +00:00
filtered.push(updatedNode);
return filtered;
}, []);
}
render() {
2018-08-30 12:13:37 +00:00
return (
2018-10-25 13:51:54 +00:00
<div className="d-flex flex-column">
<Treebeard
data={this.data(this.props.files)}
decorators={decorators}
onToggle={this.onToggle.bind(this)}
2018-10-25 11:02:13 +00:00
style={style(this.props.theme)}
/>
2018-11-08 19:48:17 +00:00
<Label className="hidden-toggle mb-0 pt-2 pr-2 pb-1 border-top text-right">
2018-10-29 11:29:20 +00:00
<span className="mr-2 align-top" style={{"fontSize": "12px"}}>Show hidden files</span>
2018-10-24 19:20:31 +00:00
<AppSwitch color="success" variant="pill" size="sm" onChange={this.props.toggleShowHiddenFiles}/>
</Label>
</div>
2018-08-30 12:13:37 +00:00
);
}
}
FileExplorer.propTypes = {
2018-08-30 12:13:37 +00:00
files: PropTypes.array,
fetchFile: PropTypes.func,
showHiddenFiles: PropTypes.bool,
2018-10-25 11:02:13 +00:00
toggleShowHiddenFiles: PropTypes.func,
theme: PropTypes.string
2018-08-30 12:13:37 +00:00
};
export default FileExplorer;