@kitconcept/volto-light-theme 6.0.0-alpha.9 → 6.0.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 -7
- package/CHANGELOG.md +221 -0
- package/README.md +6 -5
- package/locales/de/LC_MESSAGES/volto.po +171 -38
- package/locales/en/LC_MESSAGES/volto.po +170 -37
- package/locales/es/LC_MESSAGES/volto.po +171 -38
- package/locales/eu/LC_MESSAGES/volto.po +171 -38
- package/locales/pt_BR/volto.po +171 -38
- package/locales/volto.pot +171 -38
- package/package.json +15 -6
- package/src/components/Blocks/EventMetadata/View.jsx +32 -26
- package/src/components/Blocks/Listing/DefaultTemplate.jsx +19 -14
- package/src/components/Blocks/Listing/GridTemplate.jsx +9 -12
- package/src/components/Blocks/Listing/SummaryTemplate.jsx +9 -7
- package/src/components/Blocks/Teaser/DefaultBody.jsx +93 -0
- package/src/components/Footer/ColumnLinks.tsx +35 -0
- package/src/components/Footer/Footer.tsx +32 -0
- package/src/components/Footer/slots/Colophon.tsx +24 -0
- package/src/components/Footer/slots/Copyright.tsx +65 -0
- package/src/components/Footer/slots/CoreFooter.tsx +82 -0
- package/src/components/Footer/slots/FollowUsLogoAndLinks.tsx +80 -0
- package/src/components/Footer/slots/FooterLogos.tsx +44 -0
- package/src/components/Header/Header.tsx +257 -0
- package/src/components/Logo/Logo.tsx +85 -0
- package/src/components/{Footer/FooterLogos.tsx → LogosContainer/LogosContainer.tsx} +16 -36
- package/src/components/MobileNavigation/MobileNavigation.jsx +53 -18
- package/src/components/Navigation/Navigation.jsx +14 -3
- package/src/components/SearchWidget/IntranetSearchWidget.jsx +32 -5
- package/src/components/SearchWidget/SearchWidget.jsx +1 -1
- package/src/components/StickyMenu/StickyMenu.tsx +36 -0
- package/src/components/Summary/DefaultSummary.jsx +16 -0
- package/src/components/Summary/EventSummary.jsx +38 -0
- package/src/components/Summary/FileSummary.jsx +24 -0
- package/src/components/Summary/NewsItemSummary.jsx +40 -0
- package/src/components/Tags/Tags.jsx +46 -0
- package/src/components/Theme/EventView.jsx +19 -25
- package/src/components/Theme/NewsItemView.jsx +13 -9
- package/src/components/Theming/Theming.tsx +20 -17
- package/src/components/Widgets/{BlockAlignmentWidget.tsx → BlockAlignment.tsx} +9 -2
- package/src/components/Widgets/{BlockWidthWidget.tsx → BlockWidth.tsx} +10 -3
- package/src/components/Widgets/BlocksObject.tsx +353 -0
- package/src/components/Widgets/{ButtonsWidget.tsx → Buttons.tsx} +45 -4
- package/src/components/Widgets/ColorContrastChecker.tsx +117 -0
- package/src/components/Widgets/ColorPicker.tsx +59 -0
- package/src/components/Widgets/{ColorPickerWidget.tsx → ColorSwatch.tsx} +5 -5
- package/src/components/Widgets/ObjectList.tsx +342 -0
- package/src/components/Widgets/{ThemingColorPicker.tsx → RACThemingColorPicker.tsx} +4 -0
- package/src/components/Widgets/{SizeWidget.tsx → Size.tsx} +9 -2
- package/src/components/Widgets/ThemeColorSwatch.tsx +17 -0
- package/src/components/Widgets/schema/footerLinksSchema.ts +64 -0
- package/src/components/Widgets/schema/footerLogosSchema.ts +98 -0
- package/src/components/Widgets/schema/headerActionsSchema.ts +64 -0
- package/src/components/Widgets/schema/iconLinkListSchema.ts +98 -0
- package/src/config/blocks.tsx +37 -17
- package/src/config/settings.ts +54 -12
- package/src/config/slots.ts +36 -1
- package/src/config/summary.ts +24 -0
- package/src/config/widgets.ts +57 -23
- package/src/customizations/volto/components/manage/Blocks/Teaser/DefaultBody.jsx +8 -0
- package/src/customizations/volto/components/theme/Tags/Tags.jsx +11 -0
- package/src/customizations/volto/components/theme/View/RenderBlocks.jsx +2 -1
- package/src/helpers/DndSortableList.tsx +138 -0
- package/src/helpers/dates.js +22 -0
- package/src/helpers/doesNodeContainClick.js +64 -0
- package/src/helpers/useLiveData.ts +29 -0
- package/src/index.ts +31 -2
- package/src/primitives/IconLinkList.tsx +69 -0
- package/src/primitives/LinkList.tsx +35 -0
- package/src/theme/_bgcolor-blocks-layout.scss +50 -12
- package/src/theme/_content.scss +6 -0
- package/src/theme/_footer.scss +294 -41
- package/src/theme/_header.scss +132 -19
- package/src/theme/_layout.scss +11 -1
- package/src/theme/_sitemap.scss +4 -0
- package/src/theme/_utils.scss +14 -1
- package/src/theme/_variables.scss +12 -3
- package/src/theme/_widgets.scss +100 -9
- package/src/theme/blocks/_eventMetadata.scss +5 -2
- package/src/theme/blocks/_grid.scss +3 -3
- package/src/theme/blocks/_highlight.scss +17 -44
- package/src/theme/blocks/_listing.scss +25 -16
- package/src/theme/blocks/_maps.scss +3 -3
- package/src/theme/blocks/_slider.scss +5 -1
- package/src/theme/main.scss +1 -0
- package/src/theme/sticky-menu.scss +50 -0
- package/src/types.d.ts +102 -0
- package/tsconfig.json +1 -1
- package/src/components/Footer/Footer.jsx +0 -115
- package/src/components/Footer/FooterLinks.tsx +0 -57
- package/src/components/Header/Header.jsx +0 -161
- package/src/components/Logo/Logo.jsx +0 -51
- package/src/components/Widgets/AlignWidget.jsx +0 -80
- package/src/components/Widgets/BackgroundColorWidget.tsx +0 -17
- package/src/components/Widgets/BlocksObjectWidget.tsx +0 -333
- package/src/components/Widgets/FooterLinksWidget.tsx +0 -106
- package/src/components/Widgets/FooterLogosWidget.tsx +0 -120
- package/src/static/container-query-polyfill.modern.js +0 -1
- package/src/types/index.d.ts +0 -1
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import isEmpty from 'lodash/isEmpty';
|
|
2
|
-
import { addAppURL, flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
3
|
-
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
4
|
-
import type { BlocksData } from '@plone/types';
|
|
5
|
-
import config from '@plone/volto/registry';
|
|
6
|
-
|
|
7
|
-
type FooterLinksProps = { links: BlocksData; siteActions: any; lang: string };
|
|
8
|
-
|
|
9
|
-
const FooterLinks = (props: FooterLinksProps) => {
|
|
10
|
-
const { lang, links, siteActions } = props;
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<ul className="footer-links">
|
|
14
|
-
{!isEmpty(links?.blocks)
|
|
15
|
-
? links.blocks_layout.items.map((itemId) => {
|
|
16
|
-
const link = links.blocks[itemId];
|
|
17
|
-
|
|
18
|
-
if (isEmpty(link) || !link.href) return null;
|
|
19
|
-
|
|
20
|
-
const title = link.title || link.href[0]['title'];
|
|
21
|
-
const href = flattenToAppURL(link.href[0]?.['@id']);
|
|
22
|
-
|
|
23
|
-
if (!href) return null;
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<li className="item" key={href}>
|
|
27
|
-
<UniversalLink href={href}>{title}</UniversalLink>
|
|
28
|
-
</li>
|
|
29
|
-
);
|
|
30
|
-
})
|
|
31
|
-
: siteActions?.length
|
|
32
|
-
? siteActions.map((item) => (
|
|
33
|
-
<li className="item" key={item.id}>
|
|
34
|
-
<UniversalLink
|
|
35
|
-
className="item"
|
|
36
|
-
href={
|
|
37
|
-
config.settings.isMultilingual
|
|
38
|
-
? `/${lang}/${
|
|
39
|
-
item.url
|
|
40
|
-
? flattenToAppURL(item.url)
|
|
41
|
-
: addAppURL(item.id)
|
|
42
|
-
}`
|
|
43
|
-
: item.url
|
|
44
|
-
? flattenToAppURL(item.url)
|
|
45
|
-
: addAppURL(item.id)
|
|
46
|
-
}
|
|
47
|
-
>
|
|
48
|
-
{item?.title}
|
|
49
|
-
</UniversalLink>
|
|
50
|
-
</li>
|
|
51
|
-
))
|
|
52
|
-
: null}
|
|
53
|
-
</ul>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export default FooterLinks;
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
// SemanticUI-free pre-@plone/components
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import { useSelector } from 'react-redux';
|
|
4
|
-
import { Container } from '@plone/components';
|
|
5
|
-
import MobileNavigation from '../MobileNavigation/MobileNavigation';
|
|
6
|
-
import { useIntl, defineMessages } from 'react-intl';
|
|
7
|
-
import config from '@plone/volto/registry';
|
|
8
|
-
import cx from 'classnames';
|
|
9
|
-
import IntranetSearchWidget from '../SearchWidget/IntranetSearchWidget';
|
|
10
|
-
|
|
11
|
-
import Anontools from '@plone/volto/components/theme/Anontools/Anontools';
|
|
12
|
-
import LanguageSelector from '@plone/volto/components/theme/LanguageSelector/LanguageSelector';
|
|
13
|
-
import Logo from '@plone/volto/components/theme/Logo/Logo';
|
|
14
|
-
import Navigation from '@plone/volto/components/theme/Navigation/Navigation';
|
|
15
|
-
import SearchWidget from '@plone/volto/components/theme/SearchWidget/SearchWidget';
|
|
16
|
-
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
17
|
-
|
|
18
|
-
import SlotRenderer from '@plone/volto/components/theme/SlotRenderer/SlotRenderer';
|
|
19
|
-
|
|
20
|
-
const messages = defineMessages({
|
|
21
|
-
siteLabel: {
|
|
22
|
-
id: 'siteLabel',
|
|
23
|
-
defaultMessage: ' ',
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const InternetHeader = ({ pathname, siteLabel, token, siteAction }) => {
|
|
28
|
-
return (
|
|
29
|
-
<>
|
|
30
|
-
<div className="header">
|
|
31
|
-
<div className="tools-wrapper">
|
|
32
|
-
<LanguageSelector />
|
|
33
|
-
|
|
34
|
-
<div className="tools">
|
|
35
|
-
{!token && <Anontools />}
|
|
36
|
-
{siteAction &&
|
|
37
|
-
siteAction.map((item) => (
|
|
38
|
-
<UniversalLink key={item.url} href={item.url}>
|
|
39
|
-
{item.title}
|
|
40
|
-
</UniversalLink>
|
|
41
|
-
))}
|
|
42
|
-
</div>
|
|
43
|
-
{siteLabel && (
|
|
44
|
-
<div className="intranet">
|
|
45
|
-
<p>{siteLabel}</p>
|
|
46
|
-
</div>
|
|
47
|
-
)}
|
|
48
|
-
</div>
|
|
49
|
-
<div className="logo-nav-wrapper">
|
|
50
|
-
<div className="logo">
|
|
51
|
-
<Logo />
|
|
52
|
-
</div>
|
|
53
|
-
<Navigation pathname={pathname} />
|
|
54
|
-
<MobileNavigation pathname={pathname} />
|
|
55
|
-
<div className="search-wrapper navigation-desktop">
|
|
56
|
-
<div className="search">
|
|
57
|
-
<SearchWidget />
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
</>
|
|
63
|
-
);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const IntranetHeader = ({ pathname, siteLabel, token, siteAction }) => {
|
|
67
|
-
return (
|
|
68
|
-
<>
|
|
69
|
-
<div className="header">
|
|
70
|
-
<div className="tools-wrapper">
|
|
71
|
-
<LanguageSelector />
|
|
72
|
-
|
|
73
|
-
<div className="tools">
|
|
74
|
-
{!token && <Anontools />}
|
|
75
|
-
{siteAction &&
|
|
76
|
-
siteAction.map((item) => (
|
|
77
|
-
<UniversalLink key={item.url} href={item.url}>
|
|
78
|
-
{item.title}
|
|
79
|
-
</UniversalLink>
|
|
80
|
-
))}
|
|
81
|
-
</div>
|
|
82
|
-
{siteLabel && (
|
|
83
|
-
<div className="intranet">
|
|
84
|
-
<p>{siteLabel}</p>
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
</div>
|
|
88
|
-
<div className="logo-nav-wrapper">
|
|
89
|
-
<div className="logo">
|
|
90
|
-
<Logo />
|
|
91
|
-
</div>
|
|
92
|
-
<div className="search-wrapper">
|
|
93
|
-
<div className="search">
|
|
94
|
-
<IntranetSearchWidget />
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
<Navigation pathname={pathname} />
|
|
98
|
-
<MobileNavigation pathname={pathname} />
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
</>
|
|
102
|
-
);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const Header = (props) => {
|
|
106
|
-
const { pathname } = props;
|
|
107
|
-
let siteLabel = config.settings.siteLabel;
|
|
108
|
-
const intranetHeader = config.settings.intranetHeader;
|
|
109
|
-
const token = useSelector((state) => state.userSession.token);
|
|
110
|
-
const content = useSelector((state) => state.content.data);
|
|
111
|
-
const siteAction = useSelector(
|
|
112
|
-
(state) => state.content.data?.['@components']?.actions?.site_actions,
|
|
113
|
-
);
|
|
114
|
-
const navRoot = useSelector((state) => state.navroot?.data?.navroot);
|
|
115
|
-
const intl = useIntl();
|
|
116
|
-
const translatedSiteLabel = intl.formatMessage(messages.siteLabel);
|
|
117
|
-
|
|
118
|
-
siteLabel =
|
|
119
|
-
siteLabel &&
|
|
120
|
-
(translatedSiteLabel !== 'siteLabel' && translatedSiteLabel !== ' '
|
|
121
|
-
? translatedSiteLabel
|
|
122
|
-
: siteLabel);
|
|
123
|
-
|
|
124
|
-
return (
|
|
125
|
-
<>
|
|
126
|
-
<SlotRenderer name="aboveHeader" content={content} navRoot={navRoot} />
|
|
127
|
-
<header
|
|
128
|
-
className={cx('header-wrapper', { 'intranet-header': intranetHeader })}
|
|
129
|
-
>
|
|
130
|
-
<Container layout>
|
|
131
|
-
{intranetHeader ? (
|
|
132
|
-
<IntranetHeader
|
|
133
|
-
pathname={pathname}
|
|
134
|
-
siteLabel={siteLabel}
|
|
135
|
-
token={token}
|
|
136
|
-
siteAction={siteAction}
|
|
137
|
-
/>
|
|
138
|
-
) : (
|
|
139
|
-
<InternetHeader
|
|
140
|
-
pathname={pathname}
|
|
141
|
-
siteLabel={siteLabel}
|
|
142
|
-
token={token}
|
|
143
|
-
siteAction={siteAction}
|
|
144
|
-
/>
|
|
145
|
-
)}
|
|
146
|
-
</Container>
|
|
147
|
-
</header>
|
|
148
|
-
</>
|
|
149
|
-
);
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
Header.propTypes = {
|
|
153
|
-
token: PropTypes.string,
|
|
154
|
-
pathname: PropTypes.string.isRequired,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
Header.defaultProps = {
|
|
158
|
-
token: null,
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
export default Header;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// SemanticUI-free pre-@plone/components
|
|
2
|
-
import { defineMessages, useIntl } from 'react-intl';
|
|
3
|
-
import { useSelector } from 'react-redux';
|
|
4
|
-
import { Link } from 'react-router-dom';
|
|
5
|
-
import LogoImage from '@plone/volto/components/theme/Logo/Logo.svg';
|
|
6
|
-
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
7
|
-
|
|
8
|
-
const messages = defineMessages({
|
|
9
|
-
home: {
|
|
10
|
-
id: 'Home',
|
|
11
|
-
defaultMessage: 'Home',
|
|
12
|
-
},
|
|
13
|
-
logoOf: {
|
|
14
|
-
id: 'Logo of',
|
|
15
|
-
defaultMessage: 'Logo of',
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const Logo = () => {
|
|
20
|
-
const intl = useIntl();
|
|
21
|
-
const site = useSelector((state) => state.site.data);
|
|
22
|
-
const navroot = useSelector((state) => state.navroot.data);
|
|
23
|
-
const navRootPath = flattenToAppURL(navroot?.navroot?.['@id']) || '/';
|
|
24
|
-
const navRootLogo = navroot?.navroot?.logo?.download || null;
|
|
25
|
-
const navRootLogoWidth = navroot?.navroot?.logo?.width || null;
|
|
26
|
-
const navRootLogoHeight = navroot?.navroot?.logo?.height || null;
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<Link to={navRootPath} aria-label={intl.formatMessage(messages.home)}>
|
|
30
|
-
<img
|
|
31
|
-
src={
|
|
32
|
-
navRootLogo
|
|
33
|
-
? flattenToAppURL(navRootLogo)
|
|
34
|
-
: site['plone.site_logo']
|
|
35
|
-
? flattenToAppURL(site['plone.site_logo'])
|
|
36
|
-
: LogoImage
|
|
37
|
-
}
|
|
38
|
-
width={navRootLogoWidth}
|
|
39
|
-
height={navRootLogoHeight}
|
|
40
|
-
alt={
|
|
41
|
-
intl.formatMessage(messages.logoOf) + ' ' + site['plone.site_title']
|
|
42
|
-
}
|
|
43
|
-
title={
|
|
44
|
-
intl.formatMessage(messages.logoOf) + ' ' + site['plone.site_title']
|
|
45
|
-
}
|
|
46
|
-
/>
|
|
47
|
-
</Link>
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export default Logo;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { defineMessages, useIntl } from 'react-intl';
|
|
3
|
-
import { FormFieldWrapper } from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
4
|
-
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
5
|
-
import { Button } from 'semantic-ui-react';
|
|
6
|
-
import imageLeftSVG from '@plone/volto/icons/image-left.svg';
|
|
7
|
-
import imageRightSVG from '@plone/volto/icons/image-right.svg';
|
|
8
|
-
import imageFitSVG from '@plone/volto/icons/image-fit.svg';
|
|
9
|
-
import imageWideSVG from '@plone/volto/icons/image-wide.svg';
|
|
10
|
-
import imageFullSVG from '@plone/volto/icons/image-full.svg';
|
|
11
|
-
|
|
12
|
-
const messages = defineMessages({
|
|
13
|
-
left: {
|
|
14
|
-
id: 'Left',
|
|
15
|
-
defaultMessage: 'Left',
|
|
16
|
-
},
|
|
17
|
-
right: {
|
|
18
|
-
id: 'Right',
|
|
19
|
-
defaultMessage: 'Right',
|
|
20
|
-
},
|
|
21
|
-
center: {
|
|
22
|
-
id: 'Center',
|
|
23
|
-
defaultMessage: 'Center',
|
|
24
|
-
},
|
|
25
|
-
wide: {
|
|
26
|
-
id: 'Wide',
|
|
27
|
-
defaultMessage: 'Wide',
|
|
28
|
-
},
|
|
29
|
-
full: {
|
|
30
|
-
id: 'Full',
|
|
31
|
-
defaultMessage: 'Full',
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const AlignWidget = (props) => {
|
|
36
|
-
const intl = useIntl();
|
|
37
|
-
|
|
38
|
-
const {
|
|
39
|
-
id,
|
|
40
|
-
onChange,
|
|
41
|
-
actions = ['left', 'right', 'center', 'full'],
|
|
42
|
-
value,
|
|
43
|
-
} = props;
|
|
44
|
-
|
|
45
|
-
React.useEffect(() => {
|
|
46
|
-
if (!props.value && props.default) {
|
|
47
|
-
props.onChange(props.id, props.default);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const ICON_MAP = {
|
|
52
|
-
left: imageLeftSVG,
|
|
53
|
-
right: imageRightSVG,
|
|
54
|
-
center: imageFitSVG,
|
|
55
|
-
wide: imageWideSVG,
|
|
56
|
-
full: imageFullSVG,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<FormFieldWrapper {...props} className="align-widget">
|
|
61
|
-
<div className="align-buttons">
|
|
62
|
-
{actions.map((action) => (
|
|
63
|
-
<Button.Group key={action}>
|
|
64
|
-
<Button
|
|
65
|
-
icon
|
|
66
|
-
basic
|
|
67
|
-
aria-label={intl.formatMessage(messages[action])}
|
|
68
|
-
onClick={() => onChange(id, action)}
|
|
69
|
-
active={(action === 'center' && !value) || value === action}
|
|
70
|
-
>
|
|
71
|
-
<Icon name={ICON_MAP[action]} size="24px" />
|
|
72
|
-
</Button>
|
|
73
|
-
</Button.Group>
|
|
74
|
-
))}
|
|
75
|
-
</div>
|
|
76
|
-
</FormFieldWrapper>
|
|
77
|
-
);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export default AlignWidget;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import ColorPickerWidget from '@plone/volto/components/manage/Widgets/ColorPickerWidget';
|
|
2
|
-
import config from '@plone/volto/registry';
|
|
3
|
-
import type { ColorPickerWidgetProps } from '@plone/volto/components/manage/Widgets/ColorPickerWidget';
|
|
4
|
-
|
|
5
|
-
const BackgroundColorWidget = (props: ColorPickerWidgetProps) => {
|
|
6
|
-
const colors: ColorPickerWidgetProps['colors'] = config.blocks.themes;
|
|
7
|
-
|
|
8
|
-
const defaultValue = colors.find(
|
|
9
|
-
(color) => color.name === config.settings.defaultBackgroundColor,
|
|
10
|
-
)?.style;
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<ColorPickerWidget {...props} default={defaultValue} colors={colors} />
|
|
14
|
-
);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default BackgroundColorWidget;
|
|
@@ -1,333 +0,0 @@
|
|
|
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;
|