@eeacms/volto-eea-website-theme 1.34.0 → 2.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.
Files changed (54) hide show
  1. package/.eslintrc.js +7 -2
  2. package/CHANGELOG.md +44 -20
  3. package/docker-compose.yml +1 -1
  4. package/jest-addon.config.js +3 -0
  5. package/package.json +2 -1
  6. package/src/components/manage/Blocks/LayoutSettings/index.js +3 -1
  7. package/src/components/manage/Blocks/Title/index.js +3 -1
  8. package/src/components/manage/Blocks/Title/schema.js +3 -1
  9. package/src/components/theme/Banner/View.jsx +12 -5
  10. package/src/components/theme/DraftBackground/DraftBackground.jsx +1 -0
  11. package/src/components/theme/DraftBackground/DraftBackground.test.jsx +85 -0
  12. package/src/config.js +2 -0
  13. package/src/customizations/@plone/volto-slate/blocks/Text/TextBlockView.jsx +32 -0
  14. package/src/customizations/@plone/volto-slate/editor/render.jsx +75 -0
  15. package/src/customizations/@plone/volto-slate/elementEditor/utils.js +76 -75
  16. package/src/customizations/volto/components/manage/Blocks/Grid/Edit.jsx +70 -0
  17. package/src/customizations/volto/components/manage/Blocks/Grid/View.jsx +61 -0
  18. package/src/customizations/volto/components/manage/Blocks/Grid/readme.md +1 -0
  19. package/src/customizations/volto/components/manage/Blocks/Image/Edit.jsx +82 -23
  20. package/src/customizations/volto/components/manage/Blocks/Image/Edit.test.jsx +10 -3
  21. package/src/customizations/volto/components/manage/Blocks/Image/View.jsx +110 -111
  22. package/src/customizations/volto/components/manage/Blocks/Image/schema.js +17 -2
  23. package/src/customizations/volto/components/manage/Blocks/LeadImage/Edit.jsx +35 -14
  24. package/src/customizations/volto/components/manage/Blocks/LeadImage/View.jsx +65 -79
  25. package/src/customizations/volto/components/manage/Display/Display.jsx +306 -0
  26. package/src/customizations/volto/components/manage/Display/Readme.md +1 -0
  27. package/src/customizations/volto/components/manage/Sidebar/SidebarPopup copy.jsx +82 -0
  28. package/src/customizations/volto/components/manage/Toolbar/More.jsx +541 -0
  29. package/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx +3 -1
  30. package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.jsx +24 -14
  31. package/src/customizations/volto/components/manage/Widgets/README.md +1 -0
  32. package/src/customizations/volto/components/manage/Workflow/README.txt +1 -0
  33. package/src/customizations/volto/components/manage/Workflow/Workflow.jsx +324 -0
  34. package/src/customizations/volto/components/manage/Workflow/Workflow.test.jsx +81 -0
  35. package/src/customizations/volto/components/theme/Comments/Comments.jsx +1 -2
  36. package/src/customizations/volto/components/theme/ContactForm/ContactForm.jsx +1 -1
  37. package/src/customizations/volto/components/theme/EventDetails/EventDetails.jsx +1 -0
  38. package/src/index.js +21 -16
  39. package/src/middleware/ok.js +4 -2
  40. package/src/middleware/voltoCustom.js +4 -2
  41. package/src/slate.js +10 -8
  42. package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/README.txt +0 -1
  43. package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/StyleMenu.jsx +0 -157
  44. package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/utils.js +0 -168
  45. package/src/customizations/volto/components/manage/Add/Add.jsx +0 -498
  46. package/src/customizations/volto/components/manage/Add/readme.md +0 -1
  47. package/src/customizations/volto/components/manage/Contents/ContentsPropertiesModal.jsx +0 -232
  48. package/src/customizations/volto/components/manage/Form/Form.jsx +0 -810
  49. package/src/customizations/volto/components/manage/Form/Form.test.jsx +0 -1124
  50. package/src/customizations/volto/components/manage/Form/ModalForm.jsx +0 -326
  51. package/src/customizations/volto/components/manage/Sharing/Sharing.jsx +0 -528
  52. package/src/customizations/volto/components/manage/Sharing/Sharing.test.jsx +0 -72
  53. package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.test.jsx +0 -193
  54. package/src/customizations/volto/components/theme/AppExtras/AppExtras.jsx +0 -27
@@ -9,8 +9,12 @@ import PropTypes from 'prop-types';
9
9
  import { UniversalLink } from '@plone/volto/components';
10
10
  import { Icon } from 'semantic-ui-react';
11
11
  import cx from 'classnames';
12
- import { withBlockExtensions } from '@plone/volto/helpers';
13
- import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers';
12
+ import {
13
+ flattenToAppURL,
14
+ isInternalURL,
15
+ withBlockExtensions,
16
+ } from '@plone/volto/helpers';
17
+ import config from '@plone/volto/registry';
14
18
  import { Copyright } from '@eeacms/volto-eea-design-system/ui';
15
19
 
16
20
  /**
@@ -19,131 +23,126 @@ import { Copyright } from '@eeacms/volto-eea-design-system/ui';
19
23
  * @extends Component
20
24
  */
21
25
  export const View = (props) => {
22
- const { data, detached } = props;
23
- const href = data?.href?.[0]?.['@id'] || '';
26
+ const { className, data, detached, style } = props;
24
27
  const { copyright, copyrightIcon, copyrightPosition } = data;
25
- // const [hovering, setHovering] = React.useState(false);
26
- const [viewLoaded, setViewLoaded] = React.useState(false);
27
-
28
+ const href = data?.href?.[0]?.['@id'] || '';
28
29
  const showCopyright = data?.size === 'l' || !data.size;
29
30
 
30
- React.useEffect(() => {
31
- setViewLoaded(true);
32
- }, []);
31
+ const Image = config.getComponent({ name: 'Image' }).component;
33
32
 
34
33
  return (
35
34
  <>
36
- {viewLoaded && (
35
+ <div
36
+ className={cx(
37
+ 'block image align',
38
+ {
39
+ center: !Boolean(data.align),
40
+ detached,
41
+ },
42
+ data.align,
43
+ className,
44
+ )}
45
+ style={style}
46
+ >
37
47
  <div
38
48
  className={cx(
39
- 'block image align',
49
+ 'image-block-container',
40
50
  {
41
- center: !Boolean(data.align),
42
- detached,
51
+ large: data.size === 'l',
52
+ medium: data.size === 'm',
53
+ small: data.size === 's',
43
54
  },
44
- data.align,
55
+ data?.align ? data?.align : '',
45
56
  )}
46
57
  >
47
- <div
48
- className={cx(
49
- 'image-block-container',
50
- {
51
- large: data.size === 'l',
52
- medium: data.size === 'm',
53
- small: data.size === 's',
54
- },
55
- data?.align ? data?.align : '',
56
- )}
57
- >
58
- {data.url && (
59
- <>
60
- {(() => {
61
- const image = (
62
- <>
63
- <img
64
- className={cx(
65
- {
66
- 'full-width': data.align === 'full',
67
- large: data.size === 'l',
68
- medium: data.size === 'm',
69
- small: data.size === 's',
70
- },
71
- data?.styles?.objectPosition,
72
- )}
73
- src={
74
- isInternalURL(data.url)
75
- ? // Backwards compat in the case that the block is storing the full server URL
76
- (() => {
77
- if (data.align === 'full')
78
- return `${flattenToAppURL(
79
- data.url,
80
- )}/@@images/image/huge`;
81
- if (data.size === 'l')
82
- return `${flattenToAppURL(
83
- data.url,
84
- )}/@@images/image/great`;
85
- if (data.size === 'm')
86
- return `${flattenToAppURL(
87
- data.url,
88
- )}/@@images/image/preview`;
89
- if (data.size === 's')
90
- return `${flattenToAppURL(
91
- data.url,
92
- )}/@@images/image/mini`;
58
+ {data.url && (
59
+ <>
60
+ {(() => {
61
+ const image = (
62
+ <>
63
+ <Image
64
+ className={cx(
65
+ {
66
+ 'full-width': data.align === 'full',
67
+ large: data.size === 'l',
68
+ medium: data.size === 'm',
69
+ small: data.size === 's',
70
+ },
71
+ data?.styles?.objectPosition,
72
+ )}
73
+ item={
74
+ data.image_scales
75
+ ? {
76
+ '@id': data.url,
77
+ image_field: data.image_field,
78
+ image_scales: data.image_scales,
79
+ }
80
+ : undefined
81
+ }
82
+ src={
83
+ data.image_scales
84
+ ? undefined
85
+ : isInternalURL(data.url)
86
+ ? // Backwards compat in the case that the block is storing the full server URL
87
+ (() => {
88
+ if (data.size === 'l')
89
+ return `${flattenToAppURL(
90
+ data.url,
91
+ )}/@@images/image`;
92
+ if (data.size === 'm')
93
+ return `${flattenToAppURL(
94
+ data.url,
95
+ )}/@@images/image/preview`;
96
+ if (data.size === 's')
93
97
  return `${flattenToAppURL(
94
98
  data.url,
95
- )}/@@images/image/great`;
96
- })()
97
- : data.url
98
- }
99
- alt={data.alt || ''}
100
- loading="lazy"
101
- />
102
- <div
103
- // onMouseEnter={() => setHovering(true)}
104
- // onMouseLeave={() => setHovering(false)}
105
- className={`copyright-wrapper ${
106
- copyrightPosition ? copyrightPosition : 'left'
107
- }`}
108
- >
109
- {copyright && showCopyright ? (
110
- <Copyright copyrightPosition={copyrightPosition}>
111
- <Copyright.Icon>
112
- <Icon className={copyrightIcon} />
113
- </Copyright.Icon>
114
- {/*<div*/}
115
- {/* className={cx(*/}
116
- {/* 'copyright-hover-container',*/}
117
- {/* !hovering ? 'hiddenStructure' : '',*/}
118
- {/* )}*/}
119
- {/*>*/}
120
- <Copyright.Text>{copyright}</Copyright.Text>
121
- {/*</div>*/}
122
- </Copyright>
123
- ) : (
124
- ''
125
- )}
126
- </div>
127
- </>
99
+ )}/@@images/image/mini`;
100
+ return `${flattenToAppURL(
101
+ data.url,
102
+ )}/@@images/image`;
103
+ })()
104
+ : data.url
105
+ }
106
+ sizes={config.blocks.blocksConfig.image.getSizes(data)}
107
+ alt={data.alt || ''}
108
+ loading="lazy"
109
+ responsive={true}
110
+ />
111
+ <div
112
+ className={`copyright-wrapper ${
113
+ copyrightPosition ? copyrightPosition : 'left'
114
+ }`}
115
+ >
116
+ {copyright && showCopyright ? (
117
+ <Copyright copyrightPosition={copyrightPosition}>
118
+ <Copyright.Icon>
119
+ <Icon className={copyrightIcon} />
120
+ </Copyright.Icon>
121
+ <Copyright.Text>{copyright}</Copyright.Text>
122
+ </Copyright>
123
+ ) : (
124
+ ''
125
+ )}
126
+ </div>
127
+ </>
128
+ );
129
+ if (href) {
130
+ return (
131
+ <UniversalLink
132
+ href={href}
133
+ openLinkInNewTab={data.openLinkInNewTab}
134
+ >
135
+ {image}
136
+ </UniversalLink>
128
137
  );
129
- if (href) {
130
- return (
131
- <UniversalLink
132
- href={href}
133
- openLinkInNewTab={data.openLinkInNewTab}
134
- >
135
- {image}
136
- </UniversalLink>
137
- );
138
- } else {
139
- return image;
140
- }
141
- })()}
142
- </>
143
- )}
144
- </div>
138
+ } else {
139
+ return image;
140
+ }
141
+ })()}
142
+ </>
143
+ )}
145
144
  </div>
146
- )}
145
+ </div>
147
146
  </>
148
147
  );
149
148
  };
@@ -37,6 +37,10 @@ const messages = defineMessages({
37
37
  id: 'Alt text hint link text',
38
38
  defaultMessage: 'Describe the purpose of the image.',
39
39
  },
40
+ linkSettings: {
41
+ id: 'Link settings',
42
+ defaultMessage: 'Link settings',
43
+ },
40
44
  });
41
45
 
42
46
  export function ImageSchema({ formData, intl }) {
@@ -61,7 +65,7 @@ export function ImageSchema({ formData, intl }) {
61
65
  ? [
62
66
  {
63
67
  id: 'link_settings',
64
- title: 'Link settings',
68
+ title: intl.formatMessage(messages.linkSettings),
65
69
  fields: ['href', 'openLinkInNewTab'],
66
70
  },
67
71
  ]
@@ -80,7 +84,7 @@ export function ImageSchema({ formData, intl }) {
80
84
  href="https://www.w3.org/WAI/tutorials/images/decision-tree/"
81
85
  title={intl.formatMessage(messages.openLinkInNewTab)}
82
86
  target="_blank"
83
- rel="noopener"
87
+ rel="noopener noreferrer"
84
88
  >
85
89
  {intl.formatMessage(messages.AltTextHintLinkText)}
86
90
  </a>{' '}
@@ -136,3 +140,14 @@ export function ImageSchema({ formData, intl }) {
136
140
  required: [],
137
141
  };
138
142
  }
143
+
144
+ export const gridImageDisableSizeAndPositionHandlersSchema = ({
145
+ schema,
146
+ formData,
147
+ intl,
148
+ }) => {
149
+ schema.fieldsets[0].fields = schema.fieldsets[0].fields.filter(
150
+ (item) => !['align', 'size'].includes(item),
151
+ );
152
+ return schema;
153
+ };
@@ -10,10 +10,11 @@ import { defineMessages, injectIntl } from 'react-intl';
10
10
  import cx from 'classnames';
11
11
  import { Message } from 'semantic-ui-react';
12
12
  import { isEqual } from 'lodash';
13
+
13
14
  import { Copyright } from '@eeacms/volto-eea-design-system/ui';
14
15
  import { Icon } from 'semantic-ui-react';
15
16
  import { LeadImageSidebar, SidebarPortal } from '@plone/volto/components';
16
- import { flattenToAppURL } from '@plone/volto/helpers';
17
+ import config from '@plone/volto/registry';
17
18
 
18
19
  import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
19
20
 
@@ -80,11 +81,18 @@ class Edit extends Component {
80
81
  * @returns {string} Markup for the component.
81
82
  */
82
83
  render() {
84
+ const Image = config.getComponent({ name: 'Image' }).component;
83
85
  const { data, properties } = this.props;
86
+ const { copyright, copyrightIcon, copyrightPosition } = data;
84
87
  const placeholder =
85
88
  this.props.data.placeholder ||
86
89
  this.props.intl.formatMessage(messages.ImageBlockInputPlaceholder);
87
- const { copyright, copyrightIcon, copyrightPosition, styles } = data;
90
+
91
+ const hasImage = !!properties.image;
92
+ const hasImageData = hasImage && !!properties.image.data;
93
+ const className = cx('responsive', { 'full-image': data.align === 'full' });
94
+ const altText = data.image_caption || properties.image_caption || '';
95
+
88
96
  return (
89
97
  <div
90
98
  className={cx(
@@ -100,7 +108,7 @@ class Edit extends Component {
100
108
  `image-block-container ${data?.align ? data?.align : ''}`,
101
109
  )}
102
110
  >
103
- {!properties.image && (
111
+ {!hasImage && (
104
112
  <Message>
105
113
  <center>
106
114
  <img src={imageBlockSVG} alt="" />
@@ -108,19 +116,17 @@ class Edit extends Component {
108
116
  </center>
109
117
  </Message>
110
118
  )}
111
- {properties.image && (
119
+ {hasImage && hasImageData && (
112
120
  <div className="image-block">
113
121
  <img
114
- className={cx(
115
- { 'full-width': data.align === 'full' },
116
- styles?.objectPosition,
117
- )}
118
- src={
119
- properties.image.data
120
- ? `data:${properties.image['content-type']};base64,${properties.image.data}`
121
- : flattenToAppURL(properties.image.download)
122
- }
123
- alt={data.image_caption || ''}
122
+ className={(className, data?.styles?.objectPosition)}
123
+ src={`data:${properties.image['content-type']};base64,${properties.image.data}`}
124
+ width={properties.image.width}
125
+ height={properties.image.height}
126
+ alt={altText}
127
+ style={{
128
+ aspectRatio: `${properties.image.width}/${properties.image.height}`,
129
+ }}
124
130
  />
125
131
  <div className="copyright-wrapper">
126
132
  {copyright ? (
@@ -136,6 +142,21 @@ class Edit extends Component {
136
142
  </div>
137
143
  </div>
138
144
  )}
145
+ {hasImage && !hasImageData && (
146
+ <Image
147
+ className={className}
148
+ item={properties}
149
+ imageField="image"
150
+ sizes={(() => {
151
+ if (data.align === 'full' || data.align === 'center')
152
+ return '100vw';
153
+ if (data.align === 'left' || data.align === 'right')
154
+ return '50vw';
155
+ return undefined;
156
+ })()}
157
+ alt={altText}
158
+ />
159
+ )}
139
160
  </div>
140
161
  <SidebarPortal selected={this.props.selected}>
141
162
  <LeadImageSidebar {...this.props} />
@@ -7,101 +7,87 @@ import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { UniversalLink } from '@plone/volto/components';
9
9
  import cx from 'classnames';
10
+ import config from '@plone/volto/registry';
10
11
  import { Copyright } from '@eeacms/volto-eea-design-system/ui';
11
12
  import { Icon } from 'semantic-ui-react';
12
- import { flattenToAppURL } from '@plone/volto/helpers';
13
13
 
14
14
  /**
15
15
  * View image block class.
16
16
  * @class View
17
17
  * @extends Component
18
18
  */
19
- const View = (props) => {
20
- const { data, properties } = props;
21
- const { copyright, copyrightIcon, copyrightPosition, styles } = data;
22
-
23
- // const [hovering, setHovering] = React.useState(false);
24
- const [viewLoaded, setViewLoaded] = React.useState(false);
25
-
26
- React.useEffect(() => {
27
- setViewLoaded(true);
28
- }, []);
19
+ const View = ({ data, properties }) => {
20
+ const { copyright, copyrightIcon, copyrightPosition } = data;
21
+ const Image = config.getComponent({ name: 'Image' }).component;
29
22
 
30
23
  return (
31
24
  <>
32
- {viewLoaded && (
33
- <p
25
+ <p
26
+ className={cx(
27
+ 'block image align',
28
+ {
29
+ center: !Boolean(data.align),
30
+ },
31
+ data.align,
32
+ )}
33
+ >
34
+ <div
34
35
  className={cx(
35
- 'block image align',
36
- {
37
- center: !Boolean(data.align),
38
- },
39
- data.align,
36
+ `image-block-container ${data?.align ? data?.align : ''}`,
40
37
  )}
41
38
  >
42
- <div
43
- className={cx(
44
- `image-block-container ${data?.align ? data?.align : ''}`,
45
- )}
46
- >
47
- {properties.image && (
48
- <>
49
- {(() => {
50
- const image = (
51
- <div className="image-block">
52
- <img
53
- className={cx(
54
- { 'full-width': data.align === 'full' },
55
- styles?.objectPosition,
56
- )}
57
- src={flattenToAppURL(properties.image.download)}
58
- alt={properties.image_caption || ''}
59
- />
60
- <div
61
- // onMouseEnter={() => setHovering(true)}
62
- // onMouseLeave={() => setHovering(false)}
63
- className={`copyright-wrapper ${
64
- copyrightPosition ? copyrightPosition : 'left'
65
- }`}
66
- >
67
- {copyright ? (
68
- <Copyright copyrightPosition={copyrightPosition}>
69
- <Copyright.Icon>
70
- <Icon className={copyrightIcon} />
71
- </Copyright.Icon>
72
- {/*<div*/}
73
- {/* className={cx(*/}
74
- {/* 'copyright-hover-container',*/}
75
- {/* !hovering ? 'hiddenStructure' : '',*/}
76
- {/* )}*/}
77
- {/*>*/}
78
- <Copyright.Text>{copyright}</Copyright.Text>
79
- {/*</div>*/}
80
- </Copyright>
81
- ) : (
82
- ''
83
- )}
84
- </div>
39
+ {properties.image && (
40
+ <>
41
+ {(() => {
42
+ const image = (
43
+ <div className="image-block">
44
+ <Image
45
+ className={cx(
46
+ { 'full-width': data.align === 'full' },
47
+ data?.styles?.objectPosition,
48
+ )}
49
+ item={properties}
50
+ imageField="image"
51
+ sizes={config.blocks.blocksConfig.leadimage.getSizes(
52
+ data,
53
+ )}
54
+ alt={properties.image_caption || ''}
55
+ responsive={true}
56
+ />
57
+ <div
58
+ className={`copyright-wrapper ${
59
+ copyrightPosition ? copyrightPosition : 'left'
60
+ }`}
61
+ >
62
+ {copyright ? (
63
+ <Copyright copyrightPosition={copyrightPosition}>
64
+ <Copyright.Icon>
65
+ <Icon className={copyrightIcon} />
66
+ </Copyright.Icon>
67
+ </Copyright>
68
+ ) : (
69
+ ''
70
+ )}
85
71
  </div>
72
+ </div>
73
+ );
74
+ if (data.href) {
75
+ return (
76
+ <UniversalLink
77
+ href={data.href}
78
+ openLinkInNewTab={data.openLinkInNewTab}
79
+ >
80
+ {image}
81
+ </UniversalLink>
86
82
  );
87
- if (data.href) {
88
- return (
89
- <UniversalLink
90
- href={data.href}
91
- openLinkInNewTab={data.openLinkInNewTab}
92
- >
93
- {image}
94
- </UniversalLink>
95
- );
96
- } else {
97
- return image;
98
- }
99
- })()}
100
- </>
101
- )}
102
- </div>
103
- </p>
104
- )}
83
+ } else {
84
+ return image;
85
+ }
86
+ })()}
87
+ </>
88
+ )}
89
+ </div>
90
+ </p>
105
91
  </>
106
92
  );
107
93
  };