@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
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { BlockEditProps } from '@plone/types';
|
|
2
|
+
import { defineMessages } from 'react-intl';
|
|
3
|
+
import type { IntlShape } from 'react-intl';
|
|
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
|
+
description: {
|
|
19
|
+
id: 'Description',
|
|
20
|
+
defaultMessage: 'Description',
|
|
21
|
+
},
|
|
22
|
+
icon: {
|
|
23
|
+
id: 'Item icon',
|
|
24
|
+
defaultMessage: 'Item icon',
|
|
25
|
+
},
|
|
26
|
+
item: {
|
|
27
|
+
id: 'Item',
|
|
28
|
+
defaultMessage: 'Item',
|
|
29
|
+
},
|
|
30
|
+
addItem: {
|
|
31
|
+
id: 'Add item',
|
|
32
|
+
defaultMessage: 'Add item',
|
|
33
|
+
},
|
|
34
|
+
headline: {
|
|
35
|
+
id: 'Headline',
|
|
36
|
+
defaultMessage: 'Headline',
|
|
37
|
+
},
|
|
38
|
+
hideDescription: {
|
|
39
|
+
id: 'Hide description',
|
|
40
|
+
defaultMessage: 'Hide description',
|
|
41
|
+
},
|
|
42
|
+
settings: {
|
|
43
|
+
id: 'Settings',
|
|
44
|
+
defaultMessage: 'Settings',
|
|
45
|
+
},
|
|
46
|
+
openLinkInNewTab: {
|
|
47
|
+
id: 'Open in a new tab',
|
|
48
|
+
defaultMessage: 'Open in a new tab',
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export function iconLinkListSchema({
|
|
53
|
+
props,
|
|
54
|
+
intl,
|
|
55
|
+
}: {
|
|
56
|
+
props: BlockEditProps;
|
|
57
|
+
intl: IntlShape;
|
|
58
|
+
}) {
|
|
59
|
+
return {
|
|
60
|
+
title: intl.formatMessage(messages.item),
|
|
61
|
+
addMessage: intl.formatMessage(messages.addItem),
|
|
62
|
+
fieldsets: [
|
|
63
|
+
{
|
|
64
|
+
id: 'default',
|
|
65
|
+
title: 'Default',
|
|
66
|
+
fields: ['title', 'icon', 'alt', 'href', 'openLinkInNewTab'],
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
|
|
70
|
+
properties: {
|
|
71
|
+
title: {
|
|
72
|
+
title: intl.formatMessage(messages.title),
|
|
73
|
+
},
|
|
74
|
+
icon: {
|
|
75
|
+
title: intl.formatMessage(messages.icon),
|
|
76
|
+
widget: 'object_browser',
|
|
77
|
+
selectedItemAttrs: ['Title', 'Description', 'image_field', '@type'],
|
|
78
|
+
mode: 'image',
|
|
79
|
+
allowExternals: true,
|
|
80
|
+
},
|
|
81
|
+
alt: {
|
|
82
|
+
title: intl.formatMessage(messages.AltText),
|
|
83
|
+
},
|
|
84
|
+
href: {
|
|
85
|
+
title: intl.formatMessage(messages.Target),
|
|
86
|
+
widget: 'object_browser',
|
|
87
|
+
mode: 'link',
|
|
88
|
+
selectedItemAttrs: ['Title', 'Description'],
|
|
89
|
+
allowExternals: true,
|
|
90
|
+
},
|
|
91
|
+
openLinkInNewTab: {
|
|
92
|
+
title: intl.formatMessage(messages.openLinkInNewTab),
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: [],
|
|
97
|
+
};
|
|
98
|
+
}
|
package/src/config/blocks.tsx
CHANGED
|
@@ -39,6 +39,7 @@ import { tocBlockSchemaEnhancer } from '../components/Blocks/Toc/schema';
|
|
|
39
39
|
import { mapsBlockSchemaEnhancer } from '../components/Blocks/Maps/schema';
|
|
40
40
|
import { sliderBlockSchemaEnhancer } from '../components/Blocks/Slider/schema';
|
|
41
41
|
import EventMetadataView from '../components/Blocks/EventMetadata/View';
|
|
42
|
+
import isEmpty from 'lodash/isEmpty';
|
|
42
43
|
|
|
43
44
|
declare module '@plone/types' {
|
|
44
45
|
export interface BlocksConfigData {
|
|
@@ -131,15 +132,23 @@ export default function install(config: ConfigType) {
|
|
|
131
132
|
},
|
|
132
133
|
];
|
|
133
134
|
|
|
134
|
-
function blockThemesEnhancer(data) {
|
|
135
|
+
function blockThemesEnhancer({ data, container }) {
|
|
135
136
|
if (!data['@type']) return {};
|
|
137
|
+
const blockConfig = config.blocks.blocksConfig[data['@type']];
|
|
138
|
+
if (!blockConfig) return {};
|
|
139
|
+
const blockStyleDefinitions =
|
|
140
|
+
// We look up for the blockThemes in the block's config, then in the global config
|
|
141
|
+
// We keep `colors` for BBB, but `themes` should be used
|
|
142
|
+
blockConfig.themes || blockConfig.colors || config.blocks.themes || [];
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
!isEmpty(container) &&
|
|
146
|
+
container.theme &&
|
|
147
|
+
(!data.theme || data.theme === 'default')
|
|
148
|
+
) {
|
|
149
|
+
return findStyleByName(blockStyleDefinitions, container.theme);
|
|
150
|
+
}
|
|
136
151
|
if (data.theme) {
|
|
137
|
-
const blockConfig = config.blocks.blocksConfig[data['@type']];
|
|
138
|
-
if (!blockConfig) return {};
|
|
139
|
-
const blockStyleDefinitions =
|
|
140
|
-
// We look up for the blockThemes in the block's config, then in the global config
|
|
141
|
-
// We keep `colors` for BBB, but `themes` should be used
|
|
142
|
-
blockConfig.themes || blockConfig.colors || config.blocks.themes || [];
|
|
143
152
|
return data.theme
|
|
144
153
|
? findStyleByName(blockStyleDefinitions, data.theme)
|
|
145
154
|
: {};
|
|
@@ -155,11 +164,11 @@ export default function install(config: ConfigType) {
|
|
|
155
164
|
method: blockThemesEnhancer,
|
|
156
165
|
});
|
|
157
166
|
|
|
158
|
-
// No required blocks
|
|
167
|
+
// No required blocks except eventMetadata
|
|
159
168
|
config.blocks.requiredBlocks = [
|
|
160
169
|
...config.blocks.requiredBlocks,
|
|
161
170
|
'eventMetadata',
|
|
162
|
-
];
|
|
171
|
+
].filter((block) => block !== 'title');
|
|
163
172
|
|
|
164
173
|
// Remove Hero Block (No longer in Volto 18)
|
|
165
174
|
// TODO: Remove already?
|
|
@@ -194,18 +203,29 @@ export default function install(config: ConfigType) {
|
|
|
194
203
|
schemaEnhancer: defaultStylingSchema,
|
|
195
204
|
};
|
|
196
205
|
|
|
206
|
+
const relabelVariation = (id, title) => {
|
|
207
|
+
const variation = config.blocks.blocksConfig.listing.variations.find(
|
|
208
|
+
(variation) => variation.id === id,
|
|
209
|
+
);
|
|
210
|
+
return variation ? { ...variation, title } : variation;
|
|
211
|
+
};
|
|
212
|
+
const listingBlockVariations = [
|
|
213
|
+
relabelVariation('default', 'List'),
|
|
214
|
+
relabelVariation('summary', 'List with images'),
|
|
215
|
+
{
|
|
216
|
+
id: 'grid',
|
|
217
|
+
title: 'Grid',
|
|
218
|
+
template: GridListingBlockTemplate,
|
|
219
|
+
},
|
|
220
|
+
...config.blocks.blocksConfig.listing.variations.filter(
|
|
221
|
+
(variation) => !['default', 'summary'].includes(variation.id),
|
|
222
|
+
),
|
|
223
|
+
].filter((variation) => !!variation);
|
|
197
224
|
config.blocks.blocksConfig.listing = {
|
|
198
225
|
...config.blocks.blocksConfig.listing,
|
|
199
226
|
schemaEnhancer: defaultStylingSchema,
|
|
200
227
|
allowed_headline_tags: [['h2', 'h2']],
|
|
201
|
-
variations:
|
|
202
|
-
...config.blocks.blocksConfig.listing.variations,
|
|
203
|
-
{
|
|
204
|
-
id: 'grid',
|
|
205
|
-
title: 'Grid',
|
|
206
|
-
template: GridListingBlockTemplate,
|
|
207
|
-
},
|
|
208
|
-
],
|
|
228
|
+
variations: listingBlockVariations,
|
|
209
229
|
};
|
|
210
230
|
|
|
211
231
|
config.blocks.blocksConfig.image = {
|
package/src/config/settings.ts
CHANGED
|
@@ -5,31 +5,73 @@ declare module '@plone/types' {
|
|
|
5
5
|
slate: {
|
|
6
6
|
useLinkedHeadings: boolean;
|
|
7
7
|
};
|
|
8
|
-
userDefinedControlPanelColors: string[];
|
|
9
8
|
}
|
|
10
9
|
}
|
|
11
10
|
|
|
11
|
+
type apiExpanderInherit = {
|
|
12
|
+
match: string;
|
|
13
|
+
GET_CONTENT: string[];
|
|
14
|
+
querystring:
|
|
15
|
+
| { [key: string]: string }
|
|
16
|
+
| ((
|
|
17
|
+
config,
|
|
18
|
+
querystring: { config: ConfigType; querystring: object },
|
|
19
|
+
) => { [key: string]: string });
|
|
20
|
+
};
|
|
21
|
+
|
|
12
22
|
export default function install(config: ConfigType) {
|
|
23
|
+
const EXPANDERS_INHERIT_BEHAVIORS =
|
|
24
|
+
'voltolighttheme.header,voltolighttheme.theme,voltolighttheme.footer,kitconcept.footer,kitconcept.sticky_menu';
|
|
13
25
|
config.settings.enableAutoBlockGroupingByBackgroundColor = true;
|
|
14
26
|
config.settings.navDepth = 3;
|
|
15
|
-
config.settings.enableFatMenu = true;
|
|
16
27
|
config.settings.slate.useLinkedHeadings = false;
|
|
17
28
|
config.settings.contentMetadataTagsImageField = 'preview_image';
|
|
18
29
|
config.settings.querystringSearchGet = true;
|
|
19
30
|
|
|
20
|
-
config.settings.siteLabel = '';
|
|
21
|
-
config.settings.intranetHeader = false;
|
|
22
|
-
|
|
23
31
|
config.settings.slidingSearchAnimation = true;
|
|
24
32
|
config.settings.openExternalLinkInNewTab = true;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
|
|
34
|
+
config.settings.apiExpanders = [
|
|
35
|
+
...config.settings.apiExpanders,
|
|
36
|
+
{
|
|
37
|
+
match: '',
|
|
38
|
+
GET_CONTENT: ['inherit'],
|
|
39
|
+
querystring: (config, querystring) => {
|
|
40
|
+
if (querystring['expand.inherit.behaviors']) {
|
|
41
|
+
return {
|
|
42
|
+
'expand.inherit.behaviors': querystring[
|
|
43
|
+
'expand.inherit.behaviors'
|
|
44
|
+
].concat(',', EXPANDERS_INHERIT_BEHAVIORS),
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
return {
|
|
48
|
+
'expand.inherit.behaviors': EXPANDERS_INHERIT_BEHAVIORS,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
} as apiExpanderInherit,
|
|
32
53
|
];
|
|
33
54
|
|
|
55
|
+
config.settings.colorMap = {
|
|
56
|
+
primary_color: {
|
|
57
|
+
colorPair: 'primary_foreground_color',
|
|
58
|
+
default: '#ffffff',
|
|
59
|
+
},
|
|
60
|
+
primary_foreground_color: {
|
|
61
|
+
colorPair: 'primary_color',
|
|
62
|
+
default: '#000000',
|
|
63
|
+
},
|
|
64
|
+
secondary_color: {
|
|
65
|
+
colorPair: 'secondary_foreground_color',
|
|
66
|
+
default: '#ecebeb',
|
|
67
|
+
},
|
|
68
|
+
secondary_foreground_color: {
|
|
69
|
+
colorPair: 'secondary_color',
|
|
70
|
+
default: '#000000',
|
|
71
|
+
},
|
|
72
|
+
accent_color: { colorPair: 'accent_foreground_color', default: '#ecebeb' },
|
|
73
|
+
accent_foreground_color: { colorPair: 'accent_color', default: '#ffffff' },
|
|
74
|
+
};
|
|
75
|
+
|
|
34
76
|
return config;
|
|
35
77
|
}
|
package/src/config/slots.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { ConfigType } from '@plone/registry';
|
|
2
2
|
import Theming from '../components/Theming/Theming';
|
|
3
|
-
import FooterLogos from '../components/Footer/FooterLogos';
|
|
3
|
+
import FooterLogos from '../components/Footer/slots/FooterLogos';
|
|
4
|
+
import FollowUsLogoAndLinks from '../components/Footer/slots/FollowUsLogoAndLinks';
|
|
5
|
+
import Colophon from '../components/Footer/slots/Colophon';
|
|
6
|
+
import CoreFooter from '../components/Footer/slots/CoreFooter';
|
|
7
|
+
import StickyMenu from '../components/StickyMenu/StickyMenu';
|
|
8
|
+
import type { Content } from '@plone/types';
|
|
9
|
+
|
|
10
|
+
export function hasInheritedBehavior(behavior: string) {
|
|
11
|
+
return ({ content }: { content: Content }) =>
|
|
12
|
+
Object.keys(content?.['@components']?.inherit || {}).includes(behavior);
|
|
13
|
+
}
|
|
4
14
|
|
|
5
15
|
export default function install(config: ConfigType) {
|
|
6
16
|
config.registerSlotComponent({
|
|
@@ -9,11 +19,36 @@ export default function install(config: ConfigType) {
|
|
|
9
19
|
component: Theming,
|
|
10
20
|
});
|
|
11
21
|
|
|
22
|
+
config.registerSlotComponent({
|
|
23
|
+
slot: 'aboveHeader',
|
|
24
|
+
name: 'StickyMenu',
|
|
25
|
+
component: StickyMenu,
|
|
26
|
+
});
|
|
27
|
+
|
|
12
28
|
config.registerSlotComponent({
|
|
13
29
|
name: 'footerLogos',
|
|
14
30
|
slot: 'preFooter',
|
|
15
31
|
component: FooterLogos,
|
|
16
32
|
});
|
|
17
33
|
|
|
34
|
+
config.registerSlotComponent({
|
|
35
|
+
name: 'coreFooter',
|
|
36
|
+
slot: 'footer',
|
|
37
|
+
component: CoreFooter,
|
|
38
|
+
predicates: [hasInheritedBehavior('kitconcept.footer')],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
config.registerSlotComponent({
|
|
42
|
+
name: 'PostFooterFollowUsLogoAndLinks',
|
|
43
|
+
slot: 'postFooter',
|
|
44
|
+
component: FollowUsLogoAndLinks,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
config.registerSlotComponent({
|
|
48
|
+
name: 'Colophon',
|
|
49
|
+
slot: 'postFooter',
|
|
50
|
+
component: Colophon,
|
|
51
|
+
});
|
|
52
|
+
|
|
18
53
|
return config;
|
|
19
54
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ConfigType } from '@plone/registry';
|
|
2
|
+
import NewsItemSummary from '../components/Summary/NewsItemSummary';
|
|
3
|
+
import EventSummary from '../components/Summary/EventSummary';
|
|
4
|
+
import FileSummary from '../components/Summary/FileSummary';
|
|
5
|
+
|
|
6
|
+
export default function install(config: ConfigType) {
|
|
7
|
+
config.registerComponent({
|
|
8
|
+
name: 'Summary',
|
|
9
|
+
component: NewsItemSummary,
|
|
10
|
+
dependencies: ['News Item'],
|
|
11
|
+
});
|
|
12
|
+
config.registerComponent({
|
|
13
|
+
name: 'Summary',
|
|
14
|
+
component: EventSummary,
|
|
15
|
+
dependencies: ['Event'],
|
|
16
|
+
});
|
|
17
|
+
config.registerComponent({
|
|
18
|
+
name: 'Summary',
|
|
19
|
+
component: FileSummary,
|
|
20
|
+
dependencies: ['File'],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return config;
|
|
24
|
+
}
|
package/src/config/widgets.ts
CHANGED
|
@@ -1,34 +1,68 @@
|
|
|
1
1
|
import type { ConfigType } from '@plone/registry';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
2
|
+
import BlockWidth from '../components/Widgets/BlockWidth';
|
|
3
|
+
import BlockAlignment from '../components/Widgets/BlockAlignment';
|
|
4
|
+
import ColorSwatch from '../components/Widgets/ColorSwatch';
|
|
5
|
+
import Size from '../components/Widgets/Size';
|
|
6
|
+
import ColorPicker from '../components/Widgets/ColorPicker';
|
|
7
|
+
import ThemeColorSwatch from '../components/Widgets/ThemeColorSwatch';
|
|
8
|
+
import BlocksObject from '../components/Widgets/BlocksObject';
|
|
9
|
+
import ObjectList from '../components/Widgets/ObjectList';
|
|
10
|
+
import { headerActionsSchema } from '../components/Widgets/schema/headerActionsSchema';
|
|
11
|
+
import { footerLogosSchema } from '../components/Widgets/schema/footerLogosSchema';
|
|
12
|
+
import { footerLinksSchema } from '../components/Widgets/schema/footerLinksSchema';
|
|
13
|
+
import { iconLinkListSchema } from '../components/Widgets/schema/iconLinkListSchema';
|
|
10
14
|
|
|
11
15
|
declare module '@plone/types' {
|
|
12
16
|
export interface WidgetsConfigByWidget {
|
|
13
|
-
|
|
14
|
-
blockWidth:
|
|
15
|
-
blockAlignment:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
sizeWidget: React.ComponentType<any>;
|
|
17
|
+
themeColorSwatch: typeof ColorSwatch;
|
|
18
|
+
blockWidth: typeof BlockWidth;
|
|
19
|
+
blockAlignment: typeof BlockAlignment;
|
|
20
|
+
size: typeof Size;
|
|
21
|
+
colorPicker: typeof ColorPicker;
|
|
22
|
+
blocksObject: typeof BlocksObject;
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
export default function install(config: ConfigType) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
config.widgets.widget.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
// Color picker widget override - use our own non-semanticUI widget
|
|
28
|
+
// This is the widget that given an array of colors, you can choose one of them
|
|
29
|
+
// `color_picker` is a terrible name for this widget, it should be `colorSwatch`
|
|
30
|
+
// ToDo: Rename it in Volto 19
|
|
31
|
+
config.widgets.widget.color_picker = ColorSwatch;
|
|
32
|
+
|
|
33
|
+
// ObjectList widget override - use our own non-semanticUI widget
|
|
34
|
+
// it uses also dnd-kit for drag and drop
|
|
35
|
+
config.widgets.widget.object_list = ObjectList;
|
|
36
|
+
|
|
37
|
+
config.widgets.widget.blockWidth = BlockWidth;
|
|
38
|
+
config.widgets.widget.blockAlignment = BlockAlignment;
|
|
39
|
+
config.widgets.widget.colorPicker = ColorPicker;
|
|
40
|
+
config.widgets.widget.size = Size;
|
|
41
|
+
config.widgets.widget.themeColorSwatch = ThemeColorSwatch;
|
|
42
|
+
|
|
43
|
+
config.registerUtility({
|
|
44
|
+
name: 'headerActions',
|
|
45
|
+
type: 'schema',
|
|
46
|
+
method: headerActionsSchema,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
config.registerUtility({
|
|
50
|
+
name: 'footerLogos',
|
|
51
|
+
type: 'schema',
|
|
52
|
+
method: footerLogosSchema,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
config.registerUtility({
|
|
56
|
+
name: 'footerLinks',
|
|
57
|
+
type: 'schema',
|
|
58
|
+
method: footerLinksSchema,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
config.registerUtility({
|
|
62
|
+
name: 'iconLinkList',
|
|
63
|
+
type: 'schema',
|
|
64
|
+
method: iconLinkListSchema,
|
|
65
|
+
});
|
|
32
66
|
|
|
33
67
|
return config;
|
|
34
68
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OVERRIDE Tags.jsx
|
|
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 Tags from '../../../../../components/Tags/Tags';
|
|
10
|
+
|
|
11
|
+
export default Tags;
|
|
@@ -88,7 +88,7 @@ const RenderBlocks = (props) => {
|
|
|
88
88
|
const themes =
|
|
89
89
|
config.blocks.blocksConfig[
|
|
90
90
|
content[blocksFieldname][group[0]]['@type']
|
|
91
|
-
]
|
|
91
|
+
]?.themes ?? config.blocks.themes;
|
|
92
92
|
|
|
93
93
|
return (
|
|
94
94
|
<MaybeWrap
|
|
@@ -145,6 +145,7 @@ const RenderBlocks = (props) => {
|
|
|
145
145
|
id={block}
|
|
146
146
|
block={block}
|
|
147
147
|
data={blockData}
|
|
148
|
+
isContainer={isContainer}
|
|
148
149
|
>
|
|
149
150
|
<Block
|
|
150
151
|
id={block}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DndContext,
|
|
3
|
+
closestCenter,
|
|
4
|
+
KeyboardSensor,
|
|
5
|
+
PointerSensor,
|
|
6
|
+
useSensor,
|
|
7
|
+
useSensors,
|
|
8
|
+
type DragEndEvent,
|
|
9
|
+
type DragStartEvent,
|
|
10
|
+
} from '@dnd-kit/core';
|
|
11
|
+
import {
|
|
12
|
+
SortableContext,
|
|
13
|
+
sortableKeyboardCoordinates,
|
|
14
|
+
verticalListSortingStrategy,
|
|
15
|
+
useSortable,
|
|
16
|
+
} from '@dnd-kit/sortable';
|
|
17
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
18
|
+
|
|
19
|
+
const SortableItem = (props) => {
|
|
20
|
+
const { uid, children, item, index, activeObject } = props;
|
|
21
|
+
const { attributes, listeners, setNodeRef, transform, transition } =
|
|
22
|
+
useSortable({
|
|
23
|
+
id: uid,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const style = {
|
|
27
|
+
transform: CSS.Transform.toString(transform),
|
|
28
|
+
transition,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div ref={setNodeRef} style={style}>
|
|
33
|
+
{children({ uid, item, index, activeObject, attributes, listeners })}
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
interface DndSortableListProps {
|
|
39
|
+
/**
|
|
40
|
+
* An object containing all items, ideally with a `@id` key with the item's
|
|
41
|
+
* unique identifier (UID).
|
|
42
|
+
*
|
|
43
|
+
* If none provided, the item index in the array is used.
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
items: Array<Record<string, any>>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A function to handle the end of a drag operation.
|
|
50
|
+
* @param {DragEndEvent} event - The drag end event.
|
|
51
|
+
*/
|
|
52
|
+
handleDragEnd: (event: DragEndEvent) => void;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The currently active object being dragged.
|
|
56
|
+
*/
|
|
57
|
+
activeObject: any;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A function to set the active object.
|
|
61
|
+
* @param {any} object - The object to set as active.
|
|
62
|
+
*/
|
|
63
|
+
setActiveObject: (object: any) => void;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A render prop function to render each sortable item.
|
|
67
|
+
* @param {object} params - The parameters for rendering the item.
|
|
68
|
+
* @param {string} params.uid - The unique identifier of the item.
|
|
69
|
+
* @param {any} params.item - The item data.
|
|
70
|
+
* @param {number} params.index - The index of the item in the sorted list.
|
|
71
|
+
* @param {any} params.activeObject - The currently active object being dragged.
|
|
72
|
+
* @param {object} params.attributes - The attributes for the sortable item.
|
|
73
|
+
* @param {object} params.listeners - The listeners for the sortable item.
|
|
74
|
+
* @returns {React.ReactNode} - The rendered sortable item.
|
|
75
|
+
*/
|
|
76
|
+
children: (params: {
|
|
77
|
+
uid: string;
|
|
78
|
+
item: any;
|
|
79
|
+
index: number;
|
|
80
|
+
activeObject: any;
|
|
81
|
+
attributes: any;
|
|
82
|
+
listeners: any;
|
|
83
|
+
}) => React.ReactNode;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const arrayToObject = (arr: Record<string, any>[]): Record<string, any> => {
|
|
87
|
+
return arr.reduce((acc, item) => {
|
|
88
|
+
acc[item['@id']] = item;
|
|
89
|
+
return acc;
|
|
90
|
+
}, {});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const DndSortableList = (props: DndSortableListProps) => {
|
|
94
|
+
const { items, children, handleDragEnd, activeObject, setActiveObject } =
|
|
95
|
+
props;
|
|
96
|
+
|
|
97
|
+
const sensors = useSensors(
|
|
98
|
+
useSensor(PointerSensor),
|
|
99
|
+
useSensor(KeyboardSensor, {
|
|
100
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
function handleDragStart(event: DragStartEvent) {
|
|
105
|
+
setActiveObject(null);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const itemIds = items ? items.map((item, index) => item['@id'] || index) : [];
|
|
109
|
+
const itemsByUid = items ? arrayToObject(items) : {};
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<DndContext
|
|
113
|
+
sensors={sensors}
|
|
114
|
+
collisionDetection={closestCenter}
|
|
115
|
+
onDragStart={handleDragStart}
|
|
116
|
+
onDragEnd={handleDragEnd}
|
|
117
|
+
>
|
|
118
|
+
<SortableContext items={itemIds} strategy={verticalListSortingStrategy}>
|
|
119
|
+
{itemIds.map((uid, index) => {
|
|
120
|
+
const item = itemsByUid[uid];
|
|
121
|
+
return (
|
|
122
|
+
<SortableItem
|
|
123
|
+
key={uid}
|
|
124
|
+
uid={uid}
|
|
125
|
+
index={index}
|
|
126
|
+
item={item}
|
|
127
|
+
activeObject={activeObject}
|
|
128
|
+
>
|
|
129
|
+
{children}
|
|
130
|
+
</SortableItem>
|
|
131
|
+
);
|
|
132
|
+
})}
|
|
133
|
+
</SortableContext>
|
|
134
|
+
</DndContext>
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export default DndSortableList;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const LONG_DATE_FORMAT = {
|
|
2
|
+
year: 'numeric',
|
|
3
|
+
month: 'long',
|
|
4
|
+
day: 'numeric',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const parseDateFromCatalog = (value) => {
|
|
8
|
+
if (value.startsWith('1969')) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return new Date(value);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const formatDateRange = ({
|
|
15
|
+
start,
|
|
16
|
+
end,
|
|
17
|
+
format = LONG_DATE_FORMAT,
|
|
18
|
+
locale = 'default',
|
|
19
|
+
}) => {
|
|
20
|
+
const formatter = new Intl.DateTimeFormat(locale || 'default', format);
|
|
21
|
+
return formatter.formatRange(start, end);
|
|
22
|
+
};
|