diff --git a/src/components/Toolbar.jsx b/src/components/Toolbar.jsx index 46ae067..bcb60f8 100644 --- a/src/components/Toolbar.jsx +++ b/src/components/Toolbar.jsx @@ -91,6 +91,7 @@ export default class Toolbar extends React.Component { /> diff --git a/src/components/inputs/CheckboxInput.jsx b/src/components/inputs/CheckboxInput.jsx index e5d661a..cfe5b3d 100644 --- a/src/components/inputs/CheckboxInput.jsx +++ b/src/components/inputs/CheckboxInput.jsx @@ -17,7 +17,9 @@ class CheckboxInput extends React.Component { checked={this.props.value} />
- +
diff --git a/src/components/inputs/StringInput.jsx b/src/components/inputs/StringInput.jsx index f9fb56e..34a550a 100644 --- a/src/components/inputs/StringInput.jsx +++ b/src/components/inputs/StringInput.jsx @@ -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) }} /> } diff --git a/src/components/modals/ExportModal.jsx b/src/components/modals/ExportModal.jsx index 17dec43..86b75d8 100644 --- a/src/components/modals/ExportModal.jsx +++ b/src/components/modals/ExportModal.jsx @@ -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 = ` @@ -56,49 +75,100 @@ class Gist extends React.Component { ` + 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 Preview,{' '} + } + return null; + } + renderLatestGist() { const gist = this.state.latestGist; const saving = this.state.saving; - if(gist) { + if(saving) { + return

Saving...

+ } else if(gist) { const user = gist.user || 'anonymous'; return

Latest saved gist:{' '} - Preview,{' '} + {this.renderPreviewLink(this)} Source

- } else if(saving) { - return

Saving...

} } render() { - return
+ return
+ {' '} + + Include preview + {this.state.preview ? +
+ + + + Get your free access token +
+ : null} {this.renderLatestGist()}
} @@ -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 {

Save style

- +
} diff --git a/src/styles/_base.scss b/src/styles/_base.scss index 0261d8e..b3273d4 100644 --- a/src/styles/_base.scss +++ b/src/styles/_base.scss @@ -72,3 +72,7 @@ label:hover { clear: both; } } + +a { + color: white; +} diff --git a/src/styles/_export.scss b/src/styles/_export.scss new file mode 100644 index 0000000..8cace42 --- /dev/null +++ b/src/styles/_export.scss @@ -0,0 +1,5 @@ +.maputnik-export-gist { + label.maputnik-checkbox-wrapper { + display: inline-block; + } +} diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 58e54bb..ccbb214 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -181,3 +181,19 @@ margin-right: $margin-3; float: right; } + +//EXPORT MODAL +.maputnik-export-gist { + .maputnik-input-block { + margin-left: 0; + margin-right: 0; + + label { + vertical-align: middle; + } + } + font-size: $font-size-6; + span { + color: $color-lowgray; + } +} diff --git a/src/styles/index.scss b/src/styles/index.scss index 8b7e47a..5bcb541 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -27,6 +27,7 @@ $toolbar-height: 40px; @import 'picker'; @import 'toolbar'; @import 'modal'; +@import 'export'; @import 'layout'; @import 'layer'; @import 'input';