2016-12-21 16:11:08 +01:00
|
|
|
import React from 'react'
|
|
|
|
import Modal from './Modal'
|
|
|
|
import Heading from '../Heading'
|
2016-12-21 19:59:37 +01:00
|
|
|
import Button from '../Button'
|
2016-12-22 11:27:53 +01:00
|
|
|
import Paragraph from '../Paragraph'
|
2016-12-21 16:11:08 +01:00
|
|
|
import InputBlock from '../inputs/InputBlock'
|
|
|
|
import StringInput from '../inputs/StringInput'
|
2016-12-21 17:21:04 +01:00
|
|
|
import SelectInput from '../inputs/SelectInput'
|
2016-12-21 17:13:21 +01:00
|
|
|
import SourceTypeEditor from '../sources/SourceTypeEditor'
|
|
|
|
|
2016-12-22 18:08:42 +01:00
|
|
|
import style from '../../libs/style'
|
2016-12-21 16:11:08 +01:00
|
|
|
import publicSources from '../../config/tilesets.json'
|
|
|
|
import colors from '../../config/colors'
|
2016-12-21 16:50:34 +01:00
|
|
|
import { margins, fontSizes } from '../../config/scales'
|
|
|
|
|
|
|
|
import AddIcon from 'react-icons/lib/md/add-circle-outline'
|
2016-12-21 19:59:37 +01:00
|
|
|
import DeleteIcon from 'react-icons/lib/md/delete'
|
2016-12-21 16:11:08 +01:00
|
|
|
|
|
|
|
class PublicSource extends React.Component {
|
|
|
|
static propTypes = {
|
|
|
|
id: React.PropTypes.string.isRequired,
|
|
|
|
type: React.PropTypes.string.isRequired,
|
|
|
|
title: React.PropTypes.string.isRequired,
|
|
|
|
onSelect: React.PropTypes.func.isRequired,
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return <div style={{
|
|
|
|
verticalAlign: 'top',
|
|
|
|
marginTop: margins[2],
|
|
|
|
marginRight: margins[2],
|
2016-12-21 16:50:34 +01:00
|
|
|
backgroundColor: colors.gray,
|
2016-12-21 16:11:08 +01:00
|
|
|
display: 'inline-block',
|
|
|
|
width: 240,
|
2016-12-21 16:50:34 +01:00
|
|
|
fontSize: fontSizes[4],
|
|
|
|
color: colors.lowgray,
|
2016-12-21 16:11:08 +01:00
|
|
|
}}>
|
2016-12-22 18:08:42 +01:00
|
|
|
<Button
|
|
|
|
onClick={() => this.props.onSelect(this.props.id)}
|
|
|
|
style={{
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
padding: margins[2],
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
}}
|
|
|
|
>
|
2016-12-21 16:50:34 +01:00
|
|
|
<div>
|
2016-12-21 19:59:37 +01:00
|
|
|
<span style={{fontWeight: 700}}>{this.props.title}</span>
|
|
|
|
<br/>
|
2016-12-21 17:13:21 +01:00
|
|
|
<span style={{fontSize: fontSizes[5]}}>#{this.props.id}</span>
|
2016-12-21 16:50:34 +01:00
|
|
|
</div>
|
2016-12-21 16:11:08 +01:00
|
|
|
<span style={{flexGrow: 1}} />
|
2016-12-21 19:59:37 +01:00
|
|
|
<AddIcon />
|
|
|
|
</Button>
|
2016-12-21 16:11:08 +01:00
|
|
|
</div>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-21 19:59:37 +01:00
|
|
|
function editorMode(source) {
|
|
|
|
if(source.type === 'geojson') return ' geojson'
|
|
|
|
if(source.type === 'vector' && source.tiles) {
|
|
|
|
return 'tilexyz'
|
|
|
|
}
|
|
|
|
return 'tilejson'
|
|
|
|
}
|
|
|
|
|
2016-12-28 15:20:07 +01:00
|
|
|
class ActiveSourceTypeEditor extends React.Component {
|
2016-12-21 16:11:08 +01:00
|
|
|
static propTypes = {
|
|
|
|
sourceId: React.PropTypes.string.isRequired,
|
|
|
|
source: React.PropTypes.object.isRequired,
|
2016-12-21 19:59:37 +01:00
|
|
|
onSourceDelete: React.PropTypes.func.isRequired,
|
|
|
|
onSourceChange: React.PropTypes.func.isRequired,
|
2016-12-21 16:11:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2016-12-21 16:50:34 +01:00
|
|
|
const inputProps = { }
|
2016-12-21 16:11:08 +01:00
|
|
|
return <div style={{
|
|
|
|
}}>
|
2016-12-21 17:13:21 +01:00
|
|
|
<div style={{
|
|
|
|
backgroundColor: colors.gray,
|
|
|
|
color: colors.lowgray,
|
|
|
|
padding: margins[1],
|
|
|
|
display: 'flex',
|
|
|
|
fontSize: fontSizes[4],
|
|
|
|
flexDirection: 'row',
|
|
|
|
}}>
|
2016-12-21 19:59:37 +01:00
|
|
|
<span style={{fontWeight: 700, fontSize: fontSizes[4], lineHeight: 2}}>#{this.props.sourceId}</span>
|
2016-12-21 17:13:21 +01:00
|
|
|
<span style={{flexGrow: 1}} />
|
2016-12-21 19:59:37 +01:00
|
|
|
<Button
|
2016-12-28 15:20:07 +01:00
|
|
|
onClick={()=> this.props.onSourceDelete(this.props.sourceId)}
|
2016-12-21 19:59:37 +01:00
|
|
|
style={{backgroundColor: 'transparent'}}
|
|
|
|
>
|
|
|
|
<DeleteIcon />
|
|
|
|
</Button>
|
2016-12-21 17:13:21 +01:00
|
|
|
</div>
|
|
|
|
<div style={{
|
|
|
|
borderColor: colors.gray,
|
|
|
|
borderWidth: 2,
|
|
|
|
borderStyle: 'solid',
|
|
|
|
padding: margins[1],
|
|
|
|
}}>
|
2016-12-21 19:59:37 +01:00
|
|
|
<SourceTypeEditor
|
|
|
|
onChange={this.props.onSourceChange}
|
|
|
|
mode={editorMode(this.props.source)}
|
|
|
|
source={this.props.source}
|
|
|
|
/>
|
2016-12-21 17:13:21 +01:00
|
|
|
</div>
|
2016-12-21 16:11:08 +01:00
|
|
|
</div>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-21 17:21:04 +01:00
|
|
|
class AddSource extends React.Component {
|
|
|
|
static propTypes = {
|
2016-12-21 19:59:37 +01:00
|
|
|
onSourceAdd: React.PropTypes.func.isRequired,
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
|
|
|
this.state = {
|
|
|
|
mode: 'tilejson',
|
2016-12-22 18:08:42 +01:00
|
|
|
source: {
|
|
|
|
id: style.generateId(),
|
|
|
|
}
|
2016-12-21 19:59:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-22 18:08:42 +01:00
|
|
|
onSourceIdChange(newId) {
|
|
|
|
this.setState({
|
|
|
|
source: {
|
|
|
|
...this.state.source,
|
|
|
|
id: newId,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-21 19:59:37 +01:00
|
|
|
onSourceChange(source) {
|
|
|
|
this.setState({
|
|
|
|
source: source
|
|
|
|
})
|
2016-12-21 17:21:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return <div>
|
|
|
|
<InputBlock label={"Source ID"}>
|
|
|
|
<StringInput
|
2016-12-22 18:08:42 +01:00
|
|
|
value={this.state.source.id}
|
|
|
|
onChange={this.onSourceIdChange.bind(this)}
|
2016-12-21 17:21:04 +01:00
|
|
|
/>
|
|
|
|
</InputBlock>
|
|
|
|
<InputBlock label={"Source Type"}>
|
|
|
|
<SelectInput
|
|
|
|
options={[
|
|
|
|
['geojson', 'GeoJSON'],
|
|
|
|
['tilejson', 'Vector (TileJSON URL)'],
|
2016-12-21 19:59:37 +01:00
|
|
|
['tilexyz', 'Vector (XYZ URLs)'],
|
2016-12-21 17:21:04 +01:00
|
|
|
]}
|
2016-12-21 19:59:37 +01:00
|
|
|
onChange={v => this.setState({mode: v})}
|
|
|
|
value={this.state.mode}
|
2016-12-21 17:21:04 +01:00
|
|
|
/>
|
|
|
|
</InputBlock>
|
2016-12-21 19:59:37 +01:00
|
|
|
<SourceTypeEditor
|
|
|
|
onChange={this.onSourceChange.bind(this)}
|
|
|
|
mode={this.state.mode}
|
|
|
|
source={this.state.source}
|
|
|
|
/>
|
2016-12-22 18:08:42 +01:00
|
|
|
<Button onClick={() => this.onSourceAdd(this.state.source)}>
|
2016-12-21 17:21:04 +01:00
|
|
|
Add Source
|
2016-12-21 19:59:37 +01:00
|
|
|
</Button>
|
2016-12-21 17:21:04 +01:00
|
|
|
</div>
|
|
|
|
}
|
|
|
|
}
|
2016-12-21 16:11:08 +01:00
|
|
|
|
|
|
|
class SourcesModal extends React.Component {
|
|
|
|
static propTypes = {
|
|
|
|
mapStyle: React.PropTypes.object.isRequired,
|
|
|
|
isOpen: React.PropTypes.bool.isRequired,
|
2016-12-22 16:35:31 +01:00
|
|
|
onOpenToggle: React.PropTypes.func.isRequired,
|
2016-12-22 18:08:42 +01:00
|
|
|
onStyleChanged: React.PropTypes.func.isRequired,
|
|
|
|
}
|
|
|
|
|
|
|
|
onSourceAdd(source) {
|
|
|
|
const changedSources = {
|
|
|
|
...this.props.mapStyle.sources,
|
|
|
|
[source.id]: source
|
|
|
|
}
|
|
|
|
|
|
|
|
const changedStyle = {
|
|
|
|
...this.props.mapStyle,
|
|
|
|
sources: changedSources
|
|
|
|
}
|
|
|
|
|
|
|
|
this.props.onStyleChanged(changedStyle)
|
2016-12-21 16:11:08 +01:00
|
|
|
}
|
|
|
|
|
2016-12-28 15:20:07 +01:00
|
|
|
deleteSource(sourceId) {
|
|
|
|
const remainingSources = { ...this.props.mapStyle.sources}
|
|
|
|
delete remainingSources[sourceId]
|
|
|
|
|
|
|
|
const changedStyle = {
|
|
|
|
...this.props.mapStyle,
|
|
|
|
sources: remainingSources
|
|
|
|
}
|
|
|
|
this.props.onStyleChanged(changedStyle)
|
|
|
|
}
|
|
|
|
|
2016-12-21 16:11:08 +01:00
|
|
|
render() {
|
|
|
|
const activeSources = Object.keys(this.props.mapStyle.sources).map(sourceId => {
|
|
|
|
const source = this.props.mapStyle.sources[sourceId]
|
2016-12-28 15:20:07 +01:00
|
|
|
return <ActiveSourceTypeEditor
|
2016-12-22 21:06:32 +01:00
|
|
|
key={sourceId}
|
|
|
|
sourceId={sourceId}
|
|
|
|
source={source}
|
2016-12-28 15:20:07 +01:00
|
|
|
onSourceDelete={this.deleteSource.bind(this)}
|
2016-12-22 21:06:32 +01:00
|
|
|
/>
|
2016-12-21 16:11:08 +01:00
|
|
|
})
|
|
|
|
|
2016-12-22 18:08:42 +01:00
|
|
|
const tilesetOptions = publicSources.filter(source => !(source.id in this.props.mapStyle.sources)).map(source => {
|
2016-12-21 16:11:08 +01:00
|
|
|
return <PublicSource
|
2016-12-22 18:08:42 +01:00
|
|
|
key={source.id}
|
|
|
|
id={source.id}
|
|
|
|
type={source.type}
|
|
|
|
title={source.title}
|
|
|
|
description={source.description}
|
|
|
|
onSelect={() => this.onSourceAdd(source)}
|
2016-12-21 16:11:08 +01:00
|
|
|
/>
|
|
|
|
})
|
|
|
|
|
2016-12-21 16:50:34 +01:00
|
|
|
const inputProps = { }
|
2016-12-21 16:11:08 +01:00
|
|
|
return <Modal
|
|
|
|
isOpen={this.props.isOpen}
|
2016-12-22 16:35:31 +01:00
|
|
|
onOpenToggle={this.props.onOpenToggle}
|
2016-12-21 16:11:08 +01:00
|
|
|
title={'Sources'}
|
|
|
|
>
|
|
|
|
<Heading level={4}>Active Sources</Heading>
|
|
|
|
{activeSources}
|
|
|
|
|
|
|
|
<Heading level={4}>Add New Source</Heading>
|
2016-12-21 19:59:37 +01:00
|
|
|
<div style={{maxWidth: 300}}>
|
|
|
|
<p style={{color: colors.lowgray, fontSize: fontSizes[5]}}>Add a new source to your style. You can only choose the source type and id at creation time!</p>
|
2016-12-22 18:08:42 +01:00
|
|
|
<AddSource onSourceAdd={this.onSourceAdd.bind(this)} />
|
2016-12-21 19:59:37 +01:00
|
|
|
</div>
|
2016-12-21 17:21:04 +01:00
|
|
|
|
2016-12-21 16:11:08 +01:00
|
|
|
<Heading level={4}>Choose Public Source</Heading>
|
2016-12-22 11:27:53 +01:00
|
|
|
<Paragraph>
|
|
|
|
Add one of the publicly availble sources to your style.
|
|
|
|
</Paragraph>
|
2016-12-21 16:11:08 +01:00
|
|
|
<div style={{maxwidth: 500}}>
|
|
|
|
{tilesetOptions}
|
|
|
|
</div>
|
|
|
|
</Modal>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default SourcesModal
|