@eeacms/volto-n2k 1.0.17 → 1.0.18

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,14 +4,22 @@ 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
+ ### [1.0.18](https://github.com/eea/volto-n2k/compare/1.0.17...1.0.18) - 25 February 2023
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat: conditional rendering for section group [Miu Razvan - [`6afd9a5`](https://github.com/eea/volto-n2k/commit/6afd9a536a520c51ad457127aa02f07fd135010e)]
12
+
13
+ #### :hammer_and_wrench: Others
14
+
15
+ - update [Miu Razvan - [`ab24f16`](https://github.com/eea/volto-n2k/commit/ab24f1624eb541d3ab492aa934c923f6cbdd245c)]
16
+ - uopdate label on habitats page [Claudia Ifrim - [`aa708e2`](https://github.com/eea/volto-n2k/commit/aa708e24b8f456407192cf1b889d893fd7b92f0e)]
7
17
  ### [1.0.17](https://github.com/eea/volto-n2k/compare/1.0.16...1.0.17) - 24 February 2023
8
18
 
9
19
  #### :hammer_and_wrench: Others
10
20
 
11
21
  - eslint fix [Miu Razvan - [`417aa35`](https://github.com/eea/volto-n2k/commit/417aa3588b32920a3e378fad8dd72de6d0f02ca3)]
12
22
  - species distribution map for birds group [Miu Razvan - [`7712d28`](https://github.com/eea/volto-n2k/commit/7712d28c0c5a79ffd33d4fc8d1d8e73af55937a2)]
13
- - update [Miu Razvan - [`6ce1f47`](https://github.com/eea/volto-n2k/commit/6ce1f4776686307f867a481b07d5bddd34e10961)]
14
- - update [Miu Razvan - [`d017393`](https://github.com/eea/volto-n2k/commit/d017393b02d3628a6a72c9f6fccf59b34e517933)]
15
23
  ### [1.0.16](https://github.com/eea/volto-n2k/compare/1.0.15...1.0.16) - 22 February 2023
16
24
 
17
25
  #### :hammer_and_wrench: Others
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-n2k",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "volto-n2k: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -21,7 +21,7 @@ const View = (props) => {
21
21
  <div className="habitat-metadata">
22
22
  <h2 className="name">{scientific_name[0]}</h2>
23
23
  <p className="info">
24
- ANNEX I habitat code&nbsp;&nbsp;&nbsp;{code_2000[0]}
24
+ Habitats Directive Annex I code&nbsp;&nbsp;&nbsp;{code_2000[0]}
25
25
  </p>
26
26
  <br />
27
27
  {/* {number_sites[0] && (
@@ -120,7 +120,8 @@ div#view .species-banner-details .ui.container > * {
120
120
 
121
121
  &:not(.with-slider) {
122
122
  display: flex;
123
- align-items: center;
123
+ flex-flow: column;
124
+ justify-content: center;
124
125
 
125
126
  .picture-wrapper {
126
127
  height: fit-content;
@@ -417,8 +417,7 @@ class Navigation extends Component {
417
417
  )}
418
418
  </Dropdown>
419
419
  ) : (
420
- <Link
421
- to={flatUrl === '' ? '/' : flatUrl}
420
+ <div
422
421
  key={flatUrl}
423
422
  className={
424
423
  this.isActive(flatUrl)
@@ -426,8 +425,10 @@ class Navigation extends Component {
426
425
  : 'item firstLevel'
427
426
  }
428
427
  >
429
- {item.title}
430
- </Link>
428
+ <Link to={flatUrl === '' ? '/' : flatUrl}>
429
+ {item.title}
430
+ </Link>
431
+ </div>
431
432
  );
432
433
  })}
433
434
  </>
@@ -0,0 +1,266 @@
1
+ import React, { useState } from 'react';
2
+ import { isEmpty } from 'lodash';
3
+ import {
4
+ BlocksForm,
5
+ SidebarPortal,
6
+ Icon,
7
+ BlockDataForm,
8
+ } from '@plone/volto/components';
9
+ import { emptyBlocksForm } from '@plone/volto/helpers';
10
+ import delightedSVG from '@plone/volto/icons/delighted.svg';
11
+ import dissatisfiedSVG from '@plone/volto/icons/dissatisfied.svg';
12
+ import PropTypes from 'prop-types';
13
+ import { Button, Segment } from 'semantic-ui-react';
14
+ import EditBlockWrapper from './EditBlockWrapper';
15
+ import EditSchema from './EditSchema';
16
+ import helpSVG from '@plone/volto/icons/help.svg';
17
+ import cx from 'classnames';
18
+ import './editor.less';
19
+
20
+ const Edit = (props) => {
21
+ const {
22
+ block,
23
+ data,
24
+ onChangeBlock,
25
+ onChangeField,
26
+ pathname,
27
+ selected,
28
+ manage,
29
+ formDescription,
30
+ } = props;
31
+
32
+ const metadata = props.metadata || props.properties;
33
+ const data_blocks = data?.data?.blocks;
34
+ const properties = isEmpty(data_blocks) ? emptyBlocksForm() : data.data;
35
+
36
+ const [selectedBlock, setSelectedBlock] = useState(
37
+ properties.blocks_layout.items[0],
38
+ );
39
+
40
+ React.useEffect(() => {
41
+ if (
42
+ isEmpty(data_blocks) &&
43
+ properties.blocks_layout.items[0] !== selectedBlock
44
+ ) {
45
+ setSelectedBlock(properties.blocks_layout.items[0]);
46
+ onChangeBlock(block, {
47
+ ...data,
48
+ data: properties,
49
+ });
50
+ }
51
+ }, [onChangeBlock, properties, selectedBlock, block, data, data_blocks]);
52
+
53
+ const blockState = {};
54
+ let charCount = 0;
55
+
56
+ /**
57
+ * Count the number of characters that are anything except using Regex
58
+ * @param {string} paragraph
59
+ * @returns
60
+ */
61
+ const countCharsWithoutSpaces = (paragraph) => {
62
+ const regex = /[^\s\\]/g;
63
+
64
+ return (paragraph.match(regex) || []).length;
65
+ };
66
+
67
+ /**
68
+ * Count the number of characters
69
+ * @param {string} paragraph
70
+ * @returns
71
+ */
72
+ const countCharsWithSpaces = (paragraph) => {
73
+ return paragraph?.length || 0;
74
+ };
75
+
76
+ /**
77
+ * Recursively look for any block that contains text or plaintext
78
+ * @param {Object} blocksObject
79
+ * @returns
80
+ */
81
+ const countTextInBlocks = (blocksObject) => {
82
+ let groupCharCount = 0;
83
+ if (!props.data.maxChars) {
84
+ return groupCharCount;
85
+ }
86
+
87
+ Object.keys(blocksObject).forEach((blockId) => {
88
+ const foundText = blocksObject[blockId]?.plaintext
89
+ ? blocksObject[blockId]?.plaintext
90
+ : blocksObject[blockId]?.text?.blocks[0]?.text
91
+ ? blocksObject[blockId].text.blocks[0].text
92
+ : blocksObject[blockId]?.data?.blocks
93
+ ? countTextInBlocks(blocksObject[blockId]?.data?.blocks)
94
+ : blocksObject[blockId]?.blocks
95
+ ? countTextInBlocks(blocksObject[blockId]?.blocks)
96
+ : '';
97
+ const resultText =
98
+ typeof foundText === 'string' || foundText instanceof String
99
+ ? foundText
100
+ : '';
101
+
102
+ groupCharCount += props.data.ignoreSpaces
103
+ ? countCharsWithoutSpaces(resultText)
104
+ : countCharsWithSpaces(resultText);
105
+ });
106
+
107
+ return groupCharCount;
108
+ };
109
+
110
+ const showCharCounter = () => {
111
+ if (data_blocks) {
112
+ charCount = countTextInBlocks(data_blocks);
113
+ }
114
+ };
115
+ showCharCounter();
116
+
117
+ const counterClass =
118
+ charCount < Math.ceil(props.data.maxChars / 1.05)
119
+ ? 'info'
120
+ : charCount < props.data.maxChars
121
+ ? 'warning'
122
+ : 'danger';
123
+
124
+ const counterComponent = props.data.maxChars ? (
125
+ <p
126
+ className={cx('counter', counterClass)}
127
+ onClick={() => {
128
+ setSelectedBlock();
129
+ props.setSidebarTab(1);
130
+ }}
131
+ aria-hidden="true"
132
+ >
133
+ {props.data.maxChars - charCount < 0 ? (
134
+ <>
135
+ <span>{`${
136
+ charCount - props.data.maxChars
137
+ } characters over the limit`}</span>
138
+ <Icon name={dissatisfiedSVG} size="24px" />
139
+ </>
140
+ ) : (
141
+ <>
142
+ <span>{`${
143
+ props.data.maxChars - charCount
144
+ } characters remaining out of ${props.data.maxChars}`}</span>
145
+ <Icon name={delightedSVG} size="24px" />
146
+ </>
147
+ )}
148
+ </p>
149
+ ) : null;
150
+
151
+ // Get editing instructions from block settings or props
152
+ let instructions = data?.instructions?.data || data?.instructions;
153
+ if (!instructions || instructions === '<p><br/></p>') {
154
+ instructions = formDescription;
155
+ }
156
+
157
+ return (
158
+ <fieldset className="section-block">
159
+ <legend
160
+ onClick={() => {
161
+ setSelectedBlock();
162
+ props.setSidebarTab(1);
163
+ }}
164
+ aria-hidden="true"
165
+ >
166
+ {data.title || 'Section'}
167
+ </legend>
168
+ <BlocksForm
169
+ metadata={metadata}
170
+ properties={properties}
171
+ manage={manage}
172
+ selectedBlock={selected ? selectedBlock : null}
173
+ allowedBlocks={data.allowedBlocks}
174
+ title={data.placeholder}
175
+ description={instructions}
176
+ onSelectBlock={(id) => {
177
+ setSelectedBlock(id);
178
+ }}
179
+ onChangeFormData={(newFormData) => {
180
+ onChangeBlock(block, {
181
+ ...data,
182
+ data: newFormData,
183
+ });
184
+ }}
185
+ onChangeField={(id, value) => {
186
+ if (['blocks', 'blocks_layout'].indexOf(id) > -1) {
187
+ blockState[id] = value;
188
+ onChangeBlock(block, {
189
+ ...data,
190
+ data: {
191
+ ...data.data,
192
+ ...blockState,
193
+ },
194
+ });
195
+ } else {
196
+ onChangeField(id, value);
197
+ }
198
+ }}
199
+ pathname={pathname}
200
+ >
201
+ {({ draginfo }, editBlock, blockProps) => (
202
+ <EditBlockWrapper
203
+ draginfo={draginfo}
204
+ blockProps={blockProps}
205
+ disabled={data.disableInnerButtons}
206
+ extraControls={
207
+ <>
208
+ {instructions && (
209
+ <>
210
+ <Button
211
+ icon
212
+ basic
213
+ title="Section help"
214
+ onClick={() => {
215
+ setSelectedBlock();
216
+ const tab = manage ? 0 : 1;
217
+ props.setSidebarTab(tab);
218
+ }}
219
+ >
220
+ <Icon name={helpSVG} className="" size="19px" />
221
+ </Button>
222
+ </>
223
+ )}
224
+ </>
225
+ }
226
+ >
227
+ {editBlock}
228
+ </EditBlockWrapper>
229
+ )}
230
+ </BlocksForm>
231
+
232
+ {counterComponent}
233
+ <SidebarPortal selected={selected && !selectedBlock}>
234
+ {instructions && (
235
+ <Segment attached>
236
+ <div dangerouslySetInnerHTML={{ __html: instructions }} />
237
+ </Segment>
238
+ )}
239
+ {!data?.readOnlySettings && (
240
+ <BlockDataForm
241
+ schema={EditSchema}
242
+ title="Section (Group) settings"
243
+ formData={data}
244
+ onChangeField={(id, value) => {
245
+ props.onChangeBlock(props.block, {
246
+ ...props.data,
247
+ [id]: value,
248
+ });
249
+ }}
250
+ />
251
+ )}
252
+ </SidebarPortal>
253
+ </fieldset>
254
+ );
255
+ };
256
+
257
+ Edit.propTypes = {
258
+ block: PropTypes.string.isRequired,
259
+ data: PropTypes.object.isRequired,
260
+ onChangeBlock: PropTypes.func.isRequired,
261
+ pathname: PropTypes.string.isRequired,
262
+ selected: PropTypes.bool.isRequired,
263
+ manage: PropTypes.bool.isRequired,
264
+ };
265
+
266
+ export default Edit;
@@ -0,0 +1,188 @@
1
+ import React from 'react';
2
+ import { Icon, BlockChooser } from '@plone/volto/components';
3
+ import { blockHasValue } from '@plone/volto/helpers';
4
+ import config from '@plone/volto/registry';
5
+ import { Button } from 'semantic-ui-react';
6
+ import includes from 'lodash/includes';
7
+ import isBoolean from 'lodash/isBoolean';
8
+ import { defineMessages, injectIntl } from 'react-intl';
9
+ import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib';
10
+ import cx from 'classnames';
11
+
12
+ import dragSVG from '@plone/volto/icons/drag.svg';
13
+ import addSVG from '@plone/volto/icons/circle-plus.svg';
14
+ import trashSVG from '@plone/volto/icons/delete.svg';
15
+
16
+ const messages = defineMessages({
17
+ unknownBlock: {
18
+ id: 'Unknown Block',
19
+ defaultMessage: 'Unknown Block {block}',
20
+ },
21
+ delete: {
22
+ id: 'delete',
23
+ defaultMessage: 'delete',
24
+ },
25
+ });
26
+
27
+ class EditBlockWrapper extends React.Component {
28
+ constructor(props) {
29
+ super(props);
30
+ this.state = {
31
+ addNewBlockOpened: false,
32
+ };
33
+ }
34
+
35
+ componentDidMount() {
36
+ document.addEventListener('mousedown', this.handleClickOutside, false);
37
+ }
38
+
39
+ componentWillUnmount() {
40
+ document.removeEventListener('mousedown', this.handleClickOutside);
41
+ }
42
+
43
+ handleClickOutside = (e) => {
44
+ if (
45
+ this.blockNode.current &&
46
+ doesNodeContainClick(this.blockNode.current, e)
47
+ )
48
+ return;
49
+
50
+ if (this.state.addNewBlockOpened) {
51
+ this.setState({
52
+ addNewBlockOpened: false,
53
+ });
54
+ return true;
55
+ }
56
+ };
57
+
58
+ blockNode = React.createRef();
59
+
60
+ render() {
61
+ const {
62
+ intl,
63
+ blockProps,
64
+ draginfo,
65
+ extraControls,
66
+ disabled,
67
+ children,
68
+ } = this.props;
69
+
70
+ const {
71
+ allowedBlocks,
72
+ block,
73
+ data,
74
+ onSelectBlock,
75
+ onDeleteBlock,
76
+ onMutateBlock,
77
+ onInsertBlock,
78
+ selected,
79
+ } = blockProps;
80
+ const type = data['@type'];
81
+ const { disableNewBlocks } = data;
82
+ const dragVisible = !data.fixed;
83
+ const visible = selected;
84
+
85
+ const required = isBoolean(data.required)
86
+ ? data.required
87
+ : includes(config.blocks.requiredBlocks, type);
88
+
89
+ // Get editing instructions from block settings or props
90
+ let instructions = data?.instructions?.data || data?.instructions;
91
+ if (!instructions || instructions === '<p><br/></p>') {
92
+ instructions = '';
93
+ }
94
+
95
+ return (
96
+ <div ref={this.blockNode}>
97
+ <div
98
+ ref={draginfo?.innerRef}
99
+ {...(selected ? draginfo?.draggableProps : null)}
100
+ className={`block-editor-${data['@type']}`}
101
+ >
102
+ {(!selected || !visible || disabled) && (
103
+ <div
104
+ style={{
105
+ display: 'none',
106
+ // keep react-beautiful-dnd happy
107
+ }}
108
+ {...draginfo.dragHandleProps}
109
+ ></div>
110
+ )}
111
+ {visible && (
112
+ <div className="block-toolbar">
113
+ {instructions ? extraControls : ''}
114
+
115
+ {!disabled && (
116
+ <>
117
+ <div
118
+ style={{
119
+ display: dragVisible ? 'inline-block' : 'none',
120
+ }}
121
+ {...draginfo.dragHandleProps}
122
+ className="drag handle wrapper-group-block"
123
+ >
124
+ <Button icon basic title="Drag and drop">
125
+ <Icon name={dragSVG} size="19px" />
126
+ </Button>
127
+ </div>
128
+
129
+ {!disableNewBlocks && !blockHasValue(data) && (
130
+ <Button
131
+ icon
132
+ basic
133
+ title="Add block"
134
+ onClick={() => {
135
+ this.setState({
136
+ addNewBlockOpened: !this.state.addNewBlockOpened,
137
+ });
138
+ }}
139
+ className="group-block-add-button"
140
+ >
141
+ <Icon name={addSVG} className="" size="19px" />
142
+ </Button>
143
+ )}
144
+ {!required && (
145
+ <Button
146
+ icon
147
+ basic
148
+ title="Remove block"
149
+ onClick={() => onDeleteBlock(block)}
150
+ className="delete-button-group-block"
151
+ aria-label={intl.formatMessage(messages.delete)}
152
+ >
153
+ <Icon name={trashSVG} size="19px" />
154
+ </Button>
155
+ )}
156
+ {this.state.addNewBlockOpened && (
157
+ <BlockChooser
158
+ onMutateBlock={(id, value) => {
159
+ onMutateBlock(id, value);
160
+ this.setState({ addNewBlockOpened: false });
161
+ }}
162
+ onInsertBlock={(id, value) => {
163
+ onSelectBlock(onInsertBlock(id, value));
164
+ this.setState({ addNewBlockOpened: false });
165
+ }}
166
+ currentBlock={block}
167
+ allowedBlocks={allowedBlocks}
168
+ />
169
+ )}
170
+ </>
171
+ )}
172
+ </div>
173
+ )}
174
+
175
+ <div
176
+ className={cx('ui drag block wrapper inner', type, {
177
+ multiSelected: this.props.multiSelected,
178
+ })}
179
+ >
180
+ {children}
181
+ </div>
182
+ </div>
183
+ </div>
184
+ );
185
+ }
186
+ }
187
+
188
+ export default injectIntl(EditBlockWrapper);
@@ -0,0 +1,41 @@
1
+ const Schema = {
2
+ title: 'Section block',
3
+ fieldsets: [
4
+ {
5
+ id: 'default',
6
+ title: 'Default',
7
+ fields: ['title', 'as', 'condition'],
8
+ },
9
+ ],
10
+ properties: {
11
+ title: {
12
+ title: 'Title',
13
+ description: 'Section friendly name',
14
+ type: 'string',
15
+ },
16
+ as: {
17
+ title: 'HTML5 element',
18
+ description: 'Select HTML5 element to be used for this block',
19
+ type: 'string',
20
+ factory: 'Choice',
21
+ default: 'div',
22
+ choices: [
23
+ ['div', 'div'],
24
+ ['section', 'section'],
25
+ ['article', 'article'],
26
+ ['aside', 'aside'],
27
+ ['details', 'details'],
28
+ ],
29
+ },
30
+ condition: {
31
+ title: 'Condition',
32
+ choices: [
33
+ ['bird', 'Is bird'],
34
+ ['species', 'Is not bird'],
35
+ ],
36
+ },
37
+ },
38
+ required: [],
39
+ };
40
+
41
+ export default Schema;
@@ -0,0 +1,116 @@
1
+ const Schema = {
2
+ title: 'Section (Group) settings',
3
+ fieldsets: [
4
+ {
5
+ id: 'default',
6
+ title: 'Default',
7
+ fields: [
8
+ 'title',
9
+ 'placeholder',
10
+ 'instructions',
11
+ 'allowedBlocks',
12
+ 'as',
13
+ 'maxChars',
14
+ 'ignoreSpaces',
15
+ 'readOnlySettings',
16
+ 'disableInnerButtons',
17
+ 'required',
18
+ 'fixed',
19
+ 'fixedLayout',
20
+ 'disableNewBlocks',
21
+ 'readOnly',
22
+ ],
23
+ },
24
+ ],
25
+ properties: {
26
+ title: {
27
+ title: 'Title',
28
+ description: 'Section friendly name',
29
+ type: 'string',
30
+ },
31
+ allowedBlocks: {
32
+ title: 'Allowed blocks',
33
+ description: 'Allow only the following blocks types',
34
+ type: 'array',
35
+ items: {
36
+ choices: [],
37
+ },
38
+ },
39
+ placeholder: {
40
+ title: 'Helper text',
41
+ description:
42
+ 'A short hint that describes the expected value within this block',
43
+ type: 'string',
44
+ },
45
+ instructions: {
46
+ title: 'Instructions',
47
+ description: 'Detailed expected value within this block',
48
+ type: 'string',
49
+ widget: 'richtext',
50
+ },
51
+ as: {
52
+ title: 'HTML5 element',
53
+ description: 'Select HTML5 element to be used for this block',
54
+ type: 'string',
55
+ factory: 'Choice',
56
+ default: 'div',
57
+ choices: [
58
+ ['div', 'div'],
59
+ ['section', 'section'],
60
+ ['article', 'article'],
61
+ ['aside', 'aside'],
62
+ ['details', 'details'],
63
+ ],
64
+ },
65
+ maxChars: {
66
+ title: 'Maximum Characters',
67
+ description: 'The maximum number of characters.',
68
+ type: 'integer',
69
+ factory: 'Integer',
70
+ },
71
+ ignoreSpaces: {
72
+ title: 'Ignore spaces',
73
+ description: 'Ignore spaces while calculating maximum characters',
74
+ type: 'boolean',
75
+ },
76
+ required: {
77
+ title: 'Required',
78
+ description: "Don't allow deletion of this block",
79
+ type: 'boolean',
80
+ },
81
+ fixed: {
82
+ title: 'Fixed position',
83
+ description: 'Disable drag & drop on this block',
84
+ type: 'boolean',
85
+ },
86
+ fixedLayout: {
87
+ title: 'Fixed layout',
88
+ description:
89
+ 'Fixed layout, New blocks created by Editor within this block will be ignored',
90
+ type: 'boolean',
91
+ },
92
+ disableNewBlocks: {
93
+ title: 'Disable new blocks',
94
+ description: 'Disable creation of new blocks after this block',
95
+ type: 'boolean',
96
+ },
97
+ readOnly: {
98
+ title: 'Read-only',
99
+ description: 'Disable editing on this block',
100
+ type: 'boolean',
101
+ },
102
+ readOnlySettings: {
103
+ title: 'Read-only settings',
104
+ description: 'Disable editing on section block settings',
105
+ type: 'boolean',
106
+ },
107
+ disableInnerButtons: {
108
+ title: 'Disable inner buttons',
109
+ description: 'Hide all block related buttons within this block',
110
+ type: 'boolean',
111
+ },
112
+ },
113
+ required: [],
114
+ };
115
+
116
+ export default Schema;
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { RenderBlocks } from '@plone/volto/components';
3
+ import config from '@plone/volto/registry';
4
+
5
+ const View = (props) => {
6
+ const { data } = props;
7
+ const condition = data.condition;
8
+ const metadata = props.metadata || props.properties;
9
+ const CustomTag = `${data.as || 'div'}`;
10
+ const customId = data?.title
11
+ ?.toLowerCase()
12
+ ?.replace(/[^a-zA-Z-\s]/gi, '')
13
+ ?.trim()
14
+ ?.replace(/\s+/gi, '-');
15
+
16
+ const ConditionalRendering =
17
+ config.blocks.blocksConfig.group.conditions?.[condition] || null;
18
+
19
+ if (ConditionalRendering) {
20
+ return (
21
+ <ConditionalRendering>
22
+ <CustomTag id={customId}>
23
+ <RenderBlocks
24
+ {...props}
25
+ metadata={metadata}
26
+ content={data?.data || {}}
27
+ />
28
+ </CustomTag>
29
+ </ConditionalRendering>
30
+ );
31
+ }
32
+
33
+ return (
34
+ <CustomTag id={customId}>
35
+ <RenderBlocks {...props} metadata={metadata} content={data?.data || {}} />
36
+ </CustomTag>
37
+ );
38
+ };
39
+
40
+ export default View;
@@ -0,0 +1,99 @@
1
+ @type: 'extra';
2
+ @element: 'custom';
3
+
4
+ @import (multiple, reference, optional) '../../theme.config';
5
+
6
+ @borderColor: rgba(120, 192, 215, 0.75);
7
+
8
+ .block-editor-group {
9
+ [data-rbd-draggable-context-id] {
10
+ margin-bottom: 1rem;
11
+ }
12
+
13
+ .block-add-button {
14
+ display: none !important;
15
+ }
16
+
17
+ .block.group.selected::before,
18
+ .block.group:hover::before {
19
+ border-style: dashed;
20
+ }
21
+
22
+ fieldset {
23
+ border: none;
24
+
25
+ legend {
26
+ position: absolute;
27
+ z-index: 3;
28
+ top: -1.3em;
29
+ left: 0;
30
+ width: fit-content;
31
+ padding: 0 1rem;
32
+ margin-right: auto;
33
+ margin-left: auto;
34
+ background-color: @pageBackground;
35
+ color: @borderColor;
36
+ cursor: pointer;
37
+ text-align: center;
38
+ }
39
+ }
40
+
41
+ .section-block {
42
+ padding-top: 1rem;
43
+ padding-bottom: 0.1rem;
44
+ margin: 0;
45
+ }
46
+
47
+ .counter {
48
+ display: grid;
49
+ align-items: center;
50
+ font-size: 85%;
51
+ grid-gap: 0.5em;
52
+ grid-template-columns: 98% auto;
53
+ text-align: end;
54
+
55
+ &.info {
56
+ color: #ccc;
57
+ }
58
+
59
+ &.danger {
60
+ color: crimson;
61
+ }
62
+
63
+ &.warning {
64
+ color: darkorange;
65
+ }
66
+ }
67
+
68
+ .blocks-form {
69
+ margin-top: 0.5rem;
70
+ }
71
+
72
+ .blocks-chooser {
73
+ right: 0;
74
+ left: auto;
75
+ margin-top: 3rem;
76
+ }
77
+
78
+ .block-toolbar {
79
+ position: absolute;
80
+ z-index: 3;
81
+ right: -9px;
82
+ display: flex;
83
+ border: none;
84
+ border: 1px solid @borderColor;
85
+ border-bottom: 1px solid @pageBackground;
86
+ margin-top: -45px;
87
+ background-color: @pageBackground;
88
+ border-top-left-radius: 1rem;
89
+ border-top-right-radius: 1rem;
90
+
91
+ .ui.basic.button {
92
+ padding: 8px 5px;
93
+ }
94
+
95
+ .ui.basic.button:hover {
96
+ background: transparent !important;
97
+ }
98
+ }
99
+ }
package/src/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /* eslint-disable no-extend-native */
2
2
  import React from 'react';
3
3
  import loadable from '@loadable/component';
4
+ import { compose } from 'redux';
5
+ import { connectToProviderData } from '@eeacms/volto-datablocks/hocs';
4
6
 
5
7
  import { hashlink, localStorage } from './reducers';
6
8
 
@@ -125,6 +127,38 @@ const applyConfig = (config) => {
125
127
  ],
126
128
  };
127
129
 
130
+ config.blocks.blocksConfig.group = {
131
+ ...(config.blocks.blocksConfig.group || {}),
132
+ conditions: {
133
+ bird: compose(
134
+ connectToProviderData((props) => ({
135
+ provider_url: '/data/natura-2000-species',
136
+ })),
137
+ )(({ children, provider_data }) => {
138
+ if (
139
+ provider_data?.species_group_name?.[0] &&
140
+ provider_data?.species_group_name?.[0] === 'Birds'
141
+ ) {
142
+ return children;
143
+ }
144
+ return null;
145
+ }),
146
+ species: compose(
147
+ connectToProviderData((props) => ({
148
+ provider_url: '/data/natura-2000-species',
149
+ })),
150
+ )(({ children, provider_data }) => {
151
+ if (
152
+ provider_data?.species_group_name?.[0] &&
153
+ provider_data?.species_group_name?.[0] !== 'Birds'
154
+ ) {
155
+ return children;
156
+ }
157
+ return null;
158
+ }),
159
+ },
160
+ };
161
+
128
162
  config.settings.slate.elements[LINK] = LinkElement;
129
163
 
130
164
  config.settings.loadables = {