Compare commits

..

28 Commits

Author SHA1 Message Date
Lukas Martinelli
5c286f8d96 Remove static fontstacks.json 2017-01-25 13:47:37 +01:00
Lukas Martinelli
404b53587f Special fontstacks.json handling for Tileserver GL 2017-01-25 13:46:46 +01:00
Lukas Martinelli
e5fbe3b74a Collapse layer groups by default #66 2017-01-25 13:34:10 +01:00
Lukas Martinelli
3f262885ca Highlight selected layer more #62 2017-01-25 13:23:54 +01:00
Lukas Martinelli
c837179f71 Clean up layer.scss 2017-01-25 13:23:29 +01:00
Lukas Martinelli
9a947658e2 Improve default property styling #92 2017-01-25 12:54:33 +01:00
Lukas Martinelli
2458d4b637 Show inspect tooltip only on click in map #90 2017-01-22 21:16:11 +01:00
Lukas Martinelli
e4850805fb Fix default tileset of OpenMapTiles #88 2017-01-18 13:06:24 +01:00
Lukas Martinelli
3a15a3bb06 Show type of feature in popup 2017-01-18 10:03:15 +01:00
Lukas Martinelli
75ca1fa930 Deal with no metadata in style 2017-01-16 20:07:21 +01:00
Lukas Martinelli
377840ca24 Fix lint issues in _modal.scss 2017-01-16 16:34:55 +01:00
Lukas Martinelli
48e9589b58 Merge pull request #86 from klokantech/gist-preview
Gist preview & access token
2017-01-16 15:48:12 +01:00
Lukas Martinelli
11e9cef834 Improve styles and text 2017-01-16 15:43:52 +01:00
jirik
7e3aa09d3e Proview & Access Token logic when saving to Gist 2017-01-16 15:13:19 +01:00
jirik
e3b7e002b4 Hypertext links are white instead of blue 2017-01-16 15:13:11 +01:00
jirik
3b7fb7ae75 Fix checkbox not showing status 2017-01-16 15:13:02 +01:00
jirik
fab004cdfe StringInput fires change if state and props values do not match
Now it is also possible to call onChange listener if new value is empty string
2017-01-16 15:12:03 +01:00
Lukas Martinelli
07523c00f0 Point styles to master not gh-pages 2017-01-16 11:08:18 +01:00
Lukas Martinelli
c15ac14f88 Bump version to v1.0.1 2017-01-16 10:14:59 +01:00
Lukas Martinelli
8f6006c19f Less opacity for default values #73 2017-01-15 17:10:38 +01:00
Lukas Martinelli
16bedcf5b1 Add minzoom and maxzoom block #77 2017-01-15 13:46:55 +01:00
Lukas Martinelli
05349d8ffe Convert filter value to number if possible #63 2017-01-15 13:39:40 +01:00
Lukas Martinelli
a1e1895651 Deal specially with has operator #84 2017-01-15 10:42:59 +01:00
Lukas Martinelli
a111599850 Save chang event on XYZ editor #85 2017-01-15 10:36:57 +01:00
Lukas Martinelli
121a95cee8 Move my key message up 2017-01-14 15:09:27 +01:00
Lukas Martinelli
decd1f3ea2 Add tilezen style 2017-01-14 14:45:04 +01:00
Lukas Martinelli
c632718324 Remove id from empty style to generate one 2017-01-14 14:41:13 +01:00
Lukas Martinelli
9509b59696 Add open Mapbox styles to gallery 2017-01-14 14:00:32 +01:00
29 changed files with 319 additions and 91 deletions

View File

@@ -8,6 +8,8 @@ targeted at developers and map designers.
- :link: Design your maps online at **http://maputnik.com/editor/** (all in local storage)
- :link: Use the [Maputnik CLI](https://github.com/maputnik/editor/wiki/Maputnik-CLI) for local style development
Mapbox has built one of the best and most amazing OSS ecosystems. A key component to ensure its longevity and independance is an OSS map designer.
## Documentation
The documentation can be found in the [Wiki](https://github.com/maputnik/editor/wiki). You are welcome to collaborate!
@@ -17,8 +19,6 @@ The documentation can be found in the [Wiki](https://github.com/maputnik/editor/
[![Design Map from Scratch](https://j.gifs.com/g5XMgl.gif)](https://youtu.be/XoDh0gEnBQo)
Mapbox has built one of the best and most amazing OSS ecosystems. A key component to ensure its longevity and independance is an OSS map designer.
## Develop
Maputnik is written in ES6 and is using [React](https://github.com/facebook/react) and [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).

View File

@@ -1,6 +1,6 @@
{
"name": "maputnik",
"version": "1.0.0",
"version": "1.0.1",
"description": "A MapboxGL visual style editor",
"main": "''",
"scripts": {
@@ -30,12 +30,11 @@
"lodash.isequal": "^4.4.0",
"lodash.throttle": "^4.1.1",
"mapbox-gl": "^0.31.0",
"mapbox-gl-inspect": "^1.2.0",
"mapbox-gl-inspect": "^1.2.1",
"mapbox-gl-style-spec": "^8.11.0",
"mousetrap": "^1.6.0",
"ol-mapbox-style": "1.0.1",
"openlayers": "^3.19.1",
"randomcolor": "^0.4.4",
"react": "^15.4.0",
"react-addons-pure-render-mixin": "^15.4.0",
"react-autocomplete": "^1.4.0",

View File

@@ -91,6 +91,7 @@ export default class Toolbar extends React.Component {
/>
<ExportModal
mapStyle={this.props.mapStyle}
onStyleChanged={this.props.onStyleChanged}
isOpen={this.state.isOpen.export}
onOpenToggle={this.toggleModal.bind(this, 'export')}
/>

View File

@@ -132,7 +132,6 @@ export default class ZoomSpecProperty extends React.Component {
if(this.props.fieldSpec['zoom-function']) {
zoomBtn = <MakeZoomFunctionButton onClick={this.makeZoomFunction.bind(this)} />
}
return <InputBlock
doc={this.props.fieldSpec.doc}
label={labelFromFieldName(this.props.fieldName)}
@@ -143,11 +142,10 @@ export default class ZoomSpecProperty extends React.Component {
}
render() {
if(isZoomField(this.props.value)) {
return this.renderZoomProperty();
} else {
return this.renderProperty();
}
const propClass = this.props.fieldSpec.default === this.props.value ? "maputnik-default-property" : "maputnik-modified-property"
return <div className={propClass}>
{isZoomField(this.props.value) ? this.renderZoomProperty() : this.renderProperty()}
</div>
}
}

View File

@@ -5,6 +5,12 @@ import StringInput from '../inputs/StringInput'
import AutocompleteInput from '../inputs/AutocompleteInput'
import SelectInput from '../inputs/SelectInput'
function tryParseInt(v) {
if (v === '') return v
if (isNaN(v)) return v
return parseFloat(v)
}
class SingleFilterEditor extends React.Component {
static propTypes = {
filter: React.PropTypes.array.isRequired,
@@ -17,7 +23,12 @@ class SingleFilterEditor extends React.Component {
}
onFilterPartChanged(filterOp, propertyName, filterArgs) {
const newFilter = [filterOp, propertyName, ...filterArgs]
let newFilter = [filterOp, propertyName, ...filterArgs.map(tryParseInt)]
if(filterOp === 'has' || filterOp === '!has') {
newFilter = [filterOp, propertyName]
} else if(filterArgs.length === 0) {
newFilter = [filterOp, propertyName, '']
}
this.props.onChange(newFilter)
}
@@ -42,12 +53,14 @@ class SingleFilterEditor extends React.Component {
options={otherFilterOps}
/>
</div>
{filterArgs.length > 0 &&
<div className="maputnik-filter-editor-args">
<StringInput
value={filterArgs.join(',')}
onChange={ v=> this.onFilterPartChanged(filterOp, propertyName, v.split(','))}
/>
</div>
}
</div>
}

View File

@@ -17,7 +17,9 @@ class CheckboxInput extends React.Component {
checked={this.props.value}
/>
<div className="maputnik-checkbox-box">
<svg className="maputnik-checkbox-icon" viewBox='0 0 32 32'>
<svg style={{
display: this.props.value ? 'inline' : 'none'
}} 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,9 +1,6 @@
import React from 'react'
import AutocompleteInput from './AutocompleteInput'
//TODO: Query available font stack dynamically
import fontStacks from '../../config/fontstacks.json'
class FontInput extends React.Component {
static propTypes = {
value: React.PropTypes.array.isRequired,

View File

@@ -27,7 +27,7 @@ class StringInput extends React.Component {
placeholder={this.props.default}
onChange={e => this.setState({ value: e.target.value })}
onBlur={() => {
if(this.state.value) this.props.onChange(this.state.value)
if(this.state.value!==this.props.value) this.props.onChange(this.state.value)
}}
/>
}

View File

@@ -6,6 +6,8 @@ import PropertyGroup from '../fields/PropertyGroup'
import LayerEditorGroup from './LayerEditorGroup'
import LayerTypeBlock from './LayerTypeBlock'
import LayerIdBlock from './LayerIdBlock'
import MinZoomBlock from './MinZoomBlock'
import MaxZoomBlock from './MaxZoomBlock'
import LayerSourceBlock from './LayerSourceBlock'
import LayerSourceLayerBlock from './LayerSourceLayerBlock'
@@ -130,6 +132,14 @@ export default class LayerEditor extends React.Component {
onChange={v => this.changeProperty(null, 'source-layer', v)}
/>
}
<MinZoomBlock
value={this.props.layer.minzoom}
onChange={v => this.changeProperty(null, 'minzoom', v)}
/>
<MaxZoomBlock
value={this.props.layer.maxzoom}
onChange={v => this.changeProperty(null, 'maxzoom', v)}
/>
</div>
case 'filter': return <div>
<div className="maputnik-filter-editor-wrapper">

View File

@@ -115,7 +115,7 @@ class LayerListContainer extends React.Component {
if(lookupKey in this.state.collapsedGroups) {
newGroups[lookupKey] = !this.state.collapsedGroups[lookupKey]
} else {
newGroups[lookupKey] = true
newGroups[lookupKey] = false
}
this.setState({
collapsedGroups: newGroups
@@ -124,7 +124,7 @@ class LayerListContainer extends React.Component {
isCollapsed(groupPrefix, idx) {
const collapsed = this.state.collapsedGroups[[groupPrefix, idx].join('-')]
return collapsed === undefined ? false : collapsed
return collapsed === undefined ? true : collapsed
}
render() {
@@ -147,7 +147,7 @@ class LayerListContainer extends React.Component {
const groupIdx = findClosestCommonPrefix(this.props.layers, idx)
const listItem = <LayerListItem
className={classnames({
'maputnik-layer-list-item-collapsed': this.isCollapsed(groupPrefix, groupIdx),
'maputnik-layer-list-item-collapsed': layers.length > 1 && this.isCollapsed(groupPrefix, groupIdx),
'maputnik-layer-list-item-group-last': idxInGroup == layers.length - 1 && layers.length > 1
})}
index={idx}

View File

@@ -0,0 +1,26 @@
import React from 'react'
import GlSpec from 'mapbox-gl-style-spec/reference/latest.js'
import InputBlock from '../inputs/InputBlock'
import NumberInput from '../inputs/NumberInput'
class MaxZoomBlock extends React.Component {
static propTypes = {
value: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired,
}
render() {
return <InputBlock label={"Max Zoom"} doc={GlSpec.layer.maxzoom.doc}>
<NumberInput
value={this.props.value}
onChange={this.props.onChange}
min={GlSpec.layer.maxzoom.minimum}
max={GlSpec.layer.maxzoom.maximum}
default={GlSpec.layer.maxzoom.maximum}
/>
</InputBlock>
}
}
export default MaxZoomBlock

View File

@@ -0,0 +1,26 @@
import React from 'react'
import GlSpec from 'mapbox-gl-style-spec/reference/latest.js'
import InputBlock from '../inputs/InputBlock'
import NumberInput from '../inputs/NumberInput'
class MinZoomBlock extends React.Component {
static propTypes = {
value: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired,
}
render() {
return <InputBlock label={"Min Zoom"} doc={GlSpec.layer.minzoom.doc}>
<NumberInput
value={this.props.value}
onChange={this.props.onChange}
min={GlSpec.layer.minzoom.minimum}
max={GlSpec.layer.minzoom.maximum}
default={GlSpec.layer.minzoom.minimum}
/>
</InputBlock>
}
}
export default MinZoomBlock

View File

@@ -23,6 +23,9 @@ function renderProperties(feature) {
function renderFeature(feature) {
return <div key={feature.id}>
<div className="maputnik-popup-layer-id">{feature.layer['source-layer']}</div>
<InputBlock key={"property-type"} label={"$type"}>
<StringInput value={feature.geometry.type} style={{backgroundColor: 'transparent'}} />
</InputBlock>
{renderProperties(feature)}
</div>
}

View File

@@ -7,6 +7,8 @@ import FeaturePropertyPopup from './FeaturePropertyPopup'
import validateColor from 'mapbox-gl-style-spec/lib/validate/validate_color'
import style from '../../libs/style.js'
import tokens from '../../config/tokens.json'
import colors from 'mapbox-gl-inspect/lib/colors'
import Color from 'color'
import { colorHighlightedLayer } from '../../libs/highlight'
import 'mapbox-gl/dist/mapbox-gl.css'
import '../../mapboxgl.css'
@@ -112,11 +114,15 @@ export default class MapboxGlMap extends React.Component {
const inspect = new MapboxInspect({
popup: new MapboxGl.Popup({
closeButton: false,
closeOnClick: false
}),
showMapPopup: true,
showMapPopupOnHover: false,
showInspectMapPopupOnHover: true,
showInspectButton: false,
assignLayerColor: (layerId, alpha) => {
return Color(colors.brightColor(layerId, alpha)).desaturate(0.5).string()
},
buildInspectStyle: (originalMapStyle, coloredLayers) => buildInspectStyle(originalMapStyle, coloredLayers, this.props.highlightedLayer),
renderPopup: features => {
if(this.props.inspectModeEnabled) {

View File

@@ -5,9 +5,11 @@ import GlSpec from 'mapbox-gl-style-spec/reference/latest.js'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import SelectInput from '../inputs/SelectInput'
import CheckboxInput from '../inputs/CheckboxInput'
import Button from '../Button'
import Modal from './Modal'
import MdFileDownload from 'react-icons/lib/md/file-download'
import style from '../../libs/style.js'
import formatStyle from 'mapbox-gl-style-spec/lib/format'
import GitHub from 'github-api'
@@ -15,18 +17,35 @@ import GitHub from 'github-api'
class Gist extends React.Component {
static propTypes = {
mapStyle: React.PropTypes.object.isRequired,
onStyleChanged: React.PropTypes.func.isRequired,
}
constructor(props) {
super(props);
this.state = {}
this.state = {
preview: false,
saving: false,
latestGist: null,
}
}
componentWillReceiveProps(nextProps) {
this.setState({
...this.state,
preview: !!(nextProps.mapStyle.metadata || {})['maputnik:openmaptiles_access_token']
})
}
onSave() {
this.setState({
...this.state,
saving: true
});
const mapStyleStr = formatStyle(this.props.mapStyle);
const preview = this.state.preview && (this.props.mapStyle.metadata || {})['maputnik:openmaptiles_access_token'];
const mapStyleStr = preview ?
formatStyle(stripAccessTokens(style.replaceAccessToken(this.props.mapStyle))) :
formatStyle(stripAccessTokens(this.props.mapStyle));
const styleTitle = this.props.mapStyle.name || 'Style';
const htmlStr = `
<!DOCTYPE html>
@@ -56,49 +75,100 @@ class Gist extends React.Component {
</body>
</html>
`
const files = {
"style.json": {
content: mapStyleStr
}
}
if(preview) {
files["index.html"] = {
content: htmlStr
}
}
const gh = new GitHub();
let gist = gh.getGist(); // not a gist yet
gist.create({
public: true,
description: styleTitle + 'Preview',
files: {
"style.json": {
content: mapStyleStr
},
"index.html": {
content: htmlStr
}
}
description: styleTitle,
files: files
}).then(function({data}) {
return gist.read();
}).then(function({data}) {
this.setState({
latestGist: data
...this.state,
latestGist: data,
saving: false,
});
}.bind(this));
}
onPreviewChange(value) {
this.setState({
...this.state,
preview: value
})
}
changeMetadataProperty(property, value) {
const changedStyle = {
...this.props.mapStyle,
metadata: {
...this.props.mapStyle.metadata,
[property]: value
}
}
this.props.onStyleChanged(changedStyle)
}
renderPreviewLink() {
const gist = this.state.latestGist;
const user = gist.user || 'anonymous';
const preview = !!gist.files['index.html'];
if(preview) {
return <span><a target="_blank" href={"https://bl.ocks.org/"+user+"/"+gist.id}>Preview</a>,{' '}</span>
}
return null;
}
renderLatestGist() {
const gist = this.state.latestGist;
const saving = this.state.saving;
if(gist) {
if(saving) {
return <p>Saving...</p>
} else if(gist) {
const user = gist.user || 'anonymous';
return <p>
Latest saved gist:{' '}
<a target="_blank" href={"https://bl.ocks.org/"+user+"/"+gist.id}>Preview</a>,{' '}
{this.renderPreviewLink(this)}
<a target="_blank" href={"https://gist.github.com/"+user+"/"+gist.id}>Source</a>
</p>
} else if(saving) {
return <p>Saving...</p>
}
}
render() {
return <div>
return <div className="maputnik-export-gist">
<Button onClick={this.onSave.bind(this)}>
<MdFileDownload />
Save to Gist (anonymous)
</Button>
{' '}
<CheckboxInput
value={this.state.preview}
name='gist-style-preview'
onChange={this.onPreviewChange.bind(this)}
/>
<span> Include preview</span>
{this.state.preview ?
<div>
<InputBlock
label={"OpenMapTiles Access Token: "}>
<StringInput
value={(this.props.mapStyle.metadata || {})['maputnik:openmaptiles_access_token']}
onChange={this.changeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}/>
</InputBlock>
<a target="_blank" href="https://openmaptiles.com/hosting/">Get your free access token</a>
</div>
: null}
{this.renderLatestGist()}
</div>
}
@@ -117,6 +187,7 @@ function stripAccessTokens(mapStyle) {
class ExportModal extends React.Component {
static propTypes = {
mapStyle: React.PropTypes.object.isRequired,
onStyleChanged: React.PropTypes.func.isRequired,
isOpen: React.PropTypes.bool.isRequired,
onOpenToggle: React.PropTypes.func.isRequired,
}
@@ -150,7 +221,7 @@ class ExportModal extends React.Component {
<div className="maputnik-modal-section">
<h4>Save style</h4>
<Gist mapStyle={this.props.mapStyle} />
<Gist mapStyle={this.props.mapStyle} onStyleChanged={this.props.onStyleChanged}/>
</div>
</Modal>
}

View File

@@ -101,7 +101,9 @@ class OpenModal extends React.Component {
<p>
Open one of the publicly available styles to start from.
</p>
<div className="maputnik-style-gallery-container">
{styleOptions}
</div>
</section>
</Modal>
}

View File

@@ -29,6 +29,15 @@ class TileURLSourceEditor extends React.Component {
onChange: React.PropTypes.func.isRequired,
}
changeTileUrl(idx, value) {
const tiles = this.props.source.tiles.slice(0)
tiles[idx] = value
this.props.onChange({
...this.props.source,
tiles: tiles
})
}
renderTileUrls() {
const prefix = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th']
const tiles = this.props.source.tiles || []
@@ -36,6 +45,7 @@ class TileURLSourceEditor extends React.Component {
return <InputBlock key={tileIndex} label={prefix[tileIndex] + " Tile URL"} doc={GlSpec.source_tile.tiles.doc}>
<StringInput
value={tileUrl}
onChange={this.changeTileUrl.bind(this, tileIndex)}
/>
</InputBlock>
})

View File

@@ -10,6 +10,5 @@
"sources": { },
"glyphs": "https://demo.tileserver.org/fonts/{fontstack}/{range}.pbf",
"sprites": "https://demo.tileserver.org/fonts/{fontstack}/{range}.pbf",
"layers": [],
"id": "empty-style"
"layers": []
}

View File

@@ -1,35 +0,0 @@
[
"Metropolis Black Italic",
"Metropolis Black",
"Metropolis Bold Italic",
"Metropolis Bold",
"Metropolis Extra Bold Italic",
"Metropolis Extra Bold",
"Metropolis Extra Light Italic",
"Metropolis Extra Light",
"Metropolis Light Italic",
"Metropolis Light",
"Metropolis Medium Italic",
"Metropolis Medium",
"Metropolis Regular Italic",
"Metropolis Regular",
"Metropolis Semi Bold Italic",
"Metropolis Semi Bold",
"Metropolis Thin Italic",
"Metropolis Thin",
"Open Sans Bold Italic",
"Open Sans Bold",
"Open Sans Extra Bold Italic",
"Open Sans Extra Bold",
"Open Sans Italic",
"Open Sans Light Italic",
"Open Sans Light",
"Open Sans Regular",
"Open Sans Semibold Italic",
"Open Sans Semibold",
"Klokantech Noto Sans Bold",
"Klokantech Noto Sans CJK Bold",
"Klokantech Noto Sans CJK Regular",
"Klokantech Noto Sans Italic",
"Klokantech Noto Sans Regular"
]

View File

@@ -2,26 +2,26 @@
{
"id": "klokantech-basic",
"title": "Klokantech Basic",
"url": "https://rawgit.com/openmaptiles/klokantech-basic-gl-style/gh-pages/style-cdn.json",
"thumbnail": "https://camo.githubusercontent.com/08dcb3dd384c6083b02e6692c939d68c4114eb33/687474703a2f2f64656d6f2e74696c657365727665722e6f72672f7374796c65732f6b6c6f6b616e746563682d62617369632f7374617469632f382e3631393138342c34372e3333363230332c31302e30372f363030783430304032782e706e67"
"url": "https://rawgit.com/openmaptiles/klokantech-basic-gl-style/master/style.json",
"thumbnail": "http://maputnik.com/thumbnails/klokantech-basic.png"
},
{
"id": "dark-matter",
"title": "Dark Matter",
"url": "https://rawgit.com/openmaptiles/dark-matter-gl-style/gh-pages/style-cdn.json",
"thumbnail": "https://camo.githubusercontent.com/258db708523e523782addeecdcc8697368a24df9/687474703a2f2f64656d6f2e74696c657365727665722e6f72672f7374796c65732f6461726b2d6d61747465722f7374617469632f382e3534303538372c34372e3337303535352c31352e30382f363030783430304032782e706e67"
"url": "https://rawgit.com/openmaptiles/dark-matter-gl-style/master/style.json",
"thumbnail": "http://maputnik.com/thumbnails/dark-matter.png"
},
{
"id": "positron",
"title": "Positron",
"url": "https://rawgit.com/openmaptiles/positron-gl-style/gh-pages/style-cdn.json",
"thumbnail": "https://camo.githubusercontent.com/56df86562b6c36b7cc44ee6e8b91eb4d8e593b66/687474703a2f2f64656d6f2e74696c657365727665722e6f72672f7374796c65732f706f736974726f6e2f7374617469632f31302e3938373235382c34362e3435333135302c342e30322f363030783430304032782e706e67"
"url": "https://rawgit.com/openmaptiles/positron-gl-style/master/style.json",
"thumbnail": "http://maputnik.com/thumbnails/positron.png"
},
{
"id": "osm-bright",
"title": "OSM Bright",
"url": "https://rawgit.com/openmaptiles/osm-bright-gl-style/gh-pages/style-cdn.json",
"thumbnail": "https://camo.githubusercontent.com/0fdf9922c6b632f903e47b3dfbcfb65e62b25046/687474703a2f2f64656d6f2e74696c657365727665722e6f72672f7374796c65732f6f736d2d6272696768742f7374617469632f382e3234333936372c34362e3931363331352c372e32312f363030783430304032782e706e67"
"url": "https://rawgit.com/openmaptiles/osm-bright-gl-style/master/style.json",
"thumbnail": "http://maputnik.com/thumbnails/osm-bright.png"
},
{
"id": "osm-liberty",
@@ -34,5 +34,29 @@
"title": "Empty Style",
"url": "https://rawgit.com/maputnik/editor/master/src/config/empty-style.json",
"thumbnail": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAQAAAAHDYbIAAAAEUlEQVR42mP8/58BDhiJ4wAA974H/U5Xe1oAAAAASUVORK5CYII="
},
{
"id": "mapbox-satellite",
"title": "Mapbox Satellite",
"url": "https://rawgit.com/mapbox/mapbox-gl-styles/master/styles/satellite-v9.json",
"thumbnail": "http://maputnik.com/thumbnails/mapbox-satellite.png"
},
{
"id": "mapbox-bright",
"title": "Mapbox Bright",
"url": "https://rawgit.com/mapbox/mapbox-gl-styles/master/styles/bright-v9.json",
"thumbnail": "http://maputnik.com/thumbnails/mapbox-bright.png"
},
{
"id": "mapbox-basic",
"title": "Mapbox Basic",
"url": "https://rawgit.com/mapbox/mapbox-gl-styles/master/styles/basic-v9.json",
"thumbnail": "http://maputnik.com/thumbnails/mapbox-basic.png"
},
{
"id": "tilezen",
"title": "Tilezen",
"url": "https://rawgit.com/lukasmartinelli/tilezen-gl-style/master/style.json",
"thumbnail": "http://maputnik.com/thumbnails/tilezen.png"
}
]

View File

@@ -6,7 +6,7 @@
},
"openmaptiles": {
"type": "vector",
"url": "https://free.tilehosting.com/data/v3.json?key=25ItXg7aI5wurYDtttD",
"url": "https://free.tilehosting.com/data/v3.json?key={key}",
"title": "OpenMapTiles"
},
"tilezen": {

View File

@@ -1,6 +1,3 @@
import randomColor from 'randomcolor'
import Color from 'color'
import stylegen from 'mapbox-gl-inspect/lib/stylegen'
import colors from 'mapbox-gl-inspect/lib/colors'
@@ -8,6 +5,12 @@ export function colorHighlightedLayer(layer) {
if(!layer || layer.type === 'background' || layer.type === 'raster') return null
function changeLayer(l) {
if(l.type === 'circle') {
l.paint['circle-radius'] = 3
} else if(l.type === 'line') {
l.paint['line-width'] = 2
}
if(layer.filter) {
l.filter = layer.filter
} else {
@@ -17,7 +20,8 @@ export function colorHighlightedLayer(layer) {
return l
}
const color = colors.brightColor(layer.id, 1)
const sourceLayerId = layer['source-layer'] || ''
const color = colors.brightColor(sourceLayerId, 1)
const layers = []
if(layer.type === "fill" || layer.type === 'fill-extrusion') {

View File

@@ -21,7 +21,12 @@ function loadJSON(url, defaultValue, cb) {
export function downloadGlyphsMetadata(urlTemplate, cb) {
if(!urlTemplate) return cb([])
const url = urlTemplate.replace('{fontstack}/{range}.pbf', 'fontstacks.json')
// Special handling because Tileserver GL serves the fontstacks metadata differently
// https://github.com/klokantech/tileserver-gl/pull/104
let url = urlTemplate.replace('/fonts/{fontstack}/{range}.pbf', '/fontstacks.json')
url = url.replace('{fontstack}/{range}.pbf', 'fontstacks.json')
loadJSON(url, [], cb)
}

View File

@@ -72,3 +72,7 @@ label:hover {
clear: both;
}
}
a {
color: white;
}

5
src/styles/_export.scss Normal file
View File

@@ -0,0 +1,5 @@
.maputnik-export-gist {
label.maputnik-checkbox-wrapper {
display: inline-block;
}
}

View File

@@ -129,3 +129,38 @@
background-color: $color-gray;
}
}
// PROPERTY
.maputnik-default-property {
.maputnik-input-block-label {
color: darken($color-lowgray, 25%);
}
.maputnik-string,
.maputnik-number,
.maputnik-color,
.maputnik-select,
.maputnik-checkbox-wrapper {
background-color: darken($color-gray, 2%);
color: darken($color-lowgray, 25%);
}
.maputnik-make-zoom-function svg {
opacity: 0.4;
}
.maputnik-multibutton .maputnik-button {
background-color: darken($color-midgray, 10%);
color: darken($color-lowgray, 25%);
&:hover {
background-color: lighten($color-midgray, 12);
color: $color-white;
}
}
.maputnik-multibutton .maputnik-button-selected {
background-color: darken($color-midgray, 2%);
color: $color-lowgray;
}
}

View File

@@ -65,6 +65,11 @@
@extend .maputnik-big-button;
}
.maputnik-style-gallery-container {
max-height: 400px;
overflow-y: scroll;
}
.maputnik-public-style {
vertical-align: top;
margin-top: 10px;
@@ -176,3 +181,21 @@
margin-right: $margin-3;
float: right;
}
//EXPORT MODAL
.maputnik-export-gist {
font-size: $font-size-6;
.maputnik-input-block {
margin-left: 0;
margin-right: 0;
label {
vertical-align: middle;
}
}
span {
color: $color-lowgray;
}
}

View File

@@ -27,6 +27,7 @@ $toolbar-height: 40px;
@import 'picker';
@import 'toolbar';
@import 'modal';
@import 'export';
@import 'layout';
@import 'layer';
@import 'input';

View File

@@ -14,7 +14,6 @@ module.exports = {
'mapbox-gl/dist/mapbox-gl.js',
//TODO: Build failure because cannot resolve migrations file
//"mapbox-gl-style-spec",
"randomcolor",
"lodash.clonedeep",
"lodash.throttle",
'color',