feat([projectBrowser, state, treeView, Sidebar, styles]): add projectBrowser, that contains folders and patches, that just could be selected and dragged at this moment, but without any outcome for state

This commit is contained in:
Kirill Shumilov
2016-08-02 18:52:44 +03:00
parent 7e882d9622
commit c8aa6032dd
13 changed files with 308 additions and 22 deletions

View File

@@ -0,0 +1,81 @@
import R from 'ramda';
import React from 'react';
import classNames from 'classnames';
import Tree from 'react-ui-tree';
class ProjectBrowserTree extends React.Component {
constructor(props) {
super(props);
this.state = {
active: null,
tree: props.tree,
};
this.onClickNode = this.onClickNode.bind(this);
this.onChange = this.onChange.bind(this);
this.renderNode = this.renderNode.bind(this);
}
componentWillReceiveProps(nextProps) {
if (nextProps.tree !== this.state.tree) {
this.updateTree(nextProps.tree);
}
}
onClickNode(node) {
const nodeRef = node;
if (!node.hasOwnProperty('leaf')) {
nodeRef.collapsed = !nodeRef.collapsed;
}
this.setState(R.assoc('active', nodeRef, this.state));
}
onChange(tree) {
this.props.onChange(tree);
}
updateTree(tree) {
this.setState(R.assoc('tree', tree, this.state));
}
bindOnClickNode(node) {
return this.onClickNode.bind(this, node);
}
renderNode(node) {
const nodeClassName = classNames('node', {
'is-active': node === this.state.active,
'is-current': (node.hasOwnProperty('leaf') && node.id === this.props.currentPatchId),
});
return (
<span
className={nodeClassName}
onClick={this.bindOnClickNode(node)}
>
{node.module}
</span>
);
}
render() {
return (
<div className="ProjectBrowserTree">
<Tree
tree={this.state.tree}
renderNode={this.renderNode}
onChange={this.onChange}
/>
</div>
);
}
}
ProjectBrowserTree.propTypes = {
tree: React.PropTypes.object.isRequired,
currentPatchId: React.PropTypes.number,
onChange: React.PropTypes.func,
};
export default ProjectBrowserTree;

View File

@@ -0,0 +1,13 @@
import React from 'react';
const Sidebar = ({ children }) => (
<div className="Sidebar">
{children}
</div>
);
Sidebar.propTypes = {
children: React.PropTypes.arrayOf(React.PropTypes.element),
};
export default Sidebar;

View File

@@ -8,6 +8,7 @@ import * as KEYCODE from '../constants/keycodes';
import { isInput } from '../utils/browser';
import Patch from './Patch';
import EventListener from 'react-event-listener';
import Sidebar from '../components/Sidebar';
import Inspector from '../components/Inspector';
import ProjectBrowser from './ProjectBrowser';
@@ -74,13 +75,15 @@ class Editor extends React.Component {
return (
<div>
<EventListener target={document} onKeyDown={this.onKeyDown} />
<ProjectBrowser />
<Inspector
selection={this.props.selection}
nodes={this.props.nodes}
nodeTypes={this.props.nodeTypes}
onPropUpdate={this.onPropUpdate}
/>
<Sidebar>
<ProjectBrowser />
<Inspector
selection={this.props.selection}
nodes={this.props.nodes}
nodeTypes={this.props.nodeTypes}
onPropUpdate={this.onPropUpdate}
/>
</Sidebar>
<Patch
size={this.patchSize}
/>

View File

@@ -1,27 +1,45 @@
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as Actions from '../actions';
// import * as Actions from '../actions';
import Selectors from '../selectors';
import ProjectBrowserTree from '../components/ProjectBrowserTree';
class ProjectBrowser extends React.Component {
constructor(props) {
super(props);
this.displayName = 'ProjectBrowser';
this.onTreeChange = this.onTreeChange.bind(this);
}
onTreeChange(newTree) {
console.log('tree changed!', newTree);
}
render() {
return <div>ProjectBrowser</div>;
return (
<div className="ProjectBrowser">
<small className="title">Project browser</small>
<ProjectBrowserTree
tree={this.props.tree}
currentPatchId={this.props.currentPatchId}
onChange={this.onTreeChange}
/>
</div>
);
}
}
ProjectBrowser.propTypes = {
tree: React.PropTypes.object.isRequired,
actions: React.PropTypes.object,
patches: React.PropTypes.object,
currentPatchId: React.PropTypes.number,
};
const mapStateToProps = (state) => ({
tree: Selectors.Project.getTreeView(state),
patches: Selectors.Project.getPatches(state),
currentPatchId: Selectors.Editor.getCurrentPatchId(state),
});

View File

@@ -596,3 +596,59 @@ export const getLinkGhost = (state) => {
to: { x: 0, y: 0 },
};
};
/*
Folders
*/
export const getFolders = R.pipe(
getProject,
R.prop('folders')
);
/*
Tree view (get / parse)
*/
export const getTreeView = (state) => {
const makeTree = (folders, patches, parentId) => {
const foldersAtLevel = R.pipe(
R.values,
R.filter(R.propEq('parentId', parentId))
)(folders);
const patchesAtLevel = R.pipe(
R.values,
R.map(R.prop('present')),
R.filter(R.propEq('folderId', parentId))
)(patches);
return R.concat(
R.map(
folder => ({
id: folder.id,
module: folder.name,
collapsed: true,
children: makeTree(folders, patches, folder.id),
}),
foldersAtLevel
),
R.map(
patch => ({
id: patch.id,
module: patch.name,
leaf: true,
}),
patchesAtLevel
)
);
};
const folders = getFolders(state);
const patches = getPatches(state);
return {
module: 'Project',
collapsed: false,
children: makeTree(folders, patches, null),
};
};
// export const parseTreeView = (state) => {};

View File

@@ -78,7 +78,8 @@ const initialState = {
},
},
nodeTypes,
counter: {
folders: {},
counter: {
patches: 1,
nodes: 1,
pins: 1,

View File

@@ -22,7 +22,7 @@
@mixin inspector-widget() {
padding: 4px;
margin-bottom: 2px;
border-top: 1px solid #ccc;
// border-top: 1px solid #ccc;
overflow: hidden;
font-size: $font-size-m;

View File

@@ -23,3 +23,13 @@ $color-ctrl-background: #2d4c29;
$color-ctrl-background-text: #fff;
$snackbar-width: 200px;
$sidebar-width: 200px;
$sidebar-background: #eee;
$sidebar-color: #000;
$sidebar-title-color: #999;
$sidebar-title-divider: #ccc;
$sidebar-selected-background: rgb(128, 160, 190);
$sidebar-selected-color: #000;
$sidebar-block-shadow: inset 0 5px 15px 1px rgba(0,0,0,.1);
$sidebar-block-divider: 1px solid #fff;

View File

@@ -1,16 +1,10 @@
.Inspector {
position: absolute;
width: 200px;
display: block;
width: 100%;
height: 100%;
background: #eee;
color: #000;
.title {
display: block;
padding: 26px 20px 4px 8px;
color: #999;
}
background: $sidebar-background;
color: $sidebar-color;
ul {
padding: 0;

View File

@@ -0,0 +1,87 @@
.ProjectBrowserTree {
width: $sidebar-width;
background: $sidebar-background;
color: $sidebar-color;
padding: 8px 0;
box-sizing: border-box;
* { box-sizing: border-box; }
.f-no-select {
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.m-tree {
position: relative;
overflow: hidden;
font-family: $font-family-normal;
font-size: $font-size-m;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.m-draggable {
position: absolute;
opacity: 0.8;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.m-node {
box-sizing: border-box;
&.placeholder {
border: 1px dashed $sidebar-selected-background;
& > * {
visibility: hidden;
}
}
.inner {
position: relative;
cursor: pointer;
padding-left: 12px;
}
.node {
display: block;
padding: 4px 6px;
&.is-active {
border-left: 100px solid $sidebar-selected-background;
border-right: 100px solid $sidebar-selected-background;
margin-left: -100px;
background: $sidebar-selected-background;
color: #006;
}
}
.collapse {
position: absolute;
left: 0;
padding: 2px 6px;
cursor: pointer;
}
.children {
display: block;
}
.caret-down:before {
font-size: $font-size-m;
content: '\25BE';
}
.caret-right:before {
font-size: $font-size-m;
content: '\25B8';
}
}
}

View File

@@ -0,0 +1,20 @@
.Sidebar {
position: absolute;
width: $sidebar-width;
height: 100%;
background: $sidebar-background;
& > * {
box-shadow: $sidebar-block-shadow;
border-bottom: $sidebar-block-divider;
}
.title {
display: block;
margin: 0 8px;
padding: 10px 20px 4px 0;
color: $sidebar-title-color;
border-bottom: 1px solid $sidebar-title-divider;
}
}

View File

@@ -14,6 +14,7 @@
'base/base';
@import
'components/Sidebar',
'components/PatchWrapper',
'components/PatchSVG',
'components/BackgroundLayer',
@@ -25,4 +26,5 @@
'components/Inspector',
'components/SnackBarList',
'components/SnackBarError',
'components/ProjectBrowserTree',
'components/CreateNodeWidget';

View File

@@ -39,6 +39,7 @@
"react-event-listener": "^0.2.1",
"react-redux": "^4.0.6",
"react-skylight": "^0.4.0",
"react-ui-tree": "^2.5.0",
"redux": "^3.0.5",
"redux-thunk": "^2.1.0",
"redux-undo": "^1.0.0-beta8",