@eeacms/volto-clms-theme 1.0.105 → 1.0.108
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 +31 -0
- package/package.json +1 -1
- package/src/components/Blocks/CclSubscriptionBlock/SubscriptionEdit.jsx +2 -2
- package/src/components/Blocks/CclSubscriptionBlock/SubscriptionView.jsx +12 -1
- package/src/components/Blocks/CclSubscriptionBlock/schema.js +5 -1
- package/src/components/Blocks/CustomTemplates/VoltoFormBlock/VocabularyWidget.jsx +7 -5
- package/src/components/Blocks/CustomTemplates/VoltoSearchBlock/FilterList.jsx +1 -1
- package/src/components/Blocks/customBlocks.js +26 -0
- package/src/components/CLMSMeetingView/CLMSMeetingView.jsx +8 -70
- package/src/components/CLMSNewsItemView/CLMSNewsItemView.jsx +54 -128
- package/src/components/CLMSRelatedItems/CLMSRelatedItems.jsx +39 -0
- package/src/components/CLMSRelatedItems/index.js +3 -0
- package/src/components/CclModal/CclModal.jsx +1 -1
- package/src/components/Widgets/ImageWidget.jsx +239 -0
- package/src/customizations/volto/components/manage/Widgets/EmailWidget.jsx +126 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,39 @@ 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.108](https://github.com/eea/volto-clms-theme/compare/1.0.107...1.0.108)
|
|
8
|
+
|
|
9
|
+
- EmailWidget fix [`cd56839`](https://github.com/eea/volto-clms-theme/commit/cd5683951ae27f7ceb51703593e898e33928bf0e)
|
|
10
|
+
|
|
11
|
+
#### [1.0.107](https://github.com/eea/volto-clms-theme/compare/1.0.106...1.0.107)
|
|
12
|
+
|
|
13
|
+
> 14 July 2022
|
|
14
|
+
|
|
15
|
+
- Develop [`#278`](https://github.com/eea/volto-clms-theme/pull/278)
|
|
16
|
+
- Minor fixes [`#277`](https://github.com/eea/volto-clms-theme/pull/277)
|
|
17
|
+
- remove unused import [`dc57cf5`](https://github.com/eea/volto-clms-theme/commit/dc57cf5d5a3c1537edd762854be35ae076fc0359)
|
|
18
|
+
- unify related items in one component [`87fa84f`](https://github.com/eea/volto-clms-theme/commit/87fa84f78c06ec666b2a5ae720e6faa76df9ed1d)
|
|
19
|
+
- show related products/datasets always [`a35faad`](https://github.com/eea/volto-clms-theme/commit/a35faad04dc54e78afa9fc47fe9545ff7fe36303)
|
|
20
|
+
- show only File items [`abb4859`](https://github.com/eea/volto-clms-theme/commit/abb48592819a4bf338fc34aebdc1f1ecd920a226)
|
|
21
|
+
|
|
22
|
+
#### [1.0.106](https://github.com/eea/volto-clms-theme/compare/1.0.105...1.0.106)
|
|
23
|
+
|
|
24
|
+
> 13 July 2022
|
|
25
|
+
|
|
26
|
+
- Develop [`#276`](https://github.com/eea/volto-clms-theme/pull/276)
|
|
27
|
+
- new field types for form [`a452429`](https://github.com/eea/volto-clms-theme/commit/a452429eff799806d58e05e3e4164bc885d6eeb9)
|
|
28
|
+
- handle SelectWidget choices until the vocabulary is loaded [`0614fb5`](https://github.com/eea/volto-clms-theme/commit/0614fb584f52571d15e37fbe921e0694594a01f4)
|
|
29
|
+
- EmailWidget fix and ImageWidget created for form block [`fc1d16b`](https://github.com/eea/volto-clms-theme/commit/fc1d16baf2466dec09d835147fc3df839811e409)
|
|
30
|
+
- lint fix [`af5f960`](https://github.com/eea/volto-clms-theme/commit/af5f9605ec147cb010245a58696087abaed55c35)
|
|
31
|
+
- EmailWidget override for correct anguage and size limitation [`8a6c253`](https://github.com/eea/volto-clms-theme/commit/8a6c253f590fcf753d1a274e8ab7767f366d8c1e)
|
|
32
|
+
- number of current filters [`195cc43`](https://github.com/eea/volto-clms-theme/commit/195cc43d351d0e9793a0f462ecf8bdf9433a1def)
|
|
33
|
+
- subscription modal block [`30db876`](https://github.com/eea/volto-clms-theme/commit/30db876826dd53db6bbb11507de11af10a71a4eb)
|
|
34
|
+
|
|
7
35
|
#### [1.0.105](https://github.com/eea/volto-clms-theme/compare/1.0.104...1.0.105)
|
|
8
36
|
|
|
37
|
+
> 11 July 2022
|
|
38
|
+
|
|
39
|
+
- Develop [`#275`](https://github.com/eea/volto-clms-theme/pull/275)
|
|
9
40
|
- File card [`#274`](https://github.com/eea/volto-clms-theme/pull/274)
|
|
10
41
|
- sort items taxonomy items [`#272`](https://github.com/eea/volto-clms-theme/pull/272)
|
|
11
42
|
- Changes in download cart [`#271`](https://github.com/eea/volto-clms-theme/pull/271)
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CclButton from '@eeacms/volto-clms-theme/components/CclButton/CclButton';
|
|
2
2
|
import { SidebarPortal } from '@plone/volto/components';
|
|
3
3
|
import { SubscriptionSchema } from './schema';
|
|
4
4
|
import InlineForm from '@plone/volto/components/manage/Form/InlineForm';
|
|
@@ -16,7 +16,7 @@ const SubscriptionBlockEdit = (props) => {
|
|
|
16
16
|
aria-hidden="true"
|
|
17
17
|
/>
|
|
18
18
|
</div>
|
|
19
|
-
<
|
|
19
|
+
<CclButton mode={'filled'}>{data.title || 'Text example...'}</CclButton>
|
|
20
20
|
<SidebarPortal selected={selected}>
|
|
21
21
|
<InlineForm
|
|
22
22
|
schema={SubscriptionSchema()}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { SubscriptionView } from '@eeacms/volto-clms-theme/components/CLMSSubscriptionView';
|
|
2
|
+
import CclModal from '@eeacms/volto-clms-theme/components/CclModal/CclModal';
|
|
3
|
+
import CclButton from '@eeacms/volto-clms-theme/components/CclButton/CclButton';
|
|
2
4
|
|
|
3
5
|
const SubscriptionBlockView = (props) => {
|
|
4
6
|
const { data } = props;
|
|
5
7
|
|
|
6
|
-
return
|
|
8
|
+
return (
|
|
9
|
+
<CclModal
|
|
10
|
+
trigger={
|
|
11
|
+
<CclButton mode={'filled'}>{data.title || 'Text example...'}</CclButton>
|
|
12
|
+
}
|
|
13
|
+
size="small"
|
|
14
|
+
>
|
|
15
|
+
<SubscriptionView type={data.type || 'events'} />
|
|
16
|
+
</CclModal>
|
|
17
|
+
);
|
|
7
18
|
};
|
|
8
19
|
|
|
9
20
|
export default SubscriptionBlockView;
|
|
@@ -4,7 +4,7 @@ export const SubscriptionSchema = () => ({
|
|
|
4
4
|
{
|
|
5
5
|
id: 'default',
|
|
6
6
|
title: 'Default',
|
|
7
|
-
fields: ['type'],
|
|
7
|
+
fields: ['type', 'title'],
|
|
8
8
|
},
|
|
9
9
|
],
|
|
10
10
|
properties: {
|
|
@@ -16,6 +16,10 @@ export const SubscriptionSchema = () => ({
|
|
|
16
16
|
['newsletter', 'newsletter'],
|
|
17
17
|
],
|
|
18
18
|
},
|
|
19
|
+
title: {
|
|
20
|
+
title: 'Title',
|
|
21
|
+
type: 'string',
|
|
22
|
+
},
|
|
19
23
|
},
|
|
20
24
|
required: ['product'],
|
|
21
25
|
});
|
|
@@ -45,11 +45,13 @@ const VocabularyWidget = ({
|
|
|
45
45
|
getVocabulary={() => {}}
|
|
46
46
|
getVocabularyTokenTitle={() => {}}
|
|
47
47
|
choices={
|
|
48
|
-
vocabItems?.loaded
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
vocabItems?.loaded
|
|
49
|
+
? [
|
|
50
|
+
...vocabItems.items.map((item) => {
|
|
51
|
+
return [item.label, item.label];
|
|
52
|
+
}),
|
|
53
|
+
]
|
|
54
|
+
: []
|
|
53
55
|
}
|
|
54
56
|
value={value}
|
|
55
57
|
onChange={onChange}
|
|
@@ -65,6 +65,7 @@ import homeBand from '@plone/volto/icons/image-wide.svg';
|
|
|
65
65
|
import linkSVG from '@plone/volto/icons/link.svg';
|
|
66
66
|
import navSVG from '@plone/volto/icons/nav.svg';
|
|
67
67
|
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
68
|
+
import ImageWidget from '@eeacms/volto-clms-theme/components/Widgets/ImageWidget';
|
|
68
69
|
|
|
69
70
|
export const customGroupBlocksOrder = [
|
|
70
71
|
{
|
|
@@ -474,6 +475,31 @@ const customBlocks = (config) => ({
|
|
|
474
475
|
isMulti: true,
|
|
475
476
|
}),
|
|
476
477
|
},
|
|
478
|
+
{
|
|
479
|
+
id: 'topic_vocabulary',
|
|
480
|
+
label: 'Topics Vocabulary',
|
|
481
|
+
component: (props) =>
|
|
482
|
+
VocabularyWidget({
|
|
483
|
+
...props,
|
|
484
|
+
vocabulary: 'clms.types.TopicsVocabulary',
|
|
485
|
+
isMulti: true,
|
|
486
|
+
}),
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
id: 'spatial_coverage_vocabulary',
|
|
490
|
+
label: 'Spatial Coverage Vocabulary',
|
|
491
|
+
component: (props) =>
|
|
492
|
+
VocabularyWidget({
|
|
493
|
+
...props,
|
|
494
|
+
vocabulary: 'clms.types.UseCaseSpatialCoverageVocabulary',
|
|
495
|
+
isMulti: true,
|
|
496
|
+
}),
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
id: 'image_field_widget',
|
|
500
|
+
label: 'Image Field Widget',
|
|
501
|
+
component: ImageWidget,
|
|
502
|
+
},
|
|
477
503
|
],
|
|
478
504
|
},
|
|
479
505
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './meetingstyles.less';
|
|
2
2
|
|
|
3
3
|
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
|
4
|
-
import { Header, Image, Message, Segment
|
|
4
|
+
import { Header, Image, Message, Segment } from 'semantic-ui-react';
|
|
5
5
|
import { Icon, Toast } from '@plone/volto/components';
|
|
6
6
|
import {
|
|
7
7
|
Recurrence,
|
|
@@ -23,6 +23,7 @@ import CclListingCards from '@eeacms/volto-clms-theme/components/Blocks/CustomTe
|
|
|
23
23
|
import config from '@plone/volto/registry';
|
|
24
24
|
import AnimateHeight from 'react-animate-height';
|
|
25
25
|
import { Accordion } from 'semantic-ui-react';
|
|
26
|
+
import { CLMSRelatedItems } from '../CLMSRelatedItems';
|
|
26
27
|
|
|
27
28
|
export const CLMSMeetingView = (props) => {
|
|
28
29
|
const { content, intl } = props;
|
|
@@ -112,15 +113,9 @@ export const CLMSMeetingView = (props) => {
|
|
|
112
113
|
);
|
|
113
114
|
history.push(props.location.pathname + '/form');
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
? content.items.map((item) => (item['@type'] === 'File' ? item : null))
|
|
119
|
-
: [];
|
|
120
|
-
const index = files.indexOf(null);
|
|
121
|
-
if (index > -1) {
|
|
122
|
-
files.splice(index, 1);
|
|
123
|
-
}
|
|
116
|
+
const files = content.items
|
|
117
|
+
? content.items.filter((item) => item['@type'] === 'File')
|
|
118
|
+
: [];
|
|
124
119
|
const RegistrationButton = ({ rContent, rMeeting_register, rIsLoggedIn }) => {
|
|
125
120
|
return (
|
|
126
121
|
<>
|
|
@@ -425,6 +420,7 @@ export const CLMSMeetingView = (props) => {
|
|
|
425
420
|
)}
|
|
426
421
|
<StringToHTML string={content.text?.data || ''} />
|
|
427
422
|
<LightGalleryListing />
|
|
423
|
+
|
|
428
424
|
{files.length > 0 && (
|
|
429
425
|
<CclListingCards
|
|
430
426
|
variation="file"
|
|
@@ -456,36 +452,7 @@ export const CLMSMeetingView = (props) => {
|
|
|
456
452
|
</Accordion.Title>
|
|
457
453
|
<Accordion.Content active={activeIndex.includes(0)}>
|
|
458
454
|
<AnimateHeight animateOpacity duration={500} height={'auto'}>
|
|
459
|
-
<
|
|
460
|
-
{content.products.map((product, key) => (
|
|
461
|
-
<li key={key}>
|
|
462
|
-
<Grid columns={2}>
|
|
463
|
-
<Grid.Column width={2}>
|
|
464
|
-
{product.image_field && (
|
|
465
|
-
<img
|
|
466
|
-
src={
|
|
467
|
-
product.image_field
|
|
468
|
-
? `${product['@id']}/@@images/image`
|
|
469
|
-
: 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg'
|
|
470
|
-
}
|
|
471
|
-
alt={
|
|
472
|
-
product.image_field
|
|
473
|
-
? product.image?.filename
|
|
474
|
-
: 'Placeholder'
|
|
475
|
-
}
|
|
476
|
-
/>
|
|
477
|
-
)}
|
|
478
|
-
</Grid.Column>
|
|
479
|
-
<Grid.Column width={10}>
|
|
480
|
-
<a href={product['@id']}>
|
|
481
|
-
<strong>{product.title}</strong>
|
|
482
|
-
</a>
|
|
483
|
-
<p>{product.description}</p>
|
|
484
|
-
</Grid.Column>
|
|
485
|
-
</Grid>
|
|
486
|
-
</li>
|
|
487
|
-
))}
|
|
488
|
-
</ul>
|
|
455
|
+
<CLMSRelatedItems items={content.products} />
|
|
489
456
|
</AnimateHeight>
|
|
490
457
|
</Accordion.Content>
|
|
491
458
|
</Accordion>
|
|
@@ -512,36 +479,7 @@ export const CLMSMeetingView = (props) => {
|
|
|
512
479
|
</Accordion.Title>
|
|
513
480
|
<Accordion.Content active={activeDatasetIndex.includes(0)}>
|
|
514
481
|
<AnimateHeight animateOpacity duration={500} height={'auto'}>
|
|
515
|
-
<
|
|
516
|
-
{content.datasets.map((dataset, key) => (
|
|
517
|
-
<li key={key}>
|
|
518
|
-
<Grid columns={2}>
|
|
519
|
-
<Grid.Column width={2}>
|
|
520
|
-
{dataset.image_field && (
|
|
521
|
-
<img
|
|
522
|
-
src={
|
|
523
|
-
dataset.image_field
|
|
524
|
-
? `${dataset['@id']}/@@images/image`
|
|
525
|
-
: 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg'
|
|
526
|
-
}
|
|
527
|
-
alt={
|
|
528
|
-
dataset.image_field
|
|
529
|
-
? dataset.image?.filename
|
|
530
|
-
: 'Placeholder'
|
|
531
|
-
}
|
|
532
|
-
/>
|
|
533
|
-
)}
|
|
534
|
-
</Grid.Column>
|
|
535
|
-
<Grid.Column width={10}>
|
|
536
|
-
<a href={dataset['@id']}>
|
|
537
|
-
<strong>{dataset.title}</strong>
|
|
538
|
-
</a>
|
|
539
|
-
<p>{dataset.description}</p>
|
|
540
|
-
</Grid.Column>
|
|
541
|
-
</Grid>
|
|
542
|
-
</li>
|
|
543
|
-
))}
|
|
544
|
-
</ul>
|
|
482
|
+
<CLMSRelatedItems items={content.datasets} />
|
|
545
483
|
</AnimateHeight>
|
|
546
484
|
</Accordion.Content>
|
|
547
485
|
</Accordion>
|
|
@@ -8,18 +8,14 @@ import CclListingCards from '@eeacms/volto-clms-theme/components/Blocks/CustomTe
|
|
|
8
8
|
import config from '@plone/volto/registry';
|
|
9
9
|
import { Icon } from '@plone/volto/components';
|
|
10
10
|
import AnimateHeight from 'react-animate-height';
|
|
11
|
-
import { Accordion
|
|
11
|
+
import { Accordion } from 'semantic-ui-react';
|
|
12
|
+
import { CLMSRelatedItems } from '../CLMSRelatedItems';
|
|
12
13
|
|
|
13
14
|
const CLMSNewsItemView = (props) => {
|
|
14
15
|
const { content } = props;
|
|
15
|
-
const files =
|
|
16
|
-
content.items
|
|
17
|
-
|
|
18
|
-
: [];
|
|
19
|
-
const index = files.indexOf(null);
|
|
20
|
-
if (index > -1) {
|
|
21
|
-
files.splice(index, 1);
|
|
22
|
-
}
|
|
16
|
+
const files = content.items
|
|
17
|
+
? content.items.filter((item) => item['@type'] === 'File')
|
|
18
|
+
: [];
|
|
23
19
|
const [activeIndex, setActiveIndex] = React.useState([99]);
|
|
24
20
|
|
|
25
21
|
const handleClick = ({ index }) => {
|
|
@@ -80,128 +76,58 @@ const CLMSNewsItemView = (props) => {
|
|
|
80
76
|
<StringToHTML string={content.text?.data || ''} />
|
|
81
77
|
</div>
|
|
82
78
|
<LightGalleryListing />
|
|
83
|
-
{files.length > 0 && (
|
|
84
|
-
<CclListingCards
|
|
85
|
-
variation="file"
|
|
86
|
-
items={files}
|
|
87
|
-
linkHref={`${files['@id']}/@@download/file`}
|
|
88
|
-
/>
|
|
89
|
-
)}
|
|
90
|
-
{content?.products?.length > 0 && (
|
|
91
|
-
<Accordion fluid styled>
|
|
92
|
-
<Accordion.Title
|
|
93
|
-
as={'h2'}
|
|
94
|
-
onClick={() => handleClick({ index: 0 })}
|
|
95
|
-
className={'accordion-title align-arrow-right'}
|
|
96
|
-
>
|
|
97
|
-
{activeIndex.includes(0) ? (
|
|
98
|
-
<Icon
|
|
99
|
-
name={iconName(content, titleIcons.opened)}
|
|
100
|
-
size="24px"
|
|
101
|
-
/>
|
|
102
|
-
) : (
|
|
103
|
-
<Icon
|
|
104
|
-
name={iconName(content, titleIcons.closed)}
|
|
105
|
-
size="24px"
|
|
106
|
-
/>
|
|
107
|
-
)}
|
|
108
|
-
<span>Related products</span>
|
|
109
|
-
</Accordion.Title>
|
|
110
|
-
<Accordion.Content active={activeIndex.includes(0)}>
|
|
111
|
-
<AnimateHeight animateOpacity duration={500} height={'auto'}>
|
|
112
|
-
<ul>
|
|
113
|
-
{content.products.map((product, key) => (
|
|
114
|
-
<li key={key}>
|
|
115
|
-
<Grid columns={2}>
|
|
116
|
-
<Grid.Column width={2}>
|
|
117
|
-
{product.image_field && (
|
|
118
|
-
<img
|
|
119
|
-
src={
|
|
120
|
-
product.image_field
|
|
121
|
-
? `${product['@id']}/@@images/image`
|
|
122
|
-
: 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg'
|
|
123
|
-
}
|
|
124
|
-
alt={
|
|
125
|
-
product.image_field
|
|
126
|
-
? product.image?.filename
|
|
127
|
-
: 'Placeholder'
|
|
128
|
-
}
|
|
129
|
-
/>
|
|
130
|
-
)}
|
|
131
|
-
</Grid.Column>
|
|
132
|
-
<Grid.Column width={10}>
|
|
133
|
-
<a href={product['@id']}>
|
|
134
|
-
<strong>{product.title}</strong>
|
|
135
|
-
</a>
|
|
136
|
-
<p>{product.description}</p>
|
|
137
|
-
</Grid.Column>
|
|
138
|
-
</Grid>
|
|
139
|
-
</li>
|
|
140
|
-
))}
|
|
141
|
-
</ul>
|
|
142
|
-
</AnimateHeight>
|
|
143
|
-
</Accordion.Content>
|
|
144
|
-
</Accordion>
|
|
145
|
-
)}
|
|
146
|
-
{content?.datasets?.length > 0 && (
|
|
147
|
-
<Accordion fluid styled>
|
|
148
|
-
<Accordion.Title
|
|
149
|
-
as={'h2'}
|
|
150
|
-
onClick={() => handleDatasetClick({ datasetindex: 0 })}
|
|
151
|
-
className={'accordion-title align-arrow-right'}
|
|
152
|
-
>
|
|
153
|
-
{activeDatasetIndex.includes(0) ? (
|
|
154
|
-
<Icon
|
|
155
|
-
name={iconName(content, titleIcons.opened)}
|
|
156
|
-
size="24px"
|
|
157
|
-
/>
|
|
158
|
-
) : (
|
|
159
|
-
<Icon
|
|
160
|
-
name={iconName(content, titleIcons.closed)}
|
|
161
|
-
size="24px"
|
|
162
|
-
/>
|
|
163
|
-
)}
|
|
164
|
-
<span>Related datasets</span>
|
|
165
|
-
</Accordion.Title>
|
|
166
|
-
<Accordion.Content active={activeDatasetIndex.includes(0)}>
|
|
167
|
-
<AnimateHeight animateOpacity duration={500} height={'auto'}>
|
|
168
|
-
<ul>
|
|
169
|
-
{content.datasets.map((dataset, key) => (
|
|
170
|
-
<li key={key}>
|
|
171
|
-
<Grid columns={2}>
|
|
172
|
-
<Grid.Column width={2}>
|
|
173
|
-
{dataset.image_field && (
|
|
174
|
-
<img
|
|
175
|
-
src={
|
|
176
|
-
dataset.image_field
|
|
177
|
-
? `${dataset['@id']}/@@images/image`
|
|
178
|
-
: 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg'
|
|
179
|
-
}
|
|
180
|
-
alt={
|
|
181
|
-
dataset.image_field
|
|
182
|
-
? dataset.image?.filename
|
|
183
|
-
: 'Placeholder'
|
|
184
|
-
}
|
|
185
|
-
/>
|
|
186
|
-
)}
|
|
187
|
-
</Grid.Column>
|
|
188
|
-
<Grid.Column width={10}>
|
|
189
|
-
<a href={dataset['@id']}>
|
|
190
|
-
<strong>{dataset.title}</strong>
|
|
191
|
-
</a>
|
|
192
|
-
<p>{dataset.description}</p>
|
|
193
|
-
</Grid.Column>
|
|
194
|
-
</Grid>
|
|
195
|
-
</li>
|
|
196
|
-
))}
|
|
197
|
-
</ul>
|
|
198
|
-
</AnimateHeight>
|
|
199
|
-
</Accordion.Content>
|
|
200
|
-
</Accordion>
|
|
201
|
-
)}
|
|
202
79
|
</div>
|
|
203
80
|
</>
|
|
204
81
|
)}
|
|
82
|
+
{files.length > 0 && (
|
|
83
|
+
<CclListingCards
|
|
84
|
+
variation="file"
|
|
85
|
+
items={files}
|
|
86
|
+
linkHref={`${files['@id']}/@@download/file`}
|
|
87
|
+
/>
|
|
88
|
+
)}
|
|
89
|
+
{content?.products?.length > 0 && (
|
|
90
|
+
<Accordion fluid styled>
|
|
91
|
+
<Accordion.Title
|
|
92
|
+
as={'h2'}
|
|
93
|
+
onClick={() => handleClick({ index: 0 })}
|
|
94
|
+
className={'accordion-title align-arrow-right'}
|
|
95
|
+
>
|
|
96
|
+
{activeIndex.includes(0) ? (
|
|
97
|
+
<Icon name={iconName(content, titleIcons.opened)} size="24px" />
|
|
98
|
+
) : (
|
|
99
|
+
<Icon name={iconName(content, titleIcons.closed)} size="24px" />
|
|
100
|
+
)}
|
|
101
|
+
<span>Related products</span>
|
|
102
|
+
</Accordion.Title>
|
|
103
|
+
<Accordion.Content active={activeIndex.includes(0)}>
|
|
104
|
+
<AnimateHeight animateOpacity duration={500} height={'auto'}>
|
|
105
|
+
<CLMSRelatedItems items={content.products} />
|
|
106
|
+
</AnimateHeight>
|
|
107
|
+
</Accordion.Content>
|
|
108
|
+
</Accordion>
|
|
109
|
+
)}
|
|
110
|
+
{content?.datasets?.length > 0 && (
|
|
111
|
+
<Accordion fluid styled>
|
|
112
|
+
<Accordion.Title
|
|
113
|
+
as={'h2'}
|
|
114
|
+
onClick={() => handleDatasetClick({ datasetindex: 0 })}
|
|
115
|
+
className={'accordion-title align-arrow-right'}
|
|
116
|
+
>
|
|
117
|
+
{activeDatasetIndex.includes(0) ? (
|
|
118
|
+
<Icon name={iconName(content, titleIcons.opened)} size="24px" />
|
|
119
|
+
) : (
|
|
120
|
+
<Icon name={iconName(content, titleIcons.closed)} size="24px" />
|
|
121
|
+
)}
|
|
122
|
+
<span>Related datasets</span>
|
|
123
|
+
</Accordion.Title>
|
|
124
|
+
<Accordion.Content active={activeDatasetIndex.includes(0)}>
|
|
125
|
+
<AnimateHeight animateOpacity duration={500} height={'auto'}>
|
|
126
|
+
<CLMSRelatedItems items={content.datasets} />
|
|
127
|
+
</AnimateHeight>
|
|
128
|
+
</Accordion.Content>
|
|
129
|
+
</Accordion>
|
|
130
|
+
)}
|
|
205
131
|
</div>
|
|
206
132
|
);
|
|
207
133
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Grid, Image } from 'semantic-ui-react';
|
|
2
|
+
import PlaceHolder from '@eeacms/volto-clms-theme/../theme/clms/img/ccl-thumbnail-placeholder.jpg';
|
|
3
|
+
|
|
4
|
+
const CLMSRelatedItems = (props) => {
|
|
5
|
+
const { items } = props;
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
{items.map((item, key) => (
|
|
10
|
+
<>
|
|
11
|
+
<Grid columns="2">
|
|
12
|
+
<Grid.Column width={3} key={key}>
|
|
13
|
+
{item.mage_field ? (
|
|
14
|
+
<Image
|
|
15
|
+
src={`${item['@id']}/@@images/image/mini`}
|
|
16
|
+
alt={item?.title || 'Placeholder'}
|
|
17
|
+
/>
|
|
18
|
+
) : (
|
|
19
|
+
<Image
|
|
20
|
+
fluid="true"
|
|
21
|
+
src={PlaceHolder}
|
|
22
|
+
alt={item?.title || 'Placeholder'}
|
|
23
|
+
/>
|
|
24
|
+
)}
|
|
25
|
+
</Grid.Column>
|
|
26
|
+
<Grid.Column width={9}>
|
|
27
|
+
<a href={item['@id']}>
|
|
28
|
+
<strong>{item.title}</strong>
|
|
29
|
+
</a>
|
|
30
|
+
{item?.description && <p>{item.description}</p>}
|
|
31
|
+
</Grid.Column>
|
|
32
|
+
</Grid>
|
|
33
|
+
</>
|
|
34
|
+
))}
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export { CLMSRelatedItems };
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileWidget component.
|
|
3
|
+
* @module components/manage/Widgets/FileWidget
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import PropTypes from 'prop-types';
|
|
8
|
+
import { Button, Image, Dimmer } from 'semantic-ui-react';
|
|
9
|
+
import { readAsDataURL } from 'promise-file-reader';
|
|
10
|
+
import { injectIntl } from 'react-intl';
|
|
11
|
+
import deleteSVG from '@plone/volto/icons/delete.svg';
|
|
12
|
+
import { Icon, FormFieldWrapper } from '@plone/volto/components';
|
|
13
|
+
import loadable from '@loadable/component';
|
|
14
|
+
import { flattenToAppURL } from '@plone/volto/helpers';
|
|
15
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
16
|
+
|
|
17
|
+
const imageMimetypes = [
|
|
18
|
+
'image/png',
|
|
19
|
+
'image/jpeg',
|
|
20
|
+
'image/webp',
|
|
21
|
+
'image/jpg',
|
|
22
|
+
'image/gif',
|
|
23
|
+
'image/svg+xml',
|
|
24
|
+
];
|
|
25
|
+
const Dropzone = loadable(() => import('react-dropzone'));
|
|
26
|
+
|
|
27
|
+
const messages = defineMessages({
|
|
28
|
+
releaseDrag: {
|
|
29
|
+
id: 'Drop images here ...',
|
|
30
|
+
defaultMessage: 'Drop images here ...',
|
|
31
|
+
},
|
|
32
|
+
editFile: {
|
|
33
|
+
id: 'Drop image here to replace the existing image',
|
|
34
|
+
defaultMessage: 'Drop image here to replace the existing image',
|
|
35
|
+
},
|
|
36
|
+
fileDrag: {
|
|
37
|
+
id: 'Drop image here to upload a new image',
|
|
38
|
+
defaultMessage: 'Drop image here to upload a new image',
|
|
39
|
+
},
|
|
40
|
+
replaceFile: {
|
|
41
|
+
id: 'Replace existing image',
|
|
42
|
+
defaultMessage: 'Replace existing image',
|
|
43
|
+
},
|
|
44
|
+
addNewFile: {
|
|
45
|
+
id: 'Choose a image',
|
|
46
|
+
defaultMessage: 'Choose a image',
|
|
47
|
+
},
|
|
48
|
+
invalid_file: {
|
|
49
|
+
id: 'The uploaded file is not valid',
|
|
50
|
+
defaultMessage: 'The uploaded file must be an image',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* FileWidget component class.
|
|
56
|
+
* @function FileWidget
|
|
57
|
+
* @returns {string} Markup of the component.
|
|
58
|
+
*
|
|
59
|
+
* To use it, in schema properties, declare a field like:
|
|
60
|
+
*
|
|
61
|
+
* ```jsx
|
|
62
|
+
* {
|
|
63
|
+
* title: "File",
|
|
64
|
+
* widget: 'file',
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
* or:
|
|
68
|
+
*
|
|
69
|
+
* ```jsx
|
|
70
|
+
* {
|
|
71
|
+
* title: "File",
|
|
72
|
+
* type: 'object',
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
*/
|
|
77
|
+
const FileWidget = (props) => {
|
|
78
|
+
const { id, value, onChange } = props;
|
|
79
|
+
const [fileType, setFileType] = React.useState(false);
|
|
80
|
+
const intl = useIntl();
|
|
81
|
+
|
|
82
|
+
React.useEffect(() => {
|
|
83
|
+
if (value && imageMimetypes.includes(value['content-type'])) {
|
|
84
|
+
setFileType(true);
|
|
85
|
+
}
|
|
86
|
+
}, [value]);
|
|
87
|
+
|
|
88
|
+
const imgsrc = value?.download
|
|
89
|
+
? `${flattenToAppURL(value?.download)}?id=${Date.now()}`
|
|
90
|
+
: null || value?.data
|
|
91
|
+
? `data:${value['content-type']};${value.encoding},${value.data}`
|
|
92
|
+
: null;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Drop handler
|
|
96
|
+
* @method onDrop
|
|
97
|
+
* @param {array} files File objects
|
|
98
|
+
* @returns {undefined}
|
|
99
|
+
*/
|
|
100
|
+
const onDrop = (files) => {
|
|
101
|
+
const file = files[0];
|
|
102
|
+
readAsDataURL(file).then((data) => {
|
|
103
|
+
const fields = data.match(/^data:(.*);(.*),(.*)$/);
|
|
104
|
+
if (
|
|
105
|
+
fields[0] !== 'image/png' ||
|
|
106
|
+
'image/jpeg' ||
|
|
107
|
+
'image/webp' ||
|
|
108
|
+
'image/jpg' ||
|
|
109
|
+
'image/gif' ||
|
|
110
|
+
'image/svg+xml'
|
|
111
|
+
) {
|
|
112
|
+
// eslint-disable-next-line no-alert
|
|
113
|
+
alert(intl.formatMessage(messages.invalid_file));
|
|
114
|
+
return;
|
|
115
|
+
} else {
|
|
116
|
+
onChange(id, {
|
|
117
|
+
data: fields[3],
|
|
118
|
+
encoding: fields[2],
|
|
119
|
+
'content-type': fields[1],
|
|
120
|
+
filename: file.name,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
let reader = new FileReader();
|
|
126
|
+
reader.onload = function () {
|
|
127
|
+
const fields = reader.result.match(/^data:(.*);(.*),(.*)$/);
|
|
128
|
+
if (imageMimetypes.includes(fields[1])) {
|
|
129
|
+
setFileType(true);
|
|
130
|
+
let imagePreview = document.getElementById(`field-${id}-image`);
|
|
131
|
+
imagePreview.src = reader.result;
|
|
132
|
+
} else {
|
|
133
|
+
setFileType(false);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
reader.readAsDataURL(files[0]);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<FormFieldWrapper {...props}>
|
|
141
|
+
<Dropzone onDrop={onDrop}>
|
|
142
|
+
{({ getRootProps, getInputProps, isDragActive }) => (
|
|
143
|
+
<div className="file-widget-dropzone" {...getRootProps()}>
|
|
144
|
+
{isDragActive && <Dimmer active></Dimmer>}
|
|
145
|
+
{fileType ? (
|
|
146
|
+
<Image
|
|
147
|
+
className="image-preview"
|
|
148
|
+
id={`field-${id}-image`}
|
|
149
|
+
size="small"
|
|
150
|
+
src={imgsrc}
|
|
151
|
+
/>
|
|
152
|
+
) : (
|
|
153
|
+
<div className="dropzone-placeholder">
|
|
154
|
+
{isDragActive ? (
|
|
155
|
+
<p className="dropzone-text">
|
|
156
|
+
{intl.formatMessage(messages.releaseDrag)}
|
|
157
|
+
</p>
|
|
158
|
+
) : value ? (
|
|
159
|
+
<p className="dropzone-text">
|
|
160
|
+
{intl.formatMessage(messages.editFile)}
|
|
161
|
+
</p>
|
|
162
|
+
) : (
|
|
163
|
+
<p className="dropzone-text">
|
|
164
|
+
{intl.formatMessage(messages.fileDrag)}
|
|
165
|
+
</p>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
)}
|
|
169
|
+
|
|
170
|
+
<label className="label-file-widget-input">
|
|
171
|
+
{value
|
|
172
|
+
? intl.formatMessage(messages.replaceFile)
|
|
173
|
+
: intl.formatMessage(messages.addNewFile)}
|
|
174
|
+
</label>
|
|
175
|
+
<input
|
|
176
|
+
{...getInputProps({
|
|
177
|
+
type: 'file',
|
|
178
|
+
style: { display: 'none' },
|
|
179
|
+
})}
|
|
180
|
+
id={`field-${id}`}
|
|
181
|
+
name={id}
|
|
182
|
+
type="file"
|
|
183
|
+
/>
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
</Dropzone>
|
|
187
|
+
<div className="field-file-name">
|
|
188
|
+
{value && value.filename}
|
|
189
|
+
{value && (
|
|
190
|
+
<Button
|
|
191
|
+
icon
|
|
192
|
+
basic
|
|
193
|
+
className="delete-button"
|
|
194
|
+
aria-label="delete file"
|
|
195
|
+
onClick={() => {
|
|
196
|
+
onChange(id, null);
|
|
197
|
+
setFileType(false);
|
|
198
|
+
}}
|
|
199
|
+
>
|
|
200
|
+
<Icon name={deleteSVG} size="20px" />
|
|
201
|
+
</Button>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
</FormFieldWrapper>
|
|
205
|
+
);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Property types.
|
|
210
|
+
* @property {Object} propTypes Property types.
|
|
211
|
+
* @static
|
|
212
|
+
*/
|
|
213
|
+
FileWidget.propTypes = {
|
|
214
|
+
id: PropTypes.string.isRequired,
|
|
215
|
+
title: PropTypes.string.isRequired,
|
|
216
|
+
description: PropTypes.string,
|
|
217
|
+
required: PropTypes.bool,
|
|
218
|
+
error: PropTypes.arrayOf(PropTypes.string),
|
|
219
|
+
value: PropTypes.shape({
|
|
220
|
+
'@type': PropTypes.string,
|
|
221
|
+
title: PropTypes.string,
|
|
222
|
+
}),
|
|
223
|
+
onChange: PropTypes.func.isRequired,
|
|
224
|
+
wrapped: PropTypes.bool,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Default properties.
|
|
229
|
+
* @property {Object} defaultProps Default properties.
|
|
230
|
+
* @static
|
|
231
|
+
*/
|
|
232
|
+
FileWidget.defaultProps = {
|
|
233
|
+
description: null,
|
|
234
|
+
required: false,
|
|
235
|
+
error: [],
|
|
236
|
+
value: null,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export default injectIntl(FileWidget);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmailWidget component.
|
|
3
|
+
* @module components/manage/Widgets/EmailWidget
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { FormFieldWrapper } from '@plone/volto/components';
|
|
7
|
+
import PropTypes from 'prop-types';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
10
|
+
|
|
11
|
+
/** EmailWidget, a widget for email addresses
|
|
12
|
+
*
|
|
13
|
+
* To use it, in schema properties, declare a field like:
|
|
14
|
+
*
|
|
15
|
+
* ```jsx
|
|
16
|
+
* {
|
|
17
|
+
* title: "Email",
|
|
18
|
+
* widget: 'email',
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
const EmailWidget = (props) => {
|
|
23
|
+
const {
|
|
24
|
+
id,
|
|
25
|
+
value = '',
|
|
26
|
+
onChange,
|
|
27
|
+
onBlur,
|
|
28
|
+
onClick,
|
|
29
|
+
minLength,
|
|
30
|
+
placeholder,
|
|
31
|
+
isDisabled,
|
|
32
|
+
} = props;
|
|
33
|
+
const inputId = `field-${id}`;
|
|
34
|
+
const intl = useIntl();
|
|
35
|
+
|
|
36
|
+
const messages = defineMessages({
|
|
37
|
+
invalid_email: {
|
|
38
|
+
id: 'The entered email address is not valid',
|
|
39
|
+
defaultMessage: 'The entered email address is not valid',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const email =
|
|
44
|
+
typeof window !== 'undefined' && document.getElementById(inputId) !== null
|
|
45
|
+
? document.getElementById(inputId).value
|
|
46
|
+
: '';
|
|
47
|
+
// email.addEventListener('input', function (e) {
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
if (email !== '') {
|
|
50
|
+
if (email.validity !== undefined) {
|
|
51
|
+
if (email.validity.typeMismatch) {
|
|
52
|
+
email.setCustomValidity(intl.formatMessage(messages.invalid_email));
|
|
53
|
+
email.reportValidity();
|
|
54
|
+
} else {
|
|
55
|
+
email.setCustomValidity('');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
62
|
+
}, [email.value]);
|
|
63
|
+
// });
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<FormFieldWrapper {...props} className="email">
|
|
67
|
+
<input
|
|
68
|
+
className="ui input"
|
|
69
|
+
id={inputId}
|
|
70
|
+
name={id}
|
|
71
|
+
type="email"
|
|
72
|
+
value={value || ''}
|
|
73
|
+
disabled={isDisabled}
|
|
74
|
+
placeholder={placeholder}
|
|
75
|
+
onChange={({ target }) =>
|
|
76
|
+
onChange(id, target.value === '' ? undefined : target.value)
|
|
77
|
+
}
|
|
78
|
+
onBlur={({ target }) =>
|
|
79
|
+
onBlur(id, target.value === '' ? undefined : target.value)
|
|
80
|
+
}
|
|
81
|
+
onClick={() => onClick()}
|
|
82
|
+
minLength={minLength || null}
|
|
83
|
+
maxLength={200}
|
|
84
|
+
/>
|
|
85
|
+
</FormFieldWrapper>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Property types
|
|
91
|
+
* @property {Object} propTypes Property types.
|
|
92
|
+
* @static
|
|
93
|
+
*/
|
|
94
|
+
EmailWidget.propTypes = {
|
|
95
|
+
id: PropTypes.string.isRequired,
|
|
96
|
+
title: PropTypes.string.isRequired,
|
|
97
|
+
description: PropTypes.string,
|
|
98
|
+
required: PropTypes.bool,
|
|
99
|
+
error: PropTypes.arrayOf(PropTypes.string),
|
|
100
|
+
value: PropTypes.string,
|
|
101
|
+
onChange: PropTypes.func.isRequired,
|
|
102
|
+
onBlur: PropTypes.func,
|
|
103
|
+
onClick: PropTypes.func,
|
|
104
|
+
minLength: PropTypes.number,
|
|
105
|
+
maxLength: PropTypes.number,
|
|
106
|
+
placeholder: PropTypes.string,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Default properties.
|
|
111
|
+
* @property {Object} defaultProps Default properties.
|
|
112
|
+
* @static
|
|
113
|
+
*/
|
|
114
|
+
EmailWidget.defaultProps = {
|
|
115
|
+
description: null,
|
|
116
|
+
required: false,
|
|
117
|
+
error: [],
|
|
118
|
+
value: null,
|
|
119
|
+
onChange: () => {},
|
|
120
|
+
onBlur: () => {},
|
|
121
|
+
onClick: () => {},
|
|
122
|
+
minLength: null,
|
|
123
|
+
maxLength: null,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default EmailWidget;
|