@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.
Files changed (98) hide show
  1. package/.changelog.draft +2 -7
  2. package/CHANGELOG.md +221 -0
  3. package/README.md +6 -5
  4. package/locales/de/LC_MESSAGES/volto.po +171 -38
  5. package/locales/en/LC_MESSAGES/volto.po +170 -37
  6. package/locales/es/LC_MESSAGES/volto.po +171 -38
  7. package/locales/eu/LC_MESSAGES/volto.po +171 -38
  8. package/locales/pt_BR/volto.po +171 -38
  9. package/locales/volto.pot +171 -38
  10. package/package.json +15 -6
  11. package/src/components/Blocks/EventMetadata/View.jsx +32 -26
  12. package/src/components/Blocks/Listing/DefaultTemplate.jsx +19 -14
  13. package/src/components/Blocks/Listing/GridTemplate.jsx +9 -12
  14. package/src/components/Blocks/Listing/SummaryTemplate.jsx +9 -7
  15. package/src/components/Blocks/Teaser/DefaultBody.jsx +93 -0
  16. package/src/components/Footer/ColumnLinks.tsx +35 -0
  17. package/src/components/Footer/Footer.tsx +32 -0
  18. package/src/components/Footer/slots/Colophon.tsx +24 -0
  19. package/src/components/Footer/slots/Copyright.tsx +65 -0
  20. package/src/components/Footer/slots/CoreFooter.tsx +82 -0
  21. package/src/components/Footer/slots/FollowUsLogoAndLinks.tsx +80 -0
  22. package/src/components/Footer/slots/FooterLogos.tsx +44 -0
  23. package/src/components/Header/Header.tsx +257 -0
  24. package/src/components/Logo/Logo.tsx +85 -0
  25. package/src/components/{Footer/FooterLogos.tsx → LogosContainer/LogosContainer.tsx} +16 -36
  26. package/src/components/MobileNavigation/MobileNavigation.jsx +53 -18
  27. package/src/components/Navigation/Navigation.jsx +14 -3
  28. package/src/components/SearchWidget/IntranetSearchWidget.jsx +32 -5
  29. package/src/components/SearchWidget/SearchWidget.jsx +1 -1
  30. package/src/components/StickyMenu/StickyMenu.tsx +36 -0
  31. package/src/components/Summary/DefaultSummary.jsx +16 -0
  32. package/src/components/Summary/EventSummary.jsx +38 -0
  33. package/src/components/Summary/FileSummary.jsx +24 -0
  34. package/src/components/Summary/NewsItemSummary.jsx +40 -0
  35. package/src/components/Tags/Tags.jsx +46 -0
  36. package/src/components/Theme/EventView.jsx +19 -25
  37. package/src/components/Theme/NewsItemView.jsx +13 -9
  38. package/src/components/Theming/Theming.tsx +20 -17
  39. package/src/components/Widgets/{BlockAlignmentWidget.tsx → BlockAlignment.tsx} +9 -2
  40. package/src/components/Widgets/{BlockWidthWidget.tsx → BlockWidth.tsx} +10 -3
  41. package/src/components/Widgets/BlocksObject.tsx +353 -0
  42. package/src/components/Widgets/{ButtonsWidget.tsx → Buttons.tsx} +45 -4
  43. package/src/components/Widgets/ColorContrastChecker.tsx +117 -0
  44. package/src/components/Widgets/ColorPicker.tsx +59 -0
  45. package/src/components/Widgets/{ColorPickerWidget.tsx → ColorSwatch.tsx} +5 -5
  46. package/src/components/Widgets/ObjectList.tsx +342 -0
  47. package/src/components/Widgets/{ThemingColorPicker.tsx → RACThemingColorPicker.tsx} +4 -0
  48. package/src/components/Widgets/{SizeWidget.tsx → Size.tsx} +9 -2
  49. package/src/components/Widgets/ThemeColorSwatch.tsx +17 -0
  50. package/src/components/Widgets/schema/footerLinksSchema.ts +64 -0
  51. package/src/components/Widgets/schema/footerLogosSchema.ts +98 -0
  52. package/src/components/Widgets/schema/headerActionsSchema.ts +64 -0
  53. package/src/components/Widgets/schema/iconLinkListSchema.ts +98 -0
  54. package/src/config/blocks.tsx +37 -17
  55. package/src/config/settings.ts +54 -12
  56. package/src/config/slots.ts +36 -1
  57. package/src/config/summary.ts +24 -0
  58. package/src/config/widgets.ts +57 -23
  59. package/src/customizations/volto/components/manage/Blocks/Teaser/DefaultBody.jsx +8 -0
  60. package/src/customizations/volto/components/theme/Tags/Tags.jsx +11 -0
  61. package/src/customizations/volto/components/theme/View/RenderBlocks.jsx +2 -1
  62. package/src/helpers/DndSortableList.tsx +138 -0
  63. package/src/helpers/dates.js +22 -0
  64. package/src/helpers/doesNodeContainClick.js +64 -0
  65. package/src/helpers/useLiveData.ts +29 -0
  66. package/src/index.ts +31 -2
  67. package/src/primitives/IconLinkList.tsx +69 -0
  68. package/src/primitives/LinkList.tsx +35 -0
  69. package/src/theme/_bgcolor-blocks-layout.scss +50 -12
  70. package/src/theme/_content.scss +6 -0
  71. package/src/theme/_footer.scss +294 -41
  72. package/src/theme/_header.scss +132 -19
  73. package/src/theme/_layout.scss +11 -1
  74. package/src/theme/_sitemap.scss +4 -0
  75. package/src/theme/_utils.scss +14 -1
  76. package/src/theme/_variables.scss +12 -3
  77. package/src/theme/_widgets.scss +100 -9
  78. package/src/theme/blocks/_eventMetadata.scss +5 -2
  79. package/src/theme/blocks/_grid.scss +3 -3
  80. package/src/theme/blocks/_highlight.scss +17 -44
  81. package/src/theme/blocks/_listing.scss +25 -16
  82. package/src/theme/blocks/_maps.scss +3 -3
  83. package/src/theme/blocks/_slider.scss +5 -1
  84. package/src/theme/main.scss +1 -0
  85. package/src/theme/sticky-menu.scss +50 -0
  86. package/src/types.d.ts +102 -0
  87. package/tsconfig.json +1 -1
  88. package/src/components/Footer/Footer.jsx +0 -115
  89. package/src/components/Footer/FooterLinks.tsx +0 -57
  90. package/src/components/Header/Header.jsx +0 -161
  91. package/src/components/Logo/Logo.jsx +0 -51
  92. package/src/components/Widgets/AlignWidget.jsx +0 -80
  93. package/src/components/Widgets/BackgroundColorWidget.tsx +0 -17
  94. package/src/components/Widgets/BlocksObjectWidget.tsx +0 -333
  95. package/src/components/Widgets/FooterLinksWidget.tsx +0 -106
  96. package/src/components/Widgets/FooterLogosWidget.tsx +0 -120
  97. package/src/static/container-query-polyfill.modern.js +0 -1
  98. 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
+ }
@@ -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 (eg. Title)
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 = {
@@ -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
- config.settings.userDefinedControlPanelColors = [
26
- 'accent_color',
27
- 'accent_foreground_color',
28
- 'primary_color',
29
- 'primary_foreground_color',
30
- 'secondary_color',
31
- 'secondary_foreground_color',
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
  }
@@ -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
+ }
@@ -1,34 +1,68 @@
1
1
  import type { ConfigType } from '@plone/registry';
2
- import ThemingColorPicker from '../components/Widgets/ThemingColorPicker';
3
- import BackgroundColorWidget from '../components/Widgets/BackgroundColorWidget';
4
- import BlockWidthWidget from '../components/Widgets/BlockWidthWidget';
5
- import BlockAlignmentWidget from '../components/Widgets/BlockAlignmentWidget';
6
- import ColorPickerWidget from '../components/Widgets/ColorPickerWidget';
7
- import FooterLogosWidget from '../components/Widgets/FooterLogosWidget';
8
- import FooterLinksWidget from '../components/Widgets/FooterLinksWidget';
9
- import SizeWidget from '../components/Widgets/SizeWidget';
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
- BackgroundColorWidget: React.ComponentType<any>;
14
- blockWidth: React.ComponentType<any>;
15
- blockAlignment: React.ComponentType<any>;
16
- themingColorPicker: typeof ThemingColorPicker;
17
- footerLogos: typeof FooterLogosWidget;
18
- footerLinks: typeof FooterLinksWidget;
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
- config.widgets.widget.BackgroundColorWidget = BackgroundColorWidget;
25
- config.widgets.widget.blockWidth = BlockWidthWidget;
26
- config.widgets.widget.blockAlignment = BlockAlignmentWidget;
27
- config.widgets.widget.color_picker = ColorPickerWidget;
28
- config.widgets.widget.themingColorPicker = ThemingColorPicker;
29
- config.widgets.widget.footerLogos = FooterLogosWidget;
30
- config.widgets.widget.footerLinks = FooterLinksWidget;
31
- config.widgets.widget.sizeWidget = SizeWidget;
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,8 @@
1
+ /**
2
+ * OVERRIDE DefaultBody.jsx
3
+ * REASON: Look up Summary component.
4
+ */
5
+
6
+ import DefaultBody from '../../../../../../components/Blocks/Teaser/DefaultBody';
7
+
8
+ export default DefaultBody;
@@ -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
- ].themes ?? config.blocks.themes;
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
+ };