Group layers #66

This commit is contained in:
Lukas Martinelli 2017-01-11 17:52:21 +01:00
parent 76d2d06e77
commit d0f047d88a
6 changed files with 142 additions and 38 deletions

View file

@ -0,0 +1,20 @@
import React from 'react'
import CollapseOpenIcon from 'react-icons/lib/md/arrow-drop-down'
import CollapseCloseIcon from 'react-icons/lib/md/arrow-drop-up'
export default class Collapser extends React.Component {
static propTypes = {
isCollapsed: React.PropTypes.bool.isRequired,
style: React.PropTypes.object,
}
render() {
const iconStyle = {
width: 20,
height: 20,
...this.props.style,
}
return this.props.isCollapsed ? <CollapseCloseIcon style={iconStyle}/> : <CollapseOpenIcon style={iconStyle} />
}
}

View file

@ -1,22 +1,6 @@
import React from 'react' import React from 'react'
import Collapse from 'react-collapse' import Collapse from 'react-collapse'
import CollapseOpenIcon from 'react-icons/lib/md/arrow-drop-down' import Collapser from './Collapser'
import CollapseCloseIcon from 'react-icons/lib/md/arrow-drop-up'
class Collapser extends React.Component {
static propTypes = {
isCollapsed: React.PropTypes.bool.isRequired,
}
render() {
const iconStyle = {
width: 20,
height: 20,
}
return this.props.isCollapsed ? <CollapseCloseIcon style={iconStyle}/> : <CollapseOpenIcon style={iconStyle} />
}
}
export default class LayerEditorGroup extends React.Component { export default class LayerEditorGroup extends React.Component {
static propTypes = { static propTypes = {

View file

@ -2,6 +2,7 @@ import React from 'react'
import cloneDeep from 'lodash.clonedeep' import cloneDeep from 'lodash.clonedeep'
import Button from '../Button' import Button from '../Button'
import LayerListGroup from './LayerListGroup'
import LayerListItem from './LayerListItem' import LayerListItem from './LayerListItem'
import AddIcon from 'react-icons/lib/md/add-circle-outline' import AddIcon from 'react-icons/lib/md/add-circle-outline'
import AddModal from '../modals/AddModal' import AddModal from '../modals/AddModal'
@ -9,6 +10,8 @@ import AddModal from '../modals/AddModal'
import style from '../../libs/style.js' import style from '../../libs/style.js'
import {SortableContainer, SortableHandle, arrayMove} from 'react-sortable-hoc'; import {SortableContainer, SortableHandle, arrayMove} from 'react-sortable-hoc';
const layerPrefix = name => name.replace(' ', '-').replace('_', '-').split('-')[0]
const layerListPropTypes = { const layerListPropTypes = {
layers: React.PropTypes.array.isRequired, layers: React.PropTypes.array.isRequired,
selectedLayerIndex: React.PropTypes.number.isRequired, selectedLayerIndex: React.PropTypes.number.isRequired,
@ -73,22 +76,69 @@ class LayerListContainer extends React.Component {
}) })
} }
render() { groupedLayers() {
const layerPanels = this.props.layers.map((layer, index) => { const groups = []
const layerId = layer.id for (let i = 0; i < this.props.layers.length; i++) {
return <LayerListItem const previousLayer = this.props.layers[i-1]
index={index} const layer = this.props.layers[i]
key={layerId} if(previousLayer && layerPrefix(previousLayer.id) == layerPrefix(layer.id)) {
layerId={layerId} const lastGroup = groups[groups.length - 1]
layerType={layer.type} lastGroup.push(layer)
visibility={(layer.layout || {}).visibility} } else {
isSelected={index === this.props.selectedLayerIndex} groups.push([layer])
onLayerSelect={this.props.onLayerSelect} }
onLayerDestroy={this.onLayerDestroy.bind(this)} }
onLayerCopy={this.onLayerCopy.bind(this)} return groups
onLayerVisibilityToggle={this.onLayerVisibilityToggle.bind(this)} }
/>
toggleLayerGroup(groupPrefix) {
groupedLayers().forEach(layers => {
if(groupPrefix === layerPrefix(layers[0].id)) {
layers.forEach(layer => {
//HACK
//In this case it is ok to modify the metadata
//because no one else depends on it
layer.metadata = {
...layer.metadata,
'maputnik:visible': false
}
})
}
}) })
}
render() {
const listItems = []
let idx = 0
this.groupedLayers().forEach(layers => {
if(layers.length > 1) {
const groupPrefix = layerPrefix(layers[0].id)
const grp = <LayerListGroup
key={'group-'+groupPrefix}
title={groupPrefix}
isActive={true}
/>
listItems.push(grp)
}
layers.forEach(layer => {
const listItem = <LayerListItem
index={idx}
key={layer.id}
layerId={layer.id}
layerType={layer.type}
visibility={(layer.layout || {}).visibility}
isSelected={idx === this.props.selectedLayerIndex}
onLayerSelect={this.props.onLayerSelect}
onLayerDestroy={this.onLayerDestroy.bind(this)}
onLayerCopy={this.onLayerCopy.bind(this)}
onLayerVisibilityToggle={this.onLayerVisibilityToggle.bind(this)}
/>
listItems.push(listItem)
idx += 1
})
})
return <div className="maputnik-layer-list"> return <div className="maputnik-layer-list">
<AddModal <AddModal
layers={this.props.layers} layers={this.props.layers}
@ -107,7 +157,7 @@ class LayerListContainer extends React.Component {
</Button> </Button>
</header> </header>
<ul className="maputnik-layer-list-container"> <ul className="maputnik-layer-list-container">
{layerPanels} {listItems}
</ul> </ul>
</div> </div>
} }

View file

@ -0,0 +1,26 @@
import React from 'react'
import Collapser from './Collapser'
export default class LayerEditorGroup extends React.Component {
static propTypes = {
title: React.PropTypes.string.isRequired,
children: React.PropTypes.element.isRequired,
isActive: React.PropTypes.bool.isRequired,
onActiveToggle: React.PropTypes.func.isRequired
}
render() {
return <div className="maputnik-layer-list-group">
<div className="maputnik-layer-list-group-header"
onClick={e => this.props.onActiveToggle(!this.props.isActive)}
>
<span className="maputnik-layer-list-group-title">{this.props.title}</span>
<span className="maputnik-space" />
<Collapser
style={{ height: 14, width: 14 }}
isCollapsed={this.props.isActive}
/>
</div>
</div>
}
}

View file

@ -80,10 +80,6 @@ class LayerListItem extends React.Component {
reactIconBase: React.PropTypes.object reactIconBase: React.PropTypes.object
} }
constructor(props) {
super(props)
}
getChildContext() { getChildContext() {
return { return {
reactIconBase: { size: 14 } reactIconBase: { size: 14 }

View file

@ -37,7 +37,6 @@
cursor: pointer; cursor: pointer;
position: relative; position: relative;
padding: 5px 10px; padding: 5px 10px;
background-color: $color-black;
line-height: 1.3; line-height: 1.3;
display: flex; display: flex;
display: -ms-flexbox; display: -ms-flexbox;
@ -69,6 +68,35 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
&-group {
//border-bottom: 2px solid $color-gray;
}
&-group-header {
font-size: $font-size-6;
color: $color-lowgray;
background-color: lighten($color-black, 2);
cursor: pointer;
user-select: none;
padding: $margin-2;
display: flex;
display: -ms-flexbox;
@include vendor-prefix(flex-direction, row)
svg {
width: 14px;
height: 14px;
}
}
&-group-title {
vertical-align: middle;
}
&-group-content {
margin-left: $margin-3;
}
} }