@eeacms/volto-cca-policy 0.1.15 → 0.1.16

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,11 +4,38 @@ 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
- ### [0.1.15](https://github.com/eea/volto-cca-policy/compare/0.1.14...0.1.15) - 27 March 2023
7
+ ### [0.1.16](https://github.com/eea/volto-cca-policy/compare/0.1.15...0.1.16) - 29 March 2023
8
8
 
9
9
  #### :hammer_and_wrench: Others
10
10
 
11
- - Retry build [Ghiță Bizău - [`d878ed0`](https://github.com/eea/volto-cca-policy/commit/d878ed0c91c7441f0f65a1caf6336de5272c9907)]
11
+ - Add whitelist for volto-nextcloud-video-block. [GhitaB - [`bb4e972`](https://github.com/eea/volto-cca-policy/commit/bb4e972fa4cdabc28f85bd902defce3906234a51)]
12
+ - Add whitelist for volto-nextcloud-video-block. [GhitaB - [`577f659`](https://github.com/eea/volto-cca-policy/commit/577f65936809f6fcb9fa6a6bacc14f7b335f9707)]
13
+ - Use UniversalLink for footer links [kreafox - [`efd34a4`](https://github.com/eea/volto-cca-policy/commit/efd34a4451b205ff5f3da022c781f425bd2f9572)]
14
+ - Make it footer contact link to work with mailto [kreafox - [`e8938dc`](https://github.com/eea/volto-cca-policy/commit/e8938dc94aa5d47998ecf505084c3ae170ed59c3)]
15
+ - Remove context navigation for RAST [kreafox - [`f85c972`](https://github.com/eea/volto-cca-policy/commit/f85c97259af58ff10b49b882eaec089cb8464f65)]
16
+ - Make footer description bold [kreafox - [`2e4184e`](https://github.com/eea/volto-cca-policy/commit/2e4184e3f8d811cdc6cd7d7732d6f8115463183f)]
17
+ - Add header override for search [kreafox - [`280489e`](https://github.com/eea/volto-cca-policy/commit/280489e6075ea31a2db4a595f681c68c0fa82b7d)]
18
+ - Set number of columns for grid block [kreafox - [`b0ef1d0`](https://github.com/eea/volto-cca-policy/commit/b0ef1d0f19e293f0a9805f913b4040c8fddb1a9c)]
19
+ - Refs #160116 - C3SIndicatorView: add disclaimer info. [GhitaB - [`765ed01`](https://github.com/eea/volto-cca-policy/commit/765ed013d38b56091c5e384ea1facaf31e3aa531)]
20
+ - Undo initialBlocks [kreafox - [`2c17118`](https://github.com/eea/volto-cca-policy/commit/2c17118e07e784bb57ce2564f1108d8183ec5b78)]
21
+ - CSS fix [kreafox - [`f77f74e`](https://github.com/eea/volto-cca-policy/commit/f77f74e01ba2458311411537e1477636bffc140f)]
22
+ - Add headerSearchBox to Header [kreafox - [`b873129`](https://github.com/eea/volto-cca-policy/commit/b873129483f32ff9ab8d1ae0f2406be75e3f7afd)]
23
+ - Add organisationName and websiteTitle to config [kreafox - [`ff41a58`](https://github.com/eea/volto-cca-policy/commit/ff41a588b4a8b0a8ff0d1f67310becbd7cbb6c1c)]
24
+ - Set initialBlocks [kreafox - [`d1741f6`](https://github.com/eea/volto-cca-policy/commit/d1741f6a0c3e68c6172a19c51c53c221b351bb5d)]
25
+ - Refs #160116 - C3SIndicatorView: iframe no border. [GhitaB - [`055d287`](https://github.com/eea/volto-cca-policy/commit/055d2872b0e33def79a6d5446d229b9febad813e)]
26
+ - Refs #160116 - C3SIndicatorView: right buttons (.btn-right). [GhitaB - [`dcf7359`](https://github.com/eea/volto-cca-policy/commit/dcf73596a53e5e0621bd2a3809598afd6233718f)]
27
+ - Refs #160116 - C3SIndicatorView: custom align for titles vs buttons. [GhitaB - [`02bdbca`](https://github.com/eea/volto-cca-policy/commit/02bdbcab131c3fa5b359d4de3749c70e26dd8285)]
28
+ - Refs #160116 - C3SIndicatorView: update url params when showDetails changes. [GhitaB - [`c7ad9d1`](https://github.com/eea/volto-cca-policy/commit/c7ad9d140f265aff75c5963d126ef4eff92b57f7)]
29
+ - Refs #160116 - C3SIndicatorView: add title for details/overview. [GhitaB - [`53fd12d`](https://github.com/eea/volto-cca-policy/commit/53fd12d42a77c9792bd677fb2d53dcd74d9c87a6)]
30
+ - Refs #160116 - C3SIndicatorView: set Details mode if #details in url. [GhitaB - [`017b9cd`](https://github.com/eea/volto-cca-policy/commit/017b9cd433aedbf0166c259126be8d4ae59b835a)]
31
+ - Refs #160116 - C3SIndicatorView: toggle Details vs Overview mode. [GhitaB - [`1c3f7af`](https://github.com/eea/volto-cca-policy/commit/1c3f7afd7f45e61c849e053337af69448b51363a)]
32
+ - Refs #160116 - C3SIndicatorView: add overview iframe. [GhitaB - [`4ed4ed6`](https://github.com/eea/volto-cca-policy/commit/4ed4ed66bc8bf71a019c89070361f257fa81afc2)]
33
+ - Refs #160116 - C3SIndicatorView: details iframe - use real data. [GhitaB - [`8fa2a7d`](https://github.com/eea/volto-cca-policy/commit/8fa2a7d3b6fa991959136e457299c16ad7d64a14)]
34
+ - Refs #160116 - C3SIndicatorView: clean code. [GhitaB - [`a5b165e`](https://github.com/eea/volto-cca-policy/commit/a5b165e8386f519dbba23c18a555d8a7bcc6cd5d)]
35
+ - WIP [Tiberiu Ichim - [`892c285`](https://github.com/eea/volto-cca-policy/commit/892c285a618b1daf92a7c0e8878a09671377ef65)]
36
+ - Refs #160116 - C3SIndicatorView: WIP iframe. [GhitaB - [`97a42aa`](https://github.com/eea/volto-cca-policy/commit/97a42aa9eaa565a4b8c08427b4d0a62f28bf5a87)]
37
+ ### [0.1.15](https://github.com/eea/volto-cca-policy/compare/0.1.14...0.1.15) - 27 March 2023
38
+
12
39
  ### [0.1.14](https://github.com/eea/volto-cca-policy/compare/0.1.13...0.1.14) - 24 March 2023
13
40
 
14
41
  #### :hammer_and_wrench: Others
@@ -319,7 +346,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
319
346
  #### :hammer_and_wrench: Others
320
347
 
321
348
  - Refs #158294 - Update supported languages list. [GhitaB - [`0a4f91f`](https://github.com/eea/volto-cca-policy/commit/0a4f91f39b7edc367bd4c127d6a8f273c7788361)]
322
- - Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`8f1f9ce`](https://github.com/eea/volto-cca-policy/commit/8f1f9ce6c22805670cc0800d3c779b6d619d0f31)]
323
349
  ### [0.1.1](https://github.com/eea/volto-cca-policy/compare/0.1.0...0.1.1) - 13 December 2022
324
350
 
325
351
  #### :hammer_and_wrench: Others
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "@eeacms/volto-cca-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -1,30 +1,125 @@
1
- import React from 'react';
2
- import {
3
- HTMLField,
4
- // ContentMetadata,
5
- // LinksList,
6
- // PublishedModifiedInfo,
7
- // ShareInfo,
8
- } from '@eeacms/volto-cca-policy/helpers';
1
+ import React, { useState, useEffect } from 'react';
2
+ import spinner from '@eeacms/volto-cca-policy/../theme//assets/images/spinner.svg';
3
+ import { HTMLField } from '@eeacms/volto-cca-policy/helpers';
9
4
  import { Grid } from 'semantic-ui-react';
10
- // import { Fragment } from 'react';
11
5
 
12
- const Details = (props) => {
13
- const showDetails = () => {
14
- // console.log("WIP details");
6
+ if (!__SERVER__) {
7
+ window.cds_toolbox = {
8
+ cds_public_path: 'https://cds.climate.copernicus.eu/toolbox/',
15
9
  };
10
+ }
11
+
12
+ const createIframe = (div_id, details_url, details_params, spinner_url) => {
13
+ return `
14
+ <iframe width="100%" height="800px" srcdoc="<html><head>
15
+ <title>CDS integration test</title>
16
+ <meta charset='utf-8' />
17
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
18
+ <script>
19
+ window.cds_toolbox = { cds_public_path: 'https://cds.climate.copernicus.eu/toolbox/' };
20
+ </script>
21
+ <script type='text/javascript' src='https://cds.climate.copernicus.eu/toolbox/toolbox-latest.js'></script>
22
+ </head>
23
+ <body>
24
+ <div class='t-ct'>
25
+ <div id='${div_id}'>
26
+ <div class='pre-app-loading'>
27
+ <img src='${spinner_url}' alt='Loading'>
28
+ <div>
29
+ ...loading configuration...
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <script type='text/javascript'>
35
+ document.addEventListener('DOMContentLoaded',
36
+ function () {
37
+ window.cds_toolbox.runApp(
38
+ '${div_id}',
39
+ '${details_url}',
40
+ ${details_params}
41
+ );
42
+ }, false);
43
+ </script>
44
+ </body></html>"
45
+ />`;
46
+ };
47
+
48
+ const Details = (props) => {
49
+ const { content } = props;
50
+ const c3s_details_url = content.details_app_toolbox_url;
51
+ const c3s_details_params = JSON.stringify(
52
+ content.details_app_parameters,
53
+ ).replace(/"/g, "'"); // we avoid double quotes in iframe text
54
+ const [spinnerUrl, setSpinnerUrl] = useState(null);
55
+
56
+ React.useEffect(() => {
57
+ setSpinnerUrl(spinner);
58
+ }, []);
16
59
 
17
60
  return (
18
- <a href="#details">
19
- <button className="ui button primary" onClick={showDetails}>
20
- Explore in detail
21
- </button>
22
- </a>
61
+ <div
62
+ className="iframe-container"
63
+ dangerouslySetInnerHTML={{
64
+ __html: createIframe(
65
+ 'toolbox-app-details',
66
+ c3s_details_url,
67
+ c3s_details_params,
68
+ spinnerUrl,
69
+ ),
70
+ }}
71
+ />
72
+ );
73
+ };
74
+
75
+ const Overview = (props) => {
76
+ const { content } = props;
77
+ const c3s_overview_url = content.overview_app_toolbox_url;
78
+ const c3s_overview_params = JSON.stringify(
79
+ content.overview_app_parameters,
80
+ ).replace(/"/g, "'"); // we avoid double quotes in iframe text
81
+ const [spinnerUrl, setSpinnerUrl] = useState(null);
82
+
83
+ React.useEffect(() => {
84
+ setSpinnerUrl(spinner);
85
+ }, []);
86
+
87
+ return (
88
+ <div
89
+ className="iframe-container"
90
+ dangerouslySetInnerHTML={{
91
+ __html: createIframe(
92
+ 'toolbox-app-overview',
93
+ c3s_overview_url,
94
+ c3s_overview_params,
95
+ spinnerUrl,
96
+ ),
97
+ }}
98
+ />
23
99
  );
24
100
  };
25
101
 
26
102
  function C3SIndicatorView(props) {
27
103
  const { content } = props;
104
+ const [showDetails, setShowDetails] = useState(false);
105
+
106
+ const toggleIframe = () => {
107
+ setShowDetails(!showDetails);
108
+ };
109
+
110
+ useEffect(() => {
111
+ if (window.location.hash === '#details') {
112
+ setShowDetails(true);
113
+ }
114
+ }, []);
115
+
116
+ useEffect(() => {
117
+ if (showDetails) {
118
+ window.history.pushState({}, '', '#details');
119
+ } else {
120
+ window.history.pushState({}, '', window.location.pathname);
121
+ }
122
+ }, [showDetails]);
28
123
 
29
124
  return (
30
125
  <div className="c3sindicator-view">
@@ -37,15 +132,39 @@ function C3SIndicatorView(props) {
37
132
  computer={12}
38
133
  className="col-full"
39
134
  >
40
- <h1>{content.title}</h1>
41
- <a href="/knowledge/european-climate-data-explorer/">
135
+ <a
136
+ href="/knowledge/european-climate-data-explorer/"
137
+ className="btn-right"
138
+ >
42
139
  <button className="ui button primary">ECDE homepage</button>
43
140
  </a>
141
+ <h1>{content.title}</h1>
44
142
  <HTMLField
45
143
  value={content.long_description}
46
144
  className="long_description"
47
145
  />
48
- <Details {...props} />
146
+ <a href="#details" className="btn-right">
147
+ <button className="ui button primary" onClick={toggleIframe}>
148
+ {showDetails ? 'Go back' : 'Explore in detail'}
149
+ </button>
150
+ </a>
151
+ <h2>
152
+ {content.indicator_title} {showDetails && ' - Explore index'}
153
+ </h2>
154
+ {!__SERVER__ && !showDetails && <Overview {...props} />}
155
+ {!__SERVER__ && showDetails && <Details {...props} />}
156
+
157
+ <p>
158
+ Content in the European Climate Data Explorer pages is delivered
159
+ by the{' '}
160
+ <a href="https://climate.copernicus.eu/">
161
+ Copernicus Climate Change Service (C3S)
162
+ </a>{' '}
163
+ implemented by ECMWF.{' '}
164
+ <a href="/knowledge/european-climate-data-explorer/disclaimer">
165
+ Disclaimer
166
+ </a>
167
+ </p>
49
168
  </Grid.Column>
50
169
  </div>
51
170
  </Grid>
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { UniversalLink } from '@plone/volto/components';
4
+
5
+ const Contact = ({ children, contacts }) =>
6
+ children?.length ? (
7
+ children
8
+ ) : (
9
+ <div className="contact-block">
10
+ {contacts?.map((contact, index) => {
11
+ return (
12
+ <div className="contact" key={index}>
13
+ <UniversalLink href={contact.link} className="bold">
14
+ {contact.text}
15
+ </UniversalLink>
16
+ {contact.children && (
17
+ <div className="subcontact">
18
+ {contact.children.map((child, index) => (
19
+ <UniversalLink href={child.link} key={index}>
20
+ {child.text}
21
+ </UniversalLink>
22
+ ))}
23
+ </div>
24
+ )}
25
+ </div>
26
+ );
27
+ })}
28
+ </div>
29
+ );
30
+
31
+ Contact.propTypes = {
32
+ contacts: PropTypes.array,
33
+ header: PropTypes.string,
34
+ };
35
+
36
+ export default Contact;
@@ -4,9 +4,8 @@
4
4
  */
5
5
 
6
6
  import React from 'react';
7
- import { Dropdown, Image } from 'semantic-ui-react';
7
+ import { Dropdown, Image } from 'semantic-ui-react'; // Container, Menu, Grid
8
8
  import { connect, useDispatch, useSelector } from 'react-redux';
9
-
10
9
  import { withRouter } from 'react-router-dom';
11
10
  import { UniversalLink } from '@plone/volto/components';
12
11
  import {
@@ -24,9 +23,10 @@ import eeaFlag from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/
24
23
  import config from '@plone/volto/registry';
25
24
  import { compose } from 'recompose';
26
25
  import { BodyClass } from '@plone/volto/helpers';
27
-
28
26
  import cx from 'classnames';
29
27
 
28
+ import HeaderMain from './HeaderMain';
29
+
30
30
  function removeTrailingSlash(path) {
31
31
  return path.replace(/\/+$/, '');
32
32
  }
@@ -59,6 +59,7 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
59
59
 
60
60
  const { eea } = config.settings;
61
61
  const headerOpts = eea.headerOpts || {};
62
+ // const headerSearchBox = eea.headerSearchBox || [];
62
63
  const { logo, logoWhite } = headerOpts || {};
63
64
  const width = useSelector((state) => state.screen?.width);
64
65
  const dispatch = useDispatch();
@@ -198,8 +199,9 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
198
199
  </Header.TopDropdownMenu>
199
200
  )}
200
201
  </Header.TopHeader>
201
- <Header.Main
202
+ {/* <Header.Main
202
203
  pathname={pathname}
204
+ headerSearchBox={headerSearchBox}
203
205
  inverted={isHomePageInverse ? true : false}
204
206
  transparency={isHomePageInverse ? true : false}
205
207
  logo={
@@ -262,7 +264,73 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
262
264
  {props?.iconPosition === 'right' && props?.children}
263
265
  </UniversalLink>
264
266
  )}
265
- ></Header.Main>
267
+ ></Header.Main> */}
268
+
269
+ <HeaderMain
270
+ inverted={isHomePageInverse ? true : false}
271
+ transparency={isHomePageInverse ? true : false}
272
+ pathname={pathname}
273
+ logo={
274
+ <div {...(isSubsite ? { className: 'logo-wrapper' } : {})}>
275
+ {!!subsite && subsite.title ? (
276
+ <>
277
+ {subsite.subsite_logo ? (
278
+ <Logo
279
+ src={subsite.subsite_logo?.scales.preview.download}
280
+ title={subsite.title}
281
+ alt={subsite.title}
282
+ url={flattenToAppURL(subsite['@id'])}
283
+ />
284
+ ) : (
285
+ subsite.title
286
+ )}
287
+ <div className="subsite-logo">
288
+ <Logo
289
+ src={isHomePageInverse ? logoWhite : logo}
290
+ title={eea.websiteTitle}
291
+ alt={eea.organisationName}
292
+ url={eea.logoTargetUrl}
293
+ />
294
+ </div>
295
+ </>
296
+ ) : (
297
+ <Logo
298
+ src={isHomePageInverse ? logoWhite : logo}
299
+ title={eea.websiteTitle}
300
+ alt={eea.organisationName}
301
+ url={eea.logoTargetUrl}
302
+ />
303
+ )}
304
+ </div>
305
+ }
306
+ menuItems={items}
307
+ renderGlobalMenuItem={(item, { onClick }) => (
308
+ <a
309
+ href={item.url || '/'}
310
+ title={item.title}
311
+ onClick={(e) => {
312
+ e.preventDefault();
313
+ onClick(e, item);
314
+ }}
315
+ >
316
+ {item.title}
317
+ </a>
318
+ )}
319
+ renderMenuItem={(item, options, props) => (
320
+ <UniversalLink
321
+ href={item.url || '/'}
322
+ title={item.title}
323
+ {...(options || {})}
324
+ className={cx(options?.className, {
325
+ active: item.url === router_pathname,
326
+ })}
327
+ >
328
+ {props?.iconPosition !== 'right' && props?.children}
329
+ <span>{item.title}</span>
330
+ {props?.iconPosition === 'right' && props?.children}
331
+ </UniversalLink>
332
+ )}
333
+ />
266
334
  </Header>
267
335
  );
268
336
  };
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Header component.
3
+ * @module components/theme/Header/Header
4
+ */
5
+
6
+ import React from 'react'; // , { Component }
7
+ import { useHistory } from 'react-router-dom';
8
+ import { Link } from 'react-router-dom';
9
+
10
+ import { Container, Image, Menu, Grid } from 'semantic-ui-react';
11
+
12
+ import closeIcon from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/images/Header/close-line.svg';
13
+ import searchIcon from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/images/Header/search-line.svg';
14
+ import burgerIcon from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/images/Header/menu-line.svg';
15
+
16
+ import HeaderMenuPopUp from './HeaderMenuPopUp';
17
+
18
+ const HeaderMain = ({
19
+ logo,
20
+ menuItems,
21
+ renderMenuItem,
22
+ renderGlobalMenuItem,
23
+ pathname,
24
+ transparency,
25
+ inverted,
26
+ }) => {
27
+ const history = useHistory();
28
+ const [activeItem, setActiveItem] = React.useState(pathname);
29
+ const [menuIsActive, setMenuIsActive] = React.useState(false);
30
+ const [burger, setBurger] = React.useState('');
31
+
32
+ React.useEffect(() => {
33
+ setMenuIsActive(false);
34
+
35
+ setBurger('');
36
+ // remove active menu when we have no pathname which means we hit logo to go home
37
+ if (!pathname) {
38
+ setActiveItem('');
39
+ }
40
+ }, [pathname]);
41
+
42
+ const mobileBurgerOnClick = () => {
43
+ if (burger === '') {
44
+ setBurger('open');
45
+ setMenuIsActive(true);
46
+ } else {
47
+ setBurger('');
48
+ setMenuIsActive(false);
49
+ setActiveItem('');
50
+ }
51
+ };
52
+
53
+ const menuOnClickOutside = () => {
54
+ // restore active element if nothing was selected from the menu dropdown
55
+ if (pathname !== activeItem) {
56
+ setActiveItem(pathname);
57
+ }
58
+ // close mobile navigation when clicking outside if we have value for nav
59
+ if (burger) {
60
+ setBurger('');
61
+ }
62
+ // always close the menu
63
+ setMenuIsActive(false);
64
+ };
65
+
66
+ const menuOnClick = (e, item) => {
67
+ setActiveItem(item['@id'] || item.url);
68
+ if (item.items.length) {
69
+ setMenuIsActive(true);
70
+ } else {
71
+ history.push(item.url);
72
+ }
73
+ };
74
+
75
+ // Listens for escape keydown event
76
+ React.useEffect(() => {
77
+ const escKeyPressed = (e) => {
78
+ if (e.key === 'Escape') {
79
+ // menuOnClickOutside();
80
+ // restore active element if nothing was selected from the menu dropdown
81
+ if (pathname !== activeItem) {
82
+ setActiveItem(pathname);
83
+ }
84
+ // close mobile navigation when clicking outside if we have value for nav
85
+ if (burger) {
86
+ setBurger('');
87
+ }
88
+ // always close the menu & search
89
+ setMenuIsActive(false);
90
+ }
91
+ };
92
+
93
+ document.addEventListener('keydown', escKeyPressed);
94
+
95
+ return () => {
96
+ document.removeEventListener('keydown', escKeyPressed);
97
+ };
98
+ }, [activeItem, burger, pathname]);
99
+
100
+ const node = React.useRef();
101
+ const mobileMenuBurgerRef = React.useRef();
102
+ const desktopMenuRef = React.useRef();
103
+
104
+ return (
105
+ <div
106
+ className={`main bar ${transparency ? 'transparency' : ''}`}
107
+ ref={node}
108
+ >
109
+ <Container>
110
+ <Grid>
111
+ <Grid.Column mobile={8} tablet={8} computer={4}>
112
+ {logo}
113
+ </Grid.Column>
114
+ <Grid.Column mobile={4} tablet={4} computer={8}>
115
+ <div className={inverted ? 'main-menu inverted' : 'main-menu'}>
116
+ {menuItems && (
117
+ <div
118
+ className="ui text eea-main-menu tablet or lower hidden menu"
119
+ ref={desktopMenuRef}
120
+ id={'navigation'}
121
+ >
122
+ {menuItems.map((item) => (
123
+ <Menu.Item
124
+ name={item['@id'] || item.url}
125
+ key={item['@id'] || item.url}
126
+ active={
127
+ activeItem.indexOf(item['@id']) !== -1 ||
128
+ activeItem.indexOf(item.url) !== -1
129
+ }
130
+ >
131
+ {renderGlobalMenuItem(item, {
132
+ onClick: menuOnClick,
133
+ })}
134
+ </Menu.Item>
135
+ ))}
136
+ </div>
137
+ )}
138
+
139
+ <Link to="/en/mission/knowledge-and-data/search-the-database">
140
+ <button
141
+ className="search-action"
142
+ tabIndex="0"
143
+ aria-pressed="false"
144
+ aria-haspopup="true"
145
+ >
146
+ <Image src={searchIcon} alt="search button open/close" />
147
+ </button>
148
+ </Link>
149
+
150
+ <BurgerAction
151
+ className={`mobile ${burger}`}
152
+ onClick={mobileBurgerOnClick}
153
+ ref={mobileMenuBurgerRef}
154
+ >
155
+ <Image
156
+ src={burger === 'open' ? `${closeIcon}` : `${burgerIcon}`}
157
+ alt="menu icon open/close"
158
+ />
159
+ </BurgerAction>
160
+ </div>
161
+ </Grid.Column>
162
+ </Grid>
163
+ </Container>
164
+ <HeaderMenuPopUp
165
+ renderMenuItem={renderMenuItem}
166
+ activeItem={activeItem}
167
+ menuItems={menuItems}
168
+ pathName={pathname}
169
+ onClose={menuOnClickOutside}
170
+ triggerRefs={[mobileMenuBurgerRef, desktopMenuRef]}
171
+ visible={menuIsActive}
172
+ />
173
+ </div>
174
+ );
175
+ };
176
+
177
+ const BurgerAction = React.forwardRef((props, ref) => (
178
+ <button
179
+ ref={ref}
180
+ className={`burger-action ${props.className}`}
181
+ tabIndex="0"
182
+ aria-pressed="false"
183
+ aria-haspopup="true"
184
+ onClick={props.onClick}
185
+ >
186
+ {props.children}
187
+ </button>
188
+ ));
189
+
190
+ export default HeaderMain;
@@ -0,0 +1,373 @@
1
+ import React from 'react';
2
+ import { Transition } from 'semantic-ui-react';
3
+ import { Container, Grid, List, Icon, Accordion } from 'semantic-ui-react';
4
+
5
+ import { cloneDeep } from 'lodash';
6
+
7
+ import { useClickOutside } from '@eeacms/volto-eea-design-system/helpers';
8
+
9
+ const createColumns = (item, length, renderMenuItem) => {
10
+ let subArrays = [];
11
+ let size = length;
12
+ for (let i = 0; i < item.items.length; i += size) {
13
+ subArrays.push(item.items.slice(i, i + size));
14
+ }
15
+
16
+ const column = subArrays.map((subArray, index) => (
17
+ <Grid.Column key={index}>
18
+ <List>
19
+ {subArray.map((arrayItem, idx) => (
20
+ <React.Fragment key={idx}>
21
+ {renderMenuItem(arrayItem, {
22
+ className: 'item',
23
+ role: 'listitem',
24
+ key: idx,
25
+ })}
26
+ </React.Fragment>
27
+ ))}
28
+ </List>
29
+ </Grid.Column>
30
+ ));
31
+
32
+ return column;
33
+ };
34
+
35
+ const ItemGrid = ({ item, columns, length, renderMenuItem }) => (
36
+ <>
37
+ {renderMenuItem(item, { className: 'sub-title' })}
38
+ {item.items.length ? (
39
+ <Grid columns={columns}>
40
+ {createColumns(item, length, renderMenuItem)}
41
+ </Grid>
42
+ ) : null}
43
+ </>
44
+ );
45
+
46
+ const Item = ({ item, icon = false, iconName, renderMenuItem }) => (
47
+ <>
48
+ {renderMenuItem(item, { className: 'sub-title' })}
49
+ <List className="menu-list">
50
+ {item.items.map((listItem, index) => (
51
+ <React.Fragment key={index}>
52
+ {renderMenuItem(
53
+ listItem,
54
+ {
55
+ className: 'item',
56
+ key: index,
57
+ role: 'listitem',
58
+ },
59
+ { children: icon && <Icon className={iconName} /> },
60
+ )}
61
+ </React.Fragment>
62
+ ))}
63
+ </List>
64
+ </>
65
+ );
66
+
67
+ const Topics = ({ menuItem, renderMenuItem }) => (
68
+ <Grid>
69
+ {menuItem.items.map((section, index) => (
70
+ <React.Fragment key={index}>
71
+ {section.title === 'At a glance' ? (
72
+ <Grid.Column width={3} id="at-a-glance">
73
+ <Item item={section} key={index} renderMenuItem={renderMenuItem} />
74
+ </Grid.Column>
75
+ ) : (
76
+ <Grid.Column width={9} key={index} id="topics-right-column">
77
+ <ItemGrid
78
+ item={section}
79
+ columns={4}
80
+ length={10}
81
+ key={index}
82
+ renderMenuItem={renderMenuItem}
83
+ />
84
+ </Grid.Column>
85
+ )}
86
+ </React.Fragment>
87
+ ))}
88
+ </Grid>
89
+ );
90
+
91
+ const Countries = ({ menuItem, renderMenuItem }) => (
92
+ <Grid>
93
+ <Grid.Column width={8}>
94
+ {menuItem.items.map((section, index) => (
95
+ <React.Fragment key={index}>
96
+ {section.title === 'EEA member countries' && (
97
+ <ItemGrid
98
+ item={section}
99
+ columns={5}
100
+ length={7}
101
+ renderMenuItem={renderMenuItem}
102
+ />
103
+ )}
104
+ </React.Fragment>
105
+ ))}
106
+ </Grid.Column>
107
+ <Grid.Column width={4}>
108
+ <Grid columns={1} className="nested-grid">
109
+ {menuItem.items.map((section, index) => (
110
+ <React.Fragment key={index}>
111
+ {section.title !== 'EEA member countries' && (
112
+ <Grid.Column>
113
+ <ItemGrid
114
+ item={section}
115
+ columns={2}
116
+ length={3}
117
+ renderMenuItem={renderMenuItem}
118
+ />
119
+ </Grid.Column>
120
+ )}
121
+ </React.Fragment>
122
+ ))}
123
+ </Grid>
124
+ </Grid.Column>
125
+ </Grid>
126
+ );
127
+
128
+ const StandardMegaMenuGrid = ({ menuItem, renderMenuItem }) => (
129
+ <Grid columns={4}>
130
+ {menuItem.items.map((section, index) => (
131
+ <Grid.Column key={index}>
132
+ <Item item={section} renderMenuItem={renderMenuItem} />
133
+ </Grid.Column>
134
+ ))}
135
+ </Grid>
136
+ );
137
+
138
+ const FirstLevelContent = ({ element, renderMenuItem, pathName }) => {
139
+ const topics = element.title === 'Topics' ? true : false;
140
+ let defaultIndex = -1;
141
+
142
+ return (
143
+ <>
144
+ {!topics ? (
145
+ <React.Fragment>
146
+ {element.items.map((item, index) => {
147
+ let firstLevelPanels = [];
148
+ if (!item.items.length) {
149
+ return (
150
+ <React.Fragment key={index}>
151
+ {renderMenuItem(item, { className: 'item sub-title' })}
152
+ </React.Fragment>
153
+ );
154
+ }
155
+ let x = {};
156
+ x.key = item['@id'] || item['url'];
157
+ if (pathName.indexOf(item.url) !== -1) {
158
+ defaultIndex = index;
159
+ }
160
+ x.title = (
161
+ <Accordion.Title key={`title=${index}`} as="button">
162
+ {item.title}
163
+ <Icon className="ri-arrow-down-s-line" size="small" />
164
+ </Accordion.Title>
165
+ );
166
+ let overflow_item = cloneDeep(item);
167
+ overflow_item.title = 'See all';
168
+ x.content = (
169
+ <Accordion.Content>
170
+ {renderMenuItem(overflow_item, {
171
+ className: 'item title-item',
172
+ })}
173
+ <SecondLevelContent
174
+ element={item}
175
+ renderMenuItem={renderMenuItem}
176
+ />
177
+ </Accordion.Content>
178
+ );
179
+ firstLevelPanels.push(x);
180
+ return (
181
+ <Accordion.Accordion
182
+ panels={firstLevelPanels}
183
+ key={index}
184
+ defaultActiveIndex={defaultIndex === index ? 0 : -1}
185
+ />
186
+ );
187
+ })}
188
+ </React.Fragment>
189
+ ) : (
190
+ <SecondLevelContent
191
+ element={element}
192
+ topics={true}
193
+ renderMenuItem={renderMenuItem}
194
+ />
195
+ )}
196
+ </>
197
+ );
198
+ };
199
+
200
+ const SecondLevelContent = ({ element, topics = false, renderMenuItem }) => {
201
+ let content;
202
+ if (topics) {
203
+ const atAGlance = element.items.find(
204
+ (element) => element.title === 'At a glance',
205
+ );
206
+ const inDepth = element.items.find(
207
+ (element) => element.url.indexOf('in-depth') !== -1,
208
+ );
209
+ content = (
210
+ <List>
211
+ {atAGlance &&
212
+ atAGlance.items.map((item, index) => (
213
+ <React.Fragment key={index}>
214
+ {renderMenuItem(item, {
215
+ key: index,
216
+ role: 'listitem',
217
+ className: 'item',
218
+ })}
219
+ </React.Fragment>
220
+ ))}
221
+ {inDepth && (
222
+ <React.Fragment key={inDepth.url}>
223
+ {renderMenuItem(inDepth, {
224
+ key: inDepth.url,
225
+ role: 'listitem',
226
+ className: 'item',
227
+ })}
228
+ </React.Fragment>
229
+ )}
230
+ </List>
231
+ );
232
+ } else {
233
+ content = (
234
+ <List>
235
+ {element.items.map((item, index) => (
236
+ <React.Fragment key={index}>
237
+ {renderMenuItem(item, {
238
+ key: index,
239
+ role: 'listitem',
240
+ className: 'item',
241
+ })}
242
+ </React.Fragment>
243
+ ))}
244
+ </List>
245
+ );
246
+ }
247
+
248
+ return <>{content}</>;
249
+ };
250
+
251
+ const NestedAccordion = ({ menuItems, renderMenuItem, pathName }) => {
252
+ let defaultIndex = -1;
253
+ const rootPanels = [];
254
+ menuItems.forEach((element, index) => {
255
+ let x = {};
256
+ x.key = index;
257
+
258
+ if (pathName.indexOf(element.url) !== -1) {
259
+ defaultIndex = index;
260
+ }
261
+ x.title = (
262
+ <Accordion.Title key={`title-${index}`} index={index} as="button">
263
+ {element.title}
264
+ <Icon className="ri-arrow-down-s-line" size="small" />
265
+ </Accordion.Title>
266
+ );
267
+ let overview = cloneDeep(element);
268
+ x.content = (
269
+ <Accordion.Content key={index}>
270
+ <div className="mega-menu-title">
271
+ {/* Inverted right labeled button as a category title - Mobile */}
272
+ {renderMenuItem(
273
+ overview,
274
+ { className: 'ui button inverted icon right labeled' },
275
+ {
276
+ iconPosition: 'right',
277
+ children: (
278
+ <>
279
+ {/* Add word overview to titles */}
280
+ <span> overview</span>
281
+ <Icon className={'arrow right icon'} alt={'Title icon'} />
282
+ </>
283
+ ),
284
+ },
285
+ )}
286
+ </div>
287
+ <FirstLevelContent
288
+ element={element}
289
+ renderMenuItem={renderMenuItem}
290
+ pathName={pathName}
291
+ />
292
+ </Accordion.Content>
293
+ );
294
+ rootPanels.push(x);
295
+ });
296
+
297
+ return <Accordion defaultActiveIndex={defaultIndex} panels={rootPanels} />;
298
+ };
299
+
300
+ function HeaderMenuPopUp({
301
+ menuItems,
302
+ renderMenuItem,
303
+ pathName,
304
+ onClose,
305
+ triggerRefs,
306
+ activeItem,
307
+ visible,
308
+ }) {
309
+ const nodeRef = React.useRef();
310
+ useClickOutside({ targetRefs: [nodeRef, ...triggerRefs], callback: onClose });
311
+
312
+ const menuItem = menuItems.find(
313
+ (current) => current.url === activeItem || current['@id'] === activeItem,
314
+ );
315
+
316
+ return (
317
+ <Transition visible={visible} animation="slide down" duration={300}>
318
+ <div id="mega-menu" ref={nodeRef}>
319
+ <Container>
320
+ {menuItem && (
321
+ <div className="menu-content tablet hidden mobile hidden">
322
+ {/* Inverted right labeled button as a category title,
323
+ for topics the button goes inside the grid */}
324
+ {menuItem.title && (
325
+ <div className="mega-menu-title">
326
+ {renderMenuItem(
327
+ menuItem,
328
+ { className: 'ui button inverted icon right labeled' },
329
+ {
330
+ iconPosition: 'right',
331
+ children: (
332
+ <>
333
+ {/* Add word overview to titles */}
334
+ <span> overview</span>
335
+ <Icon
336
+ className={'arrow right icon'}
337
+ alt={'Title icon'}
338
+ />
339
+ </>
340
+ ),
341
+ },
342
+ )}
343
+ </div>
344
+ )}
345
+ {menuItem.title === 'Topics' ? (
346
+ <Topics menuItem={menuItem} renderMenuItem={renderMenuItem} />
347
+ ) : menuItem.title === 'Countries' ? (
348
+ <Countries
349
+ menuItem={menuItem}
350
+ renderMenuItem={renderMenuItem}
351
+ />
352
+ ) : (
353
+ <StandardMegaMenuGrid
354
+ menuItem={menuItem}
355
+ renderMenuItem={renderMenuItem}
356
+ />
357
+ )}
358
+ </div>
359
+ )}
360
+ <div className="tablet only mobile only">
361
+ <NestedAccordion
362
+ menuItems={menuItems}
363
+ renderMenuItem={renderMenuItem}
364
+ pathName={pathName}
365
+ />
366
+ </div>
367
+ </Container>
368
+ </div>
369
+ </Transition>
370
+ );
371
+ }
372
+
373
+ export default HeaderMenuPopUp;
package/src/index.js CHANGED
@@ -96,13 +96,8 @@ const applyConfig = (config) => {
96
96
  {
97
97
  icon: 'comment outline',
98
98
  text: 'Contact',
99
- link: '/en/mission/the-mission/contact-us',
99
+ link: 'climate.adapt@eea.europa.eu',
100
100
  },
101
- // {
102
- // icon: 'envelope outline',
103
- // text: 'Sign up to our newsletter',
104
- // link: '/newsletter',
105
- // },
106
101
  ],
107
102
  },
108
103
  headerSearchBox: [
@@ -114,8 +109,16 @@ const applyConfig = (config) => {
114
109
  // 'Looking for more information? Try searching the full EEA website content',
115
110
  // buttonTitle: 'Go to full site search',
116
111
  },
112
+ // {
113
+ // path: '/en/mission',
114
+ // placeholder: 'Search...',
115
+ // description: 'Looking for more information?',
116
+ // buttonTitle: 'Go to advanced search',
117
+ // },
117
118
  ],
118
119
  logoTargetUrl: '/en',
120
+ organisationName: 'Climate-ADAPT',
121
+ websiteTitle: 'Climate-ADAPT',
119
122
  };
120
123
 
121
124
  // Enable volto-embed
@@ -128,6 +131,19 @@ const applyConfig = (config) => {
128
131
  config.blocks.blocksConfig.video.restricted = false;
129
132
  }
130
133
 
134
+ config.blocks.blocksConfig.__grid = {
135
+ ...config.blocks.blocksConfig.__grid,
136
+ maxNumberOfColumns: 5,
137
+ };
138
+
139
+ config.blocks.blocksConfig.nextCloudVideo = {
140
+ ...config.blocks.blocksConfig.nextCloudVideo,
141
+ whiteList: [
142
+ 'https://cmshare.eea.europa.eu',
143
+ 'https://shareit.eea.europa.eu',
144
+ ],
145
+ };
146
+
131
147
  //console.log(config);
132
148
  config.views.contentTypesViews = {
133
149
  ...config.views.contentTypesViews,
@@ -145,13 +161,13 @@ const applyConfig = (config) => {
145
161
  };
146
162
 
147
163
  config.settings.contextNavigationLocations = [
148
- {
149
- title: 'Regional Adaptation Support Tool',
150
- columns: 4,
151
- topLevel: 2,
152
- bottomLevel: 0,
153
- rootPath: '/mission/knowledge-and-data/regional-adaptation-support-tool',
154
- },
164
+ // {
165
+ // title: 'Regional Adaptation Support Tool',
166
+ // columns: 4,
167
+ // topLevel: 2,
168
+ // bottomLevel: 0,
169
+ // rootPath: '/mission/knowledge-and-data/regional-adaptation-support-tool',
170
+ // },
155
171
  {
156
172
  title: 'UrbanAST',
157
173
  topLevel: 3,
@@ -46,7 +46,19 @@ div.video-view {
46
46
  }
47
47
  }
48
48
 
49
+ // C3S Indicator view styles
50
+ div.c3sindicator-view {
51
+ iframe {
52
+ border: none;
53
+ }
54
+ }
55
+
49
56
  // General styles
57
+ .btn-right {
58
+ margin: calc(2rem - 0.1em) 0em 1rem;
59
+ float: right;
60
+ }
61
+
50
62
  div.share-info {
51
63
  margin-top: 1em;
52
64
  text-align: right;
@@ -76,6 +88,10 @@ div.content-metadata {
76
88
 
77
89
  // Mission subsites
78
90
  body.subsite-mkh {
91
+ .top.bar .ui.container {
92
+ z-index: 3;
93
+ }
94
+
79
95
  &.subsite-root {
80
96
  .segment.content-area {
81
97
  padding-top: 0;
@@ -99,6 +115,7 @@ body.subsite-mkh {
99
115
 
100
116
  p {
101
117
  font-size: 1.125rem;
118
+ font-weight: 600;
102
119
  }
103
120
  }
104
121
 
@@ -134,7 +151,7 @@ body.subsite-mkh {
134
151
  }
135
152
 
136
153
  .eea.header .subsite-logo {
137
- z-index: unset;
154
+ z-index: 1;
138
155
  height: 100%;
139
156
 
140
157
  .logo {