@plone/volto 17.0.0-alpha.14 → 17.0.0-alpha.16

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 (99) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +25 -0
  3. package/cypress/support/commands.js +18 -0
  4. package/locales/ca/LC_MESSAGES/volto.po +41 -0
  5. package/locales/ca.json +1 -1
  6. package/locales/de/LC_MESSAGES/volto.po +41 -0
  7. package/locales/de.json +1 -1
  8. package/locales/en/LC_MESSAGES/volto.po +41 -0
  9. package/locales/en.json +1 -1
  10. package/locales/es/LC_MESSAGES/volto.po +41 -0
  11. package/locales/es.json +1 -1
  12. package/locales/eu/LC_MESSAGES/volto.po +41 -0
  13. package/locales/eu.json +1 -1
  14. package/locales/fi/LC_MESSAGES/volto.po +41 -0
  15. package/locales/fi.json +1 -1
  16. package/locales/fr/LC_MESSAGES/volto.po +41 -0
  17. package/locales/fr.json +1 -1
  18. package/locales/it/LC_MESSAGES/volto.po +41 -0
  19. package/locales/it.json +1 -1
  20. package/locales/ja/LC_MESSAGES/volto.po +41 -0
  21. package/locales/ja.json +1 -1
  22. package/locales/nl/LC_MESSAGES/volto.po +41 -0
  23. package/locales/nl.json +1 -1
  24. package/locales/pt/LC_MESSAGES/volto.po +41 -0
  25. package/locales/pt.json +1 -1
  26. package/locales/pt_BR/LC_MESSAGES/volto.po +41 -0
  27. package/locales/pt_BR.json +1 -1
  28. package/locales/ro/LC_MESSAGES/volto.po +41 -0
  29. package/locales/ro.json +1 -1
  30. package/locales/volto.pot +42 -1
  31. package/locales/zh_CN/LC_MESSAGES/volto.po +41 -0
  32. package/locales/zh_CN.json +1 -1
  33. package/package.json +1 -1
  34. package/packages/volto-slate/package.json +1 -1
  35. package/packages/volto-slate/src/actions/index.js +1 -1
  36. package/packages/volto-slate/src/blocks/Text/index.js +10 -2
  37. package/packages/volto-slate/src/editor/index.js +4 -4
  38. package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
  39. package/packages/volto-slate/src/editor/ui/index.js +15 -15
  40. package/packages/volto-slate/src/index.js +2 -2
  41. package/src/components/manage/AnchorPlugin/index.jsx +2 -2
  42. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
  43. package/src/components/manage/Blocks/Block/BlocksForm.jsx +19 -2
  44. package/src/components/manage/Blocks/Block/Edit.jsx +1 -1
  45. package/src/components/manage/Blocks/Block/Style.jsx +2 -2
  46. package/src/components/manage/Blocks/Container/Data.jsx +32 -0
  47. package/src/components/manage/Blocks/Container/Edit.jsx +174 -0
  48. package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +120 -0
  49. package/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +84 -0
  50. package/src/components/manage/Blocks/Container/SimpleContainerToolbar.jsx +54 -0
  51. package/src/components/manage/Blocks/Grid/Edit.jsx +33 -0
  52. package/src/components/manage/Blocks/Grid/View.jsx +42 -0
  53. package/src/components/manage/Blocks/Grid/adapter.js +14 -0
  54. package/src/components/manage/Blocks/Grid/grid-1.svg +6 -0
  55. package/src/components/manage/Blocks/Grid/grid-2.svg +9 -0
  56. package/src/components/manage/Blocks/Grid/grid-3.svg +10 -0
  57. package/src/components/manage/Blocks/Grid/grid-4.svg +11 -0
  58. package/src/components/manage/Blocks/Grid/schema.js +35 -0
  59. package/src/components/manage/Blocks/Grid/templates.js +47 -0
  60. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +2 -1
  61. package/src/components/manage/Blocks/Image/schema.js +11 -0
  62. package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
  63. package/src/components/manage/Blocks/Listing/getAsyncData.js +3 -5
  64. package/src/components/manage/Blocks/Search/components/index.js +13 -13
  65. package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
  66. package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
  67. package/src/components/manage/Blocks/Teaser/schema.js +5 -0
  68. package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
  69. package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
  70. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +38 -0
  71. package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +34 -0
  72. package/src/components/manage/TemplateChooser/template.svg +10 -0
  73. package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
  74. package/src/components/theme/Component/Component.jsx +1 -1
  75. package/src/components/theme/View/RenderBlocks.jsx +56 -27
  76. package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
  77. package/src/config/Blocks.jsx +44 -0
  78. package/src/config/RichTextEditor/Blocks.jsx +2 -2
  79. package/src/config/RichTextEditor/FromHTML.jsx +2 -2
  80. package/src/config/RichTextEditor/Styles.jsx +1 -1
  81. package/src/constants/Indexes.js +3 -1
  82. package/src/express-middleware/devproxy.js +1 -1
  83. package/src/express-middleware/files.js +3 -3
  84. package/src/express-middleware/images.js +4 -4
  85. package/src/express-middleware/robotstxt.js +1 -1
  86. package/src/express-middleware/sitemap.js +1 -1
  87. package/src/express-middleware/static.js +3 -3
  88. package/src/helpers/Blocks/Blocks.js +26 -0
  89. package/src/helpers/Blocks/Blocks.test.js +21 -0
  90. package/src/helpers/Extensions/index.js +2 -1
  91. package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
  92. package/src/helpers/Utils/Utils.js +25 -0
  93. package/src/helpers/index.js +11 -10
  94. package/src/icons/grid-block.svg +11 -0
  95. package/src/middleware/index.js +2 -2
  96. package/src/start-server.js +2 -2
  97. package/theme/themes/pastanaga/extras/blocks.less +3 -1
  98. package/theme/themes/pastanaga/extras/grid.less +426 -0
  99. package/theme/themes/pastanaga/extras/main.less +1 -0
@@ -0,0 +1,174 @@
1
+ import { useState } from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import { pickBy } from 'lodash';
4
+ import { BlocksForm, SidebarPortal } from '@plone/volto/components';
5
+ import PropTypes from 'prop-types';
6
+ import ContainerData from './Data';
7
+ import DefaultEditBlockWrapper from './EditBlockWrapper';
8
+ import SimpleContainerToolbar from './SimpleContainerToolbar';
9
+ import { v4 as uuid } from 'uuid';
10
+ import { blocksFormGenerator } from '@plone/volto/helpers';
11
+
12
+ import DefaultTemplateChooser from '@plone/volto/components/manage/TemplateChooser/TemplateChooser';
13
+
14
+ import config from '@plone/volto/registry';
15
+
16
+ const ContainerBlockEdit = (props) => {
17
+ const {
18
+ block,
19
+ data,
20
+ direction = 'horizontal',
21
+ onChangeBlock,
22
+ onChangeField,
23
+ pathname,
24
+ selected,
25
+ manage,
26
+ } = props;
27
+
28
+ const intl = useIntl();
29
+ const blockType = data['@type'];
30
+ const metadata = props.metadata || props.properties;
31
+ const isInitialized = data?.blocks && data?.blocks_layout;
32
+ const properties = isInitialized ? data : blocksFormGenerator(0, '');
33
+ const blockConfig = config.blocks.blocksConfig[blockType];
34
+ const blocksConfig = blockConfig.blocksConfig || props.blocksConfig;
35
+ const allowedBlocks = blockConfig.allowedBlocks;
36
+ const maxLength = blockConfig.maxLength || 8;
37
+ const templates = blockConfig.templates;
38
+ const ContainerToolbar =
39
+ blockConfig.containerToolbar || SimpleContainerToolbar;
40
+
41
+ // Custom components from config or default ones
42
+ const TemplateChooser = blockConfig.templateChooser || DefaultTemplateChooser;
43
+ const EditBlockWrapper =
44
+ blockConfig.editBlockWrapper || DefaultEditBlockWrapper;
45
+
46
+ const [selectedBlock, setSelectedBlock] = useState(
47
+ properties.blocks_layout.items[0],
48
+ );
49
+
50
+ const blockState = {};
51
+
52
+ const onAddNewBlock = () => {
53
+ const newuuid = uuid();
54
+ const type = allowedBlocks?.length === 1 ? allowedBlocks[0] : null;
55
+ const blocks = data.blocks || properties.blocks;
56
+ const blocks_layout = data.blocks_layout || properties.blocks_layout;
57
+ const newFormData = {
58
+ ...data,
59
+ blocks: {
60
+ ...blocks,
61
+ [newuuid]: { '@type': type || 'empty' },
62
+ },
63
+ blocks_layout: {
64
+ items: [...blocks_layout.items, newuuid],
65
+ },
66
+ };
67
+ if (blocks_layout.items.length < maxLength) {
68
+ onChangeBlock(block, {
69
+ ...newFormData,
70
+ });
71
+ }
72
+ };
73
+
74
+ const onSelectTemplate = (templateIndex) => {
75
+ const resultantTemplates =
76
+ allowedBlocks?.length === 1 ? templates(allowedBlocks[0]) : templates();
77
+ onChangeBlock(block, {
78
+ ...data,
79
+ ...resultantTemplates(intl)[templateIndex].blocksData,
80
+ });
81
+ };
82
+
83
+ const allowedBlocksConfig = pickBy(blocksConfig, (value, key) =>
84
+ allowedBlocks.includes(key),
85
+ );
86
+
87
+ const containerProps = {
88
+ ...props,
89
+ allowedBlocks,
90
+ allowedBlocksConfig,
91
+ blocksConfig,
92
+ blockType,
93
+ maxLength,
94
+ metadata,
95
+ onAddNewBlock,
96
+ onSelectTemplate,
97
+ selectedBlock,
98
+ setSelectedBlock,
99
+ templates,
100
+ };
101
+
102
+ return (
103
+ <>
104
+ {data.headline && <h2 className="headline">{data.headline}</h2>}
105
+
106
+ {selected && <ContainerToolbar {...containerProps} />}
107
+
108
+ {!isInitialized && templates && (
109
+ <TemplateChooser
110
+ templates={
111
+ allowedBlocks?.length === 1
112
+ ? templates(allowedBlocks[0])
113
+ : templates()
114
+ }
115
+ onSelectTemplate={onSelectTemplate}
116
+ />
117
+ )}
118
+
119
+ <BlocksForm
120
+ metadata={metadata}
121
+ properties={properties}
122
+ direction={direction}
123
+ manage={manage}
124
+ selectedBlock={selected ? selectedBlock : null}
125
+ blocksConfig={allowedBlocksConfig}
126
+ title={data.placeholder}
127
+ isContainer
128
+ stopPropagation={selectedBlock}
129
+ disableAddBlockOnEnterKey
130
+ onSelectBlock={(id) => {
131
+ setSelectedBlock(id);
132
+ }}
133
+ onChangeFormData={(newFormData) => {
134
+ onChangeBlock(block, {
135
+ ...data,
136
+ ...newFormData,
137
+ });
138
+ }}
139
+ onChangeField={(id, value) => {
140
+ if (['blocks', 'blocks_layout'].includes(id)) {
141
+ blockState[id] = value;
142
+ onChangeBlock(block, {
143
+ ...data,
144
+ ...blockState,
145
+ });
146
+ } else {
147
+ onChangeField(id, value);
148
+ }
149
+ }}
150
+ pathname={pathname}
151
+ >
152
+ {({ draginfo }, editBlock, blockProps) => (
153
+ <EditBlockWrapper draginfo={draginfo} blockProps={blockProps}>
154
+ {editBlock}
155
+ </EditBlockWrapper>
156
+ )}
157
+ </BlocksForm>
158
+ <SidebarPortal selected={selected && !selectedBlock}>
159
+ <ContainerData {...props}></ContainerData>
160
+ </SidebarPortal>
161
+ </>
162
+ );
163
+ };
164
+
165
+ ContainerBlockEdit.propTypes = {
166
+ block: PropTypes.string.isRequired,
167
+ onChangeBlock: PropTypes.func.isRequired,
168
+ pathname: PropTypes.string.isRequired,
169
+ selected: PropTypes.bool.isRequired,
170
+ manage: PropTypes.bool.isRequired,
171
+ direction: PropTypes.oneOf(['horizontal', 'vertical']),
172
+ };
173
+
174
+ export default ContainerBlockEdit;
@@ -0,0 +1,120 @@
1
+ import { Icon } from '@plone/volto/components';
2
+ import { Button } from 'semantic-ui-react';
3
+ import { defineMessages, useIntl } from 'react-intl';
4
+ import NewBlockAddButton from './NewBlockAddButton';
5
+ import cx from 'classnames';
6
+ import { isInteractiveElement } from '@plone/volto/helpers';
7
+
8
+ import clearSVG from '@plone/volto/icons/clear.svg';
9
+
10
+ const messages = defineMessages({
11
+ delete: {
12
+ id: 'Remove element {index}',
13
+ defaultMessage: 'Remove element {index}',
14
+ },
15
+ reset: {
16
+ id: 'Reset element {index}',
17
+ defaultMessage: 'Reset element {index}',
18
+ },
19
+ });
20
+
21
+ const EditBlockWrapper = (props) => {
22
+ const intl = useIntl();
23
+
24
+ const { blockProps, draginfo, children } = props;
25
+ const {
26
+ block,
27
+ selected,
28
+ type,
29
+ blocksConfig,
30
+ onChangeBlock,
31
+ onDeleteBlock,
32
+ onSelectBlock,
33
+ data,
34
+ index,
35
+ } = blockProps;
36
+
37
+ function onResetBlock() {
38
+ onChangeBlock(block, { '@type': 'empty' });
39
+ }
40
+
41
+ return (
42
+ <div
43
+ ref={draginfo.innerRef}
44
+ {...draginfo.draggableProps}
45
+ {...draginfo.dragHandleProps}
46
+ className={cx(`block-editor-${data['@type']} contained`, { selected })}
47
+ >
48
+ <div
49
+ role="presentation"
50
+ className="cell-wrapper"
51
+ onClick={(e) => {
52
+ onSelectBlock(block);
53
+ }}
54
+ >
55
+ {type !== 'empty' ? (
56
+ <Button
57
+ aria-label={intl.formatMessage(messages.reset, {
58
+ index,
59
+ })}
60
+ basic
61
+ icon
62
+ onClick={(e) => onResetBlock(block, {})}
63
+ className="remove-block-button"
64
+ >
65
+ <Icon name={clearSVG} className="circled" size="24px" />
66
+ </Button>
67
+ ) : (
68
+ <Button
69
+ basic
70
+ icon
71
+ className="remove-block-button"
72
+ onClick={(e) => onDeleteBlock(block, true)}
73
+ aria-label={intl.formatMessage(messages.delete, {
74
+ index,
75
+ })}
76
+ >
77
+ <Icon
78
+ name={clearSVG}
79
+ className="circled"
80
+ size="24px"
81
+ color="#e40166"
82
+ />
83
+ </Button>
84
+ )}
85
+ {type && type !== 'empty' ? (
86
+ <div className={cx('ui drag block inner', type)}>{children}</div>
87
+ ) : (
88
+ <div
89
+ className={cx('gridBlock-empty-placeholder', {
90
+ selected: selected,
91
+ })}
92
+ role="presentation"
93
+ onClick={(e) => {
94
+ onSelectBlock(block);
95
+ // If the click is in the button, then
96
+ if (isInteractiveElement(e.target)) {
97
+ e.stopPropagation();
98
+ }
99
+ }}
100
+ >
101
+ <p>Add a new block</p>
102
+ <NewBlockAddButton
103
+ block={block}
104
+ index={index}
105
+ blocksConfig={blocksConfig}
106
+ onMutateBlock={(block, value) =>
107
+ onChangeBlock(block, {
108
+ ...data,
109
+ ...value,
110
+ })
111
+ }
112
+ />
113
+ </div>
114
+ )}
115
+ </div>
116
+ </div>
117
+ );
118
+ };
119
+
120
+ export default EditBlockWrapper;
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ import { Button, Ref } from 'semantic-ui-react';
3
+ import { defineMessages, useIntl } from 'react-intl';
4
+ import { BlockChooser, Icon } from '@plone/volto/components';
5
+ import { useDetectClickOutside } from '@plone/volto/helpers';
6
+ import addSVG from '@plone/volto/icons/add.svg';
7
+ import { usePopper } from 'react-popper';
8
+ import { Portal } from 'react-portal';
9
+
10
+ const messages = defineMessages({
11
+ addBlock: {
12
+ id: 'Add block in position {index}',
13
+ defaultMessage: 'Add block in position {index}',
14
+ },
15
+ });
16
+
17
+ const NewBlockAddButton = (props) => {
18
+ const intl = useIntl();
19
+ const { blocksConfig, block, index, onMutateBlock } = props;
20
+ const [isOpenMenu, setOpenMenu] = React.useState(false);
21
+
22
+ const blockChooserRef = useDetectClickOutside({
23
+ onTriggered: () => setOpenMenu(false),
24
+ triggerKeys: ['Escape'],
25
+ });
26
+
27
+ const [referenceElement, setReferenceElement] = React.useState(null);
28
+ const [popperElement, setPopperElement] = React.useState(null);
29
+ const { styles, attributes } = usePopper(referenceElement, popperElement, {
30
+ placement: 'bottom',
31
+ modifiers: [
32
+ {
33
+ name: 'offset',
34
+ options: {
35
+ offset: [0, -30],
36
+ },
37
+ },
38
+ {
39
+ name: 'flip',
40
+ options: {
41
+ fallbackPlacements: ['right', 'top-start'],
42
+ },
43
+ },
44
+ ],
45
+ });
46
+
47
+ return (
48
+ <>
49
+ <Ref innerRef={setReferenceElement}>
50
+ <Button
51
+ basic
52
+ icon
53
+ onClick={() => setOpenMenu(true)}
54
+ className="add-block-button"
55
+ aria-label={intl.formatMessage(messages.addBlock, {
56
+ index,
57
+ })}
58
+ >
59
+ <Icon name={addSVG} className="circled" size="24px" />
60
+ </Button>
61
+ </Ref>
62
+ {isOpenMenu ? (
63
+ <Portal node={document.getElementById('body')}>
64
+ <div
65
+ ref={setPopperElement}
66
+ style={styles.popper}
67
+ {...attributes.popper}
68
+ className="container-chooser-wrapper"
69
+ >
70
+ <BlockChooser
71
+ onMutateBlock={onMutateBlock}
72
+ currentBlock={block}
73
+ showRestricted
74
+ blocksConfig={blocksConfig}
75
+ ref={blockChooserRef}
76
+ />
77
+ </div>
78
+ </Portal>
79
+ ) : null}
80
+ </>
81
+ );
82
+ };
83
+
84
+ export default NewBlockAddButton;
@@ -0,0 +1,54 @@
1
+ import { defineMessages, useIntl } from 'react-intl';
2
+ import { Button } from 'semantic-ui-react';
3
+ import { Icon } from '@plone/volto/components';
4
+
5
+ import addSVG from '@plone/volto/icons/add.svg';
6
+ import configSVG from '@plone/volto/icons/configuration.svg';
7
+
8
+ const messages = defineMessages({
9
+ addBlock: {
10
+ id: 'Add element to container',
11
+ defaultMessage: 'Add element to container',
12
+ },
13
+ blockSettings: {
14
+ id: 'Container settings',
15
+ defaultMessage: 'Container settings',
16
+ },
17
+ });
18
+
19
+ const SimpleContainerToolbar = (props) => {
20
+ const { data, onAddNewBlock, maxLength, setSelectedBlock } = props;
21
+ const intl = useIntl();
22
+
23
+ return (
24
+ <div className="toolbar">
25
+ <Button.Group>
26
+ <Button
27
+ aria-label={intl.formatMessage(messages.addBlock)}
28
+ icon
29
+ basic
30
+ disabled={data?.blocks_layout?.items?.length >= maxLength}
31
+ onClick={(e) => onAddNewBlock()}
32
+ >
33
+ <Icon name={addSVG} size="24px" />
34
+ </Button>
35
+ </Button.Group>
36
+ <Button.Group>
37
+ <Button
38
+ aria-label={intl.formatMessage(messages.blockSettings)}
39
+ icon
40
+ basic
41
+ onClick={(e) => {
42
+ e.stopPropagation();
43
+ setSelectedBlock();
44
+ props.setSidebarTab(1);
45
+ }}
46
+ >
47
+ <Icon name={configSVG} size="24px" />
48
+ </Button>
49
+ </Button.Group>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default SimpleContainerToolbar;
@@ -0,0 +1,33 @@
1
+ import PropTypes from 'prop-types';
2
+ import cx from 'classnames';
3
+ import ContainerEdit from '../Container/Edit';
4
+
5
+ const GridBlockEdit = (props) => {
6
+ const { data } = props;
7
+
8
+ const columnsLength = data?.blocks_layout?.items?.length || 0;
9
+
10
+ return (
11
+ <div
12
+ className={cx({
13
+ one: columnsLength === 1,
14
+ two: columnsLength === 2,
15
+ three: columnsLength === 3,
16
+ four: columnsLength >= 4,
17
+ 'grid-items': true,
18
+ })}
19
+ >
20
+ <ContainerEdit {...props} direction="horizontal" />
21
+ </div>
22
+ );
23
+ };
24
+
25
+ GridBlockEdit.propTypes = {
26
+ block: PropTypes.string.isRequired,
27
+ onChangeBlock: PropTypes.func.isRequired,
28
+ pathname: PropTypes.string.isRequired,
29
+ selected: PropTypes.bool.isRequired,
30
+ manage: PropTypes.bool.isRequired,
31
+ };
32
+
33
+ export default GridBlockEdit;
@@ -0,0 +1,42 @@
1
+ import { Grid } from 'semantic-ui-react';
2
+ import cx from 'classnames';
3
+ import { RenderBlocks } from '@plone/volto/components';
4
+ import { withBlockExtensions } from '@plone/volto/helpers';
5
+ import config from '@plone/volto/registry';
6
+
7
+ const GridBlockView = (props) => {
8
+ const { data, path, className } = props;
9
+ const metadata = props.metadata || props.properties;
10
+ const columns = data.blocks_layout.items;
11
+ const blocksConfig =
12
+ config.blocks.blocksConfig[data['@type']].blocksConfig ||
13
+ props.blocksConfig;
14
+ const location = {
15
+ pathname: path,
16
+ };
17
+ return (
18
+ <div
19
+ className={cx('block', data['@type'], className, {
20
+ one: columns?.length === 1,
21
+ two: columns?.length === 2,
22
+ three: columns?.length === 3,
23
+ four: columns?.length === 4,
24
+ })}
25
+ >
26
+ {data.headline && <h2 className="headline">{data.headline}</h2>}
27
+
28
+ <Grid stackable stretched columns={columns.length}>
29
+ <RenderBlocks
30
+ {...props}
31
+ blockWrapperTag={Grid.Column}
32
+ metadata={metadata}
33
+ content={data}
34
+ location={location}
35
+ blocksConfig={blocksConfig}
36
+ />
37
+ </Grid>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default withBlockExtensions(GridBlockView);
@@ -0,0 +1,14 @@
1
+ export const GridBlockDataAdapter = ({
2
+ block,
3
+ data,
4
+ id,
5
+ onChangeBlock,
6
+ value,
7
+ }) => {
8
+ let dataSaved = {
9
+ ...data,
10
+ [id]: value,
11
+ };
12
+
13
+ onChangeBlock(block, dataSaved);
14
+ };
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
2
+ <g fill="none" fill-rule="evenodd">
3
+ <rect width="96" height="96" fill="#9FD1E5" rx="3"/>
4
+ <rect width="67" height="53" fill="#FFF" opacity=".9" transform="translate(15 22)"/>
5
+ </g>
6
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
2
+ <g fill="none" fill-rule="evenodd">
3
+ <rect width="96" height="96" fill="#9FD1E5" rx="3"/>
4
+ <g fill="#FFF" opacity=".9" transform="translate(9 22)">
5
+ <rect width="37" height="53"/>
6
+ <rect width="37" height="53" x="42"/>
7
+ </g>
8
+ </g>
9
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
2
+ <g fill="none" fill-rule="evenodd">
3
+ <rect width="96" height="96" fill="#9FD1E5" rx="3"/>
4
+ <g fill="#FFF" opacity=".9" transform="translate(6 22)">
5
+ <rect width="25" height="53" x="58"/>
6
+ <rect width="25" height="53"/>
7
+ <rect width="25" height="53" x="29"/>
8
+ </g>
9
+ </g>
10
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
2
+ <g fill="none" fill-rule="evenodd">
3
+ <rect width="96" height="96" fill="#9FD1E5" rx="3"/>
4
+ <g fill="#FFF" opacity=".9" transform="translate(8 22)">
5
+ <rect width="18" height="53" x="42"/>
6
+ <rect width="18" height="53" x="63"/>
7
+ <rect width="18" height="53"/>
8
+ <rect width="18" height="53" x="21"/>
9
+ </g>
10
+ </g>
11
+ </svg>
@@ -0,0 +1,35 @@
1
+ import { defineMessages } from 'react-intl';
2
+
3
+ const messages = defineMessages({
4
+ headline: {
5
+ id: 'Headline',
6
+ defaultMessage: 'Headline',
7
+ },
8
+ grid: {
9
+ id: 'Grid',
10
+ defaultMessage: 'Grid',
11
+ },
12
+ });
13
+
14
+ export const GridBlockSchema = (props) => {
15
+ const { intl } = props;
16
+
17
+ return {
18
+ title: intl.formatMessage(messages.grid),
19
+ block: 'grid',
20
+ fieldsets: [
21
+ {
22
+ id: 'default',
23
+ title: 'Default',
24
+ fields: ['headline'],
25
+ },
26
+ ],
27
+
28
+ properties: {
29
+ headline: {
30
+ title: intl.formatMessage(messages.headline),
31
+ },
32
+ },
33
+ required: [],
34
+ };
35
+ };
@@ -0,0 +1,47 @@
1
+ import { defineMessages } from 'react-intl';
2
+ import { blocksFormGenerator } from '@plone/volto/helpers';
3
+
4
+ import gridTemplate1 from './grid-1.svg';
5
+ import gridTemplate2 from './grid-2.svg';
6
+ import gridTemplate3 from './grid-3.svg';
7
+ import gridTemplate4 from './grid-4.svg';
8
+
9
+ const messages = defineMessages({
10
+ column: {
11
+ id: 'column',
12
+ defaultMessage: 'column',
13
+ },
14
+ columns: {
15
+ id: 'columns',
16
+ defaultMessage: 'columns',
17
+ },
18
+ });
19
+
20
+ const templates = (type) => (intl) => [
21
+ {
22
+ image: gridTemplate1,
23
+ id: 'gridtemplateone',
24
+ title: `1 ${intl.formatMessage(messages.column)}`,
25
+ blocksData: blocksFormGenerator(1, type),
26
+ },
27
+ {
28
+ image: gridTemplate2,
29
+ id: 'gridtemplatetwo',
30
+ title: `2 ${intl.formatMessage(messages.columns)}`,
31
+ blocksData: blocksFormGenerator(2, type),
32
+ },
33
+ {
34
+ image: gridTemplate3,
35
+ id: 'gridtemplatethree',
36
+ title: `3 ${intl.formatMessage(messages.columns)}`,
37
+ blocksData: blocksFormGenerator(3, type),
38
+ },
39
+ {
40
+ image: gridTemplate4,
41
+ id: 'gridtemplatefour',
42
+ title: `4 ${intl.formatMessage(messages.columns)}`,
43
+ blocksData: blocksFormGenerator(4, type),
44
+ },
45
+ ];
46
+
47
+ export default templates;
@@ -8,7 +8,7 @@ import { ImageSchema } from './schema';
8
8
  import imageSVG from '@plone/volto/icons/image.svg';
9
9
 
10
10
  const ImageSidebar = (props) => {
11
- const { data, block, onChangeBlock } = props;
11
+ const { blocksConfig, data, block, onChangeBlock } = props;
12
12
  const intl = useIntl();
13
13
  const schema = ImageSchema({ formData: data, intl });
14
14
  return (
@@ -55,6 +55,7 @@ const ImageSidebar = (props) => {
55
55
  onChangeBlock={onChangeBlock}
56
56
  formData={data}
57
57
  block={block}
58
+ blocksConfig={blocksConfig}
58
59
  />
59
60
  </>
60
61
  );
@@ -101,3 +101,14 @@ export function ImageSchema({ formData, intl }) {
101
101
  required: [],
102
102
  };
103
103
  }
104
+
105
+ export const gridImageDisableSizeAndPositionHandlersSchema = ({
106
+ schema,
107
+ formData,
108
+ intl,
109
+ }) => {
110
+ schema.fieldsets[0].fields = schema.fieldsets[0].fields.filter(
111
+ (item) => !['align', 'size'].includes(item),
112
+ );
113
+ return schema;
114
+ };