@kitconcept/volto-light-theme 8.0.0-alpha.3 → 8.0.0-alpha.30

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 (200) hide show
  1. package/.changelog.draft +6 -9
  2. package/CHANGELOG.md +310 -0
  3. package/locales/af/LC_MESSAGES/volto.po +645 -0
  4. package/locales/ar/LC_MESSAGES/volto.po +645 -0
  5. package/locales/bg/LC_MESSAGES/volto.po +645 -0
  6. package/locales/bn/LC_MESSAGES/volto.po +645 -0
  7. package/locales/ca/LC_MESSAGES/volto.po +645 -0
  8. package/locales/cs/LC_MESSAGES/volto.po +645 -0
  9. package/locales/cy/LC_MESSAGES/volto.po +645 -0
  10. package/locales/da/LC_MESSAGES/volto.po +645 -0
  11. package/locales/de/LC_MESSAGES/volto.po +83 -167
  12. package/locales/el/LC_MESSAGES/volto.po +645 -0
  13. package/locales/en/LC_MESSAGES/volto.po +30 -115
  14. package/locales/en_AU/LC_MESSAGES/volto.po +645 -0
  15. package/locales/en_GB/LC_MESSAGES/volto.po +645 -0
  16. package/locales/eo/LC_MESSAGES/volto.po +645 -0
  17. package/locales/es/LC_MESSAGES/volto.po +75 -160
  18. package/locales/et/LC_MESSAGES/volto.po +645 -0
  19. package/locales/eu/LC_MESSAGES/volto.po +59 -125
  20. package/locales/fa/LC_MESSAGES/volto.po +645 -0
  21. package/locales/fi/LC_MESSAGES/volto.po +645 -0
  22. package/locales/fr/LC_MESSAGES/volto.po +645 -0
  23. package/locales/fu/LC_MESSAGES/volto.po +645 -0
  24. package/locales/ga/LC_MESSAGES/volto.po +645 -0
  25. package/locales/gl/LC_MESSAGES/volto.po +645 -0
  26. package/locales/he/LC_MESSAGES/volto.po +645 -0
  27. package/locales/hi/LC_MESSAGES/volto.po +645 -0
  28. package/locales/hr/LC_MESSAGES/volto.po +645 -0
  29. package/locales/hu/LC_MESSAGES/volto.po +645 -0
  30. package/locales/hy/LC_MESSAGES/volto.po +645 -0
  31. package/locales/id/LC_MESSAGES/volto.po +645 -0
  32. package/locales/it/LC_MESSAGES/volto.po +645 -0
  33. package/locales/ja/LC_MESSAGES/volto.po +645 -0
  34. package/locales/ka/LC_MESSAGES/volto.po +645 -0
  35. package/locales/kn/LC_MESSAGES/volto.po +645 -0
  36. package/locales/ko/LC_MESSAGES/volto.po +645 -0
  37. package/locales/lt/LC_MESSAGES/volto.po +645 -0
  38. package/locales/lv/LC_MESSAGES/volto.po +645 -0
  39. package/locales/mi/LC_MESSAGES/volto.po +645 -0
  40. package/locales/mk_MK/LC_MESSAGES/volto.po +645 -0
  41. package/locales/ms/LC_MESSAGES/volto.po +645 -0
  42. package/locales/mt/LC_MESSAGES/volto.po +645 -0
  43. package/locales/my/LC_MESSAGES/volto.po +645 -0
  44. package/locales/nl/LC_MESSAGES/volto.po +645 -0
  45. package/locales/nl_BE/LC_MESSAGES/volto.po +645 -0
  46. package/locales/nn/LC_MESSAGES/volto.po +645 -0
  47. package/locales/no/LC_MESSAGES/volto.po +645 -0
  48. package/locales/pl/LC_MESSAGES/volto.po +645 -0
  49. package/locales/pt/LC_MESSAGES/volto.po +645 -0
  50. package/locales/pt_BR/LC_MESSAGES/volto.po +38 -123
  51. package/locales/rm/LC_MESSAGES/volto.po +645 -0
  52. package/locales/ro/LC_MESSAGES/volto.po +645 -0
  53. package/locales/ru/LC_MESSAGES/volto.po +645 -0
  54. package/locales/sk/LC_MESSAGES/volto.po +645 -0
  55. package/locales/sl/LC_MESSAGES/volto.po +645 -0
  56. package/locales/sm/LC_MESSAGES/volto.po +645 -0
  57. package/locales/sq/LC_MESSAGES/volto.po +645 -0
  58. package/locales/sr/LC_MESSAGES/volto.po +645 -0
  59. package/locales/sr_Cyrl/LC_MESSAGES/volto.po +645 -0
  60. package/locales/sr_Latn/LC_MESSAGES/volto.po +645 -0
  61. package/locales/sv/LC_MESSAGES/volto.po +645 -0
  62. package/locales/sw/LC_MESSAGES/volto.po +645 -0
  63. package/locales/ta/LC_MESSAGES/volto.po +645 -0
  64. package/locales/te/LC_MESSAGES/volto.po +645 -0
  65. package/locales/th/LC_MESSAGES/volto.po +645 -0
  66. package/locales/tl/LC_MESSAGES/volto.po +645 -0
  67. package/locales/to/LC_MESSAGES/volto.po +645 -0
  68. package/locales/tr/LC_MESSAGES/volto.po +645 -0
  69. package/locales/uk/LC_MESSAGES/volto.po +645 -0
  70. package/locales/vi/LC_MESSAGES/volto.po +645 -0
  71. package/locales/volto.pot +31 -116
  72. package/locales/zh_CN/LC_MESSAGES/volto.po +645 -0
  73. package/locales/zh_HK/LC_MESSAGES/volto.po +645 -0
  74. package/locales/zh_TW/LC_MESSAGES/volto.po +645 -0
  75. package/package.json +7 -4
  76. package/src/__mocks__/semantic-ui-react.ts +31 -0
  77. package/src/components/Blocks/Block/EditBlockWrapper.jsx +9 -3
  78. package/src/components/Blocks/Button/schema.js +12 -0
  79. package/src/components/Blocks/EventCalendar/Search/components/EventTemplate.tsx +1 -1
  80. package/src/components/Blocks/Image/Edit.jsx +9 -32
  81. package/src/components/Blocks/Image/View.jsx +9 -26
  82. package/src/components/Blocks/Image/adapter.js +28 -14
  83. package/src/components/Blocks/Image/adapter.test.js +156 -0
  84. package/src/components/Blocks/Image/schema.js +21 -7
  85. package/src/components/Blocks/Listing/DefaultTemplate.jsx +12 -6
  86. package/src/components/Blocks/Listing/GridTemplate.jsx +17 -7
  87. package/src/components/Blocks/Listing/ListingBody.jsx +4 -1
  88. package/src/components/Blocks/Listing/SummaryTemplate.jsx +17 -7
  89. package/src/components/Blocks/Maps/MapsSidebar.jsx +68 -0
  90. package/src/components/Blocks/Maps/View.jsx +37 -0
  91. package/src/components/Blocks/Maps/adapter.js +27 -0
  92. package/src/components/Blocks/Maps/adapter.test.js +63 -0
  93. package/src/components/Blocks/Maps/schema.js +42 -2
  94. package/src/components/Blocks/Separator/schema.js +12 -0
  95. package/src/components/Blocks/Teaser/DefaultBody.tsx +35 -6
  96. package/src/components/Blocks/Video/VideoSidebar.jsx +68 -0
  97. package/src/components/Blocks/Video/View.jsx +38 -0
  98. package/src/components/Blocks/Video/adapter.js +28 -0
  99. package/src/components/Blocks/Video/adapter.test.js +63 -0
  100. package/src/components/Blocks/Video/schema.js +42 -2
  101. package/src/components/Blocks/schema.ts +69 -0
  102. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +128 -0
  103. package/src/components/Breadcrumbs/Breadcrumbs.tsx +117 -0
  104. package/src/components/Caption/Caption.test.tsx +31 -0
  105. package/src/components/Caption/{Caption.jsx → Caption.tsx} +14 -21
  106. package/src/components/Footer/ColumnLinks.tsx +2 -2
  107. package/src/components/Footer/Footer.tsx +2 -2
  108. package/src/components/Footer/slots/Colophon.tsx +13 -1
  109. package/src/components/Footer/slots/CoreFooter.tsx +4 -2
  110. package/src/components/Footer/slots/FollowUsLogoAndLinks.tsx +12 -23
  111. package/src/components/Header/Header.tsx +3 -3
  112. package/src/components/LanguageSelector/LanguageSelector.tsx +91 -0
  113. package/src/components/MobileNavigation/MobileNavigation.jsx +11 -9
  114. package/src/components/Navigation/Navigation.test.tsx +176 -0
  115. package/src/components/Navigation/{Navigation.jsx → Navigation.tsx} +89 -42
  116. package/src/components/StickyMenu/MobileCarouselArrowButton.tsx +81 -0
  117. package/src/components/StickyMenu/MobileStickyMenu.tsx +76 -0
  118. package/src/components/Summary/DefaultSummary.tsx +10 -3
  119. package/src/components/Summary/EventSummary.tsx +10 -3
  120. package/src/components/Summary/FileSummary.tsx +10 -3
  121. package/src/components/Summary/NewsItemSummary.tsx +10 -3
  122. package/src/components/Summary/PersonSummary.tsx +10 -3
  123. package/src/components/Summary/Summary.stories.tsx +46 -30
  124. package/src/components/Tags/Tags.test.tsx +71 -0
  125. package/src/components/Tags/{Tags.jsx → Tags.tsx} +9 -25
  126. package/src/components/Theme/EventView.jsx +4 -4
  127. package/src/components/Theme/ImageView.jsx +8 -1
  128. package/src/components/Theme/NewsItemView.jsx +4 -4
  129. package/src/components/Theme/RenderBlocksV2.jsx +38 -15
  130. package/src/components/Widgets/ColorSwatch.stories.tsx +197 -0
  131. package/src/components/Widgets/ColorSwatch.test.tsx +188 -0
  132. package/src/components/Widgets/ColorSwatch.tsx +77 -39
  133. package/src/components/Widgets/ObjectList.tsx +37 -27
  134. package/src/components/Widgets/SoftTextWidget.tsx +129 -0
  135. package/src/components/Widgets/SoftTextareaWidget.tsx +118 -0
  136. package/src/components/Widgets/ThemeColorSwatch.tsx +5 -9
  137. package/src/config/blocks.tsx +83 -28
  138. package/src/config/classExtenders.ts +11 -10
  139. package/src/config/settings.ts +6 -0
  140. package/src/config/slots.ts +7 -0
  141. package/src/config/widgets.ts +5 -9
  142. package/src/customizations/volto/components/manage/Blocks/Maps/MapsSidebar.jsx +10 -0
  143. package/src/customizations/volto/components/manage/Blocks/Maps/View.jsx +10 -0
  144. package/src/customizations/volto/components/manage/Blocks/Video/VideoSidebar.jsx +10 -0
  145. package/src/customizations/volto/components/manage/Blocks/Video/View.jsx +10 -0
  146. package/src/customizations/volto/components/manage/DragDropList/DragDropList.jsx +263 -0
  147. package/src/customizations/volto/components/theme/LanguageSelector/LanguageSelector.tsx +10 -0
  148. package/src/helpers/styleDefinitions.test.tsx +30 -0
  149. package/src/helpers/styleDefinitions.ts +49 -0
  150. package/src/helpers/useLiveData.ts +7 -2
  151. package/src/index.ts +15 -0
  152. package/src/internalChecks.test.ts +94 -0
  153. package/src/primitives/Card/Card.stories.tsx +4 -1
  154. package/src/primitives/Card/Card.test.tsx +11 -33
  155. package/src/primitives/Card/Card.tsx +37 -44
  156. package/src/primitives/IconLinkList.tsx +53 -52
  157. package/src/primitives/LinkIconButton.tsx +52 -0
  158. package/src/reducers/errorContext.ts +14 -0
  159. package/src/reducers/index.ts +7 -0
  160. package/src/theme/_bgcolor-blocks-layout.scss +48 -46
  161. package/src/theme/_content.scss +12 -13
  162. package/src/theme/_export_import.scss +94 -0
  163. package/src/theme/_footer.scss +131 -64
  164. package/src/theme/_header.scss +25 -5
  165. package/src/theme/_insets.scss +1 -1
  166. package/src/theme/_layout.scss +41 -77
  167. package/src/theme/_mobile-sticky-menu.scss +92 -0
  168. package/src/theme/_search-page.scss +250 -0
  169. package/src/theme/_typo-custom.scss +24 -8
  170. package/src/theme/_variables.scss +40 -4
  171. package/src/theme/_widgets.scss +6 -17
  172. package/src/theme/blocks/_accordion.scss +11 -4
  173. package/src/theme/blocks/_form.scss +350 -0
  174. package/src/theme/blocks/_grid.scss +10 -77
  175. package/src/theme/blocks/_highlight.scss +10 -7
  176. package/src/theme/blocks/_image.scss +99 -184
  177. package/src/theme/blocks/_listing.scss +61 -128
  178. package/src/theme/blocks/_maps.scss +60 -34
  179. package/src/theme/blocks/_search.scss +3 -4
  180. package/src/theme/blocks/_table.scss +1 -0
  181. package/src/theme/blocks/_teaser.scss +7 -117
  182. package/src/theme/blocks/_toc.scss +2 -1
  183. package/src/theme/card.scss +136 -69
  184. package/src/theme/main.scss +4 -0
  185. package/src/theme/notfound.scss +2 -0
  186. package/src/theme/person.scss +7 -1
  187. package/src/theme/sticky-menu.scss +7 -5
  188. package/src/transforms/to6.ts +5 -49
  189. package/src/transforms/to8.test.js +201 -0
  190. package/src/transforms/to8.ts +109 -0
  191. package/src/types.d.ts +1 -0
  192. package/vitest.config.mjs +28 -3
  193. package/razzle.extend.js +0 -38
  194. package/src/components/Blocks/schema.js +0 -44
  195. package/src/components/Breadcrumbs/Breadcrumbs.jsx +0 -118
  196. package/src/components/Widgets/AlignWidget.tsx +0 -84
  197. package/src/components/Widgets/BlockAlignment.tsx +0 -88
  198. package/src/components/Widgets/BlockWidth.tsx +0 -101
  199. package/src/components/Widgets/Buttons.tsx +0 -167
  200. package/src/components/Widgets/Size.tsx +0 -78
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import { useSelector } from 'react-redux';
3
4
  import ConditionalLink from '@plone/volto/components/manage/ConditionalLink/ConditionalLink';
4
5
  import Card from '../../../primitives/Card/Card';
5
6
  import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers/Url/Url';
@@ -8,6 +9,8 @@ import DefaultSummary from '@kitconcept/volto-light-theme/components/Summary/Def
8
9
  import cx from 'classnames';
9
10
 
10
11
  const SummaryTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
12
+ const site = useSelector((state) => state.site?.data);
13
+ const hideProfileLinks = site?.['kitconcept.disable_profile_links'];
11
14
  let link = null;
12
15
  let href = linkHref?.[0]?.['@id'] || '';
13
16
  const PreviewImageComponent = config.getComponent('PreviewImage').component;
@@ -23,7 +26,7 @@ const SummaryTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
23
26
 
24
27
  return (
25
28
  <>
26
- <div className="items">
29
+ <ul className="items">
27
30
  {items.map((item) => {
28
31
  const CustomItemBodyTemplate = config.getComponent({
29
32
  name: 'SummaryListingItemTemplate',
@@ -34,7 +37,10 @@ const SummaryTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
34
37
  name: 'Summary',
35
38
  dependencies: [item['@type']],
36
39
  }).component || DefaultSummary;
37
- const showLink = !Summary.hideLink && !isEditMode;
40
+ let showLink = !Summary.hideLink && !isEditMode;
41
+ if (item['@type'] === 'Person' && hideProfileLinks !== undefined) {
42
+ showLink = !hideProfileLinks && !isEditMode;
43
+ }
38
44
  const ItemBodyTemplate = (props) =>
39
45
  CustomItemBodyTemplate ? (
40
46
  <CustomItemBodyTemplate item={item} />
@@ -44,14 +50,18 @@ const SummaryTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
44
50
  item={item}
45
51
  showPlaceholderImage={true}
46
52
  imageComponent={PreviewImageComponent}
53
+ sizes={`(max-width: ${config.settings.layout.tabletBreakpoint}px) 100vw, 220px`}
47
54
  />
48
- <Card.Summary a11yLabelId={props.a11yLabelId}>
49
- <Summary item={item} HeadingTag="h3" />
55
+ <Card.Summary
56
+ a11yLabelId={props.a11yLabelId}
57
+ LinkToItem={props.LinkToItem}
58
+ >
59
+ <Summary item={item} />
50
60
  </Card.Summary>
51
61
  </>
52
62
  );
53
63
  return (
54
- <div
64
+ <li
55
65
  className={cx('listing-item has--align--left', {
56
66
  [`${item['@type']?.toLowerCase()}-listing`]: item['@type'],
57
67
  })}
@@ -60,10 +70,10 @@ const SummaryTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
60
70
  <Card item={showLink ? item : null}>
61
71
  <ItemBodyTemplate item={item} />
62
72
  </Card>
63
- </div>
73
+ </li>
64
74
  );
65
75
  })}
66
- </div>
76
+ </ul>
67
77
 
68
78
  {link && <div className="footer">{link}</div>}
69
79
  </>
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { MapsSchema } from '@plone/volto/components/manage/Blocks/Maps/schema';
3
+ import { useIntl, defineMessages } from 'react-intl';
4
+ import globeSVG from '@plone/volto/icons/globe.svg';
5
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
6
+ import { BlockDataForm } from '@plone/volto/components/manage/Form';
7
+ import { Segment } from 'semantic-ui-react';
8
+
9
+ const messages = defineMessages({
10
+ Maps: {
11
+ id: 'Maps',
12
+ defaultMessage: 'Maps',
13
+ },
14
+ NoMaps: {
15
+ id: 'No map selected',
16
+ defaultMessage: 'No map selected',
17
+ },
18
+ });
19
+
20
+ const MapsSidebar = (props) => {
21
+ const {
22
+ data,
23
+ block,
24
+ blocksErrors,
25
+ onChangeBlock,
26
+ navRoot,
27
+ contentType,
28
+ blocksConfig,
29
+ } = props;
30
+ const intl = useIntl();
31
+ const schema = MapsSchema({ ...props, intl });
32
+ const dataAdapter = blocksConfig[data['@type']].dataAdapter;
33
+
34
+ return (
35
+ <>
36
+ {!data.url ? (
37
+ <Segment className="sidebar-metadata-container" secondary>
38
+ {intl.formatMessage(messages.NoMaps)}
39
+ <Icon name={globeSVG} size="100px" color="#b8c6c8" />
40
+ </Segment>
41
+ ) : (
42
+ <BlockDataForm
43
+ schema={schema}
44
+ title={intl.formatMessage(messages.Maps)}
45
+ // START CUSTOMIZATION
46
+ onChangeField={(id, value) => {
47
+ dataAdapter({
48
+ block,
49
+ data,
50
+ id,
51
+ onChangeBlock,
52
+ value,
53
+ });
54
+ }}
55
+ // END CUSTOMIZATION
56
+ onChangeBlock={onChangeBlock}
57
+ formData={data}
58
+ block={block}
59
+ navRoot={navRoot}
60
+ contentType={contentType}
61
+ errors={blocksErrors}
62
+ />
63
+ )}
64
+ </>
65
+ );
66
+ };
67
+
68
+ export default MapsSidebar;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * View map block.
3
+ * @module components/manage/Blocks/Maps/View
4
+ */
5
+
6
+ import React from 'react';
7
+ import { injectIntl } from 'react-intl';
8
+ import PropTypes from 'prop-types';
9
+ import cx from 'classnames';
10
+ import { compose } from 'redux';
11
+ import Body from '@plone/volto/components/manage/Blocks/Maps/Body';
12
+ import { withBlockExtensions } from '@plone/volto/helpers/Extensions';
13
+
14
+ /**
15
+ * View image block class.
16
+ * @class View
17
+ * @extends Component
18
+ */
19
+
20
+ const View = ({ data, intl, style, className }) => (
21
+ // START CUSTOMIZATION
22
+ <div className={cx('block maps', className)} style={style}>
23
+ {/* // END CUSTOMIZATION */}
24
+ <Body data={data} />
25
+ </div>
26
+ );
27
+
28
+ /**
29
+ * Property types.
30
+ * @property {Object} propTypes Property types.
31
+ * @static
32
+ */
33
+ View.propTypes = {
34
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
35
+ };
36
+
37
+ export default compose(injectIntl, withBlockExtensions)(View);
@@ -0,0 +1,27 @@
1
+ export const MapsBlockDataAdapter = ({
2
+ block,
3
+ data,
4
+ id,
5
+ onChangeBlock,
6
+ value,
7
+ }) => {
8
+ let dataSaved = {
9
+ ...data,
10
+ [id]: value,
11
+ };
12
+
13
+ const align = dataSaved.styles?.['align:noprefix'];
14
+ const isFloating = align === 'left' || align === 'right';
15
+
16
+ if (isFloating) {
17
+ dataSaved = {
18
+ ...dataSaved,
19
+ styles: {
20
+ ...dataSaved.styles,
21
+ 'blockWidth:noprefix': 'default',
22
+ },
23
+ };
24
+ }
25
+
26
+ onChangeBlock(block, dataSaved);
27
+ };
@@ -0,0 +1,63 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { MapsBlockDataAdapter } from './adapter';
3
+
4
+ const alignRight = { 'align:noprefix': 'right' };
5
+ const alignCenter = { 'align:noprefix': 'center' };
6
+
7
+ describe('MapsBlockDataAdapter', () => {
8
+ it('applies the default width for a floating map', () => {
9
+ const onChangeBlock = vi.fn();
10
+
11
+ MapsBlockDataAdapter({
12
+ block: 'block-1',
13
+ data: { '@type': 'maps', styles: { ...alignRight } },
14
+ id: 'url',
15
+ onChangeBlock,
16
+ value: 'https://maps.example.com',
17
+ });
18
+
19
+ expect(onChangeBlock).toHaveBeenCalledWith('block-1', {
20
+ '@type': 'maps',
21
+ url: 'https://maps.example.com',
22
+ styles: {
23
+ ...alignRight,
24
+ 'blockWidth:noprefix': 'default',
25
+ },
26
+ });
27
+ });
28
+
29
+ it('leaves the styles untouched for a non-floating map', () => {
30
+ const onChangeBlock = vi.fn();
31
+
32
+ MapsBlockDataAdapter({
33
+ block: 'block-1',
34
+ data: { '@type': 'maps', styles: { ...alignCenter } },
35
+ id: 'url',
36
+ onChangeBlock,
37
+ value: 'https://maps.example.com',
38
+ });
39
+
40
+ expect(onChangeBlock).toHaveBeenCalledWith('block-1', {
41
+ '@type': 'maps',
42
+ url: 'https://maps.example.com',
43
+ styles: { ...alignCenter },
44
+ });
45
+ });
46
+
47
+ it('leaves the styles untouched when no alignment is set', () => {
48
+ const onChangeBlock = vi.fn();
49
+
50
+ MapsBlockDataAdapter({
51
+ block: 'block-1',
52
+ data: { '@type': 'maps' },
53
+ id: 'url',
54
+ onChangeBlock,
55
+ value: 'https://maps.example.com',
56
+ });
57
+
58
+ expect(onChangeBlock).toHaveBeenCalledWith('block-1', {
59
+ '@type': 'maps',
60
+ url: 'https://maps.example.com',
61
+ });
62
+ });
63
+ });
@@ -1,5 +1,45 @@
1
+ import config from '@plone/volto/registry';
2
+ import { defineMessages } from 'react-intl';
3
+ import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer';
4
+
5
+ const messages = defineMessages({
6
+ BlockWidth: {
7
+ id: 'Block Width',
8
+ defaultMessage: 'Block Width',
9
+ },
10
+ Alignment: {
11
+ id: 'Alignment',
12
+ defaultMessage: 'Alignment',
13
+ },
14
+ });
1
15
  export const mapsBlockSchemaEnhancer = ({ formData, schema, intl }) => {
2
- schema.properties.align.default = 'wide';
3
- schema.properties.align.actions = ['left', 'right', 'center', 'wide', 'full'];
16
+ addStyling({ schema, intl });
17
+
18
+ schema.fieldsets[0].fields = schema.fieldsets[0].fields.filter(
19
+ (f) => f !== 'align',
20
+ );
21
+
22
+ const align = formData.styles?.['align:noprefix'];
23
+ const isFloating = align === 'left' || align === 'right';
24
+
25
+ schema.properties.styles.schema.fieldsets[0].fields = [
26
+ 'align:noprefix',
27
+ 'blockWidth:noprefix',
28
+ ...schema.properties.styles.schema.fieldsets[0].fields,
29
+ ];
30
+ schema.properties.styles.schema.properties['align:noprefix'] = {
31
+ widget: 'blockAlignment',
32
+ title: intl.formatMessage(messages.Alignment),
33
+ default: 'center',
34
+ actions: config.blocks.alignments.map((alignment) => alignment.name),
35
+ };
36
+ schema.properties.styles.schema.properties['blockWidth:noprefix'] = {
37
+ widget: 'blockWidth',
38
+ title: intl.formatMessage(messages.BlockWidth),
39
+ default: 'default',
40
+ actions: config.blocks.widths.map((width) => width.name),
41
+ };
42
+ schema.properties.styles.schema.properties['blockWidth:noprefix'].disabled =
43
+ isFloating;
4
44
  return schema;
5
45
  };
@@ -1,7 +1,19 @@
1
1
  import { defaultStylingSchema } from '../schema';
2
+ import config from '@plone/volto/registry';
2
3
 
3
4
  export const SeparatorStylingSchema = ({ schema, formData, intl }) => {
4
5
  defaultStylingSchema({ schema, formData, intl });
6
+ const styleProps = schema.properties.styles?.schema?.properties;
7
+ if (styleProps?.['align:noprefix']) {
8
+ delete styleProps['align:noprefix'].filterActions;
9
+ styleProps['align:noprefix'].actions = config.blocks.alignments.map(
10
+ (alignment) => alignment.name,
11
+ );
12
+ }
13
+ if (styleProps?.['blockWidth:noprefix']) {
14
+ delete styleProps['blockWidth:noprefix'].filterActions;
15
+ styleProps['blockWidth:noprefix'].actions = ['narrow', 'default'];
16
+ }
5
17
 
6
18
  return schema;
7
19
  };
@@ -1,11 +1,29 @@
1
+ import { useContext } from 'react';
2
+ import { useSelector } from 'react-redux';
3
+ import type { GetSiteResponse } from '@plone/types';
1
4
  import { isInternalURL } from '@plone/volto/helpers/Url/Url';
2
5
  import DefaultSummary from '@kitconcept/volto-light-theme/components/Summary/DefaultSummary';
3
6
  import type { SummaryComponentType } from '@kitconcept/volto-light-theme/components/Summary/DefaultSummary';
4
7
  import Card from '../../../primitives/Card/Card';
5
8
  import config from '@plone/volto/registry';
9
+ import { GridContext } from '@plone/volto/components/manage/Blocks/Grid/context';
10
+
11
+ type FormState = {
12
+ site: { data: GetSiteResponse };
13
+ };
6
14
 
7
15
  const TeaserDefaultTemplate = (props) => {
8
- const { data, isEditMode } = props;
16
+ const site = useSelector<FormState, GetSiteResponse>(
17
+ (state) => state.site?.data,
18
+ );
19
+ const hideProfileLinks = site?.['kitconcept.disable_profile_links'];
20
+ const { data, isEditMode, isContainer } = props;
21
+ const columns = useContext(GridContext);
22
+ const sizes = config.blocks.blocksConfig.teaser?.getSizes?.({
23
+ data,
24
+ inGrid: isContainer,
25
+ columns,
26
+ });
9
27
  const href = data.href?.[0] || {};
10
28
  const image = data.preview_image?.[0];
11
29
  const url = data.preview_image?.[0]?.['@id'];
@@ -15,25 +33,36 @@ const TeaserDefaultTemplate = (props) => {
15
33
  name: 'Summary',
16
34
  dependencies: [href['@type']],
17
35
  }).component || DefaultSummary) as SummaryComponentType;
18
- const showLink = !Summary.hideLink && !isEditMode;
36
+ let showLink = !Summary.hideLink && !isEditMode;
37
+ if (href['@type'] === 'Person' && hideProfileLinks !== undefined) {
38
+ showLink = !hideProfileLinks && !isEditMode;
39
+ }
19
40
  const { openExternalLinkInNewTab } = config.settings;
20
41
  const openLinkInNewTab =
21
42
  data.openLinkInNewTab ||
22
43
  (openExternalLinkInNewTab && !isInternalURL(href['@id']));
23
- const { '@id': id, ...filteredData } = data;
44
+
45
+ // Ensures that overridden fields are used when "overwrite" is true
46
+ // and fallbacks to empty strings if they are not provided to ensure no undefined
47
+ // values are passed
48
+ const localOverrides = {
49
+ title: data.title || '',
50
+ description: data.description || '',
51
+ head_title: data.head_title || '',
52
+ };
24
53
 
25
54
  return (
26
55
  <Card item={showLink ? href : null} openLinkInNewTab={openLinkInNewTab}>
27
56
  <Card.Image
28
57
  src={url && !image?.image_field ? url : undefined}
29
- item={!data.overwrite ? href : { ...href, ...filteredData }}
58
+ item={!data.overwrite ? href : { ...href, ...localOverrides }}
30
59
  image={data.overwrite ? image : undefined}
31
60
  imageComponent={Image}
61
+ sizes={sizes}
32
62
  />
33
63
  <Card.Summary>
34
64
  <Summary
35
- item={!data.overwrite ? href : { ...href, ...filteredData }}
36
- HeadingTag="h2"
65
+ item={!data.overwrite ? href : { ...href, ...localOverrides }}
37
66
  hide_description={props.data?.hide_description}
38
67
  />
39
68
  </Card.Summary>
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { VideoBlockSchema } from '@plone/volto/components/manage/Blocks/Video/schema';
3
+ import { Segment } from 'semantic-ui-react';
4
+ import { defineMessages, useIntl } from 'react-intl';
5
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
6
+ import { BlockDataForm } from '@plone/volto/components/manage/Form';
7
+ import videoSVG from '@plone/volto/icons/videocamera.svg';
8
+
9
+ const messages = defineMessages({
10
+ Video: {
11
+ id: 'Video',
12
+ defaultMessage: 'Video',
13
+ },
14
+ NoVideo: {
15
+ id: 'No Video selected',
16
+ defaultMessage: 'No Video selected',
17
+ },
18
+ });
19
+
20
+ const VideoSidebar = (props) => {
21
+ const {
22
+ blocksConfig,
23
+ blocksErrors,
24
+ data,
25
+ block,
26
+ onChangeBlock,
27
+ navRoot,
28
+ contentType,
29
+ } = props;
30
+ const intl = useIntl();
31
+ const schema = VideoBlockSchema({ ...props, intl });
32
+ const dataAdapter = blocksConfig[data['@type']].dataAdapter;
33
+
34
+ return (
35
+ <>
36
+ {!data.url ? (
37
+ <Segment className="sidebar-metadata-container" secondary>
38
+ {intl.formatMessage(messages.NoVideo)}
39
+ <Icon name={videoSVG} size="100px" color="#b8c6c8" />
40
+ </Segment>
41
+ ) : (
42
+ <BlockDataForm
43
+ schema={schema}
44
+ title={intl.formatMessage(messages.Video)}
45
+ // START CUSTOMIZATION
46
+ onChangeField={(id, value) => {
47
+ dataAdapter({
48
+ block,
49
+ data,
50
+ id,
51
+ onChangeBlock,
52
+ value,
53
+ });
54
+ }}
55
+ // END CUSTOMIZATION
56
+ onChangeBlock={onChangeBlock}
57
+ formData={data}
58
+ block={block}
59
+ navRoot={navRoot}
60
+ contentType={contentType}
61
+ errors={blocksErrors}
62
+ />
63
+ )}
64
+ </>
65
+ );
66
+ };
67
+
68
+ export default VideoSidebar;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * View video block.
3
+ * @module components/manage/Blocks/Video/View
4
+ */
5
+
6
+ import React from 'react';
7
+ import PropTypes from 'prop-types';
8
+ import Body from '@plone/volto/components/manage/Blocks/Video/Body';
9
+ import { withBlockExtensions } from '@plone/volto/helpers/Extensions';
10
+ import cx from 'classnames';
11
+
12
+ /**
13
+ * View video block class.
14
+ * @class View
15
+ * @extends Component
16
+ */
17
+ const View = (props) => {
18
+ const { data, className, style } = props;
19
+
20
+ return (
21
+ // START CUSTOMIZATION
22
+ <div className={cx('block video', className)} style={style}>
23
+ {/* // END CUSTOMIZATION */}
24
+ <Body data={data} />
25
+ </div>
26
+ );
27
+ };
28
+
29
+ /**
30
+ * Property types.
31
+ * @property {Object} propTypes Property types.
32
+ * @static
33
+ */
34
+ View.propTypes = {
35
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
36
+ };
37
+
38
+ export default withBlockExtensions(View);
@@ -0,0 +1,28 @@
1
+ export const VideoBlockDataAdapter = ({
2
+ block,
3
+ data,
4
+ id,
5
+ item,
6
+ onChangeBlock,
7
+ value,
8
+ }) => {
9
+ let dataSaved = {
10
+ ...data,
11
+ [id]: value,
12
+ };
13
+
14
+ const align = dataSaved.styles?.['align:noprefix'];
15
+ const isFloating = align === 'left' || align === 'right';
16
+
17
+ if (isFloating) {
18
+ dataSaved = {
19
+ ...dataSaved,
20
+ styles: {
21
+ ...dataSaved.styles,
22
+ 'blockWidth:noprefix': 'default',
23
+ },
24
+ };
25
+ }
26
+
27
+ onChangeBlock(block, dataSaved);
28
+ };
@@ -0,0 +1,63 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { VideoBlockDataAdapter } from './adapter';
3
+
4
+ const alignLeft = { 'align:noprefix': 'left' };
5
+ const alignCenter = { 'align:noprefix': 'center' };
6
+
7
+ describe('VideoBlockDataAdapter', () => {
8
+ it('applies the default width for a floating video', () => {
9
+ const onChangeBlock = vi.fn();
10
+
11
+ VideoBlockDataAdapter({
12
+ block: 'block-1',
13
+ data: { '@type': 'video', styles: { ...alignLeft } },
14
+ id: 'url',
15
+ onChangeBlock,
16
+ value: 'https://example.com/video',
17
+ });
18
+
19
+ expect(onChangeBlock).toHaveBeenCalledWith('block-1', {
20
+ '@type': 'video',
21
+ url: 'https://example.com/video',
22
+ styles: {
23
+ ...alignLeft,
24
+ 'blockWidth:noprefix': 'default',
25
+ },
26
+ });
27
+ });
28
+
29
+ it('leaves the styles untouched for a non-floating video', () => {
30
+ const onChangeBlock = vi.fn();
31
+
32
+ VideoBlockDataAdapter({
33
+ block: 'block-1',
34
+ data: { '@type': 'video', styles: { ...alignCenter } },
35
+ id: 'url',
36
+ onChangeBlock,
37
+ value: 'https://example.com/video',
38
+ });
39
+
40
+ expect(onChangeBlock).toHaveBeenCalledWith('block-1', {
41
+ '@type': 'video',
42
+ url: 'https://example.com/video',
43
+ styles: { ...alignCenter },
44
+ });
45
+ });
46
+
47
+ it('leaves the styles untouched when no alignment is set', () => {
48
+ const onChangeBlock = vi.fn();
49
+
50
+ VideoBlockDataAdapter({
51
+ block: 'block-1',
52
+ data: { '@type': 'video' },
53
+ id: 'url',
54
+ onChangeBlock,
55
+ value: 'https://example.com/video',
56
+ });
57
+
58
+ expect(onChangeBlock).toHaveBeenCalledWith('block-1', {
59
+ '@type': 'video',
60
+ url: 'https://example.com/video',
61
+ });
62
+ });
63
+ });
@@ -1,5 +1,45 @@
1
+ import config from '@plone/volto/registry';
2
+ import { defineMessages } from 'react-intl';
3
+ import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer';
4
+
5
+ const messages = defineMessages({
6
+ BlockWidth: {
7
+ id: 'Block Width',
8
+ defaultMessage: 'Block Width',
9
+ },
10
+ Alignment: {
11
+ id: 'Alignment',
12
+ defaultMessage: 'Alignment',
13
+ },
14
+ });
1
15
  export const videoBlockSchemaEnhancer = ({ formData, schema, intl }) => {
2
- schema.properties.align.default = 'wide';
3
- schema.properties.align.actions = ['left', 'right', 'center', 'wide', 'full'];
16
+ addStyling({ schema, intl });
17
+
18
+ schema.fieldsets[0].fields = schema.fieldsets[0].fields.filter(
19
+ (f) => f !== 'align',
20
+ );
21
+
22
+ const align = formData.styles?.['align:noprefix'];
23
+ const isFloating = align === 'left' || align === 'right';
24
+
25
+ schema.properties.styles.schema.fieldsets[0].fields = [
26
+ 'align:noprefix',
27
+ 'blockWidth:noprefix',
28
+ ...schema.properties.styles.schema.fieldsets[0].fields,
29
+ ];
30
+ schema.properties.styles.schema.properties['align:noprefix'] = {
31
+ widget: 'blockAlignment',
32
+ title: intl.formatMessage(messages.Alignment),
33
+ default: 'center',
34
+ actions: config.blocks.alignments.map((alignment) => alignment.name),
35
+ };
36
+ schema.properties.styles.schema.properties['blockWidth:noprefix'] = {
37
+ widget: 'blockWidth',
38
+ title: intl.formatMessage(messages.BlockWidth),
39
+ default: 'default',
40
+ actions: config.blocks.widths.map((width) => width.name),
41
+ };
42
+ schema.properties.styles.schema.properties['blockWidth:noprefix'].disabled =
43
+ isFloating;
4
44
  return schema;
5
45
  };