@kitconcept/volto-light-theme 6.0.0-alpha.2 → 6.0.0-alpha.3

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 CHANGED
@@ -1,7 +1,13 @@
1
- ## 6.0.0-alpha.2 (2024-11-25)
1
+ ## 6.0.0-alpha.3 (2024-12-05)
2
+
3
+ ### Feature
4
+
5
+ - New look and feel specs for footer logos. @sneridagh
6
+ Added two slots: `preFooter` and `postFooter`. [#437](https://github.com/kitconcept/volto-light-theme/pull/437)
2
7
 
3
8
  ### Bugfix
4
9
 
5
- - Fix Image block schema bug on creation. @sneridagh [#434](https://github.com/kitconcept/volto-light-theme/pull/434)
10
+ - Fixed edge case when you delete the image content type from the site. @sneridagh [#437](https://github.com/kitconcept/volto-light-theme/pull/437)
11
+ - Fixed layout shift jumps on RAC Popovers. @sneridagh [#440](https://github.com/kitconcept/volto-light-theme/pull/440)
6
12
 
7
13
 
package/CHANGELOG.md CHANGED
@@ -8,6 +8,18 @@
8
8
 
9
9
  <!-- towncrier release notes start -->
10
10
 
11
+ ## 6.0.0-alpha.3 (2024-12-05)
12
+
13
+ ### Feature
14
+
15
+ - New look and feel specs for footer logos. @sneridagh
16
+ Added two slots: `preFooter` and `postFooter`. [#437](https://github.com/kitconcept/volto-light-theme/pull/437)
17
+
18
+ ### Bugfix
19
+
20
+ - Fixed edge case when you delete the image content type from the site. @sneridagh [#437](https://github.com/kitconcept/volto-light-theme/pull/437)
21
+ - Fixed layout shift jumps on RAC Popovers. @sneridagh [#440](https://github.com/kitconcept/volto-light-theme/pull/440)
22
+
11
23
  ## 6.0.0-alpha.2 (2024-11-25)
12
24
 
13
25
  ### Bugfix
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitconcept/volto-light-theme",
3
- "version": "6.0.0-alpha.2",
3
+ "version": "6.0.0-alpha.3",
4
4
  "description": "Volto Light Theme by kitconcept",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/types/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "uuid": "^11.0.0",
40
- "@plone/components": "^2.1.1"
40
+ "@plone/components": "^2.2.1"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@eeacms/volto-accordion-block": "^10.4.6",
@@ -1,14 +1,12 @@
1
1
  // SemanticUI-free pre-@plone/components
2
2
  import React from 'react';
3
- import isEmpty from 'lodash/isEmpty';
4
- import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
3
+ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
5
4
  import { useSelector, shallowEqual } from 'react-redux';
6
- import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
7
- import ConditionalLink from '@plone/volto/components/manage/ConditionalLink/ConditionalLink';
5
+ import { useLocation } from 'react-router-dom';
8
6
  import Logo from '@plone/volto/components/theme/Logo/Logo';
9
7
  import { Container } from '@plone/components';
10
- import { flattenToAppURL, addAppURL } from '@plone/volto/helpers/Url/Url';
11
- import config from '@plone/volto/registry';
8
+ import SlotRenderer from '@plone/volto/components/theme/SlotRenderer/SlotRenderer';
9
+ import FooterLinks from './FooterLinks';
12
10
 
13
11
  const messages = defineMessages({
14
12
  copyright: {
@@ -17,27 +15,28 @@ const messages = defineMessages({
17
15
  },
18
16
  });
19
17
 
20
- /**
21
- * Component to display the footer.
22
- * @function Footer
23
- * @param {Object} intl Intl object
24
- * @returns {string} Markup of the component
25
- */
26
- const Footer = ({ intl }) => {
27
- const { settings } = config;
28
- const { lang, siteActions = [] } = useSelector(
18
+ const Footer = () => {
19
+ const intl = useIntl();
20
+ const {
21
+ content,
22
+ lang,
23
+ siteActions = [],
24
+ } = useSelector(
29
25
  (state) => ({
30
26
  lang: state.intl.locale,
31
27
  siteActions: state.actions?.actions?.site_actions,
28
+ content: state.content.data,
32
29
  }),
33
30
  shallowEqual,
34
31
  );
32
+ const location = useLocation();
35
33
  const navroot = useSelector((state) => state.navroot.data.navroot);
36
34
  const footerLinks = navroot?.footer_links;
37
- const footerLogos = navroot?.footer_logos;
38
35
 
39
36
  return (
40
37
  <footer id="footer">
38
+ <SlotRenderer name="preFooter" content={content} location={location} />
39
+
41
40
  <Container className="footer">
42
41
  <div className="footer-message">
43
42
  <FormattedMessage
@@ -84,75 +83,11 @@ const Footer = ({ intl }) => {
84
83
  }}
85
84
  />
86
85
  </div>
87
- <ul className="footer-links">
88
- {!isEmpty(footerLinks?.blocks)
89
- ? footerLinks.blocks_layout.items.map((itemId) => {
90
- const link = footerLinks.blocks[itemId];
91
- const title = link.title || link.href[0]['title'];
92
- const href = flattenToAppURL(link.href[0]['@id']);
93
-
94
- if (!href) return null;
95
-
96
- return (
97
- <li className="item" key={href}>
98
- <UniversalLink href={href}>{title}</UniversalLink>
99
- </li>
100
- );
101
- })
102
- : siteActions?.length
103
- ? siteActions.map((item) => (
104
- <li className="item" key={item.id}>
105
- <UniversalLink
106
- className="item"
107
- href={
108
- settings.isMultilingual
109
- ? `/${lang}/${
110
- item.url
111
- ? flattenToAppURL(item.url)
112
- : addAppURL(item.id)
113
- }`
114
- : item.url
115
- ? flattenToAppURL(item.url)
116
- : addAppURL(item.id)
117
- }
118
- >
119
- {item?.title}
120
- </UniversalLink>
121
- </li>
122
- ))
123
- : null}
124
- </ul>
125
- <ul className="footer-logos">
126
- {!isEmpty(footerLogos?.blocks)
127
- ? footerLogos.blocks_layout.items.map((itemId) => {
128
- const logo = footerLogos.blocks[itemId];
129
- let logoHref, hrefTitle, href, srcAlt, src;
130
- if (logo?.href) {
131
- hrefTitle = logo.href[0]['title'];
132
- href = flattenToAppURL(logo.href[0]['@id']);
133
- }
134
- if (logo?.logo) {
135
- logoHref = logo.logo[0]['@id'];
136
- srcAlt = logo['alt'];
137
- src = `${flattenToAppURL(logoHref)}/${logo.logo[0].image_scales[logo.logo[0].image_field][0].download}`;
138
- }
139
-
140
- if (!src) return null;
141
-
142
- return (
143
- <li className="item" key={href}>
144
- <ConditionalLink
145
- condition={href}
146
- to={href}
147
- title={hrefTitle || srcAlt}
148
- >
149
- <img src={src} alt={srcAlt} />
150
- </ConditionalLink>
151
- </li>
152
- );
153
- })
154
- : null}
155
- </ul>
86
+ <FooterLinks
87
+ links={footerLinks}
88
+ siteActions={siteActions}
89
+ lang={lang}
90
+ />
156
91
  <div className="logo">
157
92
  <Logo />
158
93
  </div>
@@ -171,19 +106,10 @@ const Footer = ({ intl }) => {
171
106
  by kitconcept
172
107
  </div>
173
108
  </Container>
109
+
110
+ <SlotRenderer name="postFooter" content={content} location={location} />
174
111
  </footer>
175
112
  );
176
113
  };
177
114
 
178
- /**
179
- * Property types.
180
- * @property {Object} propTypes Property types.
181
- * @static
182
- */
183
- Footer.propTypes = {
184
- /**
185
- * i18n object
186
- */
187
- };
188
-
189
- export default injectIntl(Footer);
115
+ export default Footer;
@@ -0,0 +1,54 @@
1
+ import isEmpty from 'lodash/isEmpty';
2
+ import { addAppURL, flattenToAppURL } from '@plone/volto/helpers/Url/Url';
3
+ import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
4
+ import type { BlocksData } from '@plone/types';
5
+ import config from '@plone/volto/registry';
6
+
7
+ type FooterLinksProps = { links: BlocksData; siteActions: any; lang: string };
8
+
9
+ const FooterLinks = (props: FooterLinksProps) => {
10
+ const { lang, links, siteActions } = props;
11
+
12
+ return (
13
+ <ul className="footer-links">
14
+ {!isEmpty(links?.blocks)
15
+ ? links.blocks_layout.items.map((itemId) => {
16
+ const link = links.blocks[itemId];
17
+ const title = link.title || link.href[0]['title'];
18
+ const href = flattenToAppURL(link.href[0]['@id']);
19
+
20
+ if (!href) return null;
21
+
22
+ return (
23
+ <li className="item" key={href}>
24
+ <UniversalLink href={href}>{title}</UniversalLink>
25
+ </li>
26
+ );
27
+ })
28
+ : siteActions?.length
29
+ ? siteActions.map((item) => (
30
+ <li className="item" key={item.id}>
31
+ <UniversalLink
32
+ className="item"
33
+ href={
34
+ config.settings.isMultilingual
35
+ ? `/${lang}/${
36
+ item.url
37
+ ? flattenToAppURL(item.url)
38
+ : addAppURL(item.id)
39
+ }`
40
+ : item.url
41
+ ? flattenToAppURL(item.url)
42
+ : addAppURL(item.id)
43
+ }
44
+ >
45
+ {item?.title}
46
+ </UniversalLink>
47
+ </li>
48
+ ))
49
+ : null}
50
+ </ul>
51
+ );
52
+ };
53
+
54
+ export default FooterLinks;
@@ -0,0 +1,75 @@
1
+ import type { Content } from '@plone/types';
2
+ import isEmpty from 'lodash/isEmpty';
3
+ import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
4
+ import ConditionalLink from '@plone/volto/components/manage/ConditionalLink/ConditionalLink';
5
+ import { useSelector } from 'react-redux';
6
+ import { Container } from '@plone/components';
7
+
8
+ type FormState = {
9
+ content: {
10
+ data: Content;
11
+ };
12
+ navroot: {
13
+ data: {
14
+ navroot: Content;
15
+ };
16
+ };
17
+ };
18
+
19
+ const FooterLogos = () => {
20
+ const navroot = useSelector<FormState, Content>(
21
+ (state) => state.navroot.data.navroot,
22
+ );
23
+ const logos = navroot?.footer_logos;
24
+
25
+ return (
26
+ <Container layout>
27
+ <ul className="footer-logos">
28
+ {!isEmpty(logos?.blocks)
29
+ ? logos.blocks_layout.items.map((itemId) => {
30
+ const logo = logos.blocks[itemId];
31
+ const logoInfo: {
32
+ hrefTitle: string;
33
+ href: string;
34
+ logoHref: string;
35
+ src: string;
36
+ srcAlt: string;
37
+ } = {
38
+ hrefTitle: '',
39
+ href: '',
40
+ logoHref: '',
41
+ src: '',
42
+ srcAlt: '',
43
+ };
44
+ if (logo?.href) {
45
+ logoInfo.hrefTitle = logo.href[0]['title'];
46
+ logoInfo.href = flattenToAppURL(logo.href[0]['@id']);
47
+ }
48
+ if (logo?.logo && logo.logo[0]?.image_scales) {
49
+ logoInfo.logoHref = logo.logo[0]['@id'];
50
+ logoInfo.srcAlt = logo['alt'];
51
+ logoInfo.src = `${flattenToAppURL(logoInfo.logoHref)}/${logo.logo[0].image_scales[logo.logo[0].image_field][0].download}`;
52
+ }
53
+
54
+ if (!logoInfo.src) return null;
55
+
56
+ return (
57
+ <li className="item" key={logoInfo.href}>
58
+ {/* @ts-ignore */}
59
+ <ConditionalLink
60
+ condition={logoInfo.href}
61
+ to={logoInfo.href}
62
+ title={logoInfo.hrefTitle || logoInfo.srcAlt}
63
+ >
64
+ <img src={logoInfo.src} alt={logoInfo.srcAlt} />
65
+ </ConditionalLink>
66
+ </li>
67
+ );
68
+ })
69
+ : null}
70
+ </ul>
71
+ </Container>
72
+ );
73
+ };
74
+
75
+ export default FooterLogos;
@@ -1,5 +1,6 @@
1
1
  import type { ConfigType } from '@plone/registry';
2
2
  import Theming from '../components/Theming/Theming';
3
+ import FooterLogos from '../components/Footer/FooterLogos';
3
4
 
4
5
  export default function install(config: ConfigType) {
5
6
  config.registerSlotComponent({
@@ -8,5 +9,11 @@ export default function install(config: ConfigType) {
8
9
  component: Theming,
9
10
  });
10
11
 
12
+ config.registerSlotComponent({
13
+ name: 'footerLogos',
14
+ slot: 'preFooter',
15
+ component: FooterLogos,
16
+ });
17
+
11
18
  return config;
12
19
  }
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ import installWidgets from './config/widgets';
14
14
  import installSlots from './config/slots';
15
15
 
16
16
  import '@plone/components/dist/basic.css';
17
+ import type { BlocksData } from '@plone/types';
17
18
 
18
19
  defineMessages({
19
20
  Press: {
@@ -26,6 +27,12 @@ defineMessages({
26
27
  },
27
28
  });
28
29
 
30
+ declare module '@plone/types' {
31
+ export interface Content {
32
+ footer_logos: BlocksData;
33
+ }
34
+ }
35
+
29
36
  const applyConfig = (config: ConfigType) => {
30
37
  installSettings(config);
31
38
  installBlocks(config);
@@ -1,7 +1,32 @@
1
1
  #footer {
2
- margin-top: 0;
2
+ margin-top: $footer-vertical-spacing-top;
3
3
  text-align: center;
4
4
 
5
+ ul.footer-logos {
6
+ display: grid;
7
+ justify-content: center;
8
+ padding: $pre-footer-vertical-spacing 0;
9
+ padding-left: 0;
10
+ margin-top: 0;
11
+ margin-bottom: $spacing-medium;
12
+ gap: 20px;
13
+ grid-template-columns: repeat(3, 1fr);
14
+ list-style: none;
15
+
16
+ img {
17
+ max-width: 100%;
18
+ }
19
+
20
+ li.item:nth-child(3n + 1) {
21
+ /* Targets 1st, 4th, 7th, etc. */
22
+ justify-self: start;
23
+ }
24
+ li.item:nth-child(3n + 3) {
25
+ /* Targets 3rd, 6th, 9th, etc. */
26
+ justify-self: end;
27
+ }
28
+ }
29
+
5
30
  .footer {
6
31
  padding: 4.2rem 2rem;
7
32
  background-color: $lightgrey;
@@ -26,6 +51,7 @@
26
51
 
27
52
  ul {
28
53
  display: flex;
54
+ flex-wrap: wrap;
29
55
  justify-content: center;
30
56
  padding-left: 0;
31
57
  margin-top: 1.4rem;
@@ -60,6 +60,18 @@
60
60
  z-index: $zindex;
61
61
  }
62
62
 
63
+ // RAC Popovers have problems with SemanticUI CSS in the BODY tag
64
+ // SemanticUI by default uses `overflow-x: hidden`.
65
+ // TODO: Remove when https://github.com/plone/volto/pull/6513 is merged and released.
66
+ body {
67
+ overflow-x: initial;
68
+ }
69
+
70
+ // This helps not to have a little layout shift when the RAC Popovers are shown.
71
+ html[style*='padding-right'] .sidebar-container {
72
+ margin-right: 15px;
73
+ }
74
+
63
75
  // We expect initially three main containers
64
76
  .header-wrapper {
65
77
  .q.container,
@@ -274,6 +274,7 @@ $grid-block-vertical-spacing-bottom: $spacing-xlarge !default;
274
274
 
275
275
  // Footer
276
276
  $footer-vertical-spacing-top: $spacing-xlarge !default;
277
+ $pre-footer-vertical-spacing: $spacing-small !default;
277
278
 
278
279
  // Maps
279
280
  $font-weights: (