@eeacms/volto-eea-map 0.1.11 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/package.json +1 -1
  3. package/src/actionTypes.js +1 -0
  4. package/src/actions.js +1 -1
  5. package/src/components/Blocks/EEAMap/Edit.jsx +33 -2
  6. package/src/components/Blocks/EEAMap/Schema.js +7 -4
  7. package/src/components/Blocks/EEAMap/View.jsx +6 -5
  8. package/src/components/Blocks/EmbedEEAMap/Edit.jsx +36 -4
  9. package/src/components/Blocks/EmbedEEAMap/Schema.js +16 -5
  10. package/src/components/Blocks/EmbedEEAMap/View.jsx +75 -11
  11. package/src/components/ExtraViews.jsx +85 -0
  12. package/src/components/{Blocks/EEAMap/components/Webmap.jsx → Webmap.jsx} +33 -31
  13. package/src/components/index.js +6 -6
  14. package/src/components/visualization/VisualizationEditorWidget.jsx +120 -0
  15. package/src/components/{Blocks/EEAMap/components/widgets → visualization}/VisualizationView.jsx +0 -0
  16. package/src/components/{Blocks/EEAMap/components/widgets → visualization}/panelsSchema.js +0 -1
  17. package/src/components/widgets/DataQueryWidget.jsx +50 -0
  18. package/src/components/{Blocks/EEAMap/components/widgets → widgets}/LayerSelectWidget.jsx +169 -51
  19. package/src/components/{Blocks/EEAMap/components/widgets/LayersPanel.jsx → widgets/LayersPanelWidget.jsx} +2 -2
  20. package/src/components/{Blocks/EEAMap/components/widgets → widgets}/LegendWidget.jsx +45 -31
  21. package/src/components/{Blocks/EEAMap/components/widgets → widgets}/MapEditorWidget.jsx +1 -1
  22. package/src/components/{Blocks/EEAMap/components/widgets → widgets}/ObjectTypesWidget.jsx +11 -3
  23. package/src/components/widgets/panelsSchema.js +151 -0
  24. package/src/constants.js +29 -1
  25. package/src/index.js +42 -40
  26. package/src/middlewares/index.js +1 -1
  27. package/src/reducers/map_visualizations.js +1 -1
  28. package/src/static/code-line.svg +1 -0
  29. package/src/{components/Blocks/EEAMap/styles → styles}/map.css +64 -5
  30. package/src/{components/Blocks/EEAMap/utils.js → utils.js} +18 -2
  31. package/src/components/Blocks/EEAMap/components/widgets/ExtraViews.jsx +0 -86
  32. package/src/components/Blocks/EEAMap/components/widgets/VisualizationEditorWidget.jsx +0 -94
  33. package/src/components/Blocks/EEAMap/constants.js +0 -29
  34. package/src/components/Blocks/EmbedEEAMap/styles/map.css +0 -22
@@ -0,0 +1,120 @@
1
+ import React from 'react';
2
+ import { Modal, Button, Grid } from 'semantic-ui-react';
3
+
4
+ import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
5
+
6
+ import PanelsSchema from './panelsSchema';
7
+ import Webmap from '../Webmap';
8
+
9
+ const VisualizationEditorWidget = (props) => {
10
+ const [open, setOpen] = React.useState(false);
11
+ const { onChange = {}, id } = props;
12
+ const block = React.useMemo(() => props.block, [props.block]);
13
+ const value = React.useMemo(() => props.value, [props.value]);
14
+
15
+ const [intValue, setIntValue] = React.useState(value);
16
+
17
+ const dataForm = { map_data: intValue };
18
+ const handleApplyChanges = () => {
19
+ onChange(id, intValue);
20
+ setOpen(false);
21
+ };
22
+
23
+ const handleClose = () => {
24
+ setIntValue(value);
25
+ setOpen(false);
26
+ };
27
+
28
+ const handleChangeField = (val) => {
29
+ setIntValue(val);
30
+ };
31
+
32
+ let schema = PanelsSchema({ data: dataForm });
33
+
34
+ React.useEffect(() => {
35
+ if (!intValue.general) {
36
+ setIntValue({
37
+ ...intValue,
38
+ general: {
39
+ print_position: 'top-right',
40
+ zoom_position: 'top-right',
41
+ centerOnExtent: true,
42
+ },
43
+ });
44
+ }
45
+ if (!intValue.base) {
46
+ setIntValue({
47
+ ...intValue,
48
+ base: {
49
+ base_layer: 'gray-vector',
50
+ },
51
+ });
52
+ }
53
+ }, [intValue]);
54
+
55
+ return (
56
+ <FormFieldWrapper {...props}>
57
+ <div className="wrapper">
58
+ <Button
59
+ floated="right"
60
+ size="tiny"
61
+ onClick={(e) => {
62
+ e.preventDefault();
63
+ e.stopPropagation();
64
+ setOpen(true);
65
+ }}
66
+ >
67
+ Open Map Editor
68
+ </Button>
69
+ </div>
70
+
71
+ {open && (
72
+ <Modal
73
+ id="map-editor-modal"
74
+ style={{ width: '95% !important' }}
75
+ open={true}
76
+ >
77
+ <Modal.Content scrolling>
78
+ <Grid stackable reversed="mobile vertically tablet vertically">
79
+ <Grid.Column
80
+ mobile={12}
81
+ tablet={12}
82
+ computer={5}
83
+ className="map-editor-column"
84
+ >
85
+ <InlineForm
86
+ block={block}
87
+ schema={schema}
88
+ onChangeField={(id, value) => {
89
+ handleChangeField(value);
90
+ }}
91
+ formData={dataForm}
92
+ />
93
+ </Grid.Column>
94
+ <Grid.Column mobile={12} tablet={12} computer={7}>
95
+ <div className="webmap-container">
96
+ <Webmap data={intValue} editMode={true} />
97
+ </div>
98
+ </Grid.Column>
99
+ </Grid>
100
+ </Modal.Content>
101
+ <Modal.Actions>
102
+ <Grid>
103
+ <Grid.Row>
104
+ <div className="map-edit-actions-container">
105
+ <Button onClick={handleClose}>Close</Button>
106
+ <Button color="green" onClick={handleApplyChanges}>
107
+ Apply changes
108
+ </Button>
109
+ </div>
110
+ </Grid.Row>
111
+ </Grid>
112
+ </Modal.Actions>
113
+ </Modal>
114
+ )}
115
+ <Webmap data={value} editMode={true} />
116
+ </FormFieldWrapper>
117
+ );
118
+ };
119
+
120
+ export default VisualizationEditorWidget;
@@ -79,7 +79,6 @@ const GeneralSchema = ({ data = {} }) => {
79
79
  type: 'boolean',
80
80
  description:
81
81
  'This will override latitude/longitude/zoom level and will lock zoom/moving the map.',
82
- default: true,
83
82
  },
84
83
  zoom_position: {
85
84
  title: 'Zoom position',
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { FormFieldWrapper, Field } from '@plone/volto/components';
3
+ import { Accordion, Segment } from 'semantic-ui-react';
4
+
5
+ const DataQueryWidget = (props) => {
6
+ const { value, onChange, id } = props;
7
+
8
+ const onChangeAlias = (fieldId, fieldValue) => {
9
+ let altValue = value;
10
+ value[fieldId] = { ...value[fieldId], alias: fieldValue };
11
+ onChange(id, altValue);
12
+ };
13
+
14
+ return (
15
+ <div>
16
+ <FormFieldWrapper {...props} noForInFieldLabel></FormFieldWrapper>
17
+ <div className="data-query-widget-field">
18
+ {value && value.length > 0 ? (
19
+ value.map((param, i) => (
20
+ <Accordion
21
+ key={i}
22
+ fluid
23
+ styled
24
+ style={{ border: '1px solid lightgray', marginBottom: '15px' }}
25
+ >
26
+ <Accordion.Content active={true}>
27
+ <Segment>
28
+ <p className="data-param-title">
29
+ <strong>{param.i}:</strong> {param.v.join(', ')}
30
+ </p>
31
+ <Field
32
+ id={i}
33
+ title="Map to"
34
+ type="string"
35
+ onChange={onChangeAlias}
36
+ value={param?.alias}
37
+ />
38
+ </Segment>
39
+ </Accordion.Content>
40
+ </Accordion>
41
+ ))
42
+ ) : (
43
+ <p style={{ textAlign: 'center' }}>No parameters set</p>
44
+ )}
45
+ </div>
46
+ </div>
47
+ );
48
+ };
49
+
50
+ export default DataQueryWidget;
@@ -4,15 +4,22 @@ import { Input, Select, Button, Grid } from 'semantic-ui-react';
4
4
  import { QueryBuilder } from 'react-querybuilder';
5
5
  import 'react-querybuilder/dist/query-builder.css';
6
6
 
7
+ import RichTextWidget from 'volto-slate/widgets/RichTextWidget';
8
+
9
+ import { connect } from 'react-redux';
10
+ import { compose } from 'redux';
11
+
12
+ import { getContent } from '@plone/volto/actions';
13
+
7
14
  import checkSVG from '@plone/volto/icons/check.svg';
8
15
  import closeSVG from '@plone/volto/icons/clear.svg';
9
16
  import aheadSVG from '@plone/volto/icons/ahead.svg';
10
17
  import resetSVG from '@plone/volto/icons/reset.svg';
11
18
 
12
- import { fetchArcgisData } from '../../utils';
19
+ import { fetchArcGISData } from '../../utils';
13
20
 
14
21
  const LayerSelectWidget = (props) => {
15
- const { onChange, id } = props;
22
+ const { onChange, id, data_query } = props;
16
23
 
17
24
  const value = React.useMemo(() => props.value || {}, [props.value]);
18
25
 
@@ -23,6 +30,7 @@ const LayerSelectWidget = (props) => {
23
30
  layer,
24
31
  fields = [],
25
32
  query = '',
33
+ description = '',
26
34
  } = value;
27
35
 
28
36
  const [mapData, setMapData] = React.useState(map_data);
@@ -30,6 +38,7 @@ const LayerSelectWidget = (props) => {
30
38
  const [serviceUrlError, setServiceUrlError] = React.useState('');
31
39
  const [serviceUrl, setServiceUrl] = React.useState(map_service_url);
32
40
  const [selectedLayer, setSelectedLayer] = React.useState(layer);
41
+
33
42
  const [availableLayers, setAvailableLayers] = React.useState(
34
43
  available_layers,
35
44
  );
@@ -39,7 +48,7 @@ const LayerSelectWidget = (props) => {
39
48
  const handleServiceUrlCheck = async () => {
40
49
  // fetch url, save it, populate layers options
41
50
  try {
42
- let mapData = await fetchArcgisData(serviceUrl);
51
+ let mapData = await fetchArcGISData(serviceUrl);
43
52
  setCheckColor('green');
44
53
  setMapData(mapData);
45
54
  setServiceUrlError('');
@@ -56,6 +65,7 @@ const LayerSelectWidget = (props) => {
56
65
  map_service_url: serviceUrl,
57
66
  available_layers: availableLayers,
58
67
  map_data: mapData,
68
+ description,
59
69
  });
60
70
  } catch (e) {
61
71
  setCheckColor('youtube');
@@ -63,9 +73,58 @@ const LayerSelectWidget = (props) => {
63
73
  }
64
74
  };
65
75
 
76
+ React.useEffect(() => {
77
+ props.getContent('', null, id);
78
+ // eslint-disable-next-line react-hooks/exhaustive-deps
79
+ }, []);
80
+
81
+ React.useEffect(() => {
82
+ if (query && !builtQuery) {
83
+ setBuiltQuery(query);
84
+ }
85
+ }, [query, builtQuery]);
86
+
87
+ React.useEffect(() => {
88
+ //detect existing queries in block content. If it exists. Apply matching queries to layer on fresh layer load
89
+ if (
90
+ map_service_url &&
91
+ layer &&
92
+ !query &&
93
+ data_query &&
94
+ data_query.length > 0
95
+ ) {
96
+ let autoQuery = {
97
+ combinator: 'or',
98
+ rules: [],
99
+ };
100
+ data_query.forEach((param, i) => {
101
+ if (
102
+ fields &&
103
+ fields.length > 0 &&
104
+ fields.filter(
105
+ (field, j) => field.name === param.alias || field.name === param.i,
106
+ ).length > 0
107
+ ) {
108
+ autoQuery.rules = [
109
+ ...autoQuery.rules,
110
+ { field: param.alias || param.i, operator: '=', value: param.v[0] },
111
+ ];
112
+ }
113
+ });
114
+ if (autoQuery.rules.length > 0) {
115
+ onChange(id, {
116
+ ...value,
117
+ query: autoQuery,
118
+ });
119
+ setBuiltQuery(autoQuery);
120
+ }
121
+ }
122
+ // eslint-disable-next-line react-hooks/exhaustive-deps
123
+ }, [map_service_url, layer, query, data_query, fields]);
124
+
66
125
  const handleLayerFetch = async (service_url, id) => {
67
126
  try {
68
- let fullLayer = await fetchArcgisData(`${service_url}/${id}`);
127
+ let fullLayer = await fetchArcGISData(`${service_url}/${id}`);
69
128
  return fullLayer;
70
129
  } catch (e) {}
71
130
  };
@@ -94,13 +153,24 @@ const LayerSelectWidget = (props) => {
94
153
  }
95
154
  };
96
155
 
156
+ const handleChangeDescription = (val) => {
157
+ if (val) {
158
+ onChange(id, {
159
+ ...value,
160
+ description: val,
161
+ });
162
+ }
163
+ };
164
+
97
165
  const handleChangeServiceUrl = (value) => {
98
166
  setServiceUrlError('');
99
167
  setCheckColor('');
100
- setServiceUrl(value);
101
168
  setAvailableLayers('');
102
169
  setBuiltQuery('');
103
170
  setSelectedLayer('');
171
+ setMapData('');
172
+
173
+ setServiceUrl(value);
104
174
  };
105
175
 
106
176
  const handleReset = () => {
@@ -110,8 +180,8 @@ const LayerSelectWidget = (props) => {
110
180
  setAvailableLayers(available_layers);
111
181
  setBuiltQuery('');
112
182
  setSelectedLayer(layer);
183
+ setMapData(map_data);
113
184
  };
114
-
115
185
  return (
116
186
  <div
117
187
  style={{
@@ -119,54 +189,71 @@ const LayerSelectWidget = (props) => {
119
189
  }}
120
190
  >
121
191
  <Grid>
122
- <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
123
- Service URL
124
- </h5>
125
- <Grid.Row>
126
- <Input
127
- type="text"
128
- onChange={(e, { value }) => handleChangeServiceUrl(value)}
129
- style={{ width: '100%' }}
130
- error={serviceUrlError}
131
- value={serviceUrl}
132
- // action
133
- // actionPosition="right"
134
- ></Input>
135
-
136
- <span style={{ fontSize: '12px', color: 'darkred' }}>
137
- {serviceUrlError.error}
138
- </span>
139
- </Grid.Row>
140
- {serviceUrl && (
192
+ <div className="spaced-row">
193
+ <Grid.Row stretched>
194
+ <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
195
+ Service URL
196
+ </h5>
197
+ </Grid.Row>
198
+
141
199
  <Grid.Row>
142
- {serviceUrl !== map_service_url && (
200
+ <Input
201
+ type="text"
202
+ onChange={(e, { value }) => handleChangeServiceUrl(value)}
203
+ style={{ width: '100%' }}
204
+ error={serviceUrlError}
205
+ value={serviceUrl}
206
+ ></Input>
207
+
208
+ <span style={{ fontSize: '12px', color: 'darkred' }}>
209
+ {serviceUrlError.error}
210
+ </span>
211
+ </Grid.Row>
212
+ {serviceUrl && (
213
+ <Grid.Row style={{ display: 'flex' }}>
214
+ {serviceUrl !== map_service_url && (
215
+ <Button
216
+ size="small"
217
+ compact
218
+ className="layer-reset-button"
219
+ onClick={handleReset}
220
+ >
221
+ <Icon name={resetSVG} title="Reset" size="20px" />
222
+ </Button>
223
+ )}
143
224
  <Button
144
225
  size="small"
226
+ color={checkColor}
145
227
  compact
146
- className="layer-reset-button"
147
- onClick={handleReset}
228
+ className="layer-check-button"
229
+ onClick={handleServiceUrlCheck}
148
230
  >
149
- <Icon name={resetSVG} title="Reset" size="20px" />
231
+ <Icon
232
+ name={serviceUrlError ? closeSVG : checkSVG}
233
+ title="Submit"
234
+ size="20px"
235
+ />
150
236
  </Button>
151
- )}
152
- <Button
153
- size="small"
154
- color={checkColor}
155
- compact
156
- className="layer-check-button"
157
- onClick={handleServiceUrlCheck}
158
- >
159
- <Icon
160
- name={serviceUrlError ? closeSVG : checkSVG}
161
- title="Submit"
162
- size="20px"
163
- />
164
- </Button>
165
- </Grid.Row>
237
+ </Grid.Row>
238
+ )}
239
+ </div>
240
+ {mapData && mapData.mapName && (
241
+ <div className="spaced-row">
242
+ <Grid.Row>
243
+ <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
244
+ Map name:
245
+ </h5>
246
+ <p>{mapData.mapName}</p>
247
+ </Grid.Row>
248
+ </div>
166
249
  )}
167
250
  {availableLayers && availableLayers.length > 0 && (
168
- <>
169
- <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>Layer</h5>
251
+ <div className="spaced-row">
252
+ <Grid.Row>
253
+ <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
254
+ Layer
255
+ </h5>
256
+ </Grid.Row>
170
257
  <Grid.Row>
171
258
  <Select
172
259
  onChange={(e, { value }) => handleSelectLayer(value)}
@@ -176,10 +263,31 @@ const LayerSelectWidget = (props) => {
176
263
  value={selectedLayer}
177
264
  />
178
265
  </Grid.Row>
179
- </>
266
+ </div>
267
+ )}
268
+ {availableLayers && availableLayers.length > 0 && (
269
+ <div className="spaced-row">
270
+ <Grid.Row stretched>
271
+ <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
272
+ Description
273
+ </h5>
274
+ </Grid.Row>
275
+ <Grid.Row stretched>
276
+ <div className="map-layer-description-field">
277
+ <RichTextWidget
278
+ title="description"
279
+ onChange={(name, value) => {
280
+ handleChangeDescription(value);
281
+ }}
282
+ value={value.description}
283
+ placeholder="Set Description"
284
+ />
285
+ </div>
286
+ </Grid.Row>
287
+ </div>
180
288
  )}
181
289
  {availableLayers && fields && fields.length > 0 && (
182
- <>
290
+ <div className="spaced-row">
183
291
  <h5 style={{ padding: '0', margin: '15px 0px 5px 0px' }}>
184
292
  Query Layer
185
293
  </h5>
@@ -194,7 +302,7 @@ const LayerSelectWidget = (props) => {
194
302
  />
195
303
  </Grid.Row>
196
304
  {builtQuery && (
197
- <Grid.Row>
305
+ <Grid.Row style={{ display: 'flex' }}>
198
306
  <Button
199
307
  type="submit"
200
308
  size="tiny"
@@ -223,11 +331,21 @@ const LayerSelectWidget = (props) => {
223
331
  <strong>{field.alias}</strong> ({field.type})
224
332
  </p>
225
333
  ))}
226
- </>
334
+ </div>
227
335
  )}
228
336
  </Grid>
229
337
  </div>
230
338
  );
231
339
  };
232
340
 
233
- export default LayerSelectWidget;
341
+ export default compose(
342
+ connect(
343
+ (state, props) => ({
344
+ content: state.content.data,
345
+ data_query: state.content.data.data_query,
346
+ }),
347
+ {
348
+ getContent,
349
+ },
350
+ ),
351
+ )(LayerSelectWidget);
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Button } from 'semantic-ui-react';
3
3
  import LayerSelectWidget from './LayerSelectWidget';
4
4
 
5
- const LayersPanel = ({ data, onChange, block }) => {
5
+ const LayersPanelWidget = ({ data, onChange, block }) => {
6
6
  const map_layers = React.useMemo(() => data.map_layers || [], [
7
7
  data.map_layers,
8
8
  ]);
@@ -55,4 +55,4 @@ const LayersPanel = ({ data, onChange, block }) => {
55
55
  );
56
56
  };
57
57
 
58
- export default LayersPanel;
58
+ export default LayersPanelWidget;
@@ -1,19 +1,20 @@
1
1
  import React from 'react';
2
2
  import { Grid } from 'semantic-ui-react';
3
- import { fetchArcgisData } from '../../utils';
3
+ import { fetchArcGISData, setLegendColumns } from '../../utils';
4
4
  import { Icon } from '@plone/volto/components';
5
+ import { serializeNodes } from 'volto-slate/editor/render';
5
6
 
6
7
  import rightKeySVG from '@plone/volto/icons/right-key.svg';
7
8
  import downKeySVG from '@plone/volto/icons/down-key.svg';
9
+ import { withDeviceSize } from '../../hocs';
8
10
 
9
11
  const LayerLegend = ({ data }) => {
10
- const [expand, setExpand] = React.useState(true);
11
12
  const [legendRows, setLegendRows] = React.useState([]);
12
13
 
13
14
  const { id, name } = data.layer || {};
14
15
 
15
16
  const fetchLegend = async (url, activeLayerID) => {
16
- let legendData = await fetchArcgisData(url);
17
+ let legendData = await fetchArcGISData(url);
17
18
 
18
19
  const { layers = [] } = legendData;
19
20
  const selectedLayer = layers.filter((l, i) => l.layerId === activeLayerID);
@@ -27,27 +28,18 @@ const LayerLegend = ({ data }) => {
27
28
  // eslint-disable-next-line react-hooks/exhaustive-deps
28
29
  }, [id, data.map_service_url]);
29
30
  return (
30
- <div style={{ display: 'flex', flexDirection: 'column' }}>
31
+ <Grid.Column>
31
32
  <h5
32
- role="presentation"
33
- onClick={() => setExpand(!expand)}
34
33
  style={{
35
34
  marginTop: '15px',
36
35
  marginBottom: '5px',
37
- cursor: 'pointer',
38
- display: 'flex',
39
36
  }}
40
37
  >
41
- <Icon
42
- name={expand ? downKeySVG : rightKeySVG}
43
- title={expand ? 'Collapse' : 'Expand'}
44
- size="17px"
45
- />
46
38
  {name}
47
39
  </h5>
40
+ {data.description && serializeNodes(data.description)}
48
41
  <div style={{ display: 'flex', flexDirection: 'column' }}>
49
- {expand &&
50
- legendRows.length > 0 &&
42
+ {legendRows.length > 0 &&
51
43
  legendRows.map((item, i) => {
52
44
  return (
53
45
  <span key={i} style={{ display: 'flex', alignItems: 'center' }}>
@@ -62,39 +54,61 @@ const LayerLegend = ({ data }) => {
62
54
  );
63
55
  })}
64
56
  </div>
65
- </div>
57
+ </Grid.Column>
66
58
  );
67
59
  };
68
60
 
69
61
  const LegendWidget = (props) => {
70
62
  const data = React.useMemo(() => props.data, [props.data]);
63
+ const { device = '' } = props;
64
+
65
+ const [expand, setExpand] = React.useState(true);
66
+
71
67
  const { layers = {} } = data;
72
- const { map_layers = [] } = layers;
68
+ const map_layers =
69
+ layers &&
70
+ layers.map_layers &&
71
+ layers.map_layers.length > 0 &&
72
+ layers.map_layers.length > 3
73
+ ? layers?.map_layers.slice(0, 3)
74
+ : layers?.map_layers;
73
75
 
76
+ const legendColumns =
77
+ map_layers && setLegendColumns(map_layers.length, device);
74
78
  return (
75
79
  <>
76
- <div style={{ margin: '10px 0' }}>
77
- <Grid>
78
- <Grid.Row>
79
- <Grid.Column>
80
- <h4>Legend:</h4>
81
- {map_layers.length === 0 && (
82
- <p>
83
- No layer found for legend. Please add a map layer from editor.
84
- </p>
85
- )}
86
-
80
+ <div className="legend-container">
81
+ <h4
82
+ role="presentation"
83
+ className="legend-title"
84
+ onClick={() => setExpand(!expand)}
85
+ >
86
+ <Icon
87
+ name={expand ? downKeySVG : rightKeySVG}
88
+ title={expand ? 'Collapse' : 'Expand'}
89
+ size="17px"
90
+ />
91
+ Legend:
92
+ </h4>
93
+ <Grid columns={legendColumns}>
94
+ {(!map_layers || map_layers.length === 0) && (
95
+ <p>
96
+ No layer found for legend. Please add a map layer from editor.
97
+ </p>
98
+ )}
99
+ {expand && (
100
+ <Grid.Row divided>
87
101
  {map_layers &&
88
102
  map_layers.length > 0 &&
89
103
  map_layers.map((l, i) => (
90
104
  <LayerLegend key={i} data={l.map_layer} />
91
105
  ))}
92
- </Grid.Column>
93
- </Grid.Row>
106
+ </Grid.Row>
107
+ )}
94
108
  </Grid>
95
109
  </div>
96
110
  </>
97
111
  );
98
112
  };
99
113
 
100
- export default React.memo(LegendWidget);
114
+ export default withDeviceSize(React.memo(LegendWidget));
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Modal, Button, Grid } from 'semantic-ui-react';
3
3
  import Webmap from '../Webmap';
4
+
4
5
  import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
5
6
 
6
7
  import PanelsSchema from './panelsSchema';
@@ -37,7 +38,6 @@ const MapEditorWidget = (props) => {
37
38
  };
38
39
 
39
40
  let schema = PanelsSchema({ data: dataForm });
40
-
41
41
  return (
42
42
  <FormFieldWrapper {...props}>
43
43
  <Modal