@eeacms/volto-n2k 1.1.12 → 1.2.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.md +16 -0
- package/package.json +1 -1
- package/src/components/manage/Blocks/TilesImages/Edit.jsx +6 -5
- package/src/components/manage/Blocks/TilesImages/View.jsx +10 -32
- package/src/components/manage/Blocks/TilesImages/index.js +16 -0
- package/src/components/manage/Blocks/TilesImages/schema.js +24 -12
- package/src/components/manage/Blocks/TilesImages/variations/Default/Copyright.jsx +36 -0
- package/src/components/manage/Blocks/TilesImages/variations/Default/Default.jsx +55 -0
- package/src/components/manage/Blocks/TilesImages/variations/ImageGallery/ImageGallery.jsx +108 -0
- package/src/components/manage/Blocks/TilesImages/variations/ImageGallery/styles.less +21 -0
- /package/src/components/manage/Blocks/TilesImages/{styles.less → variations/Default/styles.less} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [1.2.1](https://github.com/eea/volto-n2k/compare/1.2.0...1.2.1) - 3 February 2026
|
|
8
|
+
|
|
9
|
+
#### :bug: Bug Fixes
|
|
10
|
+
|
|
11
|
+
- fix: edit style [nileshgulia1 - [`a823420`](https://github.com/eea/volto-n2k/commit/a823420dfc8cd6fc4421d2888028faaf25d2fffa)]
|
|
12
|
+
|
|
13
|
+
### [1.2.0](https://github.com/eea/volto-n2k/compare/1.1.12...1.2.0) - 3 February 2026
|
|
14
|
+
|
|
15
|
+
#### :rocket: New Features
|
|
16
|
+
|
|
17
|
+
- feat: add new variation for ImageGallery for Case Studies CT [nileshgulia1 - [`48173c5`](https://github.com/eea/volto-n2k/commit/48173c5626b94597e57af236ecb14a55383f63b1)]
|
|
18
|
+
- feat: add copyright text to tiles images refs-296409 [nileshgulia1 - [`614187b`](https://github.com/eea/volto-n2k/commit/614187b2d5c2cffcb1e2bf74ca72e88b2886520d)]
|
|
19
|
+
|
|
20
|
+
#### :hammer_and_wrench: Others
|
|
21
|
+
|
|
22
|
+
- bump v1.2.0 [nileshgulia1 - [`f94e2ff`](https://github.com/eea/volto-n2k/commit/f94e2ff9b244c126dff1930dcef265567712f4bc)]
|
|
7
23
|
### [1.1.12](https://github.com/eea/volto-n2k/compare/1.1.11...1.1.12) - 27 January 2026
|
|
8
24
|
|
|
9
25
|
#### :hammer_and_wrench: Others
|
package/package.json
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { SidebarPortal } from '@plone/volto/components';
|
|
3
|
-
import
|
|
3
|
+
import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm';
|
|
4
4
|
import TilesImagesView from './View';
|
|
5
5
|
import getSchema from './schema';
|
|
6
|
-
import './styles.less';
|
|
7
6
|
|
|
8
7
|
const Edit = (props) => {
|
|
9
|
-
const { selected = false } = props;
|
|
10
|
-
const schema = getSchema();
|
|
8
|
+
const { selected = false, data = {} } = props;
|
|
9
|
+
const schema = getSchema({ formData: data });
|
|
11
10
|
|
|
12
11
|
return (
|
|
13
12
|
<>
|
|
14
13
|
<TilesImagesView {...props} mode="edit" />
|
|
15
14
|
<SidebarPortal selected={selected}>
|
|
16
|
-
<
|
|
15
|
+
<BlockDataForm
|
|
17
16
|
schema={schema}
|
|
18
17
|
title={schema.title}
|
|
19
18
|
onChangeField={(id, value) => {
|
|
@@ -22,6 +21,8 @@ const Edit = (props) => {
|
|
|
22
21
|
[id]: value,
|
|
23
22
|
});
|
|
24
23
|
}}
|
|
24
|
+
onChangeBlock={props.onChangeBlock}
|
|
25
|
+
block={props.block}
|
|
25
26
|
formData={props.data}
|
|
26
27
|
/>
|
|
27
28
|
</SidebarPortal>
|
|
@@ -1,38 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import './styles.less';
|
|
2
|
+
import { withBlockExtensions } from '@plone/volto/helpers/Extensions';
|
|
3
|
+
import config from '@plone/volto/registry';
|
|
5
4
|
|
|
6
5
|
const View = (props) => {
|
|
7
|
-
const {
|
|
8
|
-
const images = data.images || [];
|
|
6
|
+
const { mode = 'view', variation } = props;
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
className={cx('p-image', {
|
|
17
|
-
'with-border': data.hasBorder ?? true,
|
|
18
|
-
'rounded-border': data.rounded ?? true,
|
|
19
|
-
})}
|
|
20
|
-
>
|
|
21
|
-
<UniversalLink href={image.link || '#'} title={image.title}>
|
|
22
|
-
<img
|
|
23
|
-
src={`${image.image}/@@images/image/mini`}
|
|
24
|
-
alt={image.title}
|
|
25
|
-
style={
|
|
26
|
-
data.size
|
|
27
|
-
? { width: `${data.size}px`, height: `${data.size}px` }
|
|
28
|
-
: {}
|
|
29
|
-
}
|
|
30
|
-
/>
|
|
31
|
-
</UniversalLink>
|
|
32
|
-
</p>
|
|
33
|
-
))}
|
|
34
|
-
</div>
|
|
35
|
-
);
|
|
8
|
+
const variations =
|
|
9
|
+
config.blocks?.blocksConfig['tiles_images']?.variations || [];
|
|
10
|
+
const defaultVariation = variations.filter((item) => item.isDefault)?.[0];
|
|
11
|
+
const Template = variation?.template ?? defaultVariation?.template ?? null;
|
|
12
|
+
|
|
13
|
+
return <Template {...props} mode={mode} />;
|
|
36
14
|
};
|
|
37
15
|
|
|
38
|
-
export default View;
|
|
16
|
+
export default withBlockExtensions(View);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import TilesImagesEdit from './Edit';
|
|
2
|
+
import ImageGallery from './variations/ImageGallery/ImageGallery';
|
|
3
|
+
import DefaultView from './variations/Default/Default';
|
|
2
4
|
import TilesImagesView from './View';
|
|
3
5
|
import worldSVG from '@plone/volto/icons/world.svg';
|
|
4
6
|
|
|
@@ -18,6 +20,20 @@ export default function applyConfig(config) {
|
|
|
18
20
|
addPermission: [],
|
|
19
21
|
view: [],
|
|
20
22
|
},
|
|
23
|
+
variations: [
|
|
24
|
+
{
|
|
25
|
+
id: 'default',
|
|
26
|
+
isDefault: true,
|
|
27
|
+
title: 'Default',
|
|
28
|
+
template: DefaultView,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'imageGallery',
|
|
32
|
+
isDefault: false,
|
|
33
|
+
title: 'ImageGallery',
|
|
34
|
+
template: ImageGallery,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
21
37
|
};
|
|
22
38
|
return config;
|
|
23
39
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
const imageSchema = {
|
|
1
|
+
const imageSchema = ({ formData }) => ({
|
|
2
2
|
title: 'Image',
|
|
3
3
|
fieldsets: [
|
|
4
4
|
{
|
|
5
5
|
id: 'default',
|
|
6
6
|
title: 'Default',
|
|
7
|
-
fields: [
|
|
7
|
+
fields: [
|
|
8
|
+
'image',
|
|
9
|
+
...(formData?.variation !== 'imageGallery' ? ['link'] : []),
|
|
10
|
+
'title',
|
|
11
|
+
'copyright',
|
|
12
|
+
],
|
|
8
13
|
},
|
|
9
14
|
],
|
|
10
15
|
properties: {
|
|
11
16
|
image: {
|
|
12
|
-
title: '
|
|
17
|
+
title: 'Image',
|
|
13
18
|
widget: 'object_by_path',
|
|
14
19
|
},
|
|
15
20
|
link: {
|
|
@@ -19,11 +24,14 @@ const imageSchema = {
|
|
|
19
24
|
title: {
|
|
20
25
|
title: 'Title',
|
|
21
26
|
},
|
|
27
|
+
copyright: {
|
|
28
|
+
title: 'Copyright',
|
|
29
|
+
},
|
|
22
30
|
},
|
|
23
|
-
required: [
|
|
24
|
-
};
|
|
31
|
+
required: [],
|
|
32
|
+
});
|
|
25
33
|
|
|
26
|
-
export default function getSchema() {
|
|
34
|
+
export default function getSchema({ formData }) {
|
|
27
35
|
return {
|
|
28
36
|
title: 'Tiles images',
|
|
29
37
|
fieldsets: [
|
|
@@ -32,11 +40,15 @@ export default function getSchema() {
|
|
|
32
40
|
title: 'Default',
|
|
33
41
|
fields: ['theme', 'images'],
|
|
34
42
|
},
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
...(formData?.variation === 'default'
|
|
44
|
+
? [
|
|
45
|
+
{
|
|
46
|
+
id: 'advanced',
|
|
47
|
+
title: 'Advanced',
|
|
48
|
+
fields: ['size', 'hasBorder', 'rounded'],
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
: []),
|
|
40
52
|
],
|
|
41
53
|
properties: {
|
|
42
54
|
size: {
|
|
@@ -65,7 +77,7 @@ export default function getSchema() {
|
|
|
65
77
|
images: {
|
|
66
78
|
title: 'Images',
|
|
67
79
|
widget: 'object_list',
|
|
68
|
-
schema: imageSchema,
|
|
80
|
+
schema: imageSchema({ formData }),
|
|
69
81
|
},
|
|
70
82
|
},
|
|
71
83
|
required: [],
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
Copyright.propTypes = {
|
|
5
|
+
copyrightPosition: PropTypes.oneOf(['left', 'right']),
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function Copyright({ children, ...rest }) {
|
|
9
|
+
return (
|
|
10
|
+
<div className={`eea copyright ${rest.copyrightPosition}`}>
|
|
11
|
+
<div className={'wrapper'}>{children}</div>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
Copyright.Prefix = ({ children, ...rest }) =>
|
|
17
|
+
children ? (
|
|
18
|
+
<span {...rest} className={'icon-prefix'}>
|
|
19
|
+
{children}
|
|
20
|
+
</span>
|
|
21
|
+
) : (
|
|
22
|
+
''
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
Copyright.Icon = ({ children, ...rest }) => (
|
|
26
|
+
<span {...rest} className={'icon-wrapper'}>
|
|
27
|
+
{children}
|
|
28
|
+
</span>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
Copyright.Text = ({ children, ...rest }) => (
|
|
32
|
+
<span {...rest} className={'icon-content'}>
|
|
33
|
+
{children}
|
|
34
|
+
</span>
|
|
35
|
+
);
|
|
36
|
+
export default Copyright;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { UniversalLink } from '@plone/volto/components';
|
|
3
|
+
import cx from 'classnames';
|
|
4
|
+
import './styles.less';
|
|
5
|
+
import Copyright from './Copyright';
|
|
6
|
+
|
|
7
|
+
const DefaultView = (props) => {
|
|
8
|
+
const { mode = 'view', data = {} } = props;
|
|
9
|
+
|
|
10
|
+
const images = data.images || [];
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={cx('tiles-images', mode, data.theme || 'light')}>
|
|
14
|
+
{mode === 'edit' && !images.length ? <p>Tiles images block</p> : ''}
|
|
15
|
+
{images.map((image) => {
|
|
16
|
+
const { copyright } = image;
|
|
17
|
+
return (
|
|
18
|
+
<p
|
|
19
|
+
key={`tile-${image.title}`}
|
|
20
|
+
className={cx('p-image', {
|
|
21
|
+
'with-border': data.hasBorder ?? true,
|
|
22
|
+
'rounded-border': data.rounded ?? true,
|
|
23
|
+
})}
|
|
24
|
+
>
|
|
25
|
+
<UniversalLink href={image.link || '#'} title={image.title}>
|
|
26
|
+
<>
|
|
27
|
+
<img
|
|
28
|
+
src={`${image.image}/@@images/image/mini`}
|
|
29
|
+
alt={image.title}
|
|
30
|
+
style={
|
|
31
|
+
data.size
|
|
32
|
+
? { width: `${data.size}px`, height: `${data.size}px` }
|
|
33
|
+
: {}
|
|
34
|
+
}
|
|
35
|
+
/>
|
|
36
|
+
<div className={`copyright-wrapper ${'left'}`}>
|
|
37
|
+
{copyright ? (
|
|
38
|
+
<Copyright copyrightPosition={'left'}>
|
|
39
|
+
<Copyright.Icon>@</Copyright.Icon>
|
|
40
|
+
<Copyright.Text>{copyright}</Copyright.Text>
|
|
41
|
+
</Copyright>
|
|
42
|
+
) : (
|
|
43
|
+
''
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
</>
|
|
47
|
+
</UniversalLink>
|
|
48
|
+
</p>
|
|
49
|
+
);
|
|
50
|
+
})}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default DefaultView;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import loadable from '@loadable/component';
|
|
3
|
+
import { Modal, Image } from 'semantic-ui-react';
|
|
4
|
+
import cx from 'classnames';
|
|
5
|
+
import 'slick-carousel/slick/slick.css';
|
|
6
|
+
import 'slick-carousel/slick/slick-theme.css';
|
|
7
|
+
|
|
8
|
+
import './styles.less';
|
|
9
|
+
|
|
10
|
+
const Slider = loadable(() => import('react-slick'));
|
|
11
|
+
|
|
12
|
+
const ImageGallery = (props) => {
|
|
13
|
+
const { data = {}, mode } = props;
|
|
14
|
+
const items = data.images || [];
|
|
15
|
+
const [open, setOpen] = React.useState(false);
|
|
16
|
+
const [slideIndex, setSlideIndex] = React.useState(0);
|
|
17
|
+
|
|
18
|
+
const [updateCount, setUpdateCount] = React.useState(0);
|
|
19
|
+
const sliderRef = React.useRef(null);
|
|
20
|
+
|
|
21
|
+
const carouselSettings = React.useMemo(
|
|
22
|
+
() => ({
|
|
23
|
+
afterChange: () => setUpdateCount(updateCount + 1),
|
|
24
|
+
beforeChange: (current, next) => setSlideIndex(next),
|
|
25
|
+
infinite: true,
|
|
26
|
+
slidesToShow: 1,
|
|
27
|
+
slidesToScroll: 1,
|
|
28
|
+
dots: false,
|
|
29
|
+
arrows: true,
|
|
30
|
+
adaptiveHeight: true,
|
|
31
|
+
autoplay: false,
|
|
32
|
+
fade: false,
|
|
33
|
+
useTransform: false,
|
|
34
|
+
initialSlide: slideIndex,
|
|
35
|
+
}),
|
|
36
|
+
[slideIndex, setSlideIndex, updateCount],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const handleClick = () => {
|
|
40
|
+
if (items.length) {
|
|
41
|
+
setSlideIndex(0);
|
|
42
|
+
setOpen(true);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const image = items[slideIndex];
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className="image-gallery">
|
|
50
|
+
<div
|
|
51
|
+
tabIndex={0}
|
|
52
|
+
role="button"
|
|
53
|
+
onKeyDown={handleClick}
|
|
54
|
+
onClick={handleClick}
|
|
55
|
+
>
|
|
56
|
+
<Image
|
|
57
|
+
src={`${items[0]?.image}/@@images/image/preview`}
|
|
58
|
+
alt={items[0]?.title}
|
|
59
|
+
className={cx('preview-image', {
|
|
60
|
+
'image-gallery-preview': mode === 'edit',
|
|
61
|
+
})}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
{mode === 'view' ? (
|
|
65
|
+
<Modal
|
|
66
|
+
closeIcon
|
|
67
|
+
open={open}
|
|
68
|
+
className="slider-modal"
|
|
69
|
+
onClose={() => setOpen(false)}
|
|
70
|
+
onOpen={() => setOpen(true)}
|
|
71
|
+
>
|
|
72
|
+
<Modal.Content>
|
|
73
|
+
<h3>{image?.title}</h3>
|
|
74
|
+
<p>{image?.description}</p>
|
|
75
|
+
<Slider {...carouselSettings} ref={sliderRef}>
|
|
76
|
+
{items.map((item, i) => {
|
|
77
|
+
return item.copyright ? (
|
|
78
|
+
<div key={i}>
|
|
79
|
+
<div className="image-slide">
|
|
80
|
+
<div className="image-rights">@ {item.copyright}</div>
|
|
81
|
+
<Image
|
|
82
|
+
src={`${item.image}/@@images/image/larger`}
|
|
83
|
+
alt={item?.title}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
) : (
|
|
88
|
+
<Image
|
|
89
|
+
key={i}
|
|
90
|
+
src={`${item.image}/@@images/image/larger`}
|
|
91
|
+
alt={item?.title}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
})}
|
|
95
|
+
</Slider>
|
|
96
|
+
<div className="slide-image-count">
|
|
97
|
+
<strong>{slideIndex + 1}</strong> of {items.length}
|
|
98
|
+
</div>
|
|
99
|
+
</Modal.Content>
|
|
100
|
+
</Modal>
|
|
101
|
+
) : (
|
|
102
|
+
<p>Save the block to preview the Image Gallery Carousel.</p>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export default ImageGallery;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.image-slide {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
|
|
5
|
+
.image-rights {
|
|
6
|
+
position: absolute;
|
|
7
|
+
z-index: 100;
|
|
8
|
+
right: 0em;
|
|
9
|
+
bottom: 0em;
|
|
10
|
+
left: 0em;
|
|
11
|
+
padding: 10px;
|
|
12
|
+
// background: rgba(0, 0, 0, 0.5); /* optional: semi-transparent background */
|
|
13
|
+
color: white; /* text color */
|
|
14
|
+
font-size: 14px; /* adjust font size as needed */
|
|
15
|
+
text-align: left; /* optional: center the text */
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.image-gallery-preview {
|
|
20
|
+
width: auto !important;
|
|
21
|
+
}
|
/package/src/components/manage/Blocks/TilesImages/{styles.less → variations/Default/styles.less}
RENAMED
|
File without changes
|