@kitconcept/volto-light-theme 5.0.1 → 6.0.0-alpha.1
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.draft +2 -8
- package/CHANGELOG.md +38 -0
- package/README.md +7 -367
- package/package.json +20 -7
- package/razzle.extend.js +38 -0
- package/src/components/Anontools/Anontools.jsx +1 -1
- package/src/components/Blocks/Button/schema.js +25 -5
- package/src/components/Blocks/EventMetadata/View.jsx +8 -7
- package/src/components/Blocks/Image/Edit.jsx +4 -6
- package/src/components/Blocks/Image/ImageSidebar.jsx +4 -2
- package/src/components/Blocks/Image/View.jsx +3 -6
- package/src/components/Blocks/Image/schema.js +37 -6
- package/src/components/Blocks/Listing/DefaultTemplate.jsx +3 -2
- package/src/components/Blocks/Listing/GridTemplate.jsx +4 -2
- package/src/components/Blocks/Listing/ImageGallery.jsx +2 -2
- package/src/components/Blocks/Listing/SummaryTemplate.jsx +3 -2
- package/src/components/Blocks/Search/components/SearchInput.jsx +1 -1
- package/src/components/Blocks/Separator/schema.js +59 -0
- package/src/components/Blocks/Slider/DefaultBody.jsx +4 -2
- package/src/components/Blocks/Teaser/schema.js +21 -1
- package/src/components/Blocks/schema.js +16 -15
- package/src/components/Breadcrumbs/Breadcrumbs.jsx +4 -3
- package/src/components/Footer/Footer.jsx +77 -27
- package/src/components/Header/Header.jsx +34 -29
- package/src/components/LanguageSelector/{LanguageSelector.js → LanguageSelector.jsx} +11 -7
- package/src/components/Logo/Logo.jsx +28 -22
- package/src/components/MobileNavigation/MobileNavigation.jsx +3 -2
- package/src/components/MobileNavigation/MobileToolsFooter.jsx +1 -1
- package/src/components/Navigation/Navigation.jsx +4 -3
- package/src/components/SearchWidget/IntranetSearchWidget.jsx +1 -1
- package/src/components/SearchWidget/SearchWidget.jsx +1 -1
- package/src/components/Theme/EventView.jsx +3 -2
- package/src/components/Theme/FileView.jsx +1 -1
- package/src/components/Theme/NewsItemView.jsx +1 -1
- package/src/components/Theming/Theming.tsx +52 -0
- package/src/components/Widgets/AlignWidget.jsx +2 -2
- package/src/components/Widgets/BackgroundColorWidget.tsx +18 -0
- package/src/components/Widgets/BlockAlignmentWidget.tsx +81 -0
- package/src/components/Widgets/BlockWidthWidget.tsx +94 -0
- package/src/components/Widgets/BlocksObjectWidget.tsx +333 -0
- package/src/components/Widgets/ButtonsWidget.tsx +68 -0
- package/src/components/Widgets/ColorPickerWidget.tsx +60 -0
- package/src/components/Widgets/FooterLinksWidget.tsx +106 -0
- package/src/components/Widgets/FooterLogosWidget.tsx +120 -0
- package/src/components/Widgets/ThemingColorPicker.tsx +33 -0
- package/src/config/blocks.tsx +352 -0
- package/src/config/classExtenders.ts +101 -0
- package/src/config/settings.ts +35 -0
- package/src/config/slots.ts +12 -0
- package/src/config/widgets.ts +31 -0
- package/src/customizations/volto/components/theme/View/RenderBlocks.jsx +97 -80
- package/src/customizations/volto/components/theme/View/RenderBlocks.test.jsx +16 -48
- package/src/helpers/helpers.test.ts +51 -0
- package/src/helpers/helpers.ts +48 -0
- package/src/index.ts +54 -0
- package/src/theme/_bgcolor-blocks-layout.scss +1127 -20
- package/src/theme/_footer.scss +8 -5
- package/src/theme/_header.scss +3 -8
- package/src/theme/_layout.scss +24 -7
- package/src/theme/_typo-custom.scss +1 -1
- package/src/theme/_variables.scss +95 -12
- package/src/theme/_widgets.scss +102 -0
- package/src/theme/blocks/_accordion.scss +2 -4
- package/src/theme/blocks/_button.scss +32 -31
- package/src/theme/blocks/_eventMetadata.scss +7 -0
- package/src/theme/blocks/_grid.scss +11 -36
- package/src/theme/blocks/_highlight.scss +1 -0
- package/src/theme/blocks/_image.scss +38 -17
- package/src/theme/blocks/_introduction.scss +16 -0
- package/src/theme/blocks/_listing.scss +1 -6
- package/src/theme/blocks/_search.scss +1 -23
- package/src/theme/blocks/_separator.scss +17 -20
- package/src/theme/blocks/_slider.scss +57 -56
- package/src/theme/blocks/_teaser.scss +3 -3
- package/src/theme/main.scss +1 -0
- package/src/transforms/to6.ts +94 -0
- package/tsconfig.json +33 -0
- package/.release-it.json +0 -31
- package/babel.config.js +0 -17
- package/build/messages/src/components/Anontools/Anontools.json +0 -10
- package/build/messages/src/components/Blocks/Button/schema.json +0 -6
- package/build/messages/src/components/Blocks/EventMetadata/View.json +0 -30
- package/build/messages/src/components/Blocks/Image/Edit.json +0 -10
- package/build/messages/src/components/Blocks/Image/ImageSidebar.json +0 -18
- package/build/messages/src/components/Blocks/Image/schema.json +0 -10
- package/build/messages/src/components/Blocks/Listing/ListingBody.json +0 -26
- package/build/messages/src/components/Blocks/Search/TopSideFacets.json +0 -10
- package/build/messages/src/components/Blocks/Search/components/SearchDetails.json +0 -10
- package/build/messages/src/components/Blocks/Search/components/SearchInput.json +0 -6
- package/build/messages/src/components/Blocks/Slider/DefaultBody.json +0 -18
- package/build/messages/src/components/Blocks/Slider/schema.json +0 -14
- package/build/messages/src/components/Blocks/schema.json +0 -6
- package/build/messages/src/components/Breadcrumbs/Breadcrumbs.json +0 -10
- package/build/messages/src/components/Footer/Footer.json +0 -30
- package/build/messages/src/components/Header/Header.json +0 -6
- package/build/messages/src/components/LanguageSelector/LanguageSelector.json +0 -6
- package/build/messages/src/components/Logo/Logo.json +0 -10
- package/build/messages/src/components/MobileNavigation/MobileNavigation.json +0 -26
- package/build/messages/src/components/Navigation/Navigation.json +0 -10
- package/build/messages/src/components/SearchWidget/IntranetSearchWidget.json +0 -14
- package/build/messages/src/components/SearchWidget/SearchWidget.json +0 -10
- package/build/messages/src/components/Theme/EventView.json +0 -6
- package/build/messages/src/components/Widgets/AlignWidget.json +0 -22
- package/build/messages/src/index.json +0 -10
- package/news/.gitkeep +0 -0
- package/src/components/Atoms/Container/Container.jsx +0 -32
- package/src/components/Atoms/README.md +0 -1
- package/src/components/Atoms/helpers.jsx +0 -9
- package/src/components/CQPolyfill.jsx +0 -9
- package/src/index.js +0 -367
- package/towncrier.toml +0 -33
- /package/src/components/Blocks/Slate/{ExtraAlignWrapper.js → ExtraAlignWrapper.jsx} +0 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
3
|
+
import omit from 'lodash/omit';
|
|
4
|
+
import { Accordion, Button, Segment } from 'semantic-ui-react';
|
|
5
|
+
import DragDropList from '@plone/volto/components/manage/DragDropList/DragDropList';
|
|
6
|
+
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
7
|
+
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
8
|
+
import { applySchemaDefaults } from '@plone/volto/helpers/Blocks/Blocks';
|
|
9
|
+
import ObjectWidget from '@plone/volto/components/manage/Widgets/ObjectWidget';
|
|
10
|
+
import {
|
|
11
|
+
getBlocksFieldname,
|
|
12
|
+
getBlocksLayoutFieldname,
|
|
13
|
+
moveBlock,
|
|
14
|
+
} from '@plone/volto/helpers/Blocks/Blocks';
|
|
15
|
+
|
|
16
|
+
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
17
|
+
import downSVG from '@plone/volto/icons/down-key.svg';
|
|
18
|
+
import deleteSVG from '@plone/volto/icons/delete.svg';
|
|
19
|
+
import addSVG from '@plone/volto/icons/add.svg';
|
|
20
|
+
import dragSVG from '@plone/volto/icons/drag.svg';
|
|
21
|
+
import { v4 as uuid } from 'uuid';
|
|
22
|
+
import type { BlocksData } from '@plone/types';
|
|
23
|
+
|
|
24
|
+
const messages = defineMessages({
|
|
25
|
+
labelRemoveItem: {
|
|
26
|
+
id: 'Remove item',
|
|
27
|
+
defaultMessage: 'Remove item',
|
|
28
|
+
},
|
|
29
|
+
labelCollapseItem: {
|
|
30
|
+
id: 'Collapse item',
|
|
31
|
+
defaultMessage: 'Collapse item',
|
|
32
|
+
},
|
|
33
|
+
labelShowItem: {
|
|
34
|
+
id: 'Show item',
|
|
35
|
+
defaultMessage: 'Show item',
|
|
36
|
+
},
|
|
37
|
+
emptyObjectList: {
|
|
38
|
+
id: 'Empty object list',
|
|
39
|
+
defaultMessage: 'Empty object list',
|
|
40
|
+
},
|
|
41
|
+
add: {
|
|
42
|
+
id: 'Add (object list)',
|
|
43
|
+
defaultMessage: 'Add',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export type BlocksObjectWidgetProps = {
|
|
48
|
+
id: string;
|
|
49
|
+
block: string;
|
|
50
|
+
fieldSet: string;
|
|
51
|
+
title: string;
|
|
52
|
+
value?: BlocksData;
|
|
53
|
+
default?: string | object;
|
|
54
|
+
required?: boolean;
|
|
55
|
+
missing_value?: unknown;
|
|
56
|
+
className?: string;
|
|
57
|
+
onChange: (id: string, value: any) => void;
|
|
58
|
+
activeObject: number;
|
|
59
|
+
setActiveObject: (index: number) => void;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function deleteBlock(formData, blockId: string) {
|
|
63
|
+
const blocksFieldname = getBlocksFieldname(formData);
|
|
64
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(formData);
|
|
65
|
+
|
|
66
|
+
let newFormData = {
|
|
67
|
+
...formData,
|
|
68
|
+
[blocksLayoutFieldname]: {
|
|
69
|
+
items: formData[blocksLayoutFieldname].items.filter(
|
|
70
|
+
(value) => value !== blockId,
|
|
71
|
+
),
|
|
72
|
+
},
|
|
73
|
+
[blocksFieldname]: omit(formData[blocksFieldname], [blockId]),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return newFormData;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* This is a DataGridField-equivalent widget for schema-based values.
|
|
81
|
+
* The shape of the items in the array is defined using a schema.
|
|
82
|
+
*
|
|
83
|
+
* ObjectListWidget can receive an optional `schemaExtender` prop which is
|
|
84
|
+
* a function that can mutate the schema for each individual item in the array.
|
|
85
|
+
* An example schema definition of the a field that renders with the
|
|
86
|
+
* ObjectListWidget:
|
|
87
|
+
*
|
|
88
|
+
* ```jsx
|
|
89
|
+
* columns: {
|
|
90
|
+
* title: 'Columns',
|
|
91
|
+
* description: 'Leave empty to show all columns',
|
|
92
|
+
* schema: SomeItemSchema,
|
|
93
|
+
* widget: 'object_list',
|
|
94
|
+
* schemaExtender: (schema, data) => {
|
|
95
|
+
* const mutated = lodash.cloneDeep(schema);
|
|
96
|
+
* mutated.properties.extraField = {
|
|
97
|
+
* title: 'Extra field',
|
|
98
|
+
* }
|
|
99
|
+
* mutated.fieldsets[0].fields.push('extraField');
|
|
100
|
+
* return mutated;
|
|
101
|
+
* },
|
|
102
|
+
* activeObject: 0, // Current active object drilled down from the schema (if present)
|
|
103
|
+
* setActiveObject: () => {} // The current active object state updater function drilled down from the schema (if present)
|
|
104
|
+
* },
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
const ObjectListWidget = (props: BlocksObjectWidgetProps) => {
|
|
108
|
+
const { block, fieldSet, id, schema, value, onChange, schemaExtender } =
|
|
109
|
+
props;
|
|
110
|
+
const [localActiveObject, setLocalActiveObject] = useState(
|
|
111
|
+
props.activeObject ?? value?.blocks_layout?.items?.length - 1,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
let activeObject: number, setActiveObject: (index: number) => void;
|
|
115
|
+
if (
|
|
116
|
+
(props.activeObject || props.activeObject === 0) &&
|
|
117
|
+
props.setActiveObject
|
|
118
|
+
) {
|
|
119
|
+
activeObject = props.activeObject;
|
|
120
|
+
setActiveObject = props.setActiveObject;
|
|
121
|
+
} else {
|
|
122
|
+
activeObject = localActiveObject;
|
|
123
|
+
setActiveObject = setLocalActiveObject;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const intl = useIntl();
|
|
127
|
+
|
|
128
|
+
function handleChangeActiveObject(e, blockProps) {
|
|
129
|
+
const { index } = blockProps;
|
|
130
|
+
const newIndex = activeObject === index ? -1 : index;
|
|
131
|
+
|
|
132
|
+
setActiveObject(newIndex);
|
|
133
|
+
}
|
|
134
|
+
const objectSchema = typeof schema === 'function' ? schema(props) : schema;
|
|
135
|
+
|
|
136
|
+
const topLayerShadow = '0 1px 1px rgba(0,0,0,0.15)';
|
|
137
|
+
const secondLayer = ', 0 10px 0 -5px #eee, 0 10px 1px -4px rgba(0,0,0,0.15)';
|
|
138
|
+
const thirdLayer = ', 0 20px 0 -10px #eee, 0 20px 1px -9px rgba(0,0,0,0.15)';
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div className="objectlist-widget">
|
|
142
|
+
<FormFieldWrapper {...props} noForInFieldLabel className="objectlist">
|
|
143
|
+
<div className="add-item-button-wrapper">
|
|
144
|
+
<Button
|
|
145
|
+
compact
|
|
146
|
+
icon
|
|
147
|
+
aria-label={
|
|
148
|
+
objectSchema.addMessage ||
|
|
149
|
+
`${intl.formatMessage(messages.add)} ${objectSchema.title}`
|
|
150
|
+
}
|
|
151
|
+
onClick={(e) => {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
const newId = uuid();
|
|
154
|
+
const data = {};
|
|
155
|
+
|
|
156
|
+
const objSchema = schemaExtender
|
|
157
|
+
? schemaExtender(schema, data, intl)
|
|
158
|
+
: objectSchema;
|
|
159
|
+
const dataWithDefaults = applySchemaDefaults({
|
|
160
|
+
data,
|
|
161
|
+
schema: objSchema,
|
|
162
|
+
intl,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
onChange(id, {
|
|
166
|
+
...(value || {}),
|
|
167
|
+
blocks: {
|
|
168
|
+
...value?.blocks,
|
|
169
|
+
[newId]: dataWithDefaults,
|
|
170
|
+
},
|
|
171
|
+
blocks_layout: {
|
|
172
|
+
...value?.blocks_layout,
|
|
173
|
+
items: [...(value?.blocks_layout?.items || []), newId],
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
setActiveObject(value?.blocks_layout?.items?.length || 0);
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
<Icon name={addSVG} size="18px" />
|
|
181
|
+
|
|
182
|
+
{/* Custom addMessage in schema, else default to English */}
|
|
183
|
+
{objectSchema.addMessage ||
|
|
184
|
+
`${intl.formatMessage(messages.add)} ${objectSchema.title}`}
|
|
185
|
+
</Button>
|
|
186
|
+
</div>
|
|
187
|
+
{value?.blocks_layout?.items?.length === 0 && (
|
|
188
|
+
<input
|
|
189
|
+
aria-labelledby={`fieldset-${
|
|
190
|
+
fieldSet || 'default'
|
|
191
|
+
}-field-label-${id}`}
|
|
192
|
+
type="hidden"
|
|
193
|
+
value={intl.formatMessage(messages.emptyObjectList)}
|
|
194
|
+
/>
|
|
195
|
+
)}
|
|
196
|
+
</FormFieldWrapper>
|
|
197
|
+
{/* {value?.blocks_layout?.items.map((blockId, index) => {
|
|
198
|
+
const blockData = value?.blocks[blockId];
|
|
199
|
+
return (
|
|
200
|
+
<ObjectWidget
|
|
201
|
+
id={`${blockId}-${index}`}
|
|
202
|
+
key={`ow-${blockId}-${index}`}
|
|
203
|
+
block={block}
|
|
204
|
+
schema={
|
|
205
|
+
schemaExtender
|
|
206
|
+
? schemaExtender(schema, blockData, intl)
|
|
207
|
+
: objectSchema
|
|
208
|
+
}
|
|
209
|
+
value={blockData}
|
|
210
|
+
onChange={(fi, fv) => {
|
|
211
|
+
const changedBlockId = fi.slice(0, -2);
|
|
212
|
+
const newvalue = { ...value.blocks[changedBlockId], ...fv };
|
|
213
|
+
onChange(id, {
|
|
214
|
+
...value,
|
|
215
|
+
blocks: { ...value.blocks, [changedBlockId]: newvalue },
|
|
216
|
+
});
|
|
217
|
+
}}
|
|
218
|
+
/>
|
|
219
|
+
);
|
|
220
|
+
})} */}
|
|
221
|
+
<DragDropList
|
|
222
|
+
style={{
|
|
223
|
+
boxShadow: `${topLayerShadow}${value?.blocks_layout?.items?.length > 1 ? secondLayer : ''}${
|
|
224
|
+
value?.blocks_layout?.items?.length > 2 ? thirdLayer : ''
|
|
225
|
+
}`,
|
|
226
|
+
}}
|
|
227
|
+
forwardedAriaLabelledBy={`fieldset-${
|
|
228
|
+
fieldSet || 'default'
|
|
229
|
+
}-field-label-${id}`}
|
|
230
|
+
childList={
|
|
231
|
+
value?.blocks_layout?.items?.map((blockId) => [
|
|
232
|
+
blockId,
|
|
233
|
+
value.blocks[blockId],
|
|
234
|
+
]) || []
|
|
235
|
+
}
|
|
236
|
+
onMoveItem={(result) => {
|
|
237
|
+
const { source, destination } = result;
|
|
238
|
+
if (!destination) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const newFormData = moveBlock(value, source.index, destination.index);
|
|
242
|
+
onChange(id, newFormData);
|
|
243
|
+
return true;
|
|
244
|
+
}}
|
|
245
|
+
>
|
|
246
|
+
{({ child, childId, index, draginfo }) => {
|
|
247
|
+
return (
|
|
248
|
+
<div
|
|
249
|
+
ref={draginfo.innerRef}
|
|
250
|
+
{...draginfo.draggableProps}
|
|
251
|
+
key={childId}
|
|
252
|
+
>
|
|
253
|
+
<Accordion key={index} fluid styled>
|
|
254
|
+
<Accordion.Title
|
|
255
|
+
active={activeObject === index}
|
|
256
|
+
index={index}
|
|
257
|
+
onClick={handleChangeActiveObject}
|
|
258
|
+
aria-label={`${
|
|
259
|
+
activeObject === index
|
|
260
|
+
? intl.formatMessage(messages.labelCollapseItem)
|
|
261
|
+
: intl.formatMessage(messages.labelShowItem)
|
|
262
|
+
} #${index + 1}`}
|
|
263
|
+
>
|
|
264
|
+
<button
|
|
265
|
+
style={{
|
|
266
|
+
visibility: 'visible',
|
|
267
|
+
display: 'inline-block',
|
|
268
|
+
}}
|
|
269
|
+
{...draginfo.dragHandleProps}
|
|
270
|
+
className="drag handle"
|
|
271
|
+
>
|
|
272
|
+
<Icon name={dragSVG} size="18px" />
|
|
273
|
+
</button>
|
|
274
|
+
|
|
275
|
+
<div className="accordion-title-wrapper">
|
|
276
|
+
{`${objectSchema.title} #${index + 1}`}
|
|
277
|
+
</div>
|
|
278
|
+
<div className="accordion-tools">
|
|
279
|
+
<button
|
|
280
|
+
aria-label={`${intl.formatMessage(
|
|
281
|
+
messages.labelRemoveItem,
|
|
282
|
+
)} #${index + 1}`}
|
|
283
|
+
onClick={() => {
|
|
284
|
+
onChange(id, deleteBlock(value, childId));
|
|
285
|
+
}}
|
|
286
|
+
>
|
|
287
|
+
<Icon name={deleteSVG} size="20px" color="#e40166" />
|
|
288
|
+
</button>
|
|
289
|
+
{activeObject === index ? (
|
|
290
|
+
<Icon name={upSVG} size="20px" />
|
|
291
|
+
) : (
|
|
292
|
+
<Icon name={downSVG} size="20px" />
|
|
293
|
+
)}
|
|
294
|
+
</div>
|
|
295
|
+
</Accordion.Title>
|
|
296
|
+
<Accordion.Content active={activeObject === index}>
|
|
297
|
+
<Segment>
|
|
298
|
+
<ObjectWidget
|
|
299
|
+
id={`${childId}-${index}`}
|
|
300
|
+
key={`ow-${childId}-${index}`}
|
|
301
|
+
block={block}
|
|
302
|
+
schema={
|
|
303
|
+
schemaExtender
|
|
304
|
+
? schemaExtender(schema, child, intl)
|
|
305
|
+
: objectSchema
|
|
306
|
+
}
|
|
307
|
+
value={child}
|
|
308
|
+
onChange={(fi, fv) => {
|
|
309
|
+
const changedBlockId = fi.slice(0, -2);
|
|
310
|
+
const newvalue = {
|
|
311
|
+
...value.blocks[changedBlockId],
|
|
312
|
+
...fv,
|
|
313
|
+
};
|
|
314
|
+
onChange(id, {
|
|
315
|
+
...value,
|
|
316
|
+
blocks: {
|
|
317
|
+
...value.blocks,
|
|
318
|
+
[changedBlockId]: newvalue,
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}}
|
|
322
|
+
/>
|
|
323
|
+
</Segment>
|
|
324
|
+
</Accordion.Content>
|
|
325
|
+
</Accordion>
|
|
326
|
+
</div>
|
|
327
|
+
);
|
|
328
|
+
}}
|
|
329
|
+
</DragDropList>
|
|
330
|
+
</div>
|
|
331
|
+
);
|
|
332
|
+
};
|
|
333
|
+
export default ObjectListWidget;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
3
|
+
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
4
|
+
import { Button } from '@plone/components';
|
|
5
|
+
import { isEqual, find } from 'lodash';
|
|
6
|
+
|
|
7
|
+
// Move to an unified `StyleDefinition` type
|
|
8
|
+
type Actions =
|
|
9
|
+
| {
|
|
10
|
+
name: string;
|
|
11
|
+
label: string;
|
|
12
|
+
style: Record<`--${string}`, string>;
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
name: string;
|
|
16
|
+
label: string;
|
|
17
|
+
style: undefined;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ButtonsWidgetProps = {
|
|
21
|
+
id: string;
|
|
22
|
+
onChange: Function;
|
|
23
|
+
actions: Actions[];
|
|
24
|
+
actionsInfoMap: Record<string, string[]>;
|
|
25
|
+
filterActions: string[];
|
|
26
|
+
value: string;
|
|
27
|
+
default: string;
|
|
28
|
+
disabled: boolean;
|
|
29
|
+
isDisabled: boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const ButtonsWidget = (props: ButtonsWidgetProps) => {
|
|
33
|
+
const { disabled, id, onChange, actions, actionsInfoMap, value, isDisabled } =
|
|
34
|
+
props;
|
|
35
|
+
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
if (!props.value && props.default) {
|
|
38
|
+
props.onChange(
|
|
39
|
+
props.id,
|
|
40
|
+
find(actions, { name: props.default })?.style || props.default,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<FormFieldWrapper {...props} className="widget">
|
|
47
|
+
<div className="buttons buttons-widget">
|
|
48
|
+
{actions.map((action) => (
|
|
49
|
+
<Button
|
|
50
|
+
key={action.name}
|
|
51
|
+
aria-label={actionsInfoMap[action.name][1]}
|
|
52
|
+
onPress={() => onChange(id, action.style || action.name)}
|
|
53
|
+
className={isEqual(value, action.style) ? 'active' : null}
|
|
54
|
+
isDisabled={disabled || isDisabled}
|
|
55
|
+
>
|
|
56
|
+
<Icon
|
|
57
|
+
name={actionsInfoMap[action.name][0]}
|
|
58
|
+
title={actionsInfoMap[action.name][1] || action.name}
|
|
59
|
+
size="24px"
|
|
60
|
+
/>
|
|
61
|
+
</Button>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
</FormFieldWrapper>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default ButtonsWidget;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
2
|
+
import { Button } from '@plone/components';
|
|
3
|
+
import cx from 'classnames';
|
|
4
|
+
|
|
5
|
+
type Color =
|
|
6
|
+
| {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
style: Record<`--${string}`, string>;
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
name: string;
|
|
13
|
+
label: string;
|
|
14
|
+
style: undefined;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ColorPickerWidgetProps = {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
default?: string | object;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
missing_value?: unknown;
|
|
24
|
+
className?: string;
|
|
25
|
+
onChange: (id: string, value: any) => void;
|
|
26
|
+
colors: Color[];
|
|
27
|
+
themes: Color[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const ColorPickerWidget = (props: ColorPickerWidgetProps) => {
|
|
31
|
+
const { id, value, onChange } = props;
|
|
32
|
+
const colors = props.themes || props.colors || [];
|
|
33
|
+
|
|
34
|
+
return colors.length > 0 ? (
|
|
35
|
+
<FormFieldWrapper {...props} className="theme-picker-widget">
|
|
36
|
+
<div className="buttons">
|
|
37
|
+
{colors.map((color) => {
|
|
38
|
+
const colorName = color.name;
|
|
39
|
+
return (
|
|
40
|
+
<Button
|
|
41
|
+
key={id + colorName}
|
|
42
|
+
className={cx(colorName, { active: value === colorName })}
|
|
43
|
+
onPress={(e) => {
|
|
44
|
+
onChange(
|
|
45
|
+
id,
|
|
46
|
+
colorName === value ? props.missing_value : colorName,
|
|
47
|
+
);
|
|
48
|
+
}}
|
|
49
|
+
value={value}
|
|
50
|
+
style={color.style}
|
|
51
|
+
aria-label={color.label}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
})}
|
|
55
|
+
</div>
|
|
56
|
+
</FormFieldWrapper>
|
|
57
|
+
) : null;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default ColorPickerWidget;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
2
|
+
import BlocksObjectWidget from './BlocksObjectWidget';
|
|
3
|
+
import type { BlockEditProps } from '@plone/types';
|
|
4
|
+
|
|
5
|
+
const messages = defineMessages({
|
|
6
|
+
Target: {
|
|
7
|
+
id: 'Target',
|
|
8
|
+
defaultMessage: 'Target',
|
|
9
|
+
},
|
|
10
|
+
title: {
|
|
11
|
+
id: 'Title',
|
|
12
|
+
defaultMessage: 'Title',
|
|
13
|
+
},
|
|
14
|
+
icon: {
|
|
15
|
+
id: 'Icon',
|
|
16
|
+
defaultMessage: 'Icon',
|
|
17
|
+
},
|
|
18
|
+
description: {
|
|
19
|
+
id: 'Description',
|
|
20
|
+
defaultMessage: 'Description',
|
|
21
|
+
},
|
|
22
|
+
logo: {
|
|
23
|
+
id: 'Logo image',
|
|
24
|
+
defaultMessage: 'Logo image',
|
|
25
|
+
},
|
|
26
|
+
item: {
|
|
27
|
+
id: 'Item',
|
|
28
|
+
defaultMessage: 'Item',
|
|
29
|
+
},
|
|
30
|
+
items: {
|
|
31
|
+
id: 'Items',
|
|
32
|
+
defaultMessage: 'Items',
|
|
33
|
+
},
|
|
34
|
+
addLink: {
|
|
35
|
+
id: 'Add link',
|
|
36
|
+
defaultMessage: 'Add link',
|
|
37
|
+
},
|
|
38
|
+
headline: {
|
|
39
|
+
id: 'Headline',
|
|
40
|
+
defaultMessage: 'Headline',
|
|
41
|
+
},
|
|
42
|
+
itemsToShow: {
|
|
43
|
+
id: 'Items to show',
|
|
44
|
+
defaultMessage: 'Items to show',
|
|
45
|
+
},
|
|
46
|
+
hideDescription: {
|
|
47
|
+
id: 'Hide description',
|
|
48
|
+
defaultMessage: 'Hide description',
|
|
49
|
+
},
|
|
50
|
+
settings: {
|
|
51
|
+
id: 'Settings',
|
|
52
|
+
defaultMessage: 'Settings',
|
|
53
|
+
},
|
|
54
|
+
openLinkInNewTab: {
|
|
55
|
+
id: 'Open in a new tab',
|
|
56
|
+
defaultMessage: 'Open in a new tab',
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const FooterLinksWidget = (props) => {
|
|
61
|
+
const { value, onChange } = props;
|
|
62
|
+
const intl = useIntl();
|
|
63
|
+
|
|
64
|
+
function schema(props: BlockEditProps) {
|
|
65
|
+
return {
|
|
66
|
+
title: intl.formatMessage(messages.item),
|
|
67
|
+
addMessage: intl.formatMessage(messages.addLink),
|
|
68
|
+
fieldsets: [
|
|
69
|
+
{
|
|
70
|
+
id: 'default',
|
|
71
|
+
title: 'Default',
|
|
72
|
+
fields: ['title', 'href', 'openLinkInNewTab'],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
|
|
76
|
+
properties: {
|
|
77
|
+
title: {
|
|
78
|
+
title: intl.formatMessage(messages.title),
|
|
79
|
+
},
|
|
80
|
+
href: {
|
|
81
|
+
title: intl.formatMessage(messages.Target),
|
|
82
|
+
widget: 'object_browser',
|
|
83
|
+
mode: 'link',
|
|
84
|
+
selectedItemAttrs: ['Title', 'Description', '@type'],
|
|
85
|
+
allowExternals: true,
|
|
86
|
+
},
|
|
87
|
+
openLinkInNewTab: {
|
|
88
|
+
title: intl.formatMessage(messages.openLinkInNewTab),
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
required: [],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<BlocksObjectWidget
|
|
98
|
+
{...props}
|
|
99
|
+
value={value}
|
|
100
|
+
schema={schema}
|
|
101
|
+
onChange={onChange}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default FooterLinksWidget;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
2
|
+
import BlocksObjectWidget from './BlocksObjectWidget';
|
|
3
|
+
import type { BlockEditProps } from '@plone/types';
|
|
4
|
+
|
|
5
|
+
const messages = defineMessages({
|
|
6
|
+
Target: {
|
|
7
|
+
id: 'Target',
|
|
8
|
+
defaultMessage: 'Target',
|
|
9
|
+
},
|
|
10
|
+
title: {
|
|
11
|
+
id: 'Title',
|
|
12
|
+
defaultMessage: 'Title',
|
|
13
|
+
},
|
|
14
|
+
AltText: {
|
|
15
|
+
id: 'Alt text',
|
|
16
|
+
defaultMessage: 'Alt text',
|
|
17
|
+
},
|
|
18
|
+
icon: {
|
|
19
|
+
id: 'Icon',
|
|
20
|
+
defaultMessage: 'Icon',
|
|
21
|
+
},
|
|
22
|
+
description: {
|
|
23
|
+
id: 'Description',
|
|
24
|
+
defaultMessage: 'Description',
|
|
25
|
+
},
|
|
26
|
+
logo: {
|
|
27
|
+
id: 'Logo image',
|
|
28
|
+
defaultMessage: 'Logo image',
|
|
29
|
+
},
|
|
30
|
+
item: {
|
|
31
|
+
id: 'Item',
|
|
32
|
+
defaultMessage: 'Item',
|
|
33
|
+
},
|
|
34
|
+
items: {
|
|
35
|
+
id: 'Items',
|
|
36
|
+
defaultMessage: 'Items',
|
|
37
|
+
},
|
|
38
|
+
addLogo: {
|
|
39
|
+
id: 'Add logo',
|
|
40
|
+
defaultMessage: 'Add logo',
|
|
41
|
+
},
|
|
42
|
+
headline: {
|
|
43
|
+
id: 'Headline',
|
|
44
|
+
defaultMessage: 'Headline',
|
|
45
|
+
},
|
|
46
|
+
itemsToShow: {
|
|
47
|
+
id: 'Items to show',
|
|
48
|
+
defaultMessage: 'Items to show',
|
|
49
|
+
},
|
|
50
|
+
hideDescription: {
|
|
51
|
+
id: 'Hide description',
|
|
52
|
+
defaultMessage: 'Hide description',
|
|
53
|
+
},
|
|
54
|
+
settings: {
|
|
55
|
+
id: 'Settings',
|
|
56
|
+
defaultMessage: 'Settings',
|
|
57
|
+
},
|
|
58
|
+
openLinkInNewTab: {
|
|
59
|
+
id: 'Open in a new tab',
|
|
60
|
+
defaultMessage: 'Open in a new tab',
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const FooterLogosWidget = (props) => {
|
|
65
|
+
const { value, onChange } = props;
|
|
66
|
+
const intl = useIntl();
|
|
67
|
+
|
|
68
|
+
function schema(props: BlockEditProps) {
|
|
69
|
+
return {
|
|
70
|
+
title: intl.formatMessage(messages.item),
|
|
71
|
+
addMessage: intl.formatMessage(messages.addLogo),
|
|
72
|
+
fieldsets: [
|
|
73
|
+
{
|
|
74
|
+
id: 'default',
|
|
75
|
+
title: 'Default',
|
|
76
|
+
fields: ['logo', 'alt', 'href', 'openLinkInNewTab'],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
|
|
80
|
+
properties: {
|
|
81
|
+
title: {
|
|
82
|
+
title: intl.formatMessage(messages.title),
|
|
83
|
+
},
|
|
84
|
+
logo: {
|
|
85
|
+
title: intl.formatMessage(messages.logo),
|
|
86
|
+
widget: 'object_browser',
|
|
87
|
+
selectedItemAttrs: ['Title', 'Description', 'image_field', '@type'],
|
|
88
|
+
mode: 'image',
|
|
89
|
+
allowExternals: true,
|
|
90
|
+
},
|
|
91
|
+
alt: {
|
|
92
|
+
title: intl.formatMessage(messages.AltText),
|
|
93
|
+
},
|
|
94
|
+
href: {
|
|
95
|
+
title: intl.formatMessage(messages.Target),
|
|
96
|
+
widget: 'object_browser',
|
|
97
|
+
mode: 'link',
|
|
98
|
+
selectedItemAttrs: ['Title', 'Description'],
|
|
99
|
+
allowExternals: true,
|
|
100
|
+
},
|
|
101
|
+
openLinkInNewTab: {
|
|
102
|
+
title: intl.formatMessage(messages.openLinkInNewTab),
|
|
103
|
+
type: 'boolean',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
required: [],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<BlocksObjectWidget
|
|
112
|
+
{...props}
|
|
113
|
+
value={value}
|
|
114
|
+
schema={schema}
|
|
115
|
+
onChange={onChange}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export default FooterLogosWidget;
|