@kitconcept/volto-light-theme 7.3.1 → 8.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 +3 -3
- package/CHANGELOG.md +20 -0
- package/package.json +4 -17
- package/src/components/Blocks/Block/Edit.jsx +4 -1
- package/src/components/Blocks/Block/EditBlockWrapper.jsx +9 -4
- package/src/components/Blocks/Image/ImageSidebar.jsx +13 -1
- package/src/components/Blocks/Slider/schema.js +3 -33
- package/src/components/Theme/RenderBlocks.jsx +1 -0
- package/src/components/Widgets/ColorPicker.tsx +2 -1
- package/src/components/Widgets/ObjectList.tsx +8 -2
- package/src/config/blocks.tsx +1 -20
- package/src/theme/blocks/_slider.scss +3 -18
- package/src/components/Blocks/Slider/Data.jsx +0 -161
- package/src/components/Blocks/Slider/DefaultBody.jsx +0 -153
- package/src/components/Blocks/Slider/SliderVariants.jsx +0 -152
- package/src/components/Blocks/Slider/View.jsx +0 -179
- package/src/components/LanguageSelector/LanguageSelector.jsx +0 -76
- package/src/customizations/@kitconcept/volto-slider-block/components/Data.jsx +0 -11
- package/src/customizations/@kitconcept/volto-slider-block/components/DefaultBody.jsx +0 -11
- package/src/customizations/@kitconcept/volto-slider-block/components/View.jsx +0 -11
- package/src/customizations/volto/components/theme/LanguageSelector/LanguageSelector.js +0 -11
package/.changelog.draft
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
##
|
|
1
|
+
## 8.0.0-alpha.1 (2025-10-27)
|
|
2
2
|
|
|
3
|
-
###
|
|
3
|
+
### Breaking
|
|
4
4
|
|
|
5
|
-
-
|
|
5
|
+
- Transfer all custom code related to slider to the add-on. @sneridagh [#694](https://github.com/kitconcept/volto-light-theme/pull/694)
|
|
6
6
|
|
|
7
7
|
|
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,26 @@
|
|
|
8
8
|
|
|
9
9
|
<!-- towncrier release notes start -->
|
|
10
10
|
|
|
11
|
+
## 8.0.0-alpha.1 (2025-10-27)
|
|
12
|
+
|
|
13
|
+
### Breaking
|
|
14
|
+
|
|
15
|
+
- Transfer all custom code related to slider to the add-on. @sneridagh [#694](https://github.com/kitconcept/volto-light-theme/pull/694)
|
|
16
|
+
|
|
17
|
+
## 8.0.0-alpha.0 (2025-10-24)
|
|
18
|
+
|
|
19
|
+
### Breaking
|
|
20
|
+
|
|
21
|
+
- Use Volto 19a9. @sneridagh
|
|
22
|
+
Use `@plone/components` 4.0.0 alpha.
|
|
23
|
+
Recommended add-ons are not included by default as `peerDependencies`.
|
|
24
|
+
|
|
25
|
+
Breaking change: Please, check the [upgrade guide](https://volto-light-theme.readthedocs.io/how-to-guides/upgrade-guide.html) for more information. [#693](https://github.com/kitconcept/volto-light-theme/pull/693)
|
|
26
|
+
|
|
27
|
+
### Feature
|
|
28
|
+
|
|
29
|
+
- To reduce the size of the main VLT repository, snapshots for visual regression testing are now stored in a separate repository (kitconcept/vlt-visual-regression). @sneridagh [#690](https://github.com/kitconcept/volto-light-theme/pull/690)
|
|
30
|
+
|
|
11
31
|
## 7.3.1 (2025-10-08)
|
|
12
32
|
|
|
13
33
|
### Bugfix
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitconcept/volto-light-theme",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-alpha.1",
|
|
4
4
|
"description": "Volto Light Theme by kitconcept",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"release-it": "^19.0.3",
|
|
46
46
|
"typescript": "^5.7.3",
|
|
47
47
|
"vitest": "^3.1.2",
|
|
48
|
-
"@plone/types": "
|
|
48
|
+
"@plone/types": "2.0.0-alpha.7"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@dnd-kit/core": "6.0.8",
|
|
@@ -57,23 +57,10 @@
|
|
|
57
57
|
"react-aria-components": "^1.7.0",
|
|
58
58
|
"react-colorful": "^5.6.1",
|
|
59
59
|
"uuid": "^11.0.0",
|
|
60
|
-
"@plone/components": "^
|
|
60
|
+
"@plone/components": "^4.0.0-alpha.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"
|
|
64
|
-
"@kitconcept/volto-banner-block": "^1.1.0",
|
|
65
|
-
"@kitconcept/volto-bm3-compat": "^1.0.0-alpha.1",
|
|
66
|
-
"@kitconcept/volto-button-block": "^4.0.0-alpha.0",
|
|
67
|
-
"@kitconcept/volto-carousel-block": "^2.0.0-alpha.3",
|
|
68
|
-
"@kitconcept/volto-dsgvo-banner": "^2.5.1",
|
|
69
|
-
"@kitconcept/volto-heading-block": "^2.5.0",
|
|
70
|
-
"@kitconcept/volto-highlight-block": "^4.4.0",
|
|
71
|
-
"@kitconcept/volto-introduction-block": "^1.1.0",
|
|
72
|
-
"@kitconcept/volto-logos-block": "^3.0.0-alpha.1",
|
|
73
|
-
"@kitconcept/volto-separator-block": "^4.2.1",
|
|
74
|
-
"@kitconcept/volto-slider-block": "^6.4.0",
|
|
75
|
-
"@plonegovbr/volto-social-media": "^2.0.0-alpha.10",
|
|
76
|
-
"classnames": "^2.2.6",
|
|
63
|
+
"classnames": "^2.5.1",
|
|
77
64
|
"lodash": "4.17.21",
|
|
78
65
|
"react": "18.2.0",
|
|
79
66
|
"react-dom": "18.2.0",
|
|
@@ -151,7 +151,7 @@ export class Edit extends Component {
|
|
|
151
151
|
*/
|
|
152
152
|
render() {
|
|
153
153
|
const { blocksConfig = config.blocks.blocksConfig } = this.props;
|
|
154
|
-
const { editable, type } = this.props;
|
|
154
|
+
const { editable, type, isContainer: parentIsContainer } = this.props;
|
|
155
155
|
const required = isBoolean(this.props.data.required)
|
|
156
156
|
? this.props.data.required
|
|
157
157
|
: includes(config.blocks.requiredBlocks, type);
|
|
@@ -275,6 +275,7 @@ export class Edit extends Component {
|
|
|
275
275
|
selected: this.props.selected || this.props.multiSelected,
|
|
276
276
|
multiSelected: this.props.multiSelected,
|
|
277
277
|
hovered: this.props.hovered === this.props.id,
|
|
278
|
+
error: !!this.props.blocksErrors?.[this.props.id],
|
|
278
279
|
},
|
|
279
280
|
)}
|
|
280
281
|
ref={this.blockNode}
|
|
@@ -291,6 +292,7 @@ export class Edit extends Component {
|
|
|
291
292
|
{...this.props}
|
|
292
293
|
blockNode={this.blockNode}
|
|
293
294
|
data={this.props.data}
|
|
295
|
+
className={cx({ contained: parentIsContainer })}
|
|
294
296
|
/>
|
|
295
297
|
</MaybeWrap>
|
|
296
298
|
|
|
@@ -433,6 +435,7 @@ export class Edit extends Component {
|
|
|
433
435
|
selected: this.props.selected || this.props.multiSelected,
|
|
434
436
|
multiSelected: this.props.multiSelected,
|
|
435
437
|
hovered: this.props.hovered === this.props.id,
|
|
438
|
+
error: !!this.props.blocksErrors?.[this.props.id],
|
|
436
439
|
})}
|
|
437
440
|
// END CUSTOMIZATION
|
|
438
441
|
style={{ outline: 'none' }}
|
|
@@ -21,9 +21,13 @@ import BlockChooserButton from '@plone/volto/components/manage/BlockChooser/Bloc
|
|
|
21
21
|
import trashSVG from '@plone/volto/icons/delete.svg';
|
|
22
22
|
|
|
23
23
|
const messages = defineMessages({
|
|
24
|
-
|
|
25
|
-
id: '
|
|
26
|
-
defaultMessage: 'delete',
|
|
24
|
+
delete_block: {
|
|
25
|
+
id: 'delete_block',
|
|
26
|
+
defaultMessage: 'delete {type} block',
|
|
27
|
+
},
|
|
28
|
+
drag_block: {
|
|
29
|
+
id: 'drag_block',
|
|
30
|
+
defaultMessage: 'drag {type} block',
|
|
27
31
|
},
|
|
28
32
|
});
|
|
29
33
|
|
|
@@ -99,6 +103,7 @@ const EditBlockWrapper = (props) => {
|
|
|
99
103
|
}}
|
|
100
104
|
{...draginfo.dragHandleProps}
|
|
101
105
|
className="drag handle wrapper"
|
|
106
|
+
aria-label={intl.formatMessage(messages.drag_block, { type })}
|
|
102
107
|
>
|
|
103
108
|
<Icon name={dragSVG} size="18px" />
|
|
104
109
|
</div>
|
|
@@ -111,7 +116,7 @@ const EditBlockWrapper = (props) => {
|
|
|
111
116
|
basic
|
|
112
117
|
onClick={() => onDeleteBlock(block, true)}
|
|
113
118
|
className="delete-button"
|
|
114
|
-
aria-label={intl.formatMessage(messages.
|
|
119
|
+
aria-label={intl.formatMessage(messages.delete_block, { type })}
|
|
115
120
|
>
|
|
116
121
|
<Icon name={trashSVG} size="18px" />
|
|
117
122
|
</Button>
|
|
@@ -11,7 +11,15 @@ import imageSVG from '@plone/volto/icons/image.svg';
|
|
|
11
11
|
import trashSVG from '@plone/volto/icons/delete.svg';
|
|
12
12
|
|
|
13
13
|
const ImageSidebar = (props) => {
|
|
14
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
blocksConfig,
|
|
16
|
+
blocksErrors,
|
|
17
|
+
data,
|
|
18
|
+
block,
|
|
19
|
+
onChangeBlock,
|
|
20
|
+
navRoot,
|
|
21
|
+
contentType,
|
|
22
|
+
} = props;
|
|
15
23
|
const intl = useIntl();
|
|
16
24
|
const schema = ImageSchema({ formData: data, intl });
|
|
17
25
|
// START CUSTOMIZATION
|
|
@@ -26,6 +34,7 @@ const ImageSidebar = (props) => {
|
|
|
26
34
|
</h2>
|
|
27
35
|
<Button.Group>
|
|
28
36
|
<Button
|
|
37
|
+
type="button"
|
|
29
38
|
title={intl.formatMessage(messages.clear)}
|
|
30
39
|
basic
|
|
31
40
|
disabled={!data.url}
|
|
@@ -107,6 +116,9 @@ const ImageSidebar = (props) => {
|
|
|
107
116
|
formData={data}
|
|
108
117
|
block={block}
|
|
109
118
|
blocksConfig={blocksConfig}
|
|
119
|
+
navRoot={navRoot}
|
|
120
|
+
contentType={contentType}
|
|
121
|
+
errors={blocksErrors}
|
|
110
122
|
/>
|
|
111
123
|
</>
|
|
112
124
|
);
|
|
@@ -1,41 +1,11 @@
|
|
|
1
|
-
import { defineMessages } from 'react-intl';
|
|
2
1
|
import { defaultStylingSchema } from '../schema';
|
|
3
2
|
|
|
4
|
-
const messages = defineMessages({
|
|
5
|
-
flagAlign: {
|
|
6
|
-
id: 'Flag align',
|
|
7
|
-
defaultMessage: 'Align',
|
|
8
|
-
},
|
|
9
|
-
buttonText: {
|
|
10
|
-
id: 'Button text',
|
|
11
|
-
defaultMessage: 'Button text',
|
|
12
|
-
},
|
|
13
|
-
hideButton: {
|
|
14
|
-
id: 'Hide Button',
|
|
15
|
-
defaultMessage: 'Hide Button',
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
|
|
19
3
|
export const sliderBlockSchemaEnhancer = ({ formData, schema, intl }) => {
|
|
20
4
|
defaultStylingSchema({ schema, formData, intl });
|
|
21
5
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
schema.properties.slides.schema.fieldsets[0].fields.push('hideButton');
|
|
27
|
-
schema.properties.slides.schema.properties.hideButton = {
|
|
28
|
-
title: intl.formatMessage(messages.hideButton),
|
|
29
|
-
type: 'boolean',
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
schema.properties.slides.schema.fieldsets[0].fields.push('flagAlign');
|
|
33
|
-
schema.properties.slides.schema.properties.flagAlign = {
|
|
34
|
-
widget: 'inner_align',
|
|
35
|
-
title: intl.formatMessage(messages.flagAlign),
|
|
36
|
-
actions: ['left', 'right'],
|
|
37
|
-
default: 'left',
|
|
38
|
-
};
|
|
6
|
+
// Override flagAlign widget to inner_align
|
|
7
|
+
// ToDo: Remove when backported to Volto 19
|
|
8
|
+
schema.properties.slides.schema.properties.flagAlign.widget = 'inner_align';
|
|
39
9
|
|
|
40
10
|
return schema;
|
|
41
11
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
2
2
|
import { HexColorPicker, HexColorInput } from 'react-colorful';
|
|
3
3
|
import { Button, Dialog, DialogTrigger, Popover } from 'react-aria-components';
|
|
4
|
-
import { ColorSwatch
|
|
4
|
+
import { ColorSwatch } from '@plone/components';
|
|
5
|
+
import { CloseIcon } from '@plone/components/Icons';
|
|
5
6
|
import ColorContrastChecker from './ColorContrastChecker';
|
|
6
7
|
import config from '@plone/volto/registry';
|
|
7
8
|
|
|
@@ -215,8 +215,14 @@ const ObjectListWidget = (props: ObjectListWidgetProps) => {
|
|
|
215
215
|
intl,
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
const newValue = [...(value || []), dataWithDefaults];
|
|
219
|
+
|
|
220
|
+
onChange(id, newValue);
|
|
221
|
+
|
|
222
|
+
// Set active the new object ensuring the state is updated after adding the new item
|
|
223
|
+
setTimeout(() => {
|
|
224
|
+
setActiveObject(newValue.length - 1);
|
|
225
|
+
}, 0);
|
|
220
226
|
}}
|
|
221
227
|
>
|
|
222
228
|
<Icon name={addSVG} size="18px" />
|
package/src/config/blocks.tsx
CHANGED
|
@@ -46,8 +46,6 @@ import SearchBlockViewEvent from '../components/Blocks/EventCalendar/Search/Sear
|
|
|
46
46
|
import SearchBlockEditEvent from '../components/Blocks/EventCalendar/Search/SearchBlockEdit';
|
|
47
47
|
import SearchBlockSchemaEvent from '../components/Blocks/EventCalendar/Search/schema';
|
|
48
48
|
import EventCalenderTemplate from '../components/Blocks/EventCalendar/Search/components/EventTemplate';
|
|
49
|
-
import SliderVariants from '../components/Blocks/Slider/SliderVariants';
|
|
50
|
-
import DefaultBody from '../customizations/@kitconcept/volto-slider-block/components/DefaultBody';
|
|
51
49
|
|
|
52
50
|
declare module '@plone/types' {
|
|
53
51
|
export interface BlocksConfigData {
|
|
@@ -418,24 +416,7 @@ export default function install(config: ConfigType) {
|
|
|
418
416
|
};
|
|
419
417
|
|
|
420
418
|
// Slider Block
|
|
421
|
-
config.blocks.blocksConfig.slider =
|
|
422
|
-
...config.blocks.blocksConfig.slider,
|
|
423
|
-
variations: [
|
|
424
|
-
{
|
|
425
|
-
id: 'default',
|
|
426
|
-
title: 'Default',
|
|
427
|
-
isDefault: true,
|
|
428
|
-
view: DefaultBody,
|
|
429
|
-
},
|
|
430
|
-
|
|
431
|
-
{
|
|
432
|
-
id: 'simple',
|
|
433
|
-
title: 'Simple',
|
|
434
|
-
view: SliderVariants,
|
|
435
|
-
},
|
|
436
|
-
],
|
|
437
|
-
schemaEnhancer: sliderBlockSchemaEnhancer,
|
|
438
|
-
};
|
|
419
|
+
config.blocks.blocksConfig.slider.schemaEnhancer = sliderBlockSchemaEnhancer;
|
|
439
420
|
|
|
440
421
|
return config;
|
|
441
422
|
}
|
|
@@ -113,7 +113,7 @@ $sliderImagesAspectRatio: var(--slider-images-aspect-ratio, 16/9);
|
|
|
113
113
|
position: relative;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
.
|
|
116
|
+
.teaser-item button {
|
|
117
117
|
display: initial;
|
|
118
118
|
padding: 8px 20px;
|
|
119
119
|
border: 1px solid currentColor;
|
|
@@ -189,7 +189,7 @@ $sliderImagesAspectRatio: var(--slider-images-aspect-ratio, 16/9);
|
|
|
189
189
|
padding: 60px 20px;
|
|
190
190
|
background: var(--theme-color);
|
|
191
191
|
color: var(--theme-foreground-color);
|
|
192
|
-
|
|
192
|
+
button,
|
|
193
193
|
.title > h2,
|
|
194
194
|
p.slider-description {
|
|
195
195
|
color: var(--theme-foreground-color) !important;
|
|
@@ -238,23 +238,8 @@ $sliderImagesAspectRatio: var(--slider-images-aspect-ratio, 16/9);
|
|
|
238
238
|
display: none;
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
-
|
|
241
|
+
button {
|
|
242
242
|
color: var(--theme-foreground-color);
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
-
|
|
247
|
-
.ui.buttons.refresh.slider button {
|
|
248
|
-
display: flex;
|
|
249
|
-
align-items: center;
|
|
250
|
-
padding: 0.5833em 0.833em;
|
|
251
|
-
background-color: #e8e8e8 !important;
|
|
252
|
-
color: rgba(0, 0, 0, 0.6) !important;
|
|
253
|
-
font-size: 0.85714286rem;
|
|
254
|
-
font-weight: bold;
|
|
255
|
-
|
|
256
|
-
svg {
|
|
257
|
-
padding: 0 0 0 0.5em;
|
|
258
|
-
margin-right: 0;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { useIntl, defineMessages } from 'react-intl';
|
|
2
|
-
import { useDispatch } from 'react-redux';
|
|
3
|
-
import { BlockDataForm } from '@plone/volto/components/manage/Form';
|
|
4
|
-
import { SliderSchema } from '@kitconcept/volto-slider-block/components/schema';
|
|
5
|
-
import { toast } from 'react-toastify';
|
|
6
|
-
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
7
|
-
import Toast from '@plone/volto/components/manage/Toast/Toast';
|
|
8
|
-
import { getContent } from '@plone/volto/actions/content/content';
|
|
9
|
-
import isEmpty from 'lodash/isEmpty';
|
|
10
|
-
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
11
|
-
import { Button } from 'semantic-ui-react';
|
|
12
|
-
import reloadSVG from '@plone/volto/icons/reload.svg';
|
|
13
|
-
import { messages as defaultMessages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
|
|
14
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
15
|
-
|
|
16
|
-
const messages = defineMessages({
|
|
17
|
-
resetSlider: {
|
|
18
|
-
id: 'Reset the block',
|
|
19
|
-
defaultMessage: 'Reset the block',
|
|
20
|
-
},
|
|
21
|
-
refreshSlider: {
|
|
22
|
-
id: 'Refresh source content',
|
|
23
|
-
defaultMessage: 'Refresh source content',
|
|
24
|
-
},
|
|
25
|
-
invalidSlider: {
|
|
26
|
-
id: 'Invalid Slider source',
|
|
27
|
-
defaultMessage: 'Invalid Slider source',
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
function getImageField(resp) {
|
|
32
|
-
if (!resp) return null;
|
|
33
|
-
|
|
34
|
-
if (resp.preview_image_link) return 'preview_image_link';
|
|
35
|
-
if (resp.preview_image) return 'preview_image';
|
|
36
|
-
if (resp.image) return 'image';
|
|
37
|
-
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const SliderData = (props) => {
|
|
42
|
-
const {
|
|
43
|
-
block,
|
|
44
|
-
blocksConfig,
|
|
45
|
-
data,
|
|
46
|
-
onChangeBlock,
|
|
47
|
-
navRoot,
|
|
48
|
-
contentType,
|
|
49
|
-
activeObject,
|
|
50
|
-
} = props;
|
|
51
|
-
const dispatch = useDispatch();
|
|
52
|
-
const intl = useIntl();
|
|
53
|
-
const schema = SliderSchema({ ...props, intl });
|
|
54
|
-
|
|
55
|
-
const dataTransformer = (resp, data, activeObject) => {
|
|
56
|
-
let hrefData = {
|
|
57
|
-
'@id': flattenToAppURL(resp['@id']),
|
|
58
|
-
'@type': resp?.['@type'],
|
|
59
|
-
Description: resp?.description,
|
|
60
|
-
Title: resp.title,
|
|
61
|
-
hasPreviewImage: getImageField(resp) ? true : false,
|
|
62
|
-
head_title: resp.head_title ?? null,
|
|
63
|
-
image_field: getImageField(resp),
|
|
64
|
-
image_scales: {
|
|
65
|
-
preview_image: [resp?.preview_image],
|
|
66
|
-
image: [resp?.image],
|
|
67
|
-
preview_image_link: resp?.preview_image_link
|
|
68
|
-
? [
|
|
69
|
-
{
|
|
70
|
-
...resp?.preview_image_link?.['image_scales']?.image?.[0],
|
|
71
|
-
base_path: resp?.preview_image_link?.['@id'],
|
|
72
|
-
},
|
|
73
|
-
]
|
|
74
|
-
: [],
|
|
75
|
-
},
|
|
76
|
-
title: resp.title,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const updatedSlides = cloneDeep(data.slides);
|
|
80
|
-
|
|
81
|
-
updatedSlides[activeObject] = {
|
|
82
|
-
'@id': data.slides[activeObject]['@id'],
|
|
83
|
-
description: resp?.description,
|
|
84
|
-
title: resp?.title,
|
|
85
|
-
flagAlign: data.slides[activeObject]?.flagAlign,
|
|
86
|
-
href: [hrefData],
|
|
87
|
-
};
|
|
88
|
-
return {
|
|
89
|
-
...data,
|
|
90
|
-
slides: updatedSlides,
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const refresh = () => {
|
|
95
|
-
if (data.slides[activeObject]?.href?.[0]?.['@id']) {
|
|
96
|
-
dispatch(
|
|
97
|
-
getContent(
|
|
98
|
-
flattenToAppURL(data.slides[activeObject].href[0]['@id']),
|
|
99
|
-
null,
|
|
100
|
-
`${block}-slider-${activeObject}`,
|
|
101
|
-
),
|
|
102
|
-
)
|
|
103
|
-
.then((resp) => {
|
|
104
|
-
if (resp) {
|
|
105
|
-
let blockData = dataTransformer(resp, data, activeObject);
|
|
106
|
-
onChangeBlock(block, blockData);
|
|
107
|
-
}
|
|
108
|
-
})
|
|
109
|
-
.catch((e) => {
|
|
110
|
-
toast.error(
|
|
111
|
-
<Toast
|
|
112
|
-
error
|
|
113
|
-
title={props.intl.formatMessage(defaultMessages.error)}
|
|
114
|
-
content={props.intl.formatMessage(messages.invalidSlider)}
|
|
115
|
-
/>,
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const ActionButton = (
|
|
122
|
-
<Button.Group className="refresh slider">
|
|
123
|
-
<Button
|
|
124
|
-
aria-label={intl.formatMessage(messages.refreshSlider)}
|
|
125
|
-
type="button"
|
|
126
|
-
basic
|
|
127
|
-
onClick={() => refresh()}
|
|
128
|
-
disabled={isEmpty(data.slides)}
|
|
129
|
-
>
|
|
130
|
-
{intl.formatMessage(messages.refreshSlider)}
|
|
131
|
-
<Icon name={reloadSVG} size="20px" color="#00000099" />
|
|
132
|
-
</Button>
|
|
133
|
-
</Button.Group>
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const dataAdapter = blocksConfig[data['@type']].dataAdapter;
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<BlockDataForm
|
|
140
|
-
schema={schema}
|
|
141
|
-
title={schema.title}
|
|
142
|
-
onChangeField={(id, value) => {
|
|
143
|
-
dataAdapter({
|
|
144
|
-
block,
|
|
145
|
-
data,
|
|
146
|
-
id,
|
|
147
|
-
onChangeBlock,
|
|
148
|
-
value,
|
|
149
|
-
});
|
|
150
|
-
}}
|
|
151
|
-
onChangeBlock={onChangeBlock}
|
|
152
|
-
formData={data}
|
|
153
|
-
block={block}
|
|
154
|
-
actionButton={ActionButton}
|
|
155
|
-
navRoot={navRoot}
|
|
156
|
-
contentType={contentType}
|
|
157
|
-
/>
|
|
158
|
-
);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
export default SliderData;
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { useIntl, defineMessages } from 'react-intl';
|
|
3
|
-
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
4
|
-
import MaybeWrap from '@plone/volto/components/manage/MaybeWrap/MaybeWrap';
|
|
5
|
-
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
6
|
-
import { Input, Button, Message } from 'semantic-ui-react';
|
|
7
|
-
import { isInternalURL } from '@plone/volto/helpers/Url/Url';
|
|
8
|
-
import cx from 'classnames';
|
|
9
|
-
import navTreeSVG from '@plone/volto/icons/nav.svg';
|
|
10
|
-
import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
|
|
11
|
-
import config from '@plone/volto/registry';
|
|
12
|
-
|
|
13
|
-
const messages = defineMessages({
|
|
14
|
-
PleaseChooseContent: {
|
|
15
|
-
id: 'Please choose an existing content as source for this element',
|
|
16
|
-
defaultMessage:
|
|
17
|
-
'Please choose an existing content as source for this element',
|
|
18
|
-
},
|
|
19
|
-
moreInfo: {
|
|
20
|
-
id: 'moreInfo',
|
|
21
|
-
defaultMessage: 'More info',
|
|
22
|
-
},
|
|
23
|
-
source: {
|
|
24
|
-
id: 'Source',
|
|
25
|
-
defaultMessage: 'Source',
|
|
26
|
-
},
|
|
27
|
-
ButtonText: {
|
|
28
|
-
id: 'Continue reading',
|
|
29
|
-
defaultMessage: 'Continue reading',
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const DefaultImage = (props) => <img {...props} alt={props.alt || ''} />;
|
|
34
|
-
|
|
35
|
-
const SliderBody = ({
|
|
36
|
-
index,
|
|
37
|
-
onChangeBlock,
|
|
38
|
-
block,
|
|
39
|
-
data,
|
|
40
|
-
dataBlock,
|
|
41
|
-
isEditMode,
|
|
42
|
-
openObjectBrowser,
|
|
43
|
-
}) => {
|
|
44
|
-
const intl = useIntl();
|
|
45
|
-
const href = data.href?.[0];
|
|
46
|
-
const image = data.preview_image?.[0];
|
|
47
|
-
|
|
48
|
-
const Image = config.getComponent('Image').component || DefaultImage;
|
|
49
|
-
const { openExternalLinkInNewTab } = config.settings;
|
|
50
|
-
|
|
51
|
-
const handleClick = () => {
|
|
52
|
-
openObjectBrowser({
|
|
53
|
-
onSelectItem: (url, document) => {
|
|
54
|
-
dataBlock.slides[index].title = document.Title;
|
|
55
|
-
dataBlock.slides[index].description = document.Description;
|
|
56
|
-
dataBlock.slides[index].href = [
|
|
57
|
-
{
|
|
58
|
-
'@id': document['@id'],
|
|
59
|
-
Title: document.Title,
|
|
60
|
-
Description: document.Description,
|
|
61
|
-
title: document.Title,
|
|
62
|
-
image_field: document.image_field,
|
|
63
|
-
hasPreviewImage: document.hasPreviewImage,
|
|
64
|
-
},
|
|
65
|
-
];
|
|
66
|
-
onChangeBlock(block, dataBlock);
|
|
67
|
-
},
|
|
68
|
-
mode: 'link',
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<div
|
|
74
|
-
className={cx('grid-teaser-item top', {
|
|
75
|
-
'empty-slide': !href && isEditMode,
|
|
76
|
-
})}
|
|
77
|
-
>
|
|
78
|
-
{!href && isEditMode && (
|
|
79
|
-
<Message>
|
|
80
|
-
<div className="grid-teaser-item default">
|
|
81
|
-
<img src={imageBlockSVG} alt="" />
|
|
82
|
-
<p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
|
|
83
|
-
<div className="toolbar-inner">
|
|
84
|
-
<Button.Group>
|
|
85
|
-
<Button onClick={handleClick} icon basic>
|
|
86
|
-
<Icon name={navTreeSVG} size="24px" />
|
|
87
|
-
</Button>
|
|
88
|
-
</Button.Group>
|
|
89
|
-
<Input
|
|
90
|
-
placeholder={`${intl.formatMessage(messages.source)}...`}
|
|
91
|
-
onClick={handleClick}
|
|
92
|
-
onFocus={(e) => e.target.blur()}
|
|
93
|
-
/>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</Message>
|
|
97
|
-
)}
|
|
98
|
-
{href && (
|
|
99
|
-
<div className="teaser-item top">
|
|
100
|
-
<MaybeWrap
|
|
101
|
-
condition={!isEditMode}
|
|
102
|
-
as={UniversalLink}
|
|
103
|
-
href={href['@id']}
|
|
104
|
-
target={
|
|
105
|
-
data.openLinkInNewTab ||
|
|
106
|
-
(openExternalLinkInNewTab && !isInternalURL(href['@id']))
|
|
107
|
-
? '_blank'
|
|
108
|
-
: null
|
|
109
|
-
}
|
|
110
|
-
tabIndex="-1"
|
|
111
|
-
>
|
|
112
|
-
{(href?.hasPreviewImage || href.image_field || image) && (
|
|
113
|
-
<div className="highlight-image-wrapper gradient">
|
|
114
|
-
<Image
|
|
115
|
-
item={image || href}
|
|
116
|
-
imageField={image ? image.image_field : href.image_field}
|
|
117
|
-
alt=""
|
|
118
|
-
loading="lazy"
|
|
119
|
-
responsive={true}
|
|
120
|
-
/>
|
|
121
|
-
</div>
|
|
122
|
-
)}
|
|
123
|
-
{/* START CUSTOMIZATION */}
|
|
124
|
-
<div
|
|
125
|
-
className={cx(
|
|
126
|
-
'teaser-item-title fix-width-issue',
|
|
127
|
-
`has--slider--flagAlign--${data.flagAlign}`,
|
|
128
|
-
)}
|
|
129
|
-
>
|
|
130
|
-
{/* END CUSTOMIZATION */}
|
|
131
|
-
<div className="title">
|
|
132
|
-
{data?.head_title && (
|
|
133
|
-
<span className="supertitle">{data?.head_title}</span>
|
|
134
|
-
)}
|
|
135
|
-
<h2>{data?.nav_title || data?.title}</h2>
|
|
136
|
-
</div>
|
|
137
|
-
<p>{data?.description}</p>
|
|
138
|
-
{/* START CUSTOMIZATION */}
|
|
139
|
-
{!data.hideButton && (
|
|
140
|
-
<Button tabIndex={'-1'}>
|
|
141
|
-
{data.buttonText || intl.formatMessage(messages.ButtonText)}
|
|
142
|
-
</Button>
|
|
143
|
-
)}
|
|
144
|
-
{/* END CUSTOMIZATION */}
|
|
145
|
-
</div>
|
|
146
|
-
</MaybeWrap>
|
|
147
|
-
</div>
|
|
148
|
-
)}
|
|
149
|
-
</div>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
export default SliderBody;
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { useIntl, defineMessages } from 'react-intl';
|
|
3
|
-
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
4
|
-
import MaybeWrap from '@plone/volto/components/manage/MaybeWrap/MaybeWrap';
|
|
5
|
-
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
6
|
-
import { Input, Button, Message } from 'semantic-ui-react';
|
|
7
|
-
import { isInternalURL } from '@plone/volto/helpers/Url/Url';
|
|
8
|
-
import cx from 'classnames';
|
|
9
|
-
import navTreeSVG from '@plone/volto/icons/nav.svg';
|
|
10
|
-
import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
|
|
11
|
-
import config from '@plone/volto/registry';
|
|
12
|
-
|
|
13
|
-
const messages = defineMessages({
|
|
14
|
-
PleaseChooseContent: {
|
|
15
|
-
id: 'Please choose an existing content as source for this element',
|
|
16
|
-
defaultMessage:
|
|
17
|
-
'Please choose an existing content as source for this element',
|
|
18
|
-
},
|
|
19
|
-
moreInfo: {
|
|
20
|
-
id: 'moreInfo',
|
|
21
|
-
defaultMessage: 'More info',
|
|
22
|
-
},
|
|
23
|
-
source: {
|
|
24
|
-
id: 'Source',
|
|
25
|
-
defaultMessage: 'Source',
|
|
26
|
-
},
|
|
27
|
-
ButtonText: {
|
|
28
|
-
id: 'Continue reading',
|
|
29
|
-
defaultMessage: 'Continue reading',
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const DefaultImage = (props) => <img {...props} alt={props.alt || ''} />;
|
|
34
|
-
|
|
35
|
-
const SliderVariants = ({
|
|
36
|
-
index,
|
|
37
|
-
onChangeBlock,
|
|
38
|
-
block,
|
|
39
|
-
data,
|
|
40
|
-
dataBlock,
|
|
41
|
-
isEditMode,
|
|
42
|
-
openObjectBrowser,
|
|
43
|
-
}) => {
|
|
44
|
-
const intl = useIntl();
|
|
45
|
-
const href = data.href?.[0];
|
|
46
|
-
const image = data.preview_image?.[0];
|
|
47
|
-
|
|
48
|
-
const Image = config.getComponent('Image').component || DefaultImage;
|
|
49
|
-
const { openExternalLinkInNewTab } = config.settings;
|
|
50
|
-
|
|
51
|
-
const handleClick = () => {
|
|
52
|
-
openObjectBrowser({
|
|
53
|
-
onSelectItem: (url, document) => {
|
|
54
|
-
dataBlock.slides[index].title = document.Title;
|
|
55
|
-
dataBlock.slides[index].description = document.Description;
|
|
56
|
-
dataBlock.slides[index].href = [
|
|
57
|
-
{
|
|
58
|
-
'@id': document['@id'],
|
|
59
|
-
Title: document.Title,
|
|
60
|
-
Description: document.Description,
|
|
61
|
-
title: document.Title,
|
|
62
|
-
image_field: document.image_field,
|
|
63
|
-
hasPreviewImage: document.hasPreviewImage,
|
|
64
|
-
},
|
|
65
|
-
];
|
|
66
|
-
onChangeBlock(block, dataBlock);
|
|
67
|
-
},
|
|
68
|
-
mode: 'link',
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<div
|
|
74
|
-
className={cx('grid-teaser-item top', {
|
|
75
|
-
'empty-slide': !href && isEditMode,
|
|
76
|
-
})}
|
|
77
|
-
>
|
|
78
|
-
{!href && isEditMode && (
|
|
79
|
-
<Message>
|
|
80
|
-
<div className="grid-teaser-item default">
|
|
81
|
-
<img src={imageBlockSVG} alt="" />
|
|
82
|
-
<p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
|
|
83
|
-
<div className="toolbar-inner">
|
|
84
|
-
<Button.Group>
|
|
85
|
-
<Button onClick={handleClick} icon basic>
|
|
86
|
-
<Icon name={navTreeSVG} size="24px" />
|
|
87
|
-
</Button>
|
|
88
|
-
</Button.Group>
|
|
89
|
-
<Input
|
|
90
|
-
placeholder={`${intl.formatMessage(messages.source)}...`}
|
|
91
|
-
onClick={handleClick}
|
|
92
|
-
onFocus={(e) => e.target.blur()}
|
|
93
|
-
/>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</Message>
|
|
97
|
-
)}
|
|
98
|
-
{href && (
|
|
99
|
-
<MaybeWrap
|
|
100
|
-
condition={!isEditMode}
|
|
101
|
-
as={UniversalLink}
|
|
102
|
-
href={href['@id']}
|
|
103
|
-
className="link-container"
|
|
104
|
-
target={
|
|
105
|
-
data.openLinkInNewTab ||
|
|
106
|
-
(openExternalLinkInNewTab && !isInternalURL(href['@id']))
|
|
107
|
-
? '_blank'
|
|
108
|
-
: null
|
|
109
|
-
}
|
|
110
|
-
tabIndex="-1"
|
|
111
|
-
>
|
|
112
|
-
<div
|
|
113
|
-
className={cx(
|
|
114
|
-
'teaser-item top',
|
|
115
|
-
`has--slider--flagAlign--${data.flagAlign}`,
|
|
116
|
-
dataBlock.variation,
|
|
117
|
-
)}
|
|
118
|
-
>
|
|
119
|
-
{(href?.hasPreviewImage || href.image_field || image) && (
|
|
120
|
-
<div className="highlight-image-wrapper gradient">
|
|
121
|
-
<Image
|
|
122
|
-
item={image || href}
|
|
123
|
-
imageField={image ? image.image_field : href.image_field}
|
|
124
|
-
alt=""
|
|
125
|
-
loading="lazy"
|
|
126
|
-
responsive={true}
|
|
127
|
-
/>
|
|
128
|
-
</div>
|
|
129
|
-
)}
|
|
130
|
-
<div className="teaser-item-title fix-width-issue">
|
|
131
|
-
<div className="title">
|
|
132
|
-
{data?.head_title && (
|
|
133
|
-
<span className="supertitle">{data?.head_title}</span>
|
|
134
|
-
)}
|
|
135
|
-
<h2>{data?.nav_title || data?.title}</h2>
|
|
136
|
-
</div>
|
|
137
|
-
<p className="slider-description">{data?.description}</p>
|
|
138
|
-
|
|
139
|
-
{!data.hideButton && (
|
|
140
|
-
<Button tabIndex={'-1'}>
|
|
141
|
-
{data.buttonText || intl.formatMessage(messages.ButtonText)}
|
|
142
|
-
</Button>
|
|
143
|
-
)}
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
</MaybeWrap>
|
|
147
|
-
)}
|
|
148
|
-
</div>
|
|
149
|
-
);
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
export default SliderVariants;
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import { Message } from 'semantic-ui-react';
|
|
3
|
-
import useEmblaCarousel from 'embla-carousel-react';
|
|
4
|
-
import Autoplay from 'embla-carousel-autoplay';
|
|
5
|
-
import cx from 'classnames';
|
|
6
|
-
import { defineMessages, useIntl } from 'react-intl';
|
|
7
|
-
import Body from '@kitconcept/volto-slider-block/components/Body';
|
|
8
|
-
import withBlockExtensions from '@plone/volto/helpers/Extensions/withBlockExtensions';
|
|
9
|
-
import {
|
|
10
|
-
DotButton,
|
|
11
|
-
NextButton,
|
|
12
|
-
PrevButton,
|
|
13
|
-
} from '@kitconcept/volto-slider-block/components/DotsAndArrows';
|
|
14
|
-
import teaserTemplate from '@kitconcept/volto-slider-block/icons/teaser-template.svg';
|
|
15
|
-
|
|
16
|
-
const messages = defineMessages({
|
|
17
|
-
PleaseChooseContent: {
|
|
18
|
-
id: 'Please choose an existing content as source for this element',
|
|
19
|
-
defaultMessage:
|
|
20
|
-
'Please choose an existing content as source for this element',
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const SliderView = (props) => {
|
|
25
|
-
const {
|
|
26
|
-
className,
|
|
27
|
-
data,
|
|
28
|
-
isEditMode = false,
|
|
29
|
-
block,
|
|
30
|
-
openObjectBrowser,
|
|
31
|
-
onChangeBlock,
|
|
32
|
-
slideIndex,
|
|
33
|
-
setSlideIndex,
|
|
34
|
-
} = props;
|
|
35
|
-
const intl = useIntl();
|
|
36
|
-
|
|
37
|
-
const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
|
|
38
|
-
const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
|
|
39
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
40
|
-
const [scrollSnaps, setScrollSnaps] = useState([]);
|
|
41
|
-
const autoplay =
|
|
42
|
-
data.autoplayEnabled !== undefined ? data.autoplayEnabled : false;
|
|
43
|
-
const autoplayOptions = {
|
|
44
|
-
delay: data.autoplayDelay,
|
|
45
|
-
jump: data.autoplayJump,
|
|
46
|
-
};
|
|
47
|
-
const plugins = isEditMode ? [] : autoplay ? [Autoplay(autoplayOptions)] : [];
|
|
48
|
-
|
|
49
|
-
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, plugins);
|
|
50
|
-
|
|
51
|
-
const scrollPrev = useCallback(() => {
|
|
52
|
-
if (emblaApi) {
|
|
53
|
-
emblaApi.scrollPrev();
|
|
54
|
-
setSlideIndex && setSlideIndex(selectedIndex - 1);
|
|
55
|
-
}
|
|
56
|
-
}, [emblaApi, selectedIndex, setSlideIndex]);
|
|
57
|
-
|
|
58
|
-
const scrollNext = useCallback(() => {
|
|
59
|
-
if (emblaApi) {
|
|
60
|
-
emblaApi.scrollNext();
|
|
61
|
-
setSlideIndex && setSlideIndex(selectedIndex + 1);
|
|
62
|
-
}
|
|
63
|
-
}, [emblaApi, selectedIndex, setSlideIndex]);
|
|
64
|
-
|
|
65
|
-
const scrollTo = useCallback(
|
|
66
|
-
(index) => {
|
|
67
|
-
if (emblaApi) {
|
|
68
|
-
emblaApi.scrollTo(index);
|
|
69
|
-
setSlideIndex && setSlideIndex(index);
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
[emblaApi, setSlideIndex],
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const onInit = useCallback((emblaApi) => {
|
|
76
|
-
setScrollSnaps(emblaApi.scrollSnapList());
|
|
77
|
-
}, []);
|
|
78
|
-
|
|
79
|
-
const onSelect = useCallback((emblaApi) => {
|
|
80
|
-
setSelectedIndex(emblaApi.selectedScrollSnap());
|
|
81
|
-
setPrevBtnDisabled(!emblaApi.canScrollPrev());
|
|
82
|
-
setNextBtnDisabled(!emblaApi.canScrollNext());
|
|
83
|
-
}, []);
|
|
84
|
-
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
if (!emblaApi) return;
|
|
87
|
-
|
|
88
|
-
onInit(emblaApi);
|
|
89
|
-
onSelect(emblaApi);
|
|
90
|
-
emblaApi.on('reInit', onInit);
|
|
91
|
-
emblaApi.on('reInit', onSelect);
|
|
92
|
-
emblaApi.on('select', onSelect);
|
|
93
|
-
}, [emblaApi, onInit, onSelect]);
|
|
94
|
-
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
// This syncs the current slide with the objectwidget (or other sources
|
|
97
|
-
// able to access the slider context)
|
|
98
|
-
// that can modify the SliderContext (and come here via props slideIndex)
|
|
99
|
-
if (isEditMode) {
|
|
100
|
-
scrollTo(slideIndex);
|
|
101
|
-
}
|
|
102
|
-
}, [slideIndex, scrollTo, isEditMode]);
|
|
103
|
-
|
|
104
|
-
const sliderContainerWidth = emblaApi
|
|
105
|
-
?.rootNode()
|
|
106
|
-
.getBoundingClientRect().width;
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<>
|
|
110
|
-
{/* START CUSTOMIZATION */}
|
|
111
|
-
<div
|
|
112
|
-
className={cx('block slider', data.variation || 'default', className)}
|
|
113
|
-
style={{ '--slider-container-width': `${sliderContainerWidth}px` }}
|
|
114
|
-
>
|
|
115
|
-
{/* END CUSTOMIZATION */}
|
|
116
|
-
{(data.slides?.length === 0 || !data.slides) && isEditMode && (
|
|
117
|
-
<Message>
|
|
118
|
-
<div className="teaser-item default">
|
|
119
|
-
<img src={teaserTemplate} alt="" />
|
|
120
|
-
<p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
|
|
121
|
-
</div>
|
|
122
|
-
</Message>
|
|
123
|
-
)}
|
|
124
|
-
{data.slides?.length > 0 && (
|
|
125
|
-
<>
|
|
126
|
-
<div className="slider-wrapper">
|
|
127
|
-
{!data.hideArrows && data.slides?.length > 1 && (
|
|
128
|
-
<>
|
|
129
|
-
<PrevButton onClick={scrollPrev} disabled={prevBtnDisabled} />
|
|
130
|
-
<NextButton onClick={scrollNext} disabled={nextBtnDisabled} />
|
|
131
|
-
</>
|
|
132
|
-
)}
|
|
133
|
-
|
|
134
|
-
<div className="slider-viewport" ref={emblaRef}>
|
|
135
|
-
<div className="slider-container">
|
|
136
|
-
{data.slides &&
|
|
137
|
-
data.slides.map((item, index) => {
|
|
138
|
-
return (
|
|
139
|
-
<div key={item['@id']} className="slider-slide">
|
|
140
|
-
<Body
|
|
141
|
-
{...props}
|
|
142
|
-
key={item['@id']}
|
|
143
|
-
data={item}
|
|
144
|
-
isEditMode={isEditMode}
|
|
145
|
-
dataBlock={data}
|
|
146
|
-
index={index}
|
|
147
|
-
block={block}
|
|
148
|
-
openObjectBrowser={openObjectBrowser}
|
|
149
|
-
onChangeBlock={onChangeBlock}
|
|
150
|
-
isActive={selectedIndex === index}
|
|
151
|
-
/>
|
|
152
|
-
</div>
|
|
153
|
-
);
|
|
154
|
-
})}
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
{data.slides?.length > 1 && (
|
|
159
|
-
<div className="slider-dots">
|
|
160
|
-
{scrollSnaps.map((_, index) => (
|
|
161
|
-
<DotButton
|
|
162
|
-
key={index}
|
|
163
|
-
index={index}
|
|
164
|
-
onClick={() => scrollTo(index)}
|
|
165
|
-
className={'slider-dot'.concat(
|
|
166
|
-
index === selectedIndex ? ' slider-dot--selected' : '',
|
|
167
|
-
)}
|
|
168
|
-
/>
|
|
169
|
-
))}
|
|
170
|
-
</div>
|
|
171
|
-
)}
|
|
172
|
-
</>
|
|
173
|
-
)}
|
|
174
|
-
</div>
|
|
175
|
-
</>
|
|
176
|
-
);
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export default withBlockExtensions(SliderView);
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language selector component.
|
|
3
|
-
* @module components/LanguageSelector/LanguageSelector
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React from 'react';
|
|
7
|
-
import PropTypes from 'prop-types';
|
|
8
|
-
import { Link } from 'react-router-dom';
|
|
9
|
-
|
|
10
|
-
import { useSelector } from 'react-redux';
|
|
11
|
-
import cx from 'classnames';
|
|
12
|
-
import { find, map } from 'lodash';
|
|
13
|
-
|
|
14
|
-
import Helmet from '@plone/volto/helpers/Helmet/Helmet';
|
|
15
|
-
import langmap from '@plone/volto/helpers/LanguageMap/LanguageMap';
|
|
16
|
-
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
17
|
-
import { toReactIntlLang } from '@plone/volto/helpers/Utils/Utils';
|
|
18
|
-
|
|
19
|
-
import config from '@plone/volto/registry';
|
|
20
|
-
|
|
21
|
-
import { defineMessages, useIntl } from 'react-intl';
|
|
22
|
-
|
|
23
|
-
const messages = defineMessages({
|
|
24
|
-
switchLanguageTo: {
|
|
25
|
-
id: 'Switch to',
|
|
26
|
-
defaultMessage: 'Switch to',
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const LanguageSelector = (props) => {
|
|
31
|
-
const intl = useIntl();
|
|
32
|
-
const currentLang = useSelector((state) => state.intl.locale);
|
|
33
|
-
const translations = useSelector(
|
|
34
|
-
(state) => state.content.data?.['@components']?.translations?.items,
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const { settings } = config;
|
|
38
|
-
|
|
39
|
-
return settings.isMultilingual ? (
|
|
40
|
-
<div className="language-selector">
|
|
41
|
-
{map(settings.supportedLanguages, (lang) => {
|
|
42
|
-
const translation = find(translations, { language: lang });
|
|
43
|
-
return (
|
|
44
|
-
<Link
|
|
45
|
-
aria-label={`${intl.formatMessage(
|
|
46
|
-
messages.switchLanguageTo,
|
|
47
|
-
)} ${langmap[lang].nativeName.toLowerCase()}`}
|
|
48
|
-
className={cx({ selected: toReactIntlLang(lang) === currentLang })}
|
|
49
|
-
to={translation ? flattenToAppURL(translation['@id']) : `/${lang}`}
|
|
50
|
-
title={langmap[lang].nativeName}
|
|
51
|
-
onClick={() => {
|
|
52
|
-
props.onClickAction();
|
|
53
|
-
}}
|
|
54
|
-
key={`language-selector-${lang}`}
|
|
55
|
-
>
|
|
56
|
-
{langmap[lang].nativeName}
|
|
57
|
-
</Link>
|
|
58
|
-
);
|
|
59
|
-
})}
|
|
60
|
-
</div>
|
|
61
|
-
) : (
|
|
62
|
-
<Helmet>
|
|
63
|
-
<html lang={toReactIntlLang(settings.defaultLanguage)} />
|
|
64
|
-
</Helmet>
|
|
65
|
-
);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
LanguageSelector.propTypes = {
|
|
69
|
-
onClickAction: PropTypes.func,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
LanguageSelector.defaultProps = {
|
|
73
|
-
onClickAction: () => {},
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export default LanguageSelector;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OVERRIDE Data.jsx
|
|
3
|
-
* REASON: Add Refresh source content button.
|
|
4
|
-
* FILE: https://github.com/kitconcept/volto-slider-block/blob/74cb8f01394907ff7b765c74c4a43ceb793c1c95/packages/volto-slider-block/src/components/Data.jsx
|
|
5
|
-
* DATE: 2025-09-11
|
|
6
|
-
* DEVELOPER: @Tishasoumya-02
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import Data from '../../../../components/Blocks/Slider/Data';
|
|
10
|
-
|
|
11
|
-
export default Data;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OVERRIDE DefaultBody.jsx
|
|
3
|
-
* REASON: Adding Button and flagAlign in slider block.
|
|
4
|
-
* FILE: https://github.com/kitconcept/volto-slider-block/blob/master/src/components/DefaultBody.jsx
|
|
5
|
-
* DATE: 2023-08-02
|
|
6
|
-
* DEVELOPER: @iRohitSingh
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import SliderBody from '../../../../components/Blocks/Slider/DefaultBody';
|
|
10
|
-
|
|
11
|
-
export default SliderBody;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OVERRIDE LanguageSelector.js
|
|
3
|
-
* REASON: This theme uses a custom pre-@plone/components component
|
|
4
|
-
* SemanticUI-free located at the components folder.
|
|
5
|
-
* To override it, override the @kitconcept/volto-light-theme one instead of
|
|
6
|
-
* this one.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import LanguageSelector from '../../../../../components/LanguageSelector/LanguageSelector';
|
|
10
|
-
|
|
11
|
-
export default LanguageSelector;
|