@plone/volto 17.0.0-alpha.20 → 17.0.0-alpha.21
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/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +19 -0
- package/cypress/support/commands.js +2 -1
- package/cypress/support/e2e.js +1 -2
- package/locales/ca/LC_MESSAGES/volto.po +10 -1
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +10 -1
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +10 -1
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +10 -1
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +10 -1
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +10 -1
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +10 -1
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +11 -2
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +10 -1
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +10 -1
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +10 -1
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +10 -1
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +10 -1
- package/locales/ro.json +1 -1
- package/locales/volto.pot +10 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +10 -1
- package/locales/zh_CN.json +1 -1
- package/package.json +4 -4
- package/packages/volto-slate/package.json +1 -1
- package/src/components/index.js +1 -0
- package/src/components/manage/Blocks/Image/Edit.jsx +40 -5
- package/src/components/manage/Blocks/Image/Edit.test.jsx +2 -0
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +64 -15
- package/src/components/manage/Blocks/Image/View.jsx +25 -5
- package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
- package/src/components/manage/Blocks/Image/schema.js +1 -9
- package/src/components/manage/Blocks/Image/utils.js +14 -0
- package/src/components/manage/Blocks/LeadImage/Edit.jsx +32 -10
- package/src/components/manage/Blocks/LeadImage/Edit.test.jsx +11 -1
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +28 -9
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -2
- package/src/components/manage/Blocks/LeadImage/View.jsx +50 -38
- package/src/components/manage/Blocks/LeadImage/View.test.jsx +11 -1
- package/src/components/manage/Blocks/Listing/SummaryTemplate.jsx +1 -1
- package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +13 -23
- package/src/components/manage/Contents/Contents.jsx +8 -6
- package/src/components/manage/Sidebar/AlignBlock.jsx +1 -1
- package/src/components/theme/Image/Image.jsx +96 -0
- package/src/components/theme/Image/Image.test.jsx +125 -0
- package/src/components/theme/Logo/Logo.jsx +2 -0
- package/src/components/theme/PreviewImage/PreviewImage.jsx +25 -14
- package/src/components/theme/PreviewImage/PreviewImage.test.js +39 -16
- package/src/components/theme/View/AlbumView.jsx +11 -15
- package/src/components/theme/View/EventView.jsx +30 -23
- package/src/components/theme/View/ImageView.jsx +5 -2
- package/src/components/theme/View/ImageView.test.jsx +4 -0
- package/src/components/theme/View/ListingView.jsx +5 -3
- package/src/components/theme/View/NewsItemView.jsx +7 -13
- package/src/components/theme/View/SummaryView.jsx +4 -3
- package/src/config/Blocks.jsx +2 -0
- package/src/config/Components.jsx +2 -1
- package/src/helpers/Url/Url.js +22 -1
- package/src/helpers/Url/Url.test.js +41 -0
- package/test-setup-config.js +9 -1
- package/theme/themes/pastanaga/extras/blocks.less +2 -0
- package/theme/themes/pastanaga/extras/main.less +5 -0
- package/src/components/manage/Blocks/Teaser/utils.js +0 -44
- package/src/components/manage/Blocks/Teaser/utils.test.jsx +0 -229
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer from 'react-test-renderer';
|
|
3
|
+
import Image from './Image';
|
|
4
|
+
|
|
5
|
+
test('renders an image component with fetchpriority high', () => {
|
|
6
|
+
const component = renderer.create(
|
|
7
|
+
<Image
|
|
8
|
+
item={{
|
|
9
|
+
image: {
|
|
10
|
+
download: 'http://localhost:3000/image/@@images/image/image.png',
|
|
11
|
+
width: 400,
|
|
12
|
+
height: 400,
|
|
13
|
+
scales: {
|
|
14
|
+
preview: {
|
|
15
|
+
download:
|
|
16
|
+
'http://localhost:3000/image/@@images/image/image-400.png',
|
|
17
|
+
width: 400,
|
|
18
|
+
height: 400,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}}
|
|
23
|
+
imageField="image"
|
|
24
|
+
alt="alt text"
|
|
25
|
+
/>,
|
|
26
|
+
);
|
|
27
|
+
const json = component.toJSON();
|
|
28
|
+
expect(json).toMatchSnapshot();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('renders an image component with lazy loading', () => {
|
|
32
|
+
const component = renderer.create(
|
|
33
|
+
<Image
|
|
34
|
+
item={{
|
|
35
|
+
image: {
|
|
36
|
+
download: 'http://localhost:3000/image/@@images/image/image.png',
|
|
37
|
+
width: 400,
|
|
38
|
+
height: 400,
|
|
39
|
+
scales: {
|
|
40
|
+
preview: {
|
|
41
|
+
download:
|
|
42
|
+
'http://localhost:3000/image/@@images/image/image-400.png',
|
|
43
|
+
width: 400,
|
|
44
|
+
height: 400,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}}
|
|
49
|
+
imageField="image"
|
|
50
|
+
alt="alt text"
|
|
51
|
+
loading="lazy"
|
|
52
|
+
/>,
|
|
53
|
+
);
|
|
54
|
+
const json = component.toJSON();
|
|
55
|
+
expect(json).toMatchSnapshot();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('renders an image component with responsive class', () => {
|
|
59
|
+
const component = renderer.create(
|
|
60
|
+
<Image
|
|
61
|
+
item={{
|
|
62
|
+
image: {
|
|
63
|
+
download: 'http://localhost:3000/image/@@images/image/image.png',
|
|
64
|
+
width: 400,
|
|
65
|
+
height: 400,
|
|
66
|
+
scales: {
|
|
67
|
+
preview: {
|
|
68
|
+
download:
|
|
69
|
+
'http://localhost:3000/image/@@images/image/image-400.png',
|
|
70
|
+
width: 400,
|
|
71
|
+
height: 400,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
}}
|
|
76
|
+
imageField="image"
|
|
77
|
+
alt="alt text"
|
|
78
|
+
responsive={true}
|
|
79
|
+
/>,
|
|
80
|
+
);
|
|
81
|
+
const json = component.toJSON();
|
|
82
|
+
expect(json).toMatchSnapshot();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('renders an image component from a catalog brain', () => {
|
|
86
|
+
const component = renderer.create(
|
|
87
|
+
<Image
|
|
88
|
+
item={{
|
|
89
|
+
'@id': 'http://localhost:3000/image',
|
|
90
|
+
image_field: 'image',
|
|
91
|
+
image_scales: {
|
|
92
|
+
image: [
|
|
93
|
+
{
|
|
94
|
+
download: '@@images/image/image.png',
|
|
95
|
+
width: 400,
|
|
96
|
+
height: 400,
|
|
97
|
+
scales: {
|
|
98
|
+
preview: {
|
|
99
|
+
download: '@@images/image/image-400.png',
|
|
100
|
+
width: 400,
|
|
101
|
+
height: 400,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
}}
|
|
108
|
+
imageField="image"
|
|
109
|
+
alt="alt text"
|
|
110
|
+
/>,
|
|
111
|
+
);
|
|
112
|
+
const json = component.toJSON();
|
|
113
|
+
expect(json).toMatchSnapshot();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('renders an image component from a string src', () => {
|
|
117
|
+
const component = renderer.create(
|
|
118
|
+
<Image
|
|
119
|
+
src="http://localhost:3000/image/@@images/image/image.png"
|
|
120
|
+
alt="alt text"
|
|
121
|
+
/>,
|
|
122
|
+
);
|
|
123
|
+
const json = component.toJSON();
|
|
124
|
+
expect(json).toMatchSnapshot();
|
|
125
|
+
});
|
|
@@ -1,34 +1,45 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import PropTypes from 'prop-types';
|
|
3
2
|
|
|
4
|
-
import { flattenToAppURL } from '@plone/volto/helpers';
|
|
5
3
|
import config from '@plone/volto/registry';
|
|
6
4
|
|
|
7
5
|
import DefaultImageSVG from '@plone/volto/components/manage/Blocks/Listing/default-image.svg';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* Renders a preview image for a catalog brain result item.
|
|
11
|
-
*
|
|
12
9
|
*/
|
|
13
|
-
function PreviewImage(
|
|
14
|
-
const
|
|
15
|
-
const src = item.image_field
|
|
16
|
-
? flattenToAppURL(`${item['@id']}/@@images/${item.image_field}/${size}`)
|
|
17
|
-
: config.getComponent({
|
|
18
|
-
name: 'DefaultImage',
|
|
19
|
-
dependencies: ['listing', 'summary'],
|
|
20
|
-
}).component || DefaultImageSVG;
|
|
10
|
+
function PreviewImage({ item, alt, ...rest }) {
|
|
11
|
+
const Image = config.getComponent({ name: 'Image' }).component;
|
|
21
12
|
|
|
22
|
-
|
|
13
|
+
if (item.image_field && item.image_scales?.[item.image_field]?.[0]) {
|
|
14
|
+
return (
|
|
15
|
+
<Image item={item} imageField={item.image_field} alt={alt} {...rest} />
|
|
16
|
+
);
|
|
17
|
+
} else {
|
|
18
|
+
return (
|
|
19
|
+
<img
|
|
20
|
+
src={
|
|
21
|
+
config.getComponent({
|
|
22
|
+
name: 'DefaultImage',
|
|
23
|
+
dependencies: ['listing', 'summary'],
|
|
24
|
+
}).component || DefaultImageSVG
|
|
25
|
+
}
|
|
26
|
+
alt={alt}
|
|
27
|
+
{...rest}
|
|
28
|
+
width="400"
|
|
29
|
+
height="300"
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
PreviewImage.propTypes = {
|
|
26
|
-
size: PropTypes.string,
|
|
27
36
|
item: PropTypes.shape({
|
|
28
37
|
'@id': PropTypes.string.isRequired,
|
|
29
|
-
image_field: PropTypes.string,
|
|
30
38
|
title: PropTypes.string.isRequired,
|
|
39
|
+
image_field: PropTypes.string,
|
|
40
|
+
image_scales: PropTypes.object,
|
|
31
41
|
}),
|
|
42
|
+
alt: PropTypes.string.isRequired,
|
|
32
43
|
};
|
|
33
44
|
|
|
34
45
|
export default PreviewImage;
|
|
@@ -7,35 +7,56 @@ describe('PreviewImage', () => {
|
|
|
7
7
|
it('renders a preview image', () => {
|
|
8
8
|
const item = {
|
|
9
9
|
image_field: 'image',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
image_scales: {
|
|
11
|
+
image: [
|
|
12
|
+
{
|
|
13
|
+
download: '@@images/image',
|
|
14
|
+
width: 400,
|
|
15
|
+
height: 400,
|
|
16
|
+
scales: {
|
|
17
|
+
preview: {
|
|
18
|
+
download: '@@images/image-400.png',
|
|
19
|
+
width: 400,
|
|
20
|
+
height: 400,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
21
26
|
title: 'Item title',
|
|
22
27
|
'@id': 'http://localhost:3000/something',
|
|
23
28
|
};
|
|
24
29
|
const component = renderer.create(
|
|
25
|
-
<PreviewImage item={item}
|
|
30
|
+
<PreviewImage item={item} alt={item.title} />,
|
|
26
31
|
);
|
|
27
32
|
const json = component.toJSON();
|
|
28
33
|
expect(json).toMatchSnapshot();
|
|
29
34
|
});
|
|
30
35
|
|
|
31
|
-
it('renders a preview image with
|
|
36
|
+
it('renders a preview image with extra props', () => {
|
|
32
37
|
const item = {
|
|
33
38
|
image_field: 'image',
|
|
39
|
+
image_scales: {
|
|
40
|
+
image: [
|
|
41
|
+
{
|
|
42
|
+
download: '@@images/image',
|
|
43
|
+
width: 400,
|
|
44
|
+
height: 400,
|
|
45
|
+
scales: {
|
|
46
|
+
preview: {
|
|
47
|
+
download: '@@images/image-400.png',
|
|
48
|
+
width: 400,
|
|
49
|
+
height: 400,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
34
55
|
title: 'Item title',
|
|
35
56
|
'@id': 'http://localhost:3000/something',
|
|
36
57
|
};
|
|
37
58
|
const component = renderer.create(
|
|
38
|
-
<PreviewImage item={item}
|
|
59
|
+
<PreviewImage item={item} alt={item.title} className="extra" />,
|
|
39
60
|
);
|
|
40
61
|
const json = component.toJSON();
|
|
41
62
|
expect(json).toMatchSnapshot();
|
|
@@ -46,7 +67,9 @@ describe('PreviewImage', () => {
|
|
|
46
67
|
title: 'Item title',
|
|
47
68
|
'@id': 'http://localhost:3000/something',
|
|
48
69
|
};
|
|
49
|
-
const component = renderer.create(
|
|
70
|
+
const component = renderer.create(
|
|
71
|
+
<PreviewImage item={item} alt={item.title} />,
|
|
72
|
+
);
|
|
50
73
|
const json = component.toJSON();
|
|
51
74
|
expect(json).toMatchSnapshot();
|
|
52
75
|
});
|
|
@@ -57,7 +80,7 @@ describe('PreviewImage', () => {
|
|
|
57
80
|
'@id': 'http://localhost:3000/something',
|
|
58
81
|
};
|
|
59
82
|
const component = renderer.create(
|
|
60
|
-
<PreviewImage item={item} className="extra" />,
|
|
83
|
+
<PreviewImage item={item} alt={item.title} className="extra" />,
|
|
61
84
|
);
|
|
62
85
|
const json = component.toJSON();
|
|
63
86
|
expect(json).toMatchSnapshot();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module components/theme/View/AlbumView
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React
|
|
6
|
+
import React from 'react';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
import {
|
|
9
9
|
Container as SemanticContainer,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
Segment,
|
|
12
12
|
} from 'semantic-ui-react';
|
|
13
13
|
import { Button, Modal, Grid } from 'semantic-ui-react';
|
|
14
|
-
import { Icon, UniversalLink
|
|
14
|
+
import { Icon, UniversalLink } from '@plone/volto/components';
|
|
15
15
|
import config from '@plone/volto/registry';
|
|
16
16
|
|
|
17
17
|
import openSVG from '@plone/volto/icons/open.svg';
|
|
@@ -24,7 +24,7 @@ import backSVG from '@plone/volto/icons/back.svg';
|
|
|
24
24
|
* @param {Object} content Content object.
|
|
25
25
|
* @returns {string} Markup of the component.
|
|
26
26
|
*/
|
|
27
|
-
class AlbumView extends Component {
|
|
27
|
+
class AlbumView extends React.Component {
|
|
28
28
|
constructor(props) {
|
|
29
29
|
super(props);
|
|
30
30
|
|
|
@@ -63,6 +63,8 @@ class AlbumView extends Component {
|
|
|
63
63
|
const { content } = this.props;
|
|
64
64
|
const Container =
|
|
65
65
|
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
66
|
+
const PreviewImage = config.getComponent({ name: 'PreviewImage' })
|
|
67
|
+
.component;
|
|
66
68
|
|
|
67
69
|
return (
|
|
68
70
|
<Container className="view-wrapper">
|
|
@@ -88,17 +90,16 @@ class AlbumView extends Component {
|
|
|
88
90
|
<Segment className="imageborder">
|
|
89
91
|
<PreviewImage
|
|
90
92
|
item={item}
|
|
91
|
-
alt={
|
|
92
|
-
item.image_caption
|
|
93
|
-
? item.image_caption
|
|
94
|
-
: item.title
|
|
95
|
-
}
|
|
93
|
+
alt={item.image_caption || item.title}
|
|
96
94
|
onClick={() => {
|
|
97
95
|
this.setState({
|
|
98
96
|
openIndex: index,
|
|
99
97
|
});
|
|
100
98
|
}}
|
|
101
99
|
className="ui middle aligned image"
|
|
100
|
+
responsive={true}
|
|
101
|
+
loading="lazy"
|
|
102
|
+
title={item.title}
|
|
102
103
|
/>
|
|
103
104
|
</Segment>
|
|
104
105
|
</Grid.Column>
|
|
@@ -141,20 +142,15 @@ class AlbumView extends Component {
|
|
|
141
142
|
<Modal.Content image>
|
|
142
143
|
<PreviewImage
|
|
143
144
|
item={item}
|
|
144
|
-
alt={
|
|
145
|
-
item.image_caption
|
|
146
|
-
? item.image_caption
|
|
147
|
-
: item.title
|
|
148
|
-
}
|
|
145
|
+
alt={item.image_caption}
|
|
149
146
|
onClick={() => {
|
|
150
147
|
this.setState({
|
|
151
148
|
openIndex: index,
|
|
152
149
|
});
|
|
153
150
|
}}
|
|
154
|
-
size="large"
|
|
155
151
|
className="ui image"
|
|
152
|
+
responsive={true}
|
|
156
153
|
/>
|
|
157
|
-
|
|
158
154
|
<Modal.Description>
|
|
159
155
|
<p>{item.description}</p>
|
|
160
156
|
</Modal.Description>
|
|
@@ -6,34 +6,41 @@
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
import { hasBlocksData, flattenHTMLToAppURL } from '@plone/volto/helpers';
|
|
9
|
-
import {
|
|
9
|
+
import { Grid } from 'semantic-ui-react';
|
|
10
10
|
import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
|
|
11
11
|
import { EventDetails } from '@plone/volto/components';
|
|
12
12
|
import { Container as SemanticContainer } from 'semantic-ui-react';
|
|
13
13
|
import config from '@plone/volto/registry';
|
|
14
14
|
|
|
15
|
-
const EventTextfieldView = ({ content }) =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
15
|
+
const EventTextfieldView = ({ content }) => {
|
|
16
|
+
const Image = config.getComponent({ name: 'Image' }).component;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<React.Fragment>
|
|
20
|
+
{content.title && (
|
|
21
|
+
<h1 className="documentFirstHeading">{content.title}</h1>
|
|
22
|
+
)}
|
|
23
|
+
{content.description && (
|
|
24
|
+
<p className="documentDescription">{content.description}</p>
|
|
25
|
+
)}
|
|
26
|
+
{content.image && (
|
|
27
|
+
<Image
|
|
28
|
+
className="document-image ui right floated image"
|
|
29
|
+
item={content}
|
|
30
|
+
imageField="image"
|
|
31
|
+
alt=""
|
|
32
|
+
/>
|
|
33
|
+
)}
|
|
34
|
+
{content.text && (
|
|
35
|
+
<div
|
|
36
|
+
dangerouslySetInnerHTML={{
|
|
37
|
+
__html: flattenHTMLToAppURL(content.text.data),
|
|
38
|
+
}}
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
</React.Fragment>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
37
44
|
|
|
38
45
|
/**
|
|
39
46
|
* EventView view component class.
|
|
@@ -18,6 +18,7 @@ import config from '@plone/volto/registry';
|
|
|
18
18
|
* @returns {string} Markup of the component.
|
|
19
19
|
*/
|
|
20
20
|
const ImageView = ({ content }) => {
|
|
21
|
+
const Image = config.getComponent({ name: 'Image' }).component;
|
|
21
22
|
const Container =
|
|
22
23
|
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
23
24
|
|
|
@@ -32,9 +33,11 @@ const ImageView = ({ content }) => {
|
|
|
32
33
|
)}
|
|
33
34
|
{content?.image?.download && (
|
|
34
35
|
<a href={flattenToAppURL(content.image.download)}>
|
|
35
|
-
<
|
|
36
|
+
<Image
|
|
37
|
+
item={content}
|
|
38
|
+
imageField="image"
|
|
36
39
|
alt={content.title}
|
|
37
|
-
|
|
40
|
+
responsive={true}
|
|
38
41
|
/>
|
|
39
42
|
<figcaption>
|
|
40
43
|
<FormattedMessage
|
|
@@ -23,9 +23,13 @@ test('renders an image view component', () => {
|
|
|
23
23
|
image: {
|
|
24
24
|
size: 123123,
|
|
25
25
|
download: 'file:///preview.jpg',
|
|
26
|
+
width: 400,
|
|
27
|
+
height: 400,
|
|
26
28
|
scales: {
|
|
27
29
|
preview: {
|
|
28
30
|
download: 'file:///preview.jpg',
|
|
31
|
+
width: 400,
|
|
32
|
+
height: 400,
|
|
29
33
|
},
|
|
30
34
|
},
|
|
31
35
|
},
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
import { Segment, Container as SemanticContainer } from 'semantic-ui-react';
|
|
9
|
-
import { UniversalLink
|
|
9
|
+
import { UniversalLink } from '@plone/volto/components';
|
|
10
10
|
import config from '@plone/volto/registry';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -18,6 +18,7 @@ import config from '@plone/volto/registry';
|
|
|
18
18
|
const ListingView = ({ content }) => {
|
|
19
19
|
const Container =
|
|
20
20
|
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
21
|
+
const PreviewImage = config.getComponent({ name: 'PreviewImage' }).component;
|
|
21
22
|
|
|
22
23
|
return (
|
|
23
24
|
<Container id="page-home">
|
|
@@ -35,9 +36,10 @@ const ListingView = ({ content }) => {
|
|
|
35
36
|
{item.image_field && (
|
|
36
37
|
<PreviewImage
|
|
37
38
|
item={item}
|
|
38
|
-
|
|
39
|
-
alt={item.image_caption ? item.image_caption : item.title}
|
|
39
|
+
alt={item.image_caption}
|
|
40
40
|
className="ui image"
|
|
41
|
+
responsive={true}
|
|
42
|
+
loading="lazy"
|
|
41
43
|
/>
|
|
42
44
|
)}
|
|
43
45
|
</Segment>
|
|
@@ -5,12 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
|
-
import { Container as SemanticContainer
|
|
9
|
-
import {
|
|
10
|
-
hasBlocksData,
|
|
11
|
-
flattenToAppURL,
|
|
12
|
-
flattenHTMLToAppURL,
|
|
13
|
-
} from '@plone/volto/helpers';
|
|
8
|
+
import { Container as SemanticContainer } from 'semantic-ui-react';
|
|
9
|
+
import { hasBlocksData, flattenHTMLToAppURL } from '@plone/volto/helpers';
|
|
14
10
|
import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
|
|
15
11
|
import config from '@plone/volto/registry';
|
|
16
12
|
|
|
@@ -21,6 +17,7 @@ import config from '@plone/volto/registry';
|
|
|
21
17
|
* @returns {string} Markup of the component.
|
|
22
18
|
*/
|
|
23
19
|
const NewsItemView = ({ content }) => {
|
|
20
|
+
const Image = config.getComponent({ name: 'Image' }).component;
|
|
24
21
|
const Container =
|
|
25
22
|
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
26
23
|
|
|
@@ -41,15 +38,12 @@ const NewsItemView = ({ content }) => {
|
|
|
41
38
|
)}
|
|
42
39
|
{content.image && (
|
|
43
40
|
<Image
|
|
44
|
-
className="documentImage"
|
|
41
|
+
className="documentImage ui right floated image"
|
|
45
42
|
alt={content.title}
|
|
46
43
|
title={content.title}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
: flattenToAppURL(content.image.scales.mini.download)
|
|
51
|
-
}
|
|
52
|
-
floated="right"
|
|
44
|
+
item={content}
|
|
45
|
+
imageField="image"
|
|
46
|
+
responsive={true}
|
|
53
47
|
/>
|
|
54
48
|
)}
|
|
55
49
|
{content.text && (
|
|
@@ -8,7 +8,6 @@ import PropTypes from 'prop-types';
|
|
|
8
8
|
import { UniversalLink } from '@plone/volto/components';
|
|
9
9
|
import { Container as SemanticContainer } from 'semantic-ui-react';
|
|
10
10
|
import { FormattedMessage } from 'react-intl';
|
|
11
|
-
import PreviewImage from '../PreviewImage/PreviewImage';
|
|
12
11
|
import config from '@plone/volto/registry';
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -20,6 +19,7 @@ import config from '@plone/volto/registry';
|
|
|
20
19
|
const SummaryView = ({ content }) => {
|
|
21
20
|
const Container =
|
|
22
21
|
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
22
|
+
const PreviewImage = config.getComponent({ name: 'PreviewImage' }).component;
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<Container className="view-wrapper summary-view">
|
|
@@ -41,9 +41,10 @@ const SummaryView = ({ content }) => {
|
|
|
41
41
|
{item.image_field && (
|
|
42
42
|
<PreviewImage
|
|
43
43
|
item={item}
|
|
44
|
-
alt={item.image_caption
|
|
45
|
-
size="thumb"
|
|
44
|
+
alt={item.image_caption}
|
|
46
45
|
className="ui image floated right clear"
|
|
46
|
+
responsive={true}
|
|
47
|
+
loading="lazy"
|
|
47
48
|
/>
|
|
48
49
|
)}
|
|
49
50
|
{item.description && <p>{item.description}</p>}
|
package/src/config/Blocks.jsx
CHANGED
|
@@ -75,6 +75,7 @@ import {
|
|
|
75
75
|
DateRangeFacetFilterListEntry,
|
|
76
76
|
} from '@plone/volto/components/manage/Blocks/Search/components';
|
|
77
77
|
import getListingBlockAsyncData from '@plone/volto/components/manage/Blocks/Listing/getAsyncData';
|
|
78
|
+
import { getImageBlockSizes } from '@plone/volto/components/manage/Blocks/Image/utils';
|
|
78
79
|
|
|
79
80
|
// block sidebar schemas (not the Dexterity Layout block settings schemas)
|
|
80
81
|
import HeroImageLeftBlockSchema from '@plone/volto/components/manage/Blocks/HeroImageLeft/schema';
|
|
@@ -258,6 +259,7 @@ const blocksConfig = {
|
|
|
258
259
|
restricted: false,
|
|
259
260
|
mostUsed: true,
|
|
260
261
|
sidebarTab: 1,
|
|
262
|
+
getSizes: getImageBlockSizes,
|
|
261
263
|
},
|
|
262
264
|
leadimage: {
|
|
263
265
|
id: 'leadimage',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { App, PreviewImage } from '@plone/volto/components';
|
|
1
|
+
import { App, PreviewImage, Image } from '@plone/volto/components';
|
|
2
2
|
|
|
3
3
|
export const components = {
|
|
4
4
|
PreviewImage: { component: PreviewImage },
|
|
5
5
|
App: { component: App },
|
|
6
|
+
Image: { component: Image },
|
|
6
7
|
};
|
package/src/helpers/Url/Url.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module helpers/Url
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { last, memoize } from 'lodash';
|
|
6
|
+
import { last, memoize, isArray, isObject, isString } from 'lodash';
|
|
7
7
|
import { urlRegex, telRegex, mailRegex } from './urlRegex';
|
|
8
8
|
import prependHttp from 'prepend-http';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
@@ -251,6 +251,27 @@ export function isUrl(url) {
|
|
|
251
251
|
return urlRegex().test(url);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Get field url
|
|
256
|
+
* @method getFieldURL
|
|
257
|
+
* @param {object} data
|
|
258
|
+
* @returns {string | any} URL string value if field is of url type or any.
|
|
259
|
+
*/
|
|
260
|
+
export const getFieldURL = (data) => {
|
|
261
|
+
let url = data;
|
|
262
|
+
const _isObject = data && isObject(data) && !isArray(data);
|
|
263
|
+
if (_isObject && data['@type'] === 'URL') {
|
|
264
|
+
url = data['value'] ?? data['url'] ?? data['href'] ?? data;
|
|
265
|
+
} else if (_isObject) {
|
|
266
|
+
url = data['@id'] ?? data['url'] ?? data['href'] ?? data;
|
|
267
|
+
}
|
|
268
|
+
if (isArray(data)) {
|
|
269
|
+
url = data.map((item) => getFieldURL(item));
|
|
270
|
+
}
|
|
271
|
+
if (isString(url) && isInternalURL(url)) return flattenToAppURL(url);
|
|
272
|
+
return url;
|
|
273
|
+
};
|
|
274
|
+
|
|
254
275
|
/**
|
|
255
276
|
* Normalize URL, adds protocol (if required eg. user has not entered the protocol)
|
|
256
277
|
* @method normalizeUrl
|