@eeacms/volto-clms-theme 1.0.76 → 1.0.77

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.
@@ -0,0 +1,316 @@
1
+ import './styles.less';
2
+
3
+ // import { CardBlockSchema, HomeUsersSchema } from './HomeUsersSchema';
4
+ /** upload image */
5
+ import { Dimmer, Image, Label, Loader, Message } from 'semantic-ui-react';
6
+ import { Icon } from '@plone/volto/components';
7
+ import React, { useState } from 'react';
8
+ import { useDispatch, useSelector } from 'react-redux';
9
+ import { defineMessages, useIntl } from 'react-intl';
10
+ import { flattenToAppURL, getBaseUrl } from '@plone/volto/helpers';
11
+
12
+ import { createContent, getContent } from '@plone/volto/actions';
13
+ import editingSVG from '@plone/volto/icons/editing.svg';
14
+ import navSVG from '@plone/volto/icons/nav.svg';
15
+ import { readAsDataURL } from 'promise-file-reader';
16
+ import uploadSVG from '@plone/volto/icons/upload.svg';
17
+
18
+ const messages = defineMessages({
19
+ uploadImage: {
20
+ id: 'Upload image',
21
+ defaultMessage: 'Upload or select an image',
22
+ },
23
+ uploadingFile: {
24
+ id: 'Uploading file',
25
+ defaultMessage: 'Uploading file',
26
+ },
27
+ removeImage: {
28
+ id: 'Remove image',
29
+ defaultMessage: 'Remove image',
30
+ },
31
+ editImage: {
32
+ id: 'Edit image',
33
+ defaultMessage: 'Edit',
34
+ },
35
+ });
36
+
37
+ const onChangeCardBlockImage = (
38
+ onChangeBlock,
39
+ block,
40
+ data,
41
+ selectedCardBlock,
42
+ imageValue,
43
+ ) => {
44
+ onChangeBlock(block, {
45
+ ...data,
46
+ customCards: {
47
+ ...data.customCards,
48
+ blocks: {
49
+ ...data.customCards.blocks,
50
+ [selectedCardBlock]: {
51
+ ...data.customCards.blocks[selectedCardBlock],
52
+ image: imageValue,
53
+ },
54
+ },
55
+ },
56
+ });
57
+ };
58
+
59
+ const onUploadImage = (pathname, e, setUploading, dispatch) => {
60
+ e.stopPropagation();
61
+ e.preventDefault();
62
+ const target = e.target;
63
+ const file = target.files[0];
64
+ readAsDataURL(file).then((data) => {
65
+ setUploading(true);
66
+ const fields = data.match(/^data:(.*);(.*),(.*)$/);
67
+ dispatch(
68
+ createContent(getBaseUrl(pathname), {
69
+ '@type': 'Image',
70
+ image: {
71
+ data: fields[3],
72
+ encoding: fields[2],
73
+ 'content-type': fields[1],
74
+ filename: file.name,
75
+ },
76
+ }),
77
+ ).then((response) => {
78
+ dispatch(getContent(getBaseUrl(pathname)));
79
+ });
80
+ });
81
+ };
82
+
83
+ const ImageEditor = ({
84
+ editable,
85
+ pathname,
86
+ setUploading,
87
+ uploading,
88
+ dispatch,
89
+ onChangeBlock,
90
+ block,
91
+ data,
92
+ selected,
93
+ selectedCardBlock,
94
+ setSelectedCardBlock,
95
+ openObjectBrowser,
96
+ request,
97
+ content,
98
+ }) => {
99
+ React.useEffect(() => {
100
+ if (!__SERVER__) {
101
+ setUploading(false);
102
+ }
103
+ if (!selected) {
104
+ setSelectedCardBlock(-1);
105
+ }
106
+ // eslint-disable-next-line react-hooks/exhaustive-deps
107
+ }, [selected]);
108
+ React.useEffect(() => {
109
+ if (request?.loaded && !request?.loading && uploading) {
110
+ setUploading(false);
111
+ onChangeCardBlockImage(onChangeBlock, block, data, selectedCardBlock, {
112
+ url: flattenToAppURL(content['@id']),
113
+ alt: content?.image?.filename,
114
+ });
115
+ }
116
+ /* eslint-disable-next-line */
117
+ }, [request]);
118
+ return (
119
+ editable && (
120
+ <p>
121
+ <label className="file">
122
+ <Icon className="ui button" name={uploadSVG} size={35} />
123
+ <input
124
+ type="file"
125
+ onChange={(e) => onUploadImage(pathname, e, setUploading, dispatch)}
126
+ style={{ display: 'none' }}
127
+ />
128
+ </label>
129
+ <label className="file">
130
+ <Icon className="ui button" name={navSVG} size={35} />
131
+ <input
132
+ type="button"
133
+ onClick={(e) => {
134
+ e.stopPropagation();
135
+ e.preventDefault();
136
+ openObjectBrowser({
137
+ onSelectItem: (url, element) =>
138
+ onChangeCardBlockImage(
139
+ onChangeBlock,
140
+ block,
141
+ data,
142
+ selectedCardBlock,
143
+ {
144
+ url: element['@id'],
145
+ alt: element.title,
146
+ },
147
+ ),
148
+ });
149
+ }}
150
+ style={{ display: 'none' }}
151
+ />
152
+ </label>
153
+ </p>
154
+ )
155
+ );
156
+ };
157
+
158
+ function isSelected(selected, uid, selectedCardBlock) {
159
+ return selected && uid === selectedCardBlock;
160
+ }
161
+
162
+ const UploadingDimmer = ({ uid, selectedCardBlock, uploading, intl }) => {
163
+ return uid === selectedCardBlock && uploading ? (
164
+ <Dimmer active>
165
+ <Loader indeterminate>
166
+ {intl.formatMessage(messages.uploadingFile)}
167
+ </Loader>
168
+ </Dimmer>
169
+ ) : (
170
+ <></>
171
+ );
172
+ };
173
+
174
+ const handleEdit = (handleEditProps) => {
175
+ const {
176
+ selected,
177
+ uid,
178
+ selectedCardBlock,
179
+ setSelectedCardBlock,
180
+ openObjectBrowser,
181
+ onChangeBlock,
182
+ block,
183
+ data,
184
+ } = handleEditProps;
185
+ if (isSelected(selected, uid, selectedCardBlock)) {
186
+ openObjectBrowser({
187
+ onSelectItem: (url, element) =>
188
+ onChangeCardBlockImage(onChangeBlock, block, data, selectedCardBlock, {
189
+ url: element['@id'],
190
+ alt: element.title,
191
+ }),
192
+ });
193
+ } else {
194
+ setSelectedCardBlock(uid);
195
+ }
196
+ };
197
+
198
+ const CclImageEditor = ({
199
+ block,
200
+ data,
201
+ editable,
202
+ imageUrl,
203
+ onChangeBlock,
204
+ openObjectBrowser,
205
+ pathname,
206
+ selected,
207
+ selectedCardBlock,
208
+ setSelectedCardBlock,
209
+ uid,
210
+ }) => {
211
+ const intl = useIntl();
212
+
213
+ const [uploading, setUploading] = useState(false);
214
+ const dispatch = useDispatch();
215
+ const request = useSelector((state) => state.content.create);
216
+ const content = useSelector((state) => state.content.data);
217
+
218
+ return imageUrl ? (
219
+ <>
220
+ {isSelected(selected, uid, selectedCardBlock) && (
221
+ <Label
222
+ as="a"
223
+ color="red"
224
+ pointing="below"
225
+ onClick={() =>
226
+ onChangeCardBlockImage(
227
+ onChangeBlock,
228
+ block,
229
+ data,
230
+ selectedCardBlock,
231
+ {},
232
+ )
233
+ }
234
+ >
235
+ {intl.formatMessage(messages.removeImage)}
236
+ </Label>
237
+ )}
238
+
239
+ <div
240
+ role="button"
241
+ tabindex="0"
242
+ className="ui image edit-image-container"
243
+ onClick={(e) => {
244
+ e.stopPropagation();
245
+ e.preventDefault();
246
+ const handleEditPC = {
247
+ selected: selected,
248
+ uid: uid,
249
+ selectedCardBlock: selectedCardBlock,
250
+ setSelectedCardBlock: setSelectedCardBlock,
251
+ openObjectBrowser: openObjectBrowser,
252
+ onChangeBlock: onChangeBlock,
253
+ block: block,
254
+ data: data,
255
+ };
256
+ handleEdit(handleEditPC);
257
+ }}
258
+ onKeyDown={(e) => {
259
+ e.stopPropagation();
260
+ e.preventDefault();
261
+ const handleEditPK = {
262
+ selected: selected,
263
+ uid: uid,
264
+ selectedCardBlock: selectedCardBlock,
265
+ setSelectedCardBlock: setSelectedCardBlock,
266
+ openObjectBrowser: openObjectBrowser,
267
+ onChangeBlock: onChangeBlock,
268
+ block: block,
269
+ data: data,
270
+ };
271
+ handleEdit(handleEditPK);
272
+ }}
273
+ >
274
+ <Image size="small" src={`${imageUrl}/@@images/image/preview`} />
275
+ {isSelected(selected, uid, selectedCardBlock) && (
276
+ <div className="edit-image">
277
+ <Icon className="ui" name={editingSVG} size={35} />
278
+ {intl.formatMessage(messages.editImage)}
279
+ </div>
280
+ )}
281
+ </div>
282
+ </>
283
+ ) : (
284
+ <div className="image-add">
285
+ <Message className="image-message">
286
+ <UploadingDimmer
287
+ uid={uid}
288
+ selectedCardBlock={selectedCardBlock}
289
+ uploading={uploading}
290
+ intl={intl}
291
+ />
292
+ <center>
293
+ <h4>{intl.formatMessage(messages.uploadImage)}</h4>
294
+ <ImageEditor
295
+ editable={editable}
296
+ pathname={pathname}
297
+ setUploading={setUploading}
298
+ uploading={uploading}
299
+ dispatch={dispatch}
300
+ onChangeBlock={onChangeBlock}
301
+ block={block}
302
+ data={data}
303
+ selected={selected}
304
+ selectedCardBlock={selectedCardBlock}
305
+ setSelectedCardBlock={setSelectedCardBlock}
306
+ openObjectBrowser={openObjectBrowser}
307
+ request={request}
308
+ content={content}
309
+ />
310
+ </center>
311
+ </Message>
312
+ </div>
313
+ );
314
+ };
315
+
316
+ export default CclImageEditor;
@@ -0,0 +1,97 @@
1
+ @type: 'extra';
2
+ @element: 'custom';
3
+
4
+ @import (multiple) '../../theme.config';
5
+
6
+ @borderColor: rgba(120, 192, 215, 0.75);
7
+
8
+ .block-editor-homeUsers,
9
+ .block-editor-cardContainer {
10
+ .block-column .ui.block.inner {
11
+ .block {
12
+ margin-bottom: 0;
13
+ }
14
+ }
15
+
16
+ .block.homeUsers.selected::before,
17
+ .block.homeUsers:hover::before,
18
+ .block.cardContainer.selected::before,
19
+ .block.cardContainer:hover::before {
20
+ border-style: dashed;
21
+ }
22
+
23
+ .homeUsers-header,
24
+ .cardContainer-header {
25
+ position: absolute;
26
+ z-index: 3;
27
+ top: -1.3em;
28
+ left: 0;
29
+ width: fit-content;
30
+ padding: 0 1rem;
31
+ margin-right: auto;
32
+ margin-left: auto;
33
+ background-color: @pageBackground;
34
+ color: @borderColor;
35
+ cursor: pointer;
36
+ text-align: center;
37
+ }
38
+
39
+ .block .card-image,
40
+ .block .card-image img {
41
+ width: 300px;
42
+ }
43
+
44
+ .ui.image.edit-image-container {
45
+ height: 12rem;
46
+
47
+ img {
48
+ width: 100%;
49
+ height: 100%;
50
+ -o-object-fit: cover;
51
+ object-fit: cover;
52
+ }
53
+ }
54
+
55
+ .card-image .edit-image-container {
56
+ position: relative;
57
+ text-align: center;
58
+ }
59
+
60
+ .edit-image {
61
+ position: absolute;
62
+ top: 50%;
63
+ left: 50%;
64
+ display: none !important;
65
+ padding: 0.5rem;
66
+ background-color: white;
67
+ border-radius: 0.2rem;
68
+ font-size: 0.8rem;
69
+ transform: translate(-50%, -50%);
70
+ }
71
+
72
+ .edit-image-container:hover {
73
+ cursor: pointer;
74
+
75
+ .edit-image {
76
+ display: block !important;
77
+ }
78
+
79
+ img {
80
+ opacity: 0.8;
81
+ }
82
+ }
83
+ }
84
+
85
+ .ccl-list-items .ccl-list-item .ccl-list-item-image img {
86
+ width: 100%;
87
+ height: 100%;
88
+ object-fit: cover;
89
+ }
90
+
91
+ .ccl-container .slick-slider {
92
+ display: grid;
93
+ }
94
+
95
+ .block.selected .card-line .card-image {
96
+ text-align: center;
97
+ }
@@ -1,44 +0,0 @@
1
- export const CardBlockSchema = () => ({
2
- title: 'Product card block',
3
- fieldsets: [
4
- {
5
- id: 'default',
6
- title: 'Default',
7
- fields: ['title', 'image', 'description', 'href', 'cardStyle'],
8
- },
9
- ],
10
- properties: {
11
- title: {
12
- title: 'Title',
13
- description: 'Card title',
14
- type: 'string',
15
- placeholder: 'Card title here',
16
- },
17
- image: {
18
- title: 'Card image',
19
- },
20
- description: {
21
- title: 'Product description',
22
- type: 'string',
23
- },
24
- href: {
25
- title: 'URL',
26
- description: 'Select site content or paste external url',
27
- widget: 'object_browser',
28
- mode: 'link',
29
- selectedItemAttrs: ['Title', 'Description', '@type', '@id'],
30
- allowExternals: true,
31
- },
32
- cardStyle: {
33
- title: 'Card style',
34
- choices: [
35
- ['line', 'Line card'],
36
- ['block', 'Block card'],
37
- ['line-color', 'Colored Line card'],
38
- ['event', 'Event card'],
39
- ['news', 'News card'],
40
- ],
41
- },
42
- },
43
- required: ['product'],
44
- });
@@ -1,77 +0,0 @@
1
- import React from 'react';
2
- import CclCard from '@eeacms/volto-clms-theme/components/CclCard/CclCard';
3
-
4
- import { SidebarPortal } from '@plone/volto/components';
5
- import { CardBlockSchema } from './CardBlockSchema';
6
- import InlineForm from '@plone/volto/components/manage/Form/InlineForm';
7
-
8
- const CclCardBlockEdit = (props) => {
9
- const { block, data, onChangeBlock, selected } = props;
10
-
11
- let card = {
12
- product: data.title,
13
- description: data.description,
14
- image: {
15
- scales: {
16
- icon: {
17
- download:
18
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
19
- },
20
- large: {
21
- download:
22
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
23
- },
24
- listing: {
25
- download:
26
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
27
- },
28
- mini: {
29
- download:
30
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
31
- },
32
- preview: {
33
- download:
34
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
35
- },
36
- thumb: {
37
- download:
38
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
39
- },
40
- tile: {
41
- download:
42
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
43
- },
44
- },
45
- },
46
- url: data.url,
47
- };
48
-
49
- return (
50
- <>
51
- <div className="ccl-block-editor-header">
52
- <legend
53
- onClick={() => {
54
- props.setSidebarTab(1);
55
- }}
56
- aria-hidden="true"
57
- />
58
- </div>
59
- <CclCard type={data.cardStyle || 'line'} card={card} />
60
- <SidebarPortal selected={selected}>
61
- <InlineForm
62
- schema={CardBlockSchema()}
63
- title="Product card block"
64
- onChangeField={(id, value) => {
65
- onChangeBlock(block, {
66
- ...data,
67
- [id]: value,
68
- });
69
- }}
70
- formData={data}
71
- />
72
- </SidebarPortal>
73
- </>
74
- );
75
- };
76
-
77
- export default CclCardBlockEdit;
@@ -1,171 +0,0 @@
1
- import Enzyme, { mount } from 'enzyme';
2
-
3
- import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
4
- import CclCardBlockEdit from './CclCardBlockEdit';
5
- import { MemoryRouter } from 'react-router-dom';
6
- import { Provider } from 'react-intl-redux';
7
- import React from 'react';
8
- import configureStore from 'redux-mock-store';
9
- import renderer from 'react-test-renderer';
10
-
11
- // import { shallow } from 'enzyme';
12
-
13
- Enzyme.configure({ adapter: new Adapter() });
14
-
15
- global.__SERVER__ = true; // eslint-disable-line no-underscore-dangle
16
-
17
- const mockStore = configureStore();
18
-
19
- describe('CclCardBlockEdit', () => {
20
- it('CclCardBlockEdit block clicks', () => {
21
- const store = mockStore({
22
- content: {
23
- create: {},
24
- data: {},
25
- },
26
- intl: {
27
- locale: 'en',
28
- messages: {},
29
- },
30
- });
31
- const data = {
32
- title: 'example title',
33
- description: 'example description',
34
- image: [
35
- {
36
- scales: [
37
- {
38
- icon: {
39
- download:
40
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
41
- },
42
- large: {
43
- download:
44
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
45
- },
46
- listing: {
47
- download:
48
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
49
- },
50
- mini: {
51
- download:
52
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
53
- },
54
- preview: {
55
- download:
56
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
57
- },
58
- thumb: {
59
- download:
60
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
61
- },
62
- tile: {
63
- download:
64
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
65
- },
66
- },
67
- ],
68
- },
69
- ],
70
- url: 'https://www.google.com',
71
- };
72
- // const component = shallow(
73
- const component = mount(
74
- <Provider store={store}>
75
- <MemoryRouter>
76
- <CclCardBlockEdit
77
- data={data}
78
- block="1234"
79
- onChangeBlock={() => {
80
- return 'test';
81
- }}
82
- setSidebarTab={() => {
83
- return 'test';
84
- }}
85
- />
86
- </MemoryRouter>
87
- </Provider>,
88
- );
89
- const legend = component.find('.ccl-block-editor-header legend');
90
- legend.simulate('click');
91
- expect(legend).toBeDefined();
92
- });
93
- it('renders a CclCardBlockEdit block component', () => {
94
- const store = mockStore({
95
- content: {
96
- create: {},
97
- data: {},
98
- },
99
- intl: {
100
- locale: 'en',
101
- messages: {},
102
- },
103
- });
104
- const data = {
105
- title: 'example title',
106
- description: 'example description',
107
- image: [
108
- {
109
- scales: [
110
- {
111
- icon: {
112
- download:
113
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
114
- },
115
- large: {
116
- download:
117
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
118
- },
119
- listing: {
120
- download:
121
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
122
- },
123
- mini: {
124
- download:
125
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
126
- },
127
- preview: {
128
- download:
129
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
130
- },
131
- thumb: {
132
- download:
133
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
134
- },
135
- tile: {
136
- download:
137
- 'https://eu-copernicus.github.io/copernicus-component-library/assets/images/image_placeholder.jpg',
138
- },
139
- },
140
- ],
141
- },
142
- ],
143
- url: 'https://www.google.com',
144
- };
145
- const component = renderer.create(
146
- <Provider store={store}>
147
- <MemoryRouter>
148
- <CclCardBlockEdit
149
- data={data}
150
- block="1234"
151
- onChangeBlock={() => {
152
- return 'test';
153
- }}
154
- onSelectBlock={() => {
155
- return 'test';
156
- }}
157
- onChangeField={() => {
158
- return 'test';
159
- }}
160
- setSidebarTab={() => {
161
- return 'test';
162
- }}
163
- />
164
- </MemoryRouter>
165
- </Provider>,
166
- );
167
-
168
- const json = component.toJSON();
169
- expect(json).toMatchSnapshot();
170
- });
171
- });