@eeacms/volto-marine-policy 2.0.6 → 2.0.8

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [2.0.8](https://github.com/eea/volto-marine-policy/compare/2.0.7...2.0.8) - 16 April 2025
8
+
9
+ #### :house: Internal changes
10
+
11
+ - style: Automated code fix [eea-jenkins - [`c400842`](https://github.com/eea/volto-marine-policy/commit/c4008422b3480259c2a1101994c544b44e5b9002)]
12
+
13
+ #### :hammer_and_wrench: Others
14
+
15
+ - eslint [laszlocseh - [`ebdba1e`](https://github.com/eea/volto-marine-policy/commit/ebdba1e06ed02f3bf03442dfd578f2c1db5b1241)]
16
+ - demo sites map viewer zoom improvements [laszlocseh - [`1680f64`](https://github.com/eea/volto-marine-policy/commit/1680f644f00e1bf62e1a5471aaf25a95d152ba05)]
17
+ ### [2.0.7](https://github.com/eea/volto-marine-policy/compare/2.0.6...2.0.7) - 15 April 2025
18
+
19
+ #### :house: Internal changes
20
+
21
+ - style: Automated code fix [eea-jenkins - [`cb0de80`](https://github.com/eea/volto-marine-policy/commit/cb0de8004429b3dbeee35a1a35c098bec9ee5f4c)]
22
+ - style: Automated code fix [eea-jenkins - [`c91d18b`](https://github.com/eea/volto-marine-policy/commit/c91d18b6ee31c0a7406d41c69693f4cca87ffb2a)]
23
+
24
+ #### :hammer_and_wrench: Others
25
+
26
+ - pylint [laszlocseh - [`20a0b87`](https://github.com/eea/volto-marine-policy/commit/20a0b87ceda212c7cf9a6d2681e21dfe2546f881)]
27
+ - improvements to demo sites map viewer [laszlocseh - [`501420b`](https://github.com/eea/volto-marine-policy/commit/501420b5c8373f6bc79f31947a2275921ccd9dcf)]
7
28
  ### [2.0.6](https://github.com/eea/volto-marine-policy/compare/2.0.5...2.0.6) - 14 April 2025
8
29
 
9
30
  #### :house: Internal changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-marine-policy",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "@eeacms/volto-marine-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -74,7 +74,7 @@ export default function DemoSitesExplorerView(props) {
74
74
  <Grid.Row>
75
75
  {cases.length ? (
76
76
  <Grid columns={12}>
77
- <Grid.Column mobile={12} tablet={12} computer={12}>
77
+ <Grid.Column mobile={10} tablet={10} computer={10}>
78
78
  <DemoSitesMap
79
79
  items={cases}
80
80
  activeItems={activeItems}
@@ -85,6 +85,23 @@ export default function DemoSitesExplorerView(props) {
85
85
  setMap={setMap}
86
86
  />
87
87
  </Grid.Column>
88
+ <Grid.Column mobile={2} tablet={2} computer={2}>
89
+ <div className="legend">
90
+ <div className="legend-row legend-subtitle">Legend</div>
91
+ <div className="legend-row">
92
+ <div className="circle">
93
+ <div className="dot-demosite"></div>
94
+ </div>
95
+ <div>Demo site</div>
96
+ </div>
97
+ <div className="legend-row">
98
+ <div className="circle">
99
+ <div className="dot-region"></div>
100
+ </div>
101
+ <div>Associated region</div>
102
+ </div>
103
+ </div>
104
+ </Grid.Column>
88
105
  </Grid>
89
106
  ) : null}
90
107
  </Grid.Row>
@@ -23,6 +23,21 @@ export function DemoSitesFilter(props) {
23
23
  map,
24
24
  } = props;
25
25
 
26
+ const customOrder = props?.customOrder || [];
27
+ const entries = Object.entries(filters?.[filterName] || {});
28
+ let sortedEntries = [];
29
+
30
+ if (customOrder.length > 0) {
31
+ sortedEntries = entries.sort(
32
+ (a, b) => customOrder.indexOf(a[0]) - customOrder.indexOf(b[0]),
33
+ );
34
+ // if(entries.length > 0 ) debugger;
35
+ } else {
36
+ sortedEntries = entries.sort((a, b) => a[1].localeCompare(b[1]));
37
+ }
38
+ const sortedData = Object.fromEntries(sortedEntries);
39
+ filters[filterName] = sortedData;
40
+
26
41
  const showInputs = (event) => {
27
42
  event.currentTarget.parentElement.classList.add('active');
28
43
  };
@@ -65,7 +80,7 @@ export function DemoSitesFilter(props) {
65
80
 
66
81
  <div className="filter-inputs">
67
82
  {Object.entries(filters?.[filterName] || {})
68
- .sort((item1, item2) => item1[1].localeCompare(item2[1]))
83
+ // .sort((item1, item2) => item1[1].localeCompare(item2[1]))
69
84
  .map(([value, label], index) => (
70
85
  <label
71
86
  htmlFor={label + index}
@@ -119,12 +134,19 @@ export function DemoSitesFilters(props) {
119
134
  <>
120
135
  {!hideFilters ? (
121
136
  <DemoSitesFilter
122
- filterTitle="Objective"
137
+ filterTitle="Objective/Enabler"
123
138
  filterName="objective_filter"
124
139
  filters={filters}
125
140
  activeFilters={activeFilters}
126
141
  setActiveFilters={setActiveFilters}
127
142
  map={map}
143
+ customOrder={[
144
+ 'Protect and restore marine and freshwater ecosystems',
145
+ 'Prevent and eliminate pollution of waters',
146
+ 'Carbon-neutral and circular blue economy',
147
+ 'Digital twin of the ocean',
148
+ 'Public mobilisation and engagement',
149
+ ]}
128
150
  />
129
151
  ) : (
130
152
  ''
@@ -9,7 +9,7 @@ import InfoOverlay from './InfoOverlay';
9
9
  import FeatureInteraction from './FeatureInteraction';
10
10
  import { useMapContext } from '@eeacms/volto-openlayers-map/api';
11
11
 
12
- import { centerAndResetMapZoom, getFeatures } from './utils';
12
+ import { centerAndResetMapZoom, getFeatures, zoomMapToFeatures } from './utils';
13
13
 
14
14
  const styleCache = {};
15
15
  const MapContextGateway = ({ setMap }) => {
@@ -54,17 +54,20 @@ export default function DemoSitesMap(props) {
54
54
 
55
55
  const [clusterSource] = React.useState(
56
56
  new ol.source.Cluster({
57
- distance: 19,
57
+ distance: 0,
58
58
  source: pointsSource,
59
59
  }),
60
60
  );
61
61
 
62
62
  React.useEffect(() => {
63
+ if (!map) return null;
64
+
63
65
  if (activeItems) {
64
66
  pointsSource.clear();
65
67
  pointsSource.addFeatures(getFeatures(activeItems));
68
+ hideFilters && zoomMapToFeatures(map, getFeatures(activeItems));
66
69
  }
67
- }, [activeItems, pointsSource]);
70
+ }, [map, activeItems, pointsSource, hideFilters]);
68
71
 
69
72
  React.useEffect(() => {
70
73
  if (!map) return null;
@@ -134,7 +137,11 @@ export default function DemoSitesMap(props) {
134
137
  onClick={() => {
135
138
  // scrollToElement('search-input');
136
139
  onSelectedCase(null);
137
- centerAndResetMapZoom(map);
140
+ if (hideFilters) {
141
+ zoomMapToFeatures(map, getFeatures(activeItems));
142
+ } else {
143
+ centerAndResetMapZoom(map);
144
+ }
138
145
  map.getInteractions().array_[9].getFeatures().clear();
139
146
  }}
140
147
  >
@@ -168,10 +175,10 @@ export default function DemoSitesMap(props) {
168
175
  const selectedClusterStyle = (selectedFeature) => {
169
176
  function _clusterStyle(feature, selectedFeature) {
170
177
  const size = feature.get('features').length;
171
- let style = styleCache[size];
178
+ let clusterStyle = styleCache[size];
172
179
 
173
- if (!style) {
174
- style = new ol.style.Style({
180
+ if (!clusterStyle) {
181
+ clusterStyle = new ol.style.Style({
175
182
  image: new ol.style.Circle({
176
183
  radius: 12 + Math.min(Math.floor(size / 3), 10),
177
184
  stroke: new ol.style.Stroke({
@@ -189,10 +196,10 @@ const selectedClusterStyle = (selectedFeature) => {
189
196
  }),
190
197
  }),
191
198
  });
192
- styleCache[size] = style;
199
+ styleCache[size] = clusterStyle;
193
200
  }
194
-
195
- if (size === 1) {
201
+ // set size === 1 to enable clusterization
202
+ if (size) {
196
203
  let color = feature.values_.features[0].values_['color'];
197
204
  let width = feature.values_.features[0].values_['width'];
198
205
  let radius = feature.values_.features[0].values_['radius'];
@@ -212,7 +219,7 @@ const selectedClusterStyle = (selectedFeature) => {
212
219
  }),
213
220
  });
214
221
  } else {
215
- return style;
222
+ return clusterStyle;
216
223
  }
217
224
  }
218
225
  return _clusterStyle;
@@ -39,13 +39,25 @@ export default function FeatureDisplay({ feature }) {
39
39
  {feature.project ? (
40
40
  <div>
41
41
  <span className="popup-title blue">Project: </span>
42
- <span>{feature.project}</span>
42
+ <span>
43
+ {isValidURL(feature.project_link) ? (
44
+ <a
45
+ href={feature.project_link}
46
+ target="_blank"
47
+ rel="noopener noreferrer"
48
+ >
49
+ {feature.project}
50
+ </a>
51
+ ) : (
52
+ <span>{feature.project}</span>
53
+ )}
54
+ </span>
43
55
  </div>
44
56
  ) : (
45
57
  ''
46
58
  )}
47
59
 
48
- {feature.project_link ? (
60
+ {/* {feature.project_link ? (
49
61
  <div>
50
62
  <span className="popup-title blue">Project link: </span>
51
63
  <span>
@@ -64,26 +76,30 @@ export default function FeatureDisplay({ feature }) {
64
76
  </div>
65
77
  ) : (
66
78
  ''
67
- )}
79
+ )} */}
68
80
 
69
- <div>
70
- <span className="popup-title blue">Indicators</span>
71
- <ul>
72
- {feature.indicators.map((item, index) => {
73
- return (
74
- <li key={index}>
75
- <a
76
- target="_blank"
77
- rel="noopener noreferrer"
78
- href={item['path']}
79
- >
80
- {item['title']}
81
- </a>
82
- </li>
83
- );
84
- })}
85
- </ul>
86
- </div>
81
+ {feature.indicators.length > 0 ? (
82
+ <div>
83
+ <span className="popup-title blue">Indicators</span>
84
+ <ul>
85
+ {feature.indicators.map((item, index) => {
86
+ return (
87
+ <li key={index}>
88
+ <a
89
+ target="_blank"
90
+ rel="noopener noreferrer"
91
+ href={item['path']}
92
+ >
93
+ {item['title']}
94
+ </a>
95
+ </li>
96
+ );
97
+ })}
98
+ </ul>
99
+ </div>
100
+ ) : (
101
+ ''
102
+ )}
87
103
  {/* <div>
88
104
  <h4>Indicators</h4>
89
105
  <ul>
@@ -27,9 +27,13 @@ export default function InfoOverlay({
27
27
 
28
28
  const overlay = new ol.Overlay({
29
29
  element: document.getElementById('popup-overlay'),
30
- positioning: 'bottom-center',
31
- offset: [0, -10],
30
+ positioning: 'bottom-left',
31
+ offset: [0, 0],
32
32
  stopEvent: false,
33
+ // autoPan: true,
34
+ // autoPanAnimation: {
35
+ // duration: 250,
36
+ // },
33
37
  });
34
38
  map.addOverlay(overlay);
35
39
 
@@ -39,8 +43,12 @@ export default function InfoOverlay({
39
43
  // const popupOverlay = overlay.element; // document.getElementById('popup-overlay');
40
44
 
41
45
  if (features.length) {
46
+ const coordinate = evt.coordinate;
47
+ overlay.setPosition(coordinate);
42
48
  setShowTooltip(true);
43
49
  } else {
50
+ // const coordinate = evt.coordinate
51
+ // overlay.setPosition(coordinate);
44
52
  // handle a click in an overlay popup
45
53
  if (evt.originalEvent.target.tagName === 'A') return;
46
54
  setShowTooltip(false);
@@ -64,7 +72,7 @@ export default function InfoOverlay({
64
72
  <div
65
73
  id="popup-overlay"
66
74
  style={{
67
- position: 'absolute',
75
+ // position: 'absolute', // TODO POPUP
68
76
  zIndex: 1,
69
77
  visibility: showTooltip ? 'visible' : 'hidden',
70
78
  }}
@@ -16,9 +16,9 @@
16
16
 
17
17
  #csepopup {
18
18
  // width: 300px;
19
- width: 100%;
19
+ // width: 100%;
20
20
  // height: 100%;
21
- padding: 1em;
21
+ padding: 1em 1em 0 1em;
22
22
  // border: 1px solid black;
23
23
  // font-size: 14px;
24
24
  // line-height: initial;
@@ -37,7 +37,7 @@
37
37
  }
38
38
 
39
39
  div {
40
- margin-bottom: 16px;
40
+ margin-bottom: 1em;
41
41
  }
42
42
 
43
43
  ul {
@@ -75,27 +75,35 @@
75
75
  }
76
76
  }
77
77
 
78
+ .ol-viewport {
79
+ overflow: visible !important;
80
+ }
81
+
78
82
  .ol-overlaycontainer {
79
83
  // width: 370px;
80
84
  // height: 100%;
85
+ z-index: 10 !important;
81
86
 
82
87
  .ol-overlay-container {
83
88
  // position: relative !important;
84
- position: absolute !important;
85
- right: 30px;
86
- bottom: 30px;
87
- display: block !important;
89
+ // TODO POPUP
90
+ // position: absolute !important;
91
+ // right: 30px;
92
+ // bottom: 30px;
93
+ // display: block !important;
88
94
  // width: 100%;
89
95
  // height: 100%;
90
- background-color: #fefefe;
91
-
92
- #popup-overlay {
93
- position: relative !important;
94
- display: flex;
95
- width: 100%;
96
- height: 100%;
97
- align-items: center;
98
- }
96
+ background-color: #fafafa;
97
+ // border: 1px solid #004B7F;
98
+
99
+ // TODO POPUP
100
+ // #popup-overlay {
101
+ // position: relative !important;
102
+ // display: flex;
103
+ // width: 100%;
104
+ // height: 100%;
105
+ // align-items: center;
106
+ // }
99
107
  }
100
108
  }
101
109
 
@@ -132,7 +140,7 @@
132
140
 
133
141
  .ui.basic.button.facet-btn {
134
142
  position: relative !important;
135
- z-index: 99999;
143
+ z-index: 9;
136
144
  display: inline-block;
137
145
  overflow: hidden;
138
146
  padding: 0.5em 0em;
@@ -154,7 +162,7 @@
154
162
 
155
163
  span {
156
164
  position: relative !important;
157
- z-index: 99999;
165
+ z-index: 9;
158
166
  display: inline-block;
159
167
  overflow: hidden;
160
168
  padding: 0.5em 1em;
@@ -317,6 +325,10 @@
317
325
  }
318
326
  }
319
327
 
328
+ .active-filter-list {
329
+ width: 100%;
330
+ }
331
+
320
332
  .sui-search-box .search-input .terms-box .terms-box-left .search-icon img {
321
333
  fill: #004b7f !important;
322
334
  }
@@ -374,3 +386,56 @@
374
386
  background-color: rgba(0, 131, 224, 0.5);
375
387
  }
376
388
  }
389
+
390
+ .legend {
391
+ position: absolute;
392
+ bottom: 2em;
393
+ display: flex;
394
+ flex-direction: column;
395
+ align-items: flex-start;
396
+ gap: 0.5em;
397
+
398
+ .legend-row {
399
+ display: flex;
400
+ align-items: center;
401
+ gap: 0.5em;
402
+ }
403
+
404
+ .legend-subtitle {
405
+ font-size: 1.3em;
406
+ font-weight: 500;
407
+ }
408
+
409
+ .circle {
410
+ position: relative;
411
+ width: 22px;
412
+ min-width: 22px;
413
+ height: 22px;
414
+ /* dark green shade */
415
+ border-radius: 50%;
416
+ background-color: #007265;
417
+ gap: 0.5em;
418
+ }
419
+
420
+ .dot-demosite {
421
+ position: absolute;
422
+ top: 50%;
423
+ left: 50%;
424
+ width: 8px;
425
+ height: 8px;
426
+ border-radius: 50%;
427
+ background-color: white;
428
+ transform: translate(-50%, -50%);
429
+ }
430
+
431
+ .dot-region {
432
+ position: absolute;
433
+ top: 50%;
434
+ left: 50%;
435
+ width: 2px;
436
+ height: 2px;
437
+ border-radius: 50%;
438
+ background-color: white;
439
+ transform: translate(-50%, -50%);
440
+ }
441
+ }
@@ -48,11 +48,11 @@ export function zoomMapToFeatures(map, features, threshold = 500) {
48
48
  export function getFeatures(cases) {
49
49
  const Feature = ol.ol.Feature;
50
50
  const colors = {
51
- 'Carbon-neutral and circular blue economy': '#004b7f',
51
+ 'Carbon-neutral and circular blue economy': '#f9eb8a',
52
52
  'Digital twin of the ocean': '#004b7f',
53
53
  'Prevent and eliminate pollution of waters': '#fdaf20',
54
54
  'Protect and restore marine and freshwater ecosystems': '#007b6c',
55
- 'Public mobilisation and engagement': '#004b7f',
55
+ 'Public mobilisation and engagement': '#9e83b6',
56
56
  };
57
57
  const width = {
58
58
  'Demo site': 6,
@@ -130,7 +130,7 @@ export function filterCases(cases, activeFilters, indicatorOnly) {
130
130
  flag_indicator = true;
131
131
  } else {
132
132
  let indicators = _case.properties.indicators?.map((item) => {
133
- return item['id'].toString();
133
+ return '_' + item['id'].toString();
134
134
  });
135
135
 
136
136
  activeFilters.indicator_filter.forEach((filter) => {
@@ -188,9 +188,10 @@ export function getFilters(cases, indicatorOnly) {
188
188
  indicators.map((item) => {
189
189
  if (
190
190
  item['title'] &&
191
- !_filters.indicator_filter.hasOwnProperty(item['id'])
191
+ item['title'] !== '0' &&
192
+ !_filters.indicator_filter.hasOwnProperty('_' + item['id'])
192
193
  ) {
193
- _filters.indicator_filter[item['id']] = item['title'];
194
+ _filters.indicator_filter['_' + item['id']] = item['title'];
194
195
  }
195
196
  return [];
196
197
  });