All important stuff is in CSS now

This commit is contained in:
Lukas Martinelli
2017-01-11 11:35:33 +01:00
parent 9ef24428fe
commit b51354ae1d
22 changed files with 452 additions and 301 deletions

View File

@@ -30,10 +30,7 @@ export default class DocLabel extends React.Component {
onMouseOver={e => this.setState({showDoc: true})}
onMouseOut={e => this.setState({showDoc: false})}
className="maputnik-doc-target"
style={{
cursor: 'help',
...this.props.cursorTargetStyle,
}}
style={this.props.cursorTargetStyle}
>
{this.props.label}
</span>

View File

@@ -13,7 +13,6 @@ import FunctionIcon from 'react-icons/lib/md/functions'
import capitalize from 'lodash.capitalize'
import input from '../../config/input.js'
import colors from '../../config/colors.js'
import { margins, fontSizes } from '../../config/scales.js'
function isZoomField(value) {
return typeof value === 'object' && value.stops
@@ -22,7 +21,7 @@ function isZoomField(value) {
/** Supports displaying spec field for zoom function objects
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
*/
export default class ZoomSpecField extends React.Component {
export default class ZoomSpecProperty extends React.Component {
static propTypes = {
onChange: React.PropTypes.func.isRequired,
fieldName: React.PropTypes.string.isRequired,
@@ -85,114 +84,90 @@ export default class ZoomSpecField extends React.Component {
this.props.onChange(this.props.fieldName, changedValue)
}
render() {
if(isZoomField(this.props.value)) {
let label = <DocLabel
renderZoomProperty() {
const label = <div className="maputnik-zoom-spec-property-label">
<DocLabel
label={labelFromFieldName(this.props.fieldName)}
doc={this.props.fieldSpec.doc}
style={{
width: '50%',
}}
/>
</div>
const zoomFields = this.props.value.stops.map((stop, idx) => {
label = <DocLabel
doc={this.props.fieldSpec.doc}
style={{ width: '41%'}}
label={idx > 0 ? "" : labelFromFieldName(this.props.fieldName)}
/>
const zoomFields = this.props.value.stops.map((stop, idx) => {
const zoomLevel = stop[0]
const value = stop[1]
if(idx === 1) {
label = <label style={{...input.label, width: '41%'}}>
<Button
className="maputnik-add-stop"
style={{fontSize: fontSizes[5]}}
onClick={this.addStop.bind(this)}
>
Add stop
</Button>
</label>
}
return <div key={zoomLevel} className="maputnik-zoom-spec-property-stop-item">
{label}
<Button
className="maputnik-delete-stop"
onClick={this.deleteStop.bind(this, idx)}
>
<DocLabel
label={<DeleteIcon />}
doc={"Remove zoom level stop."}
/>
const zoomLevel = stop[0]
const value = stop[1]
return <div key={zoomLevel} style={{
...input.property,
marginLeft: 0,
marginRight: 0
}}>
{label}
<Button
className="maputnik-delete-stop"
style={{backgroundColor: null, verticalAlign: 'top'}}
onClick={this.deleteStop.bind(this, idx)}
>
<DeleteIcon />
</Button>
</Button>
<div className="maputnik-zoom-spec-property-stop-edit">
<NumberInput
style={{
width: '7.5%',
verticalAlign: 'top',
}}
value={zoomLevel}
onChange={changedStop => this.changeStop(idx, changedStop, value)}
min={0}
max={22}
/>
</div>
<div className="maputnik-zoom-spec-property-stop-value">
<SpecField
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={value}
onChange={(_, newValue) => this.changeStop(idx, zoomLevel, newValue)}
style={{
width: '41%',
marginLeft: '1.5%',
}}
/>
</div>
})
return <div style={input.property}>
{zoomFields}
</div>
} else {
})
if(this.props.fieldSpec['zoom-function']) {
return <div className="maputnik-zoom-spec-property">
{zoomFields}
<Button
className="maputnik-add-stop"
onClick={this.addStop.bind(this)}
>
Add stop
</Button>
</div>
}
}
return <div style={input.property}
className="maputnik-zoom-spec-field"
>
renderProperty() {
return <div className="maputnik-zoom-spec-property">
<DocLabel
label={labelFromFieldName(this.props.fieldName)}
doc={this.props.fieldSpec.doc}
style={{
width: this.props.fieldSpec['zoom-function'] ? '41%' : '50%',
}}
/>
{this.props.fieldSpec['zoom-function'] &&
<Button
className="maputnik-make-zoom-function"
onClick={this.makeZoomFunction.bind(this)}
>
<DocLabel
label={labelFromFieldName(this.props.fieldName)}
doc={this.props.fieldSpec.doc}
style={{
width: this.props.fieldSpec['zoom-function'] ? '41%' : '50%',
}}
label={<FunctionIcon />}
cursorTargetStyle={{ cursor: 'pointer' }}
doc={"Turn property into a zoom function to enable a map feature to change with map's zoom level."}
/>
{this.props.fieldSpec['zoom-function'] &&
<Button
className="maputnik-make-zoom-function"
style={{
verticalAlign: 'top',
backgroundColor: null,
display: 'inline-block',
paddingBottom: 0,
paddingTop: 0,
}}
onClick={this.makeZoomFunction.bind(this)}
>
<DocLabel
label={<FunctionIcon />}
cursorTargetStyle={{ cursor: 'pointer' }}
doc={"Turn property into a zoom function to enable a map feature to change with map's zoom level."}
/>
</Button>
}
<SpecField {...this.props} style={{ width: '50%' } }/>
</div>
</Button>
}
<SpecField {...this.props} style={{ width: '50%' } }/>
</div>
}
render() {
if(isZoomField(this.props.value)) {
return this.renderZoomProperty();
} else {
return this.renderProperty();
}
}
}

View File

@@ -1,8 +1,4 @@
import React from 'react'
import input from '../../config/input.js'
import colors from '../../config/colors.js'
import { margins, fontSizes } from '../../config/scales.js'
import { combiningFilterOps } from '../../libs/filterops.js'
import GlSpec from 'mapbox-gl-style-spec/reference/latest.js'
@@ -86,41 +82,28 @@ export default class CombiningFilterEditor extends React.Component {
//TODO: Implement support for nested filter
if(hasNestedCombiningFilter(filter)) {
return <div style={{
fontSize: fontSizes[5],
color: colors.midgray,
}}>
return <div className="maputnik-filter-editor-unsupported">
Nested filters are not supported.
</div>
}
return <div>
<div className="maputnik-filter-editor-compound-select" style={{ marginBottom: margins[1] }}>
return <div className="maputnik-filter-editor">
<div className="maputnik-filter-editor-compound-select">
<DocLabel
label={"Compound Filter"}
doc={GlSpec.layer.filter.doc + " Combine multiple filters together by using a compound filter."}
style={{
display: 'inline-block',
width: '49%',
}}
/>
<SelectInput
value={combiningOp}
onChange={this.onFilterPartChanged.bind(this, 0)}
options={[["all", "every filter matches"], ["none", "no filter matches"], ["any", "any filter matches"]]}
style={{
display: 'inline-block',
width: '50%',
}}
/>
</div>
{editorBlocks}
<div className="maputnik-filter-editor-add-wrapper" style={{marginTop: margins[1]}}>
<Button onClick={this.addFilterItem.bind(this)} style={{
display: 'inline-block',
marginLeft: '79%',
width: '20%',
}}>
<div className="maputnik-filter-editor-add-wrapper">
<Button
className="maputnik-add-filter"
onClick={this.addFilterItem.bind(this)}>
Add filter
</Button>
</div>

View File

@@ -10,15 +10,15 @@ class FilterEditorBlock extends React.Component {
render() {
return <div className="maputnik-filter-editor-block">
<div className="maputnik-filter-editor-block-action" style={{display: 'inline-block', width: '8%'}}>
<div className="maputnik-filter-editor-block-action">
<Button
style={{backgroundColor: null}}
className="maputnik-delete-filter"
onClick={this.props.onDelete}
>
<DeleteIcon />
</Button>
</div>
<div className="maputnik-filter-editor-block-content" style={{display: 'inline-block', width: '92%'}}>
<div className="maputnik-filter-editor-block-content">
{this.props.children}
</div>
</div>

View File

@@ -1,6 +1,5 @@
import React from 'react'
import { margins, fontSizes } from '../../config/scales.js'
import { otherFilterOps } from '../../libs/filterops.js'
import StringInput from '../inputs/StringInput'
import AutocompleteInput from '../inputs/AutocompleteInput'
@@ -11,7 +10,6 @@ class SingleFilterEditor extends React.Component {
filter: React.PropTypes.array.isRequired,
onChange: React.PropTypes.func.isRequired,
properties: React.PropTypes.object,
style: React.PropTypes.object,
}
static defaultProps = {
@@ -29,12 +27,7 @@ class SingleFilterEditor extends React.Component {
const propertyName = f[1]
const filterArgs = f.slice(2)
return <div className="maputnik-filter-editor-single"
style={{
marginTop: margins[1],
marginBottom: margins[1],
...this.props.style
}}>
return <div className="maputnik-filter-editor-single">
<div className="maputnik-filter-editor-property">
<AutocompleteInput
value={propertyName}

View File

@@ -1,7 +1,5 @@
import React from 'react'
import input from '../../config/input.js'
import colors from '../../config/colors'
import { margins } from '../../config/scales'
class CheckboxInput extends React.Component {
static propTypes = {
@@ -11,59 +9,16 @@ class CheckboxInput extends React.Component {
}
render() {
const styles = {
root: {
...input.base,
lineHeight: 0.7,
padding: 0,
position: 'relative',
textAlign: 'center ',
verticalAlign: 'middle',
cursor: 'pointer'
},
input: {
position: 'absolute',
zIndex: -1,
opacity: 0
},
box: {
display: 'inline-block',
textAlign: 'center ',
height: 15,
width: 15,
marginRight: margins[1],
marginBottom: null,
backgroundColor: colors.gray,
borderRadius: 2,
borderStyle: 'solid',
borderWidth: 2,
borderColor: colors.gray,
transition: 'background-color .1s ease-out'
},
icon: {
display: this.props.value ? null : 'none',
width: '75%',
height: '75%',
marginTop: 1,
fill: colors.lowgray
}
}
return <label style={styles.root}>
return <label className="maputnik-checkbox-wrapper">
<input
className="maputnik-checkbox"
type="checkbox"
style={{
...styles.input,
...this.props.style,
}}
style={this.props.style}
onChange={e => this.props.onChange(!this.props.value)}
checked={this.props.value}
/>
<div style={styles.box}>
<svg
viewBox='0 0 32 32'
style={styles.icon}>
<div className="maputnik-checkbox-box">
<svg className="maputnik-checkbox-icon" viewBox='0 0 32 32'>
<path d='M1 14 L5 10 L13 18 L27 4 L31 8 L13 26 z' />
</svg>
</div>

View File

@@ -1,7 +1,6 @@
import React from 'react'
import input from '../../config/input'
import DocLabel from '../fields/DocLabel'
import { margins } from '../../config/scales'
/** Wrap a component with a label */
class InputBlock extends React.Component {
@@ -29,9 +28,7 @@ class InputBlock extends React.Component {
}
render() {
return <div style={{
...this.props.style,
}}
return <div style={this.props.style}
className="maputnik-input-block"
>
{this.props.doc &&
@@ -44,11 +41,7 @@ class InputBlock extends React.Component {
/>
}
{!this.props.doc &&
<label
style={{
...input.label,
width: '50%',
}}>
<label className="maputnik-input-block-label">
{this.props.label}
</label>
}

View File

@@ -18,10 +18,7 @@ class SelectInput extends React.Component {
return <select
className="maputnik-select"
style={{
...input.select,
...this.props.style
}}
style={this.props.style}
value={this.props.value}
onChange={e => this.props.onChange(e.target.value)}
>

View File

@@ -12,11 +12,8 @@ import LayerSourceLayerBlock from './LayerSourceLayerBlock'
import InputBlock from '../inputs/InputBlock'
import MultiButtonInput from '../inputs/MultiButtonInput'
import input from '../../config/input.js'
import { changeType, changeProperty } from '../../libs/layer'
import layout from '../../config/layout.json'
import { margins, fontSizes } from '../../config/scales'
import colors from '../../config/colors'
class UnsupportedLayer extends React.Component {
render() {
@@ -90,8 +87,8 @@ export default class LayerEditor extends React.Component {
getChildContext () {
return {
reactIconBase: {
size: fontSizes[4],
color: colors.lowgray,
size: 14,
color: '#8e8e8e',
}
}
}
@@ -135,7 +132,7 @@ export default class LayerEditor extends React.Component {
}
</div>
case 'filter': return <div>
<div style={input.property}>
<div className="maputnik-filter-editor-wrapper">
<FilterEditor
filter={this.props.layer.filter}
properties={this.props.vectorLayers[this.props.layer['source-layer']]}

View File

@@ -1,7 +1,4 @@
import React from 'react'
import Color from 'color'
import colors from '../../config/colors'
import { margins, fontSizes } from '../../config/scales'
import Collapse from 'react-collapse'
import CollapseOpenIcon from 'react-icons/lib/md/arrow-drop-down'

View File

@@ -2,19 +2,7 @@ import React from 'react'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import LayerIcon from '../icons/LayerIcon'
import input from '../../config/input'
import colors from '../../config/colors'
import { margins, fontSizes } from '../../config/scales'
const Panel = (props) => {
return <div style={{
backgroundColor: colors.gray,
padding: margins[0],
fontSize: fontSizes[5],
lineHeight: 1.2,
}}>{props.children}</div>
}
function groupFeaturesBySourceLayer(features) {
const sources = {}
@@ -33,26 +21,23 @@ class FeatureLayerPopup extends React.Component {
const layers = sources[vectorLayerId].map((feature, idx) => {
return <label
key={idx}
style={{
...input.label,
display: 'block',
width: 'auto',
}}>
className="maputnik-popup-layer"
>
<LayerIcon type={feature.layer.type} style={{
width: fontSizes[4],
height: fontSizes[4],
paddingRight: margins[0],
width: 14,
height: 14,
paddingRight: 3
}}/>
{feature.layer.id}
</label>
})
return <div key={vectorLayerId}>
<Panel>{vectorLayerId}</Panel>
<div className="maputnik-popup-layer-id">{vectorLayerId}</div>
{layers}
</div>
})
return <div>
return <div className="maputnik-feature-layer-popup">
{items}
</div>
}

View File

@@ -2,9 +2,6 @@ import React from 'react'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import colors from '../../config/colors'
import { margins, fontSizes } from '../../config/scales'
function displayValue(value) {
if (typeof value === 'undefined' || value === null) return value;
if (value instanceof Date) return value.toLocaleString();
@@ -17,24 +14,15 @@ function displayValue(value) {
function renderProperties(feature) {
return Object.keys(feature.properties).map(propertyName => {
const property = feature.properties[propertyName]
return <InputBlock key={propertyName} label={propertyName} style={{marginTop: 0, marginBottom: 0}}>
return <InputBlock key={propertyName} label={propertyName}>
<StringInput value={displayValue(property)} style={{backgroundColor: 'transparent'}}/>
</InputBlock>
})
}
const Panel = (props) => {
return <div style={{
backgroundColor: colors.gray,
padding: margins[0],
fontSize: fontSizes[5],
lineHeight: 1.2,
}}>{props.children}</div>
}
function renderFeature(feature) {
return <div key={feature.id}>
<Panel>{feature.layer['source-layer']}</Panel>
<div className="maputnik-popup-layer-id">{feature.layer['source-layer']}</div>
{renderProperties(feature)}
</div>
}
@@ -43,7 +31,7 @@ class FeaturePropertyPopup extends React.Component {
render() {
const features = this.props.features
return <div>
return <div className="maputnik-feature-property-popup">
{features.map(renderFeature)}
</div>
}

View File

@@ -78,6 +78,7 @@ class AddModal extends React.Component {
onOpenToggle={this.props.onOpenToggle}
title={'Add Layer'}
>
<div className="maputnik-add-layer">
<LayerIdBlock
value={this.state.id}
onChange={v => this.setState({ id: v })}
@@ -103,6 +104,7 @@ class AddModal extends React.Component {
<Button className="maputnik-add-layer-button" onClick={this.addLayer.bind(this)}>
Add Layer
</Button>
</div>
</Modal>
}
}

View File

@@ -5,7 +5,6 @@ import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import SelectInput from '../inputs/SelectInput'
import Modal from './Modal'
import colors from '../../config/colors'
class SettingsModal extends React.Component {
static propTypes = {

View File

@@ -1,7 +1,6 @@
import React from 'react'
import GlSpec from 'mapbox-gl-style-spec/reference/latest.js'
import Modal from './Modal'
import Heading from '../Heading'
import Button from '../Button'
import Paragraph from '../Paragraph'
import InputBlock from '../inputs/InputBlock'
@@ -12,8 +11,6 @@ import SourceTypeEditor from '../sources/SourceTypeEditor'
import style from '../../libs/style'
import { deleteSource, addSource, changeSource } from '../../libs/source'
import publicSources from '../../config/tilesets.json'
import colors from '../../config/colors'
import { margins, fontSizes } from '../../config/scales'
import AddIcon from 'react-icons/lib/md/add-circle-outline'
import DeleteIcon from 'react-icons/lib/md/delete'
@@ -27,33 +24,18 @@ class PublicSource extends React.Component {
}
render() {
return <div className="maputnik-public-source" style={{
verticalAlign: 'top',
marginTop: margins[2],
marginRight: margins[2],
backgroundColor: colors.gray,
display: 'inline-block',
width: 240,
fontSize: fontSizes[4],
color: colors.lowgray,
}}>
<Button
onClick={() => this.props.onSelect(this.props.id)}
style={{
backgroundColor: 'transparent',
padding: margins[2],
display: 'flex',
flexDirection: 'row',
}}
>
<div>
<span style={{fontWeight: 700}}>{this.props.title}</span>
<br/>
<span style={{fontSize: fontSizes[5]}}>#{this.props.id}</span>
</div>
<span style={{flexGrow: 1}} />
<AddIcon />
</Button>
return <div className="maputnik-public-source">
<Button
className="maputnik-public-source-select"
onClick={() => this.props.onSelect(this.props.id)}
>
<div className="maputnik-public-source-info">
<p className="maputnik-public-source-name">{this.props.title}</p>
<p className="maputnik-public-source-id">#{this.props.id}</p>
</div>
<span className="maputnik-space" />
<AddIcon />
</Button>
</div>
}
}
@@ -81,32 +63,19 @@ class ActiveSourceTypeEditor extends React.Component {
render() {
const inputProps = { }
return <div style={{
}}>
<div className="maputnik-active-source-type-editor"
style={{
backgroundColor: colors.gray,
color: colors.lowgray,
padding: margins[1],
display: 'flex',
fontSize: fontSizes[4],
flexDirection: 'row',
}}>
<span style={{fontWeight: 700, fontSize: fontSizes[4], lineHeight: 2}}>#{this.props.sourceId}</span>
<span style={{flexGrow: 1}} />
return <div className="maputnik-active-source-type-editor">
<div className="maputnik-active-source-type-editor-header">
<span className="maputnik-active-source-type-editor-header-id">#{this.props.sourceId}</span>
<span className="maputnik-space" />
<Button
className="maputnik-active-source-type-editor-header-delete"
onClick={()=> this.props.onDelete(this.props.sourceId)}
style={{backgroundColor: 'transparent'}}
>
<DeleteIcon />
</Button>
</div>
<div style={{
borderColor: colors.gray,
borderWidth: 2,
borderStyle: 'solid',
padding: margins[1],
}}>
<div className="maputnik-active-source-type-editor-content">
<SourceTypeEditor
onChange={this.props.onChange}
mode={editorMode(this.props.source)}
@@ -163,7 +132,7 @@ class AddSource extends React.Component {
}
render() {
return <div>
return <div className="maputnik-add-source">
<InputBlock label={"Source ID"} doc={"Unique ID that identifies the source and is used in the layer to reference the source."}>
<StringInput
value={this.state.sourceId}
@@ -188,7 +157,9 @@ class AddSource extends React.Component {
mode={this.state.mode}
source={this.state.source}
/>
<Button onClick={() => this.props.onAdd(this.state.sourceId, this.state.source)}>
<Button
className="maputnik-add-source-button"
onClick={() => this.props.onAdd(this.state.sourceId, this.state.source)}>
Add Source
</Button>
</div>
@@ -239,21 +210,25 @@ class SourcesModal extends React.Component {
onOpenToggle={this.props.onOpenToggle}
title={'Sources'}
>
<Heading level={4}>Active Sources</Heading>
<div className="maputnik-modal-section">
<h4>Active Sources</h4>
{activeSources}
<Heading level={4}>Add New Source</Heading>
<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>
<AddSource
onAdd={(sourceId, source) => this.props.onStyleChanged(addSource(mapStyle, sourceId, source))}
/>
</div>
<div className="maputnik-modal-section">
<h4>Add New Source</h4>
<p>Add a new source to your style. You can only choose the source type and id at creation time!</p>
<AddSource
onAdd={(sourceId, source) => this.props.onStyleChanged(addSource(mapStyle, sourceId, source))}
/>
</div>
<Heading level={4}>Choose Public Source</Heading>
<Paragraph>
<div className="maputnik-modal-section">
<h4>Choose Public Source</h4>
<p>
Add one of the publicly availble sources to your style.
</Paragraph>
</p>
</div>
<div style={{maxwidth: 500}}>
{tilesetOptions}
</div>