feat(netlify-cms-widget-map): add map widget (#2051)
This commit is contained in:
committed by
Shawn Erquhart
parent
627e600d29
commit
18f34d2aca
@ -28,7 +28,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
include: [/(redux-notifications|react-datetime)/],
|
||||
include: [/(ol|redux-notifications|react-datetime)/],
|
||||
use: ['to-string-loader', 'css-loader'],
|
||||
},
|
||||
],
|
||||
|
4
packages/netlify-cms-widget-map/CHANGELOG.md
Normal file
4
packages/netlify-cms-widget-map/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
11
packages/netlify-cms-widget-map/README.md
Normal file
11
packages/netlify-cms-widget-map/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Docs coming soon!
|
||||
|
||||
Netlify CMS was recently converted from a single npm package to a "monorepo" of over 20 packages.
|
||||
That's over 20 Readme's! We haven't created one for this package yet, but we will soon.
|
||||
|
||||
In the meantime, you can:
|
||||
|
||||
1. Check out the [main readme](https://github.com/netlify/netlify-cms/#readme) or the [documentation
|
||||
site](https://www.netlifycms.org) for more info.
|
||||
2. Reach out to the [community chat](https://gitter.im/netlify/netlifycms/) if you need help.
|
||||
3. Help out and [write the readme yourself](https://github.com/netlify/netlify-cms/edit/master/packages/netlify-cms-widget-map/README.md)!
|
41
packages/netlify-cms-widget-map/package.json
Normal file
41
packages/netlify-cms-widget-map/package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "netlify-cms-widget-map",
|
||||
"description": "Widget for editing spatial data in Netlify CMS.",
|
||||
"version": "1.0.0",
|
||||
"homepage": "https://www.netlifycms.org/docs/widgets/#map",
|
||||
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-widget-map",
|
||||
"bugs": "https://github.com/netlify/netlify-cms/issues",
|
||||
"main": "dist/netlify-cms-widget-map.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"netlify",
|
||||
"netlify-cms",
|
||||
"widget",
|
||||
"spatial",
|
||||
"map"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"watch": "webpack -w",
|
||||
"develop": "npm run watch",
|
||||
"build": "cross-env NODE_ENV=production webpack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^2.1.0",
|
||||
"to-string-loader": "^1.1.5",
|
||||
"webpack": "^4.16.1",
|
||||
"webpack-cli": "^3.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"emotion": "^9.2.6",
|
||||
"lodash": "^4.17.10",
|
||||
"netlify-cms-ui-default": "^2.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.4.1",
|
||||
"react-immutable-proptypes": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ol": "^5.3.0"
|
||||
}
|
||||
}
|
13
packages/netlify-cms-widget-map/src/MapPreview.js
Normal file
13
packages/netlify-cms-widget-map/src/MapPreview.js
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { WidgetPreviewContainer } from 'netlify-cms-ui-default';
|
||||
|
||||
const MapPreview = ({ value }) => (
|
||||
<WidgetPreviewContainer>{value ? value.toString() : null}</WidgetPreviewContainer>
|
||||
);
|
||||
|
||||
MapPreview.propTypes = {
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
export default MapPreview;
|
5
packages/netlify-cms-widget-map/src/index.js
Normal file
5
packages/netlify-cms-widget-map/src/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
import withMapControl from './withMapControl';
|
||||
|
||||
export { withMapControl };
|
||||
export const MapControl = withMapControl();
|
||||
export MapPreview from './MapPreview';
|
76
packages/netlify-cms-widget-map/src/withMapControl.js
Normal file
76
packages/netlify-cms-widget-map/src/withMapControl.js
Normal file
@ -0,0 +1,76 @@
|
||||
import olStyles from 'ol/ol.css';
|
||||
import Map from 'ol/Map.js';
|
||||
import View from 'ol/View.js';
|
||||
import GeoJSON from 'ol/format/GeoJSON';
|
||||
import Draw from 'ol/interaction/Draw.js';
|
||||
import TileLayer from 'ol/layer/Tile.js';
|
||||
import VectorLayer from 'ol/layer/Vector.js';
|
||||
import OSMSource from 'ol/source/OSM.js';
|
||||
import VectorSource from 'ol/source/Vector.js';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { injectGlobal } from 'react-emotion';
|
||||
|
||||
injectGlobal`
|
||||
${olStyles}
|
||||
`;
|
||||
|
||||
const formatOptions = {
|
||||
dataProjection: 'EPSG:4326',
|
||||
featureProjection: 'EPSG:3857',
|
||||
};
|
||||
const getDefaultFormat = () => new GeoJSON(formatOptions);
|
||||
|
||||
const getDefaultMap = (target, featuresLayer) =>
|
||||
new Map({
|
||||
target,
|
||||
layers: [new TileLayer({ source: new OSMSource() }), featuresLayer],
|
||||
view: new View({ center: [0, 0], zoom: 2 }),
|
||||
});
|
||||
|
||||
export default function withMapControl({ getFormat, getMap } = {}) {
|
||||
return class MapControl extends React.Component {
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
field: PropTypes.object.isRequired,
|
||||
value: PropTypes.node,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
value: '',
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.mapContainer = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { field, onChange, value } = this.props;
|
||||
const format = getFormat ? getFormat(field) : getDefaultFormat(field);
|
||||
const features = value ? [format.readFeature(value)] : [];
|
||||
|
||||
const featuresSource = new VectorSource({ features, wrapX: false });
|
||||
const featuresLayer = new VectorLayer({ source: featuresSource });
|
||||
|
||||
const target = this.mapContainer.current;
|
||||
const map = getMap ? getMap(target, featuresLayer) : getDefaultMap(target, featuresLayer);
|
||||
if (features.length > 0) {
|
||||
map.getView().fit(featuresSource.getExtent(), { maxZoom: 16, padding: [80, 80, 80, 80] });
|
||||
}
|
||||
|
||||
const draw = new Draw({ source: featuresSource, type: field.get('type', 'Point') });
|
||||
map.addInteraction(draw);
|
||||
|
||||
const writeOptions = { decimals: field.get('decimals', 7) };
|
||||
draw.on('drawend', ({ feature }) => {
|
||||
featuresSource.clear();
|
||||
onChange(format.writeGeometry(feature.getGeometry(), writeOptions));
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div ref={this.mapContainer}> </div>;
|
||||
}
|
||||
};
|
||||
}
|
17
packages/netlify-cms-widget-map/webpack.config.js
Normal file
17
packages/netlify-cms-widget-map/webpack.config.js
Normal file
@ -0,0 +1,17 @@
|
||||
const { getConfig } = require('../../scripts/webpack.js');
|
||||
|
||||
const baseWebpackConfig = getConfig();
|
||||
|
||||
module.exports = {
|
||||
...baseWebpackConfig,
|
||||
module: {
|
||||
rules: [
|
||||
...baseWebpackConfig.module.rules,
|
||||
{
|
||||
test: /\.css$/,
|
||||
include: [/ol/],
|
||||
use: ['to-string-loader', 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
@ -37,6 +37,7 @@
|
||||
"netlify-cms-widget-file": "^2.2.0",
|
||||
"netlify-cms-widget-image": "^2.1.1",
|
||||
"netlify-cms-widget-list": "^2.1.0",
|
||||
"netlify-cms-widget-map": "^1.0.0",
|
||||
"netlify-cms-widget-markdown": "^2.1.0",
|
||||
"netlify-cms-widget-number": "^2.0.5",
|
||||
"netlify-cms-widget-object": "^2.0.5",
|
||||
|
@ -12,6 +12,7 @@ import { ListControl, ListPreview } from 'netlify-cms-widget-list/src';
|
||||
import { ObjectControl, ObjectPreview } from 'netlify-cms-widget-object/src';
|
||||
import { RelationControl, RelationPreview } from 'netlify-cms-widget-relation/src';
|
||||
import { BooleanControl } from 'netlify-cms-widget-boolean/src';
|
||||
import { MapControl, MapPreview } from 'netlify-cms-widget-map/src';
|
||||
|
||||
const { registerWidget } = cms;
|
||||
|
||||
@ -28,3 +29,4 @@ registerWidget('select', SelectControl, SelectPreview);
|
||||
registerWidget('object', ObjectControl, ObjectPreview);
|
||||
registerWidget('relation', RelationControl, RelationPreview);
|
||||
registerWidget('boolean', BooleanControl);
|
||||
registerWidget('map', MapControl, MapPreview);
|
||||
|
Reference in New Issue
Block a user