@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,36 @@
1
+ import { useLiveData } from '@kitconcept/volto-light-theme/helpers/useLiveData';
2
+ import IconLinkList from '@kitconcept/volto-light-theme/primitives/IconLinkList';
3
+ import type { StickyMenuSettings } from '../../types';
4
+ import type { Content } from '@plone/types';
5
+
6
+ const StickyMenu = ({ content }: { content: Content }) => {
7
+ const menuData = useLiveData<StickyMenuSettings['sticky_menu']>(
8
+ content,
9
+ 'kitconcept.sticky_menu',
10
+ 'sticky_menu',
11
+ );
12
+
13
+ const sticky_menu_color = useLiveData<
14
+ StickyMenuSettings['sticky_menu_color']
15
+ >(content, 'kitconcept.sticky_menu', 'sticky_menu_color');
16
+
17
+ const sticky_menu_foreground_color = useLiveData<
18
+ StickyMenuSettings['sticky_menu_foreground_color']
19
+ >(content, 'kitconcept.sticky_menu', 'sticky_menu_foreground_color');
20
+
21
+ return (
22
+ <div
23
+ className="sticky-menu"
24
+ style={
25
+ {
26
+ '--sticky-menu-color': sticky_menu_color,
27
+ '--sticky-menu-foreground-color': sticky_menu_foreground_color,
28
+ } as React.CSSProperties
29
+ }
30
+ >
31
+ <IconLinkList iconLinks={menuData} />
32
+ </div>
33
+ );
34
+ };
35
+
36
+ export default StickyMenu;
@@ -0,0 +1,16 @@
1
+ const DefaultSummary = (props) => {
2
+ const { item, HeadingTag = 'h3' } = props;
3
+ return (
4
+ <>
5
+ {item?.head_title && <div className="headline">{item.head_title}</div>}
6
+ <HeadingTag className="title">
7
+ {item.title ? item.title : item.id}
8
+ </HeadingTag>
9
+ {!item.hide_description && (
10
+ <p className="description">{item.description}</p>
11
+ )}
12
+ </>
13
+ );
14
+ };
15
+
16
+ export default DefaultSummary;
@@ -0,0 +1,38 @@
1
+ import {
2
+ parseDateFromCatalog,
3
+ formatDateRange,
4
+ } from '@kitconcept/volto-light-theme/helpers/dates';
5
+ import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
6
+
7
+ const EventSummary = (props) => {
8
+ const { item, HeadingTag = 'h3' } = props;
9
+ const start = parseDateFromCatalog(item.start);
10
+ const end = parseDateFromCatalog(item.end);
11
+ const headline = [
12
+ start && end ? (
13
+ <span className="day" key="day" suppressHydrationWarning>
14
+ {formatDateRange({ start, end, locale: item.Language })}
15
+ </span>
16
+ ) : start ? (
17
+ <FormattedDate key="day" date={start} />
18
+ ) : null,
19
+ item.head_title,
20
+ ]
21
+ .filter((x) => x)
22
+ .flatMap((x) => [' | ', x])
23
+ .slice(1);
24
+
25
+ return (
26
+ <>
27
+ {headline.length ? <div className="headline">{headline}</div> : null}
28
+ <HeadingTag className="title">
29
+ {item.title ? item.title : item.id}
30
+ </HeadingTag>
31
+ {!item.hide_description && (
32
+ <p className="description">{item.description}</p>
33
+ )}
34
+ </>
35
+ );
36
+ };
37
+
38
+ export default EventSummary;
@@ -0,0 +1,24 @@
1
+ import FileType from '@kitconcept/volto-light-theme/helpers/Filetype';
2
+
3
+ const FileSummary = (props) => {
4
+ const { item, HeadingTag = 'h3' } = props;
5
+
6
+ const headline = [item.getObjSize, FileType(item.mime_type), item.head_title]
7
+ .filter((x) => x)
8
+ .flatMap((x) => [' | ', x])
9
+ .slice(1);
10
+
11
+ return (
12
+ <>
13
+ {headline.length ? <div className="headline">{headline}</div> : null}
14
+ <HeadingTag className="title">
15
+ {item.title ? item.title : item.id}
16
+ </HeadingTag>
17
+ {!item.hide_description && (
18
+ <p className="description">{item.description}</p>
19
+ )}
20
+ </>
21
+ );
22
+ };
23
+
24
+ export default FileSummary;
@@ -0,0 +1,40 @@
1
+ import { parseDateFromCatalog } from '@kitconcept/volto-light-theme/helpers/dates';
2
+ import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
3
+
4
+ const NewsItemSummary = (props) => {
5
+ const { item, HeadingTag = 'h3' } = props;
6
+
7
+ const effective = parseDateFromCatalog(item.effective);
8
+ const headline = [
9
+ effective ? (
10
+ <FormattedDate
11
+ key="day"
12
+ date={effective}
13
+ format={{
14
+ year: 'numeric',
15
+ month: 'long',
16
+ day: 'numeric',
17
+ }}
18
+ className="day"
19
+ />
20
+ ) : null,
21
+ item.head_title,
22
+ ]
23
+ .filter((x) => x)
24
+ .flatMap((x) => [' | ', x])
25
+ .slice(1);
26
+
27
+ return (
28
+ <>
29
+ {headline.length ? <div className="headline">{headline}</div> : null}
30
+ <HeadingTag className="title">
31
+ {item.title ? item.title : item.id}
32
+ </HeadingTag>
33
+ {!item.hide_description && (
34
+ <p className="description">{item.description}</p>
35
+ )}
36
+ </>
37
+ );
38
+ };
39
+
40
+ export default NewsItemSummary;
@@ -0,0 +1,46 @@
1
+ import { Link } from 'react-router-dom';
2
+ import PropTypes from 'prop-types';
3
+ import { Container as SemanticContainer } from 'semantic-ui-react';
4
+ import config from '@plone/registry';
5
+
6
+ const Tags = ({ content }) => {
7
+ const tags = content?.subjects || [];
8
+ const Container =
9
+ config.getComponent({ name: 'Container' }).component || SemanticContainer;
10
+
11
+ if (!config.settings.showTags || !tags.length) return null;
12
+
13
+ return (
14
+ <Container className="default tags">
15
+ {tags.map((tag) => (
16
+ <Link className="ui label" to={`/search?Subject=${tag}`} key={tag}>
17
+ {tag}
18
+ </Link>
19
+ ))}
20
+ </Container>
21
+ );
22
+ };
23
+
24
+ /**
25
+ * Property types.
26
+ * @property {Object} propTypes Property types.
27
+ * @static
28
+ */
29
+ Tags.propTypes = {
30
+ content: PropTypes.shape({
31
+ subjects: PropTypes.arrayOf(PropTypes.string),
32
+ }),
33
+ };
34
+
35
+ /**
36
+ * Default properties.
37
+ * @property {Object} defaultProps Default properties.
38
+ * @static
39
+ */
40
+ Tags.defaultProps = {
41
+ content: {
42
+ subjects: [],
43
+ },
44
+ };
45
+
46
+ export default Tags;
@@ -10,9 +10,8 @@ import { flattenHTMLToAppURL } from '@plone/volto/helpers/Url/Url';
10
10
  import { Container as SemanticContainer } from 'semantic-ui-react';
11
11
  import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
12
12
 
13
- import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
14
13
  import config from '@plone/volto/registry';
15
- import { FormattedMessage, injectIntl } from 'react-intl';
14
+ import { injectIntl } from 'react-intl';
16
15
 
17
16
  const EventTextfieldView = ({ content }) => {
18
17
  const Image = config.getComponent({ name: 'Image' }).component;
@@ -53,37 +52,32 @@ const EventView = (props) => {
53
52
  const { content } = props;
54
53
  const Container =
55
54
  config.getComponent({ name: 'Container' }).component || SemanticContainer;
56
- const dateOptions = {
55
+
56
+ const language = content.language?.token || 'default';
57
+ const start = content.start ? new Date(content.start) : null;
58
+ const end = content.end ? new Date(content.end) : null;
59
+ const isOpenEnd = !!content.open_end;
60
+
61
+ const formatter = new Intl.DateTimeFormat(language, {
57
62
  year: 'numeric',
58
63
  month: 'long',
59
64
  day: 'numeric',
60
- hour: 'numeric',
61
- minute: 'numeric',
62
- };
65
+ });
66
+ const formattedDate =
67
+ !end || isOpenEnd
68
+ ? formatter.format(start)
69
+ : formatter.formatRange(start, end);
63
70
 
64
71
  return (
65
72
  <Container id="page-document" className="view-wrapper event-view">
66
73
  <div className="dates">
67
- {content?.start ? (
68
- <span className="day">
69
- <FormattedDate date={content?.start} format={dateOptions} />{' '}
70
- {props.intl.locale === 'de' ? ' Uhr' : ''}
71
- </span>
72
- ) : (
73
- <span className="day">
74
- <FormattedMessage id="No date" defaultMessage="No date" />
75
- </span>
76
- )}{' '}
77
- &mdash;&nbsp;
78
- {content?.end ? (
79
- <span className="day">
80
- <FormattedDate date={content?.end} format={dateOptions} />{' '}
81
- {props.intl.locale === 'de' ? ' Uhr' : ''}
82
- </span>
83
- ) : (
84
- <span className="day">
85
- <FormattedMessage id="No date" defaultMessage="No date" />
74
+ {formattedDate ? (
75
+ <span className="day" suppressHydrationWarning>
76
+ {formattedDate}
86
77
  </span>
78
+ ) : null}{' '}
79
+ {content?.head_title && (
80
+ <span className="head-title"> {content?.head_title}</span>
87
81
  )}
88
82
  </div>
89
83
  {hasBlocksData(content) ? (
@@ -3,12 +3,11 @@
3
3
  * @module components/theme/View/NewsItemView
4
4
  */
5
5
 
6
- import React from 'react';
7
6
  import PropTypes from 'prop-types';
8
7
  import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
9
- import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
10
8
  import config from '@plone/volto/registry';
11
9
  import { Container as SemanticContainer } from 'semantic-ui-react';
10
+ import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
12
11
 
13
12
  /**
14
13
  * NewsItemView view component class.
@@ -22,13 +21,18 @@ const NewsItemView = ({ content }) => {
22
21
  return (
23
22
  <Container id="page-document" className="view-wrapper newsitem-view">
24
23
  <div className="dates">
25
- {content?.effective ? (
26
- <span className="day">
27
- <FormattedDate date={content?.effective} />{' '}
28
- </span>
29
- ) : (
30
- <span className="day">No date</span>
31
- )}{' '}
24
+ {content.effective ? (
25
+ <FormattedDate
26
+ key="day"
27
+ date={content.effective}
28
+ format={{
29
+ year: 'numeric',
30
+ month: 'long',
31
+ day: 'numeric',
32
+ }}
33
+ className="day"
34
+ />
35
+ ) : null}{' '}
32
36
  {content?.head_title && (
33
37
  <span className="head-title"> {content?.head_title}</span>
34
38
  )}
@@ -2,7 +2,7 @@ import Helmet from '@plone/volto/helpers/Helmet/Helmet';
2
2
  import type { Content } from '@plone/types';
3
3
  import { useSelector } from 'react-redux';
4
4
  import isEmpty from 'lodash/isEmpty';
5
- import config from '@plone/registry';
5
+ import type { SiteThemeSettings } from '../../types';
6
6
 
7
7
  type FormState = {
8
8
  content: {
@@ -13,34 +13,37 @@ type FormState = {
13
13
  };
14
14
  };
15
15
 
16
- // TODO: Change when we have the final list of colors
17
- // and if they are nested in the serialization under a key
18
- function buildStyleTag(content: Content, colors: string[]) {
19
- if (Array.isArray(colors)) {
20
- return colors
21
- .filter((color) => content[color])
22
- .map((color) => {
23
- return `--${color.replace(/_/g, '-')}: ${content[color]}; `;
24
- })
25
- .join('');
26
- }
16
+ function buildStyleTag(content: Partial<Content>, colors: SiteThemeSettings) {
17
+ const colorKeys = Object.keys(colors);
18
+ return colorKeys
19
+ .filter((color) => content[color])
20
+ .map((color) => {
21
+ return `--${color.replace(/_/g, '-')}: ${content[color]}; `;
22
+ })
23
+ .join('');
27
24
  }
28
25
 
29
- const Theming = ({ navRoot }) => {
30
- const colorFields = config.settings.userDefinedControlPanelColors;
26
+ const Theming = ({ content }: { content: Content }) => {
27
+ const colorSettings =
28
+ content?.['@components']?.inherit?.['voltolighttheme.theme']?.data;
31
29
  const formData = useSelector<FormState, Content>(
32
30
  (state) => state.form.global,
33
31
  );
34
32
 
35
- const liveContent = navRoot ? (!isEmpty(formData) ? formData : navRoot) : {};
33
+ const liveContent = colorSettings
34
+ ? !isEmpty(formData)
35
+ ? formData
36
+ : colorSettings
37
+ : {};
36
38
 
37
39
  return (
38
40
  <>
39
41
  <Helmet>
40
42
  <style>
41
- {`
43
+ {colorSettings &&
44
+ `
42
45
  :root {
43
- ${buildStyleTag(liveContent, colorFields)}
46
+ ${buildStyleTag(liveContent, colorSettings)}
44
47
  }
45
48
  `}
46
49
  </style>
@@ -1,6 +1,9 @@
1
1
  import React from 'react';
2
2
  import { defineMessages, useIntl } from 'react-intl';
3
- import ButtonsWidget, { type ButtonsWidgetProps } from './ButtonsWidget';
3
+ import ButtonsWidget, {
4
+ type ActionInfo,
5
+ type ButtonsWidgetProps,
6
+ } from './Buttons';
4
7
  import imageFitSVG from '@plone/volto/icons/image-fit.svg';
5
8
  import imageLeftSVG from '@plone/volto/icons/image-left.svg';
6
9
  import imageRightSVG from '@plone/volto/icons/image-right.svg';
@@ -21,7 +24,11 @@ const messages = defineMessages({
21
24
  },
22
25
  });
23
26
 
24
- export const defaultActionsInfo = ({ intl }: { intl: IntlShape }) => ({
27
+ export const defaultActionsInfo = ({
28
+ intl,
29
+ }: {
30
+ intl: IntlShape;
31
+ }): Record<string, ActionInfo> => ({
25
32
  left: [imageLeftSVG, intl.formatMessage(messages.left)],
26
33
  right: [imageRightSVG, intl.formatMessage(messages.right)],
27
34
  center: [imageFitSVG, intl.formatMessage(messages.center)],
@@ -1,11 +1,14 @@
1
1
  import React from 'react';
2
2
  import { defineMessages, useIntl } from 'react-intl';
3
- import ButtonsWidget, { type ButtonsWidgetProps } from './ButtonsWidget';
3
+ import type { IntlShape } from 'react-intl';
4
+ import ButtonsWidget, {
5
+ type ActionInfo,
6
+ type ButtonsWidgetProps,
7
+ } from './Buttons';
4
8
  import imageFitSVG from '@plone/volto/icons/image-fit.svg';
5
9
  import imageNarrowSVG from '@plone/volto/icons/image-narrow.svg';
6
10
  import imageWideSVG from '@plone/volto/icons/image-wide.svg';
7
11
  import imageFullSVG from '@plone/volto/icons/image-full.svg';
8
- import type { IntlShape } from 'react-intl';
9
12
 
10
13
  const messages = defineMessages({
11
14
  narrow: {
@@ -26,7 +29,11 @@ const messages = defineMessages({
26
29
  },
27
30
  });
28
31
 
29
- export const defaultActionsInfo = ({ intl }: { intl: IntlShape }) => ({
32
+ export const defaultActionsInfo = ({
33
+ intl,
34
+ }: {
35
+ intl: IntlShape;
36
+ }): Record<string, ActionInfo> => ({
30
37
  narrow: [imageNarrowSVG, intl.formatMessage(messages.narrow)],
31
38
  default: [imageFitSVG, intl.formatMessage(messages.default)],
32
39
  layout: [imageWideSVG, intl.formatMessage(messages.layout)],