@eeacms/volto-n2k 0.1.15 → 1.0.0

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.
@@ -3,7 +3,7 @@
3
3
  * @module components/theme/Header/Header
4
4
  */
5
5
 
6
- import React, { useEffect, useContext } from 'react';
6
+ import React, { useEffect, useContext, useMemo } from 'react';
7
7
  import { matchPath, withRouter } from 'react-router';
8
8
  import { Container, Sticky } from 'semantic-ui-react';
9
9
  import { connect } from 'react-redux';
@@ -12,7 +12,7 @@ import config from '@plone/volto/registry';
12
12
  import { Anontools } from '@plone/volto/components';
13
13
  import { withLocalStorage } from '@eeacms/volto-n2k/hocs';
14
14
  import Navigation from '../Navigation/Navigation';
15
- import { StickyContext } from '~/components';
15
+ import { StickyContext } from '@eeacms/volto-bise/components';
16
16
 
17
17
  const Navbar = (props) => {
18
18
  const currentLang = props.localStorage.get('N2K_LANGUAGE');
@@ -26,6 +26,8 @@ const Navbar = (props) => {
26
26
  {currentLang ? (
27
27
  <Navigation
28
28
  isSticky={props.isSticky}
29
+ isRoot={props.isRoot}
30
+ isExplorer={props.isExplorer}
29
31
  pathname={props.pathname}
30
32
  />
31
33
  ) : (
@@ -47,37 +49,66 @@ const Navbar = (props) => {
47
49
  const Header = (props) => {
48
50
  const [isSticky, setIsSticky] = React.useState(false);
49
51
  const { stickyRef } = useContext(StickyContext);
50
- const isRoot = !!matchPath(props.pathname, {
51
- path: config.settings.multilingualRoot,
52
- exact: true,
53
- strict: false,
54
- });
52
+ const isRoot = useMemo(
53
+ () =>
54
+ matchPath(props.pathname, {
55
+ path: config.settings.n2k.multilingualRoot,
56
+ exact: true,
57
+ strict: false,
58
+ }),
59
+ [props.pathname],
60
+ );
61
+
62
+ const isExplorer = useMemo(
63
+ () =>
64
+ (isRoot &&
65
+ !config.settings.n2k.supportedLanguages.includes(isRoot.params.lang)) ||
66
+ matchPath(props.pathname, {
67
+ path: '/natura2000/explore-natura2000/*',
68
+ exact: true,
69
+ strict: false,
70
+ }),
71
+ [props.pathname, isRoot],
72
+ );
55
73
 
56
74
  useEffect(() => {
57
75
  if (!props.localStorage.get('N2K_LANGUAGE')) {
58
- props.localStorage.set('N2K_LANGUAGE', config.settings.defaultLanguage);
76
+ props.localStorage.set(
77
+ 'N2K_LANGUAGE',
78
+ config.settings.n2k.defaultLanguage,
79
+ );
59
80
  }
60
81
  /* eslint-disable-next-line */
61
82
  }, []);
62
83
 
63
- return isRoot ? (
64
- ''
84
+ return isRoot || isExplorer ? (
85
+ <div className="ui basic segment sticky-header-wrapper" role="banner">
86
+ <Navbar
87
+ {...props}
88
+ isSticky={false}
89
+ isRoot={isRoot}
90
+ isExplorer={isExplorer}
91
+ />
92
+ </div>
65
93
  ) : (
66
- <>
67
- <Sticky
68
- context={stickyRef}
69
- className="ui basic segment sticky-header-wrapper"
70
- role="banner"
71
- onStick={() => {
72
- setIsSticky(true);
73
- }}
74
- onUnstick={() => {
75
- setIsSticky(false);
76
- }}
77
- >
78
- <Navbar {...props} isSticky={isSticky} />
79
- </Sticky>
80
- </>
94
+ <Sticky
95
+ context={stickyRef}
96
+ className="ui basic segment sticky-header-wrapper"
97
+ role="banner"
98
+ onStick={() => {
99
+ setIsSticky(true);
100
+ }}
101
+ onUnstick={() => {
102
+ setIsSticky(false);
103
+ }}
104
+ >
105
+ <Navbar
106
+ {...props}
107
+ isSticky={isSticky}
108
+ isRoot={isRoot}
109
+ isExplorer={isExplorer}
110
+ />
111
+ </Sticky>
81
112
  );
82
113
  };
83
114
 
@@ -9,12 +9,14 @@ import { useSelector } from 'react-redux';
9
9
  import cx from 'classnames';
10
10
  import { langmap } from '@plone/volto/helpers';
11
11
  import { flattenToAppURL } from '@plone/volto/helpers';
12
- import { Dropdown } from 'semantic-ui-react';
12
+ import { Dropdown, Image } from 'semantic-ui-react';
13
13
  import config from '@plone/volto/registry';
14
14
  import { withLocalStorage } from '@eeacms/volto-n2k/hocs';
15
15
  import { getN2kItems, pathExists } from '@eeacms/volto-n2k/helpers';
16
16
  import './styles.less';
17
17
 
18
+ import globeIcon from '@eeacms/volto-n2k/static/global-line.svg';
19
+
18
20
  const LanguageSelector = (props) => {
19
21
  const { settings } = config;
20
22
  const content = useSelector((state) => state.content);
@@ -23,24 +25,24 @@ const LanguageSelector = (props) => {
23
25
  const pathname = props.location.pathname;
24
26
  const currentLang = localStorage.get('N2K_LANGUAGE');
25
27
  const matchRoot = matchPath(pathname, {
26
- path: settings.multilingualRoot,
28
+ path: settings.n2k.multilingualRoot,
27
29
  exact: true,
28
30
  strict: false,
29
31
  });
30
32
  const matchChild = matchPath(pathname, {
31
- path: settings.multilingualPath,
33
+ path: settings.n2k.multilingualPath,
32
34
  exact: true,
33
35
  strict: false,
34
36
  });
35
37
  const match = matchRoot || matchChild;
36
38
  const hasMultilingualSupport =
37
- match && settings.supportedLanguages.includes(match.params.lang);
39
+ match && settings.n2k.supportedLanguages.includes(match.params.lang);
38
40
  const translations = hasMultilingualSupport
39
- ? settings.supportedLanguages.map((lang) => {
41
+ ? settings.n2k.supportedLanguages.map((lang) => {
40
42
  return {
41
43
  path: matchRoot
42
44
  ? `/natura2000/${lang}`
43
- : generatePath(settings.multilingualPath, {
45
+ : generatePath(settings.n2k.multilingualPath, {
44
46
  ...match.params,
45
47
  lang,
46
48
  }),
@@ -48,20 +50,66 @@ const LanguageSelector = (props) => {
48
50
  };
49
51
  })
50
52
  : [];
51
- const supportedLanguagesOptions = settings.supportedLanguages.map((lang) => ({
52
- key: lang,
53
- value: lang,
54
- text: langmap[lang].nativeName,
55
- }));
53
+ const supportedLanguagesOptions = settings.n2k.supportedLanguages.map(
54
+ (lang) => ({
55
+ key: lang,
56
+ value: lang,
57
+ text: langmap[lang].nativeName,
58
+ }),
59
+ );
56
60
 
57
61
  return (
58
62
  <div className={cx('language-selector', props.className)}>
63
+ {/* <Header.TopDropdownMenu
64
+ id="language-switcher"
65
+ className="item"
66
+ text={`${language.toUpperCase()}`}
67
+ mobileText={`${language.toUpperCase()}`}
68
+ icon={
69
+ <Image src={globeIcon} alt="language dropdown globe icon"></Image>
70
+ }
71
+ viewportWidth={width}
72
+ >
73
+ <ul
74
+ className="wrapper language-list"
75
+ role="listbox"
76
+ aria-label="language switcher"
77
+ >
78
+ {eea.languages.map((item, index) => (
79
+ <Dropdown.Item
80
+ as="li"
81
+ key={index}
82
+ text={
83
+ <span>
84
+ {item.name}
85
+ <span className="country-code">
86
+ {item.code.toUpperCase()}
87
+ </span>
88
+ </span>
89
+ }
90
+ onClick={() => {
91
+ const translation = find(translations, {
92
+ language: item.code,
93
+ });
94
+ const to = translation
95
+ ? flattenToAppURL(translation['@id'])
96
+ : `/${item.code}`;
97
+ setLanguage(item.code);
98
+ history.push(to);
99
+ }}
100
+ ></Dropdown.Item>
101
+ ))}
102
+ </ul>
103
+ </Header.TopDropdownMenu> */}
59
104
  <Dropdown
60
105
  aria-label="Language selector"
61
106
  disabled={content.get.loading}
62
107
  placeholder="Select a language"
63
- value={currentLang}
108
+ text={currentLang}
64
109
  scrolling
110
+ icon={
111
+ <Image src={globeIcon} alt="language dropdown globe icon"></Image>
112
+ }
65
113
  options={supportedLanguagesOptions}
66
114
  onChange={(e, data) => {
67
115
  const lang = data.value;
@@ -78,7 +126,7 @@ const LanguageSelector = (props) => {
78
126
  }
79
127
  }
80
128
 
81
- if (config.settings.supportedLanguages.includes(lang)) {
129
+ if (config.settings.n2k.supportedLanguages.includes(lang)) {
82
130
  localStorage.set('N2K_LANGUAGE', lang);
83
131
  }
84
132
  }}
@@ -12,7 +12,11 @@ import { Link } from 'react-router-dom';
12
12
  import { defineMessages, injectIntl } from 'react-intl';
13
13
  import { Menu, Dropdown } from 'semantic-ui-react';
14
14
  import cx from 'classnames';
15
- import { getBaseUrl, flattenToAppURL } from '@plone/volto/helpers';
15
+ import {
16
+ getBaseUrl,
17
+ flattenToAppURL,
18
+ hasApiExpander,
19
+ } from '@plone/volto/helpers';
16
20
  import { UniversalLink, Icon } from '@plone/volto/components';
17
21
  import qs from 'querystring';
18
22
  import { getNavigation } from '@plone/volto/actions';
@@ -89,6 +93,10 @@ class Navigation extends Component {
89
93
  ).isRequired,
90
94
  };
91
95
 
96
+ static defaultProps = {
97
+ token: null,
98
+ };
99
+
92
100
  /**
93
101
  * Constructor
94
102
  * @method constructor
@@ -113,10 +121,13 @@ class Navigation extends Component {
113
121
  * @returns {undefined}
114
122
  */
115
123
  componentDidMount() {
116
- this.props.getNavigation(
117
- getBaseUrl(this.props.pathname),
118
- config.settings.navDepth,
119
- );
124
+ const { settings } = config;
125
+ if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
126
+ this.props.getNavigation(
127
+ getBaseUrl(this.props.pathname),
128
+ settings.navDepth,
129
+ );
130
+ }
120
131
  this.setState({
121
132
  isSdf: this.isSdf(),
122
133
  });
@@ -134,20 +145,23 @@ class Navigation extends Component {
134
145
  };
135
146
 
136
147
  /**
137
- * Component did update
138
- * @method componentDidUpdate
139
- * @param {Object} prevProps Prev properties
148
+ * Component will receive props
149
+ * @method componentWillReceiveProps
150
+ * @param {Object} nextProps Next properties
140
151
  * @returns {undefined}
141
152
  */
142
- componentDidUpdate(prevProps) {
153
+ UNSAFE_componentWillReceiveProps(nextProps) {
154
+ const { settings } = config;
143
155
  if (
144
- prevProps.pathname !== this.props.pathname ||
145
- prevProps.userToken !== this.props.userToken
156
+ nextProps.pathname !== this.props.pathname ||
157
+ nextProps.token !== this.props.token
146
158
  ) {
147
- this.props.getNavigation(
148
- getBaseUrl(this.props.pathname),
149
- config.settings.navDepth,
150
- );
159
+ if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
160
+ this.props.getNavigation(
161
+ getBaseUrl(nextProps.pathname),
162
+ settings.navDepth,
163
+ );
164
+ }
151
165
  this.closeMobileMenu();
152
166
  }
153
167
 
@@ -298,7 +312,7 @@ class Navigation extends Component {
298
312
  ''
299
313
  )}
300
314
 
301
- {!this.state.isSdf
315
+ {!this.state.isSdf && !this.props.isRoot && !this.props.isExplorer
302
316
  ? this.props.items.map((item) => {
303
317
  const flatUrl = flattenToAppURL(item.url);
304
318
  const itemID = item.title.split(' ').join('-').toLowerCase();
@@ -391,7 +405,7 @@ class Navigation extends Component {
391
405
  );
392
406
  })
393
407
  : ''}
394
- {!this.state.isSdf ? (
408
+ {!this.state.isSdf && !this.props.isExplorer ? (
395
409
  <Menu.Item className="firstLevel language-selector-wrapper">
396
410
  <LanguageSelector navigation={this.props.navigation} />
397
411
  </Menu.Item>
@@ -412,7 +426,7 @@ const getN2kItems = (items, localStorage) => {
412
426
  items.filter((item) => item.url === '/natura2000')?.[0]?.items || [];
413
427
  natura2000.forEach((item) => {
414
428
  const languageFolder = matchPath(item.url, {
415
- path: config.settings.multilingualRoot,
429
+ path: config.settings.n2k.multilingualRoot,
416
430
  exact: true,
417
431
  strict: false,
418
432
  });
@@ -421,7 +435,7 @@ const getN2kItems = (items, localStorage) => {
421
435
  }
422
436
  if (
423
437
  languageFolder &&
424
- !config.settings.supportedLanguages.includes(
438
+ !config.settings.n2k.supportedLanguages.includes(
425
439
  languageFolder.params.lang,
426
440
  ) &&
427
441
  item.url !== '/natura2000/sites' &&
@@ -443,10 +457,10 @@ export default compose(
443
457
  connect(
444
458
  (state, props) => {
445
459
  return {
460
+ token: state.userSession.token,
446
461
  route_parameters: state.route_parameters,
447
462
  navigation: state.navigation,
448
463
  items: getN2kItems(state.navigation.items, props.localStorage),
449
- userToken: state?.userSession?.token,
450
464
  };
451
465
  },
452
466
  { getNavigation },
@@ -91,7 +91,7 @@ const getN2kItems = (items, localStorage) => {
91
91
  items.filter((item) => item.url === '/natura2000')?.[0]?.items || [];
92
92
  natura2000.forEach((item) => {
93
93
  const languageFolder = matchPath(item.url, {
94
- path: config.settings.multilingualRoot,
94
+ path: config.settings.n2k.multilingualRoot,
95
95
  exact: true,
96
96
  strict: false,
97
97
  });
@@ -100,7 +100,7 @@ const getN2kItems = (items, localStorage) => {
100
100
  }
101
101
  if (
102
102
  languageFolder &&
103
- !config.settings.supportedLanguages.includes(
103
+ !config.settings.n2k.supportedLanguages.includes(
104
104
  languageFolder.params.lang,
105
105
  ) &&
106
106
  item.url !== '/natura2000/sites' &&
package/src/index.js CHANGED
@@ -70,35 +70,37 @@ const applyConfig = (config) => {
70
70
 
71
71
  config.settings = {
72
72
  ...config.settings,
73
- multilingualRoot: '/natura2000/:lang',
74
- multilingualPath: '/natura2000/:lang/*',
75
- defaultLanguage: 'en',
76
- supportedLanguages: [
77
- 'bg',
78
- 'hr',
79
- 'cs',
80
- 'da',
81
- 'nl',
82
- 'en',
83
- 'et',
84
- 'fi',
85
- 'fr',
86
- 'de',
87
- 'el',
88
- 'hu',
89
- 'ga',
90
- 'it',
91
- 'lv',
92
- 'lt',
93
- 'mt',
94
- 'pl',
95
- 'pt',
96
- 'ro',
97
- 'sk',
98
- 'sl',
99
- 'es',
100
- 'sv',
101
- ],
73
+ n2k: {
74
+ multilingualRoot: '/natura2000/:lang',
75
+ multilingualPath: '/natura2000/:lang/*',
76
+ defaultLanguage: 'en',
77
+ supportedLanguages: [
78
+ 'bg',
79
+ 'hr',
80
+ 'cs',
81
+ 'da',
82
+ 'nl',
83
+ 'en',
84
+ 'et',
85
+ 'fi',
86
+ 'fr',
87
+ 'de',
88
+ 'el',
89
+ 'hu',
90
+ 'ga',
91
+ 'it',
92
+ 'lv',
93
+ 'lt',
94
+ 'mt',
95
+ 'pl',
96
+ 'pt',
97
+ 'ro',
98
+ 'sk',
99
+ 'sl',
100
+ 'es',
101
+ 'sv',
102
+ ],
103
+ },
102
104
  };
103
105
 
104
106
  config.settings.themes = {
@@ -347,24 +347,22 @@ body.grey-bg {
347
347
  position: absolute;
348
348
  top: 0;
349
349
  right: 0;
350
- margin: 4px 0;
350
+ margin: 0;
351
+ margin-bottom: 0;
351
352
  transform: translateX(100%) translateY(0);
352
353
 
353
354
  &:hover {
354
355
  background-color: transparent !important;
355
356
  }
356
357
 
357
- &::before {
358
- position: absolute;
359
- top: 4px;
360
- left: 50%;
361
- display: block !important;
362
- width: 6px;
363
- height: 6px;
364
- background-color: #3b7f02;
365
- border-radius: 100%;
366
- content: '';
367
- transform: translateX(-50%);
358
+ .language-selector .ui.dropdown {
359
+ display: flex;
360
+ flex-direction: row-reverse;
361
+ align-items: center;
362
+
363
+ img {
364
+ margin-right: 0.25rem;
365
+ }
368
366
  }
369
367
  }
370
368
  }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-2.29-2.333A17.9 17.9 0 0 1 8.027 13H4.062a8.008 8.008 0 0 0 5.648 6.667zM10.03 13c.151 2.439.848 4.73 1.97 6.752A15.905 15.905 0 0 0 13.97 13h-3.94zm9.908 0h-3.965a17.9 17.9 0 0 1-1.683 6.667A8.008 8.008 0 0 0 19.938 13zM4.062 11h3.965A17.9 17.9 0 0 1 9.71 4.333 8.008 8.008 0 0 0 4.062 11zm5.969 0h3.938A15.905 15.905 0 0 0 12 4.248 15.905 15.905 0 0 0 10.03 11zm4.259-6.667A17.9 17.9 0 0 1 15.973 11h3.965a8.008 8.008 0 0 0-5.648-6.667z" fill="rgba(46,62,76,1)"/></svg>