@eeacms/volto-marine-policy 2.0.2 → 2.0.4

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 (40) hide show
  1. package/CHANGELOG.md +65 -1
  2. package/jest-addon.config.js +4 -4
  3. package/package.json +9 -8
  4. package/src/components/Blocks/DemoSitesExplorer/DemoSitesExplorerEdit.js +5 -0
  5. package/src/components/Blocks/DemoSitesExplorer/DemoSitesExplorerView.js +115 -0
  6. package/src/components/Blocks/DemoSitesExplorer/DemoSitesFilters.jsx +406 -0
  7. package/src/components/Blocks/DemoSitesExplorer/DemoSitesFilters.test.jsxZ +91 -0
  8. package/src/components/Blocks/DemoSitesExplorer/DemoSitesListing.jsx +383 -0
  9. package/src/components/Blocks/DemoSitesExplorer/DemoSitesMap.jsx +230 -0
  10. package/src/components/Blocks/DemoSitesExplorer/FeatureDisplay.jsx +97 -0
  11. package/src/components/Blocks/DemoSitesExplorer/FeatureDisplay.test.jsxZ +48 -0
  12. package/src/components/Blocks/DemoSitesExplorer/FeatureInteraction.jsx +95 -0
  13. package/src/components/Blocks/DemoSitesExplorer/InfoOverlay.jsx +79 -0
  14. package/src/components/Blocks/DemoSitesExplorer/hooks.js +20 -0
  15. package/src/components/Blocks/DemoSitesExplorer/images/icon-depth.png +0 -0
  16. package/src/components/Blocks/DemoSitesExplorer/images/icon-light.png +0 -0
  17. package/src/components/Blocks/DemoSitesExplorer/images/search.svg +3 -0
  18. package/src/components/Blocks/DemoSitesExplorer/index.js +16 -0
  19. package/src/components/Blocks/DemoSitesExplorer/mockJsdom.js +8 -0
  20. package/src/components/Blocks/DemoSitesExplorer/styles.less +376 -0
  21. package/src/components/Blocks/DemoSitesExplorer/utils.js +193 -0
  22. package/src/components/Blocks/DemoSitesExplorer/utils.test.jsZ +63 -0
  23. package/src/components/index.js +1 -0
  24. package/src/components/theme/DatabaseItemView/DatabaseItemView.jsx +0 -1
  25. package/src/express-middleware.js +37 -0
  26. package/src/index.js +13 -12
  27. package/theme/extras/print.less +64 -0
  28. package/theme/globals/site.overrides +11 -6
  29. package/theme/globals/site.variables +1 -0
  30. package/src/components/Blocks/ContextNavigation/Accordion.jsx +0 -85
  31. package/src/components/Blocks/ContextNavigation/Accordion.test.jsx +0 -106
  32. package/src/components/Blocks/ContextNavigation/AccordionContent.jsx +0 -66
  33. package/src/components/Blocks/ContextNavigation/ContextNavigation.jsx +0 -41
  34. package/src/components/Blocks/ContextNavigation/Edit.jsx +0 -41
  35. package/src/components/Blocks/ContextNavigation/Edit.test.jsx +0 -71
  36. package/src/components/Blocks/ContextNavigation/View.jsx +0 -42
  37. package/src/components/Blocks/ContextNavigation/View.test.jsx +0 -71
  38. package/src/components/Blocks/ContextNavigation/index.js +0 -25
  39. package/src/components/Blocks/ContextNavigation/schema.js +0 -43
  40. package/src/components/Blocks/ContextNavigation/styles.less +0 -65
@@ -0,0 +1,376 @@
1
+ .section-nwrm-case-studies .listing .slot-top {
2
+ padding-top: 2em;
3
+ }
4
+
5
+ #csepopup > span {
6
+ display: 'block';
7
+ margin-bottom: '10px';
8
+ background-color: '#ddd';
9
+ }
10
+
11
+ .ol-map-wrapper,
12
+ .ol-map {
13
+ height: 600px;
14
+ min-height: 600px;
15
+ }
16
+
17
+ #csepopup {
18
+ // width: 300px;
19
+ width: 100%;
20
+ // height: 100%;
21
+ padding: 1em;
22
+ // border: 1px solid black;
23
+ // font-size: 14px;
24
+ // line-height: initial;
25
+ font-size: 1rem;
26
+
27
+ a:hover {
28
+ color: #0083e0;
29
+ }
30
+
31
+ h3 {
32
+ font-size: 1.4rem;
33
+ }
34
+
35
+ h4 {
36
+ margin: 0px;
37
+ }
38
+
39
+ div {
40
+ margin-bottom: 16px;
41
+ }
42
+
43
+ ul {
44
+ margin: 0px;
45
+
46
+ li {
47
+ line-height: 22px;
48
+ }
49
+ }
50
+
51
+ p {
52
+ font-size: 13px;
53
+
54
+ p {
55
+ margin-bottom: 10px;
56
+ }
57
+ }
58
+
59
+ span.blue {
60
+ color: #069;
61
+ }
62
+
63
+ span.popup-title {
64
+ font-weight: bold;
65
+ }
66
+
67
+ span.img {
68
+ display: block;
69
+ margin-bottom: 10px;
70
+ background-color: #ddd;
71
+
72
+ img {
73
+ max-height: 133px;
74
+ }
75
+ }
76
+ }
77
+
78
+ .ol-overlaycontainer {
79
+ // width: 370px;
80
+ // height: 100%;
81
+
82
+ .ol-overlay-container {
83
+ // position: relative !important;
84
+ position: absolute !important;
85
+ right: 30px;
86
+ bottom: 30px;
87
+ display: block !important;
88
+ // width: 100%;
89
+ // height: 100%;
90
+ background-color: #dae8f4;
91
+
92
+ #popup-overlay {
93
+ position: relative !important;
94
+ display: flex;
95
+ width: 100%;
96
+ height: 100%;
97
+ align-items: center;
98
+ }
99
+ }
100
+ }
101
+
102
+ #cse-filter {
103
+ display: flex;
104
+ flex-direction: row;
105
+ margin-top: 1em;
106
+ font-family: sans-serif;
107
+ // gap: 3em;
108
+
109
+ .filter-wrapper {
110
+ // flex-grow: 1;
111
+
112
+ &.active {
113
+ button span {
114
+ // box-shadow: 0 5px 0 #ffffff, 0 0 4px rgba(0, 0, 0, 0.25);
115
+ color: #0083e0;
116
+ }
117
+
118
+ button {
119
+ box-shadow:
120
+ 0 5px 0 #ffffff,
121
+ 0 0 4px rgba(0, 0, 0, 0.25) !important;
122
+ }
123
+
124
+ .filter-inputs-wrapper {
125
+ display: block;
126
+ }
127
+ }
128
+
129
+ .ri-arrow-down-s-line:before {
130
+ content: '\ea4e';
131
+ }
132
+
133
+ .ui.basic.button.facet-btn {
134
+ position: relative !important;
135
+ z-index: 99999;
136
+ display: inline-block;
137
+ overflow: hidden;
138
+ padding: 0.5em 0em;
139
+ margin: 0 0.25em 0.25em 0;
140
+ background-color: white !important;
141
+ color: #3d5265 !important;
142
+
143
+ &:active {
144
+ background: white !important;
145
+ }
146
+
147
+ // &:hover,
148
+ // &:focus {
149
+ // color: rgba(0, 0, 0, 0.6) !important;
150
+ // }
151
+ &:hover {
152
+ box-shadow: none;
153
+ }
154
+
155
+ span {
156
+ position: relative !important;
157
+ z-index: 99999;
158
+ display: inline-block;
159
+ overflow: hidden;
160
+ padding: 0.5em 1em;
161
+ background-color: white;
162
+ }
163
+ }
164
+
165
+ .filter-inputs-wrapper {
166
+ position: absolute;
167
+ z-index: 1;
168
+ display: none;
169
+ padding: 1em;
170
+ margin-top: -3px;
171
+ background-color: #fff;
172
+ box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
173
+ color: #4f4f4f;
174
+
175
+ .filterInputText {
176
+ padding: 6px;
177
+ border: 0.5px solid #c4c4c4;
178
+ border-radius: 0;
179
+ margin-bottom: 0.7em;
180
+ font-size: 14px;
181
+ }
182
+
183
+ .filter-inputs {
184
+ overflow: auto;
185
+ min-width: 200px;
186
+ max-width: 400px;
187
+ max-height: 200px;
188
+
189
+ &::-webkit-scrollbar {
190
+ width: 8px;
191
+ height: 0.3rem !important;
192
+ }
193
+
194
+ &::-webkit-scrollbar-track {
195
+ border-radius: 10px;
196
+ background-color: #d9d9d9;
197
+ }
198
+
199
+ &::-webkit-scrollbar-thumb {
200
+ border-radius: 10px;
201
+ background: #004b7f;
202
+ }
203
+
204
+ .filter-input {
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: flex-start;
208
+ cursor: pointer;
209
+ font-size: 14px;
210
+
211
+ span {
212
+ padding-right: 5px;
213
+ }
214
+
215
+ input {
216
+ margin-right: 8px;
217
+ cursor: pointer;
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ h4 {
225
+ position: relative;
226
+ padding: 10px;
227
+ border-bottom: 1px solid #d8d8d8;
228
+ margin-bottom: 0 !important;
229
+ background-color: #005c96;
230
+ color: #fff;
231
+ cursor: pointer;
232
+ font-size: 14px;
233
+ }
234
+ }
235
+
236
+ .active-filter-list {
237
+ border: 1px solid #e6e7e8;
238
+ background-color: #f9f9f9 !important;
239
+
240
+ .filter-list-header {
241
+ display: flex;
242
+ align-items: center;
243
+ gap: 1em;
244
+
245
+ h4 {
246
+ margin: 0;
247
+ color: #3d5265;
248
+ }
249
+ }
250
+
251
+ .filter-list-content {
252
+ padding: 1em 0 0;
253
+ background-color: transparent;
254
+
255
+ .filter {
256
+ display: flex;
257
+ flex-wrap: wrap;
258
+ font-size: 15px;
259
+
260
+ .filter-wrapper {
261
+ display: flex;
262
+ flex-direction: row;
263
+ flex-wrap: wrap;
264
+ align-items: baseline;
265
+ padding: 8px 15px;
266
+ margin-top: 10px;
267
+ margin-right: 11px;
268
+ background-color: #ebebeb;
269
+ gap: 1em;
270
+
271
+ .filter-label {
272
+ font-weight: 500;
273
+ }
274
+
275
+ .filter-value {
276
+ position: relative;
277
+ display: flex;
278
+ align-items: center;
279
+ padding: 0;
280
+ border: none;
281
+ margin: 0;
282
+ background-color: transparent;
283
+ font-size: 15px;
284
+
285
+ .close.icon {
286
+ position: relative;
287
+ width: 16px;
288
+ height: 16px;
289
+ padding: 3px;
290
+ border: 1px solid #004b7f !important;
291
+ border-radius: 2px;
292
+ color: #2e3e4c;
293
+ opacity: 1;
294
+
295
+ &:before,
296
+ &:after {
297
+ position: absolute;
298
+ top: 2px;
299
+ left: 7px;
300
+ width: 1px;
301
+ height: 9px;
302
+ background-color: #004b7f !important;
303
+ content: ' ';
304
+ }
305
+
306
+ &:before {
307
+ transform: rotate(45deg);
308
+ }
309
+
310
+ &:after {
311
+ transform: rotate(-45deg);
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
319
+
320
+ .sui-search-box .search-input .terms-box .terms-box-left .search-icon img {
321
+ fill: #004b7f !important;
322
+ }
323
+
324
+ .searchlib-block .ui.basic.button.clear-btn {
325
+ color: #0083e0 !important;
326
+ }
327
+
328
+ .searchlib-block .result-item .result-info {
329
+ align-items: center;
330
+
331
+ &.show-on-map {
332
+ color: #0083e0 !important;
333
+ cursor: pointer;
334
+
335
+ .result-info-title {
336
+ color: #0083e0 !important;
337
+ }
338
+ }
339
+ }
340
+
341
+ .u-item.listing-item .result-info a {
342
+ color: #0077bc;
343
+ }
344
+
345
+ .searchlib-block .search-body-footer {
346
+ margin-top: 2em;
347
+ }
348
+
349
+ .reset-map-button.ui.button.secondary {
350
+ position: absolute;
351
+ z-index: 2;
352
+ top: 1.3em;
353
+ right: 0.7em;
354
+ display: flex;
355
+ padding: 8px 6px 8px 12px;
356
+ border: 4px solid #efefef;
357
+ border-radius: 2px;
358
+ background-color: #0083e0;
359
+ gap: 0.5em;
360
+ opacity: 0.6;
361
+
362
+ &.active {
363
+ display: flex;
364
+ }
365
+
366
+ &.inactive {
367
+ display: none;
368
+ }
369
+ }
370
+
371
+ .ol-zoom.ol-control {
372
+ .ol-zoom-in,
373
+ .ol-zoom-out {
374
+ background-color: rgba(0, 131, 224, 0.5);
375
+ }
376
+ }
@@ -0,0 +1,193 @@
1
+ import { openlayers as ol } from '@eeacms/volto-openlayers-map';
2
+
3
+ export function isValidURL(string) {
4
+ try {
5
+ new URL(string);
6
+ return true;
7
+ } catch (e) {
8
+ return false;
9
+ }
10
+ }
11
+
12
+ export function centerAndResetMapZoom(map) {
13
+ map.getView().animate({
14
+ zoom: 2.5,
15
+ duration: 1000,
16
+ center: ol.proj.transform([10, 54], 'EPSG:4326', 'EPSG:3857'),
17
+ });
18
+ }
19
+
20
+ export function scrollToElement(elementId) {
21
+ const element = document.getElementById(elementId);
22
+ element.scrollIntoView({
23
+ behavior: 'smooth',
24
+ });
25
+ }
26
+
27
+ export function getExtentOfFeatures(features) {
28
+ const points = features.map((f) => f.getGeometry().flatCoordinates);
29
+ const point = new ol.geom.MultiPoint(points);
30
+ return point.getExtent();
31
+ }
32
+
33
+ export function zoomMapToFeatures(map, features, threshold = 500) {
34
+ const extent = getExtentOfFeatures(features);
35
+ let extentBuffer = (extent[3] - extent[1] + extent[2] - extent[0]) / 4;
36
+ extentBuffer = extentBuffer < threshold ? threshold : extentBuffer;
37
+ const paddedExtent = ol.extent.buffer(extent, extentBuffer);
38
+ map.getView().fit(paddedExtent, { ...map.getSize(), duration: 1000 });
39
+ }
40
+
41
+ export function getFeatures(cases) {
42
+ const Feature = ol.ol.Feature;
43
+
44
+ return cases.map((c, index) => {
45
+ const {
46
+ geometry: { coordinates },
47
+ } = c;
48
+ const point = new Feature(
49
+ new ol.geom.Point(ol.proj.fromLonLat(coordinates)),
50
+ );
51
+ point.setId(index);
52
+ point.setProperties(
53
+ {
54
+ title: c.properties.title,
55
+ image: c.properties.image,
56
+ project: c.properties.project,
57
+ project_link: c.properties.project_link,
58
+ country: c.properties.country,
59
+ type_is_region: c.properties.type_is_region,
60
+ type: c.properties.type,
61
+ indicators: c.properties.indicators,
62
+ info: c.properties.info,
63
+ website: c.properties.website,
64
+ objective: c.properties.objective,
65
+ description: c.properties.description,
66
+ index: index,
67
+ path: c.properties.path,
68
+ color: c.properties.nwrm_type === 'Light' ? '#50B0A4' : '#0083E0',
69
+ },
70
+ false,
71
+ );
72
+ return point;
73
+ });
74
+ }
75
+
76
+ export function filterCases(cases, activeFilters, demoSitesIds, searchInput) {
77
+ const data = cases.filter((_case) => {
78
+ let flag_searchInput = false;
79
+ let flag_objective = false;
80
+ // let flag_indicator = false;
81
+ let flag_project = false;
82
+ let flag_country = false;
83
+ let flag_case = demoSitesIds
84
+ ? demoSitesIds.includes(_case.properties.url.split('/').pop())
85
+ : true;
86
+
87
+ if (!searchInput) {
88
+ flag_searchInput = true;
89
+ } else {
90
+ if (_case.properties.title.toLowerCase().match(searchInput)) {
91
+ flag_searchInput = true;
92
+ // } else if (
93
+ // _case.properties.description.toLowerCase().match(searchInput)
94
+ // ) {
95
+ // flag_searchInput = true;
96
+ }
97
+ }
98
+
99
+ // debugger;
100
+ if (!activeFilters.objective_filter.length) {
101
+ flag_objective = true;
102
+ } else {
103
+ let objective = _case.properties.objective?.map((item) => {
104
+ return item['id'].toString();
105
+ });
106
+
107
+ activeFilters.objective_filter.forEach((filter) => {
108
+ if (objective?.includes(filter)) flag_objective = true;
109
+ });
110
+ }
111
+
112
+ // if (!activeFilters.sectors.length) {
113
+ // flag_sectors = true;
114
+ // } else {
115
+ // let sectors = _case.properties.sectors?.map((item) => {
116
+ // return item.toString();
117
+ // });
118
+
119
+ // activeFilters.sectors.forEach((filter) => {
120
+ // if (sectors?.includes(filter)) flag_sectors = true;
121
+ // });
122
+ // }
123
+
124
+ if (!activeFilters.project_filter.length) {
125
+ flag_project = true;
126
+ } else {
127
+ let project = _case.properties.project;
128
+
129
+ activeFilters.project_filter.forEach((filter) => {
130
+ if (project === filter) flag_project = true;
131
+ });
132
+ }
133
+
134
+ if (!activeFilters.country_filter.length) {
135
+ flag_country = true;
136
+ } else {
137
+ let countries = _case.properties.country?.map((item) => {
138
+ return item.toString();
139
+ });
140
+
141
+ activeFilters.country_filter.forEach((filter) => {
142
+ if (countries?.includes(filter)) flag_country = true;
143
+ });
144
+ }
145
+
146
+ return flag_case &&
147
+ flag_objective &&
148
+ flag_country &&
149
+ flag_project &&
150
+ flag_searchInput
151
+ ? _case
152
+ : false;
153
+ });
154
+
155
+ return data;
156
+ }
157
+
158
+ export function getFilters(cases) {
159
+ let _filters = {
160
+ objective_filter: {},
161
+ indicator_filter: {},
162
+ project_filter: {},
163
+ country_filter: {},
164
+ };
165
+
166
+ for (let key of Object.keys(cases)) {
167
+ const _case = cases[key];
168
+ // debugger;
169
+ // let nwrms_implemented = _case.properties.measures;
170
+ // nwrms_implemented.map((item) => {
171
+ // if (!_filters.nwrms_implemented.hasOwnProperty(item['id'])) {
172
+ // _filters.nwrms_implemented[item['id']] = item['title'];
173
+ // }
174
+ // return [];
175
+ // });
176
+
177
+ let project = _case.properties.project;
178
+
179
+ if (!_filters.project_filter.hasOwnProperty(project)) {
180
+ _filters.project_filter[project] = project;
181
+ }
182
+
183
+ let countries = _case.properties.country;
184
+ countries.map((item) => {
185
+ if (!_filters.country_filter.hasOwnProperty(item)) {
186
+ _filters.country_filter[item] = item;
187
+ }
188
+ return [];
189
+ });
190
+ }
191
+
192
+ return _filters;
193
+ }
@@ -0,0 +1,63 @@
1
+ import './mockJsdom';
2
+ import '@testing-library/jest-dom/extend-expect';
3
+ import { getFeatures, filterCases, getFilters } from './utils';
4
+
5
+ describe('utils.js', () => {
6
+ const mockCases = [
7
+ {
8
+ geometry: { coordinates: [0, 0] },
9
+ properties: {
10
+ title: 'test case study',
11
+ image: '',
12
+ nwrm_type: 'light',
13
+ measures: [{ id: 'test-measure1', title: 'test measure 1' }],
14
+ description: 'test',
15
+ sectors: ['testsector'],
16
+ path: '/test-case-study',
17
+ url: 'localhost.com/test-case-study',
18
+ },
19
+ },
20
+ {
21
+ geometry: { coordinates: [0, 0] },
22
+ properties: {
23
+ title: 'case study 2',
24
+ image: '',
25
+ nwrm_type: 'light',
26
+ measures: [{ id: 'test-measure1', title: 'test measure 1' }],
27
+ description: 'test',
28
+ sectors: ['testsector'],
29
+ path: '/test-case-study',
30
+ url: 'localhost.com/test-case-study',
31
+ },
32
+ },
33
+ ];
34
+
35
+ test('getFeatures', () => {
36
+ expect(() => {
37
+ getFeatures(mockCases);
38
+ }).not.toThrowError();
39
+ });
40
+
41
+ test('filterCases', () => {
42
+ const mockActiveFilters = {
43
+ nwrms_implemented: ['test measure 1'],
44
+ sectors: ['testsector'],
45
+ };
46
+ const mockDemoSitesIds = ['test-case-study'];
47
+ const mockCasesFiltered = filterCases(
48
+ mockCases,
49
+ mockActiveFilters,
50
+ mockDemoSitesIds,
51
+ 'test',
52
+ );
53
+ expect(mockCasesFiltered).toStrictEqual([]);
54
+ });
55
+
56
+ test('getFilters', () => {
57
+ const mockFilters = getFilters(mockCases);
58
+ expect(mockFilters).toStrictEqual({
59
+ nwrms_implemented: { 'test-measure1': 'test measure 1' },
60
+ sectors: { testsector: 'testsector' },
61
+ });
62
+ });
63
+ });
@@ -13,3 +13,4 @@ export TableauShare from './theme/Tableau/TableauShare';
13
13
  export TableauFullscreen from './theme/Tableau/TableauFullscreen';
14
14
  export ItemMetadataSnippet from './theme/ItemMetadata/ItemMetadataSnippet';
15
15
  export MapPreview from './theme/MetadataListingView/MapPreview';
16
+ export DemoSitesExplorer from './Blocks/DemoSitesExplorer/DemoSitesExplorerView';
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { BodyClass } from '@plone/volto/helpers';
3
2
  import {
4
3
  ItemMetadataSnippet,
@@ -0,0 +1,37 @@
1
+ import express from 'express';
2
+ import { getAPIResourceWithAuth } from '@plone/volto/helpers';
3
+
4
+ const HEADERS = [
5
+ 'Accept-Ranges',
6
+ 'Cache-Control',
7
+ 'Content-Disposition',
8
+ 'Content-Range',
9
+ 'Content-Type',
10
+ ];
11
+
12
+ function viewMiddleware(req, res, next) {
13
+ getAPIResourceWithAuth(req)
14
+ .then((resource) => {
15
+ // Just forward the headers that we need
16
+ HEADERS.forEach((header) => {
17
+ if (resource.get(header)) {
18
+ res.set(header, resource.get(header));
19
+ }
20
+ });
21
+ res.status(resource.statusCode);
22
+ res.send(resource.body);
23
+ })
24
+ .catch(next);
25
+ }
26
+
27
+ export default function middleware(config) {
28
+ const middleware = express.Router();
29
+
30
+ // TODO: do we want catch all?
31
+ // middleware.all(['**/@@*'], viewMiddleware);
32
+
33
+ middleware.all(['**/@@demo-sites-map.arcgis.json'], viewMiddleware);
34
+ middleware.id = 'viewsMiddleware';
35
+ config.settings.expressMiddleware.push(middleware);
36
+ return config;
37
+ }