@treely/strapi-slices 7.1.1 → 7.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treely/strapi-slices",
3
- "version": "7.1.1",
3
+ "version": "7.1.3",
4
4
  "license": "MIT",
5
5
  "author": "Tree.ly FlexCo",
6
6
  "description": "@treely/strapi-slices is a open source library maintained by Tree.ly.",
@@ -134,7 +134,7 @@
134
134
  "adblock-detect-react": "^1.1.0",
135
135
  "axios": "^1.7.2",
136
136
  "axios-cache-interceptor": "^1.5.3",
137
- "boemly": "^7.0.0",
137
+ "boemly": "^7.2.0",
138
138
  "embla-carousel-auto-scroll": "^8.5.1",
139
139
  "embla-carousel-autoplay": "^8.5.1",
140
140
  "embla-carousel-react": "^8.5.1",
@@ -22,43 +22,28 @@ Default.args = {
22
22
  logos: [
23
23
  {
24
24
  id: 1,
25
- img: {
26
- id: 1,
27
- alt: 'Alt text 1',
28
- img: { data: storybookStrapiAvatarMock },
29
- },
25
+ alt: 'Alt text 1',
26
+ img: { data: storybookStrapiAvatarMock },
30
27
  },
31
28
  {
32
29
  id: 2,
33
- img: {
34
- id: 2,
35
- alt: 'Alt text 1',
36
- img: { data: storybookStrapiAvatarMock },
37
- },
30
+ alt: 'Alt text 2',
31
+ img: { data: storybookStrapiAvatarMock },
38
32
  },
39
33
  {
40
34
  id: 3,
41
- img: {
42
- id: 3,
43
- alt: 'Alt text 1',
44
- img: { data: storybookStrapiAvatarMock },
45
- },
35
+ alt: 'Alt text 3',
36
+ img: { data: storybookStrapiAvatarMock },
46
37
  },
47
38
  {
48
39
  id: 4,
49
- img: {
50
- id: 4,
51
- alt: 'Alt text 1',
52
- img: { data: storybookStrapiTreeIconMock },
53
- },
40
+ alt: 'Alt text 4',
41
+ img: { data: storybookStrapiTreeIconMock },
54
42
  },
55
43
  {
56
44
  id: 5,
57
- img: {
58
- id: 5,
59
- alt: 'Alt text 1',
60
- img: { data: storybookStrapiCoverMock },
61
- },
45
+ alt: 'Partner Logo 5',
46
+ img: { data: storybookStrapiAvatarMock },
62
47
  },
63
48
  ],
64
49
  },
@@ -71,43 +56,28 @@ WithTitle.args = {
71
56
  logos: [
72
57
  {
73
58
  id: 1,
74
- img: {
75
- id: 1,
76
- alt: 'Partner Logo 1',
77
- img: { data: storybookStrapiAvatarMock },
78
- },
59
+ alt: 'Partner Logo 1',
60
+ img: { data: storybookStrapiAvatarMock },
79
61
  },
80
62
  {
81
63
  id: 2,
82
- img: {
83
- id: 2,
84
- alt: 'Partner Logo 2',
85
- img: { data: storybookStrapiAvatarMock },
86
- },
64
+ alt: 'Partner Logo 2',
65
+ img: { data: storybookStrapiAvatarMock },
87
66
  },
88
67
  {
89
68
  id: 3,
90
- img: {
91
- id: 3,
92
- alt: 'Partner Logo 3',
93
- img: { data: storybookStrapiAvatarMock },
94
- },
69
+ alt: 'Partner Logo 3',
70
+ img: { data: storybookStrapiAvatarMock },
95
71
  },
96
72
  {
97
73
  id: 4,
98
- img: {
99
- id: 4,
100
- alt: 'Partner Logo 4',
101
- img: { data: storybookStrapiTreeIconMock },
102
- },
74
+ alt: 'Partner Logo 4',
75
+ img: { data: storybookStrapiTreeIconMock },
103
76
  },
104
77
  {
105
78
  id: 5,
106
- img: {
107
- id: 5,
108
- alt: 'Partner Logo 5',
109
- img: { data: storybookStrapiCoverMock },
110
- },
79
+ alt: 'Partner Logo 5',
80
+ img: { data: storybookStrapiCoverMock },
111
81
  },
112
82
  ],
113
83
  },
@@ -31,39 +31,33 @@ const defaultProps: CarouselMarqueeBannerProps = {
31
31
  logos: [
32
32
  {
33
33
  id: 1,
34
+ alt: 'Logo 1',
34
35
  img: {
35
- id: 1,
36
- alt: 'Logo 1',
37
- img: {
38
- data: {
39
- ...strapiMediaMock,
40
- attributes: {
41
- ...strapiMediaMock.attributes,
42
- width: 1000,
43
- height: 600,
44
- },
36
+ data: {
37
+ ...strapiMediaMock,
38
+ attributes: {
39
+ ...strapiMediaMock.attributes,
40
+ width: 1000,
41
+ height: 600,
45
42
  },
46
43
  },
47
- objectFit: 'contain',
48
44
  },
45
+ objectFit: 'contain',
49
46
  },
50
47
  {
51
48
  id: 2,
49
+ alt: 'Logo 2',
52
50
  img: {
53
- id: 2,
54
- alt: 'Logo 2',
55
- img: {
56
- data: {
57
- ...strapiMediaMock,
58
- attributes: {
59
- ...strapiMediaMock.attributes,
60
- width: 800,
61
- height: 500,
62
- },
51
+ data: {
52
+ ...strapiMediaMock,
53
+ attributes: {
54
+ ...strapiMediaMock.attributes,
55
+ width: 800,
56
+ height: 500,
63
57
  },
64
58
  },
65
- objectFit: 'cover',
66
59
  },
60
+ objectFit: 'cover',
67
61
  },
68
62
  ],
69
63
  },
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import {
3
3
  DefaultSectionContainer,
4
4
  Flex,
@@ -22,38 +22,36 @@ import { CarouselInnerContainer, LogoGrid } from './styles';
22
22
  export interface CarouselMarqueeBannerProps {
23
23
  slice: {
24
24
  title?: string;
25
- logos: {
26
- id: number;
27
- img: StrapiImage;
28
- }[];
25
+ logos: StrapiImage[];
29
26
  };
30
27
  }
31
28
 
32
- export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
29
+ // Separate component containing the actual logic
30
+ const CarouselMarqueeBannerContent: React.FC<CarouselMarqueeBannerProps> = ({
33
31
  slice,
34
- }: CarouselMarqueeBannerProps) => {
32
+ }) => {
35
33
  const [primary50] = useToken('colors', ['primary.50']);
36
34
  const { width: windowWidth } = useWindowSize();
37
- const shouldDuplicateLogos = slice.logos.length < 5;
35
+ const hasEnoughLogosForLoop = slice.logos.length >= 5;
38
36
  const LOOP_ARRAY_LENGTH = windowWidth > 2000 ? 5 : 4;
39
37
 
40
38
  // Duplicate Logos to create a full loop
41
- const logosToRender = shouldDuplicateLogos
42
- ? slice.logos
43
- : Array.from({ length: LOOP_ARRAY_LENGTH }, () => slice.logos).flat();
39
+ const logosToRender = hasEnoughLogosForLoop
40
+ ? Array.from({ length: LOOP_ARRAY_LENGTH }, () => slice.logos).flat()
41
+ : slice.logos;
44
42
 
45
43
  const [isMobile] = useMediaQuery(BREAKPOINT_MD_QUERY);
46
44
 
45
+ // Carousel setup
47
46
  const [emblaRef] = useEmblaCarousel(
48
47
  {
49
- loop: shouldDuplicateLogos ? false : true,
48
+ loop: hasEnoughLogosForLoop,
50
49
  align: 'start',
51
50
  containScroll: 'trimSnaps',
52
51
  dragFree: true,
53
52
  },
54
- shouldDuplicateLogos
55
- ? []
56
- : [
53
+ hasEnoughLogosForLoop
54
+ ? [
57
55
  AutoScroll({
58
56
  playOnInit: true,
59
57
  speed: isMobile ? 0.5 : 1,
@@ -62,16 +60,16 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
62
60
  stopOnFocusIn: false,
63
61
  }),
64
62
  ]
63
+ : []
65
64
  );
66
65
 
67
- const renderLogos = () => {
68
- if (slice.logos.length < 5) {
66
+ const renderLogos = (): React.ReactNode => {
67
+ if (!hasEnoughLogosForLoop) {
69
68
  return (
70
69
  <LogoGrid>
71
70
  {slice.logos.map((logo, index) => (
72
71
  <Box
73
72
  key={`${logo.id}-${index}`}
74
- width={isMobile ? '16' : '36'}
75
73
  flexShrink={0}
76
74
  transform="translate3d(0, 0, 0)"
77
75
  >
@@ -83,25 +81,20 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
83
81
  >
84
82
  <Box
85
83
  position="relative"
86
- maxHeight="xl"
87
- height={`calc(${
88
- isMobile
89
- ? 'var(--boemly-sizes-16)'
90
- : 'var(--boemly-sizes-36)'
91
- } / ${getClosestRatio(
92
- logo.img.img.data.attributes.width,
93
- logo.img.img.data.attributes.height
94
- )})`}
95
- width={isMobile ? '16' : '36'}
96
- borderRadius="xl"
84
+ height={isMobile ? '16' : '36'}
85
+ width={`calc(var(--boemly-sizes-10)
86
+ * ${getClosestRatio(
87
+ logo.img.data.attributes.width,
88
+ logo.img.data.attributes.height
89
+ )})`}
97
90
  >
98
91
  <Image
99
- src={strapiMediaUrl(logo.img.img, 'large')}
100
- alt={logo.img.alt}
92
+ src={strapiMediaUrl(logo.img, 'large')}
93
+ alt={logo.alt}
101
94
  fill
102
95
  style={{
103
- objectFit: logo.img.objectFit || 'contain',
104
- borderRadius: 'var(--boemly-radii-xl)',
96
+ objectFit: logo.objectFit || 'contain',
97
+ filter: 'grayscale(100%)',
105
98
  }}
106
99
  />
107
100
  </Box>
@@ -118,7 +111,6 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
118
111
  {logosToRender.map((logo, index) => (
119
112
  <Box
120
113
  key={`${logo.id}-${index}`}
121
- width={isMobile ? '16' : '36'}
122
114
  flexShrink={0}
123
115
  transform="translate3d(0, 0, 0)"
124
116
  >
@@ -130,25 +122,19 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
130
122
  >
131
123
  <Box
132
124
  position="relative"
133
- maxHeight="xl"
134
- height={`calc(${
135
- isMobile
136
- ? 'var(--boemly-sizes-16)'
137
- : 'var(--boemly-sizes-36)'
138
- } / ${getClosestRatio(
139
- logo.img.img.data.attributes.width,
140
- logo.img.img.data.attributes.height
125
+ height={isMobile ? '16' : '36'}
126
+ width={`calc(var(--boemly-sizes-10) * ${getClosestRatio(
127
+ logo.img.data.attributes.width,
128
+ logo.img.data.attributes.height
141
129
  )})`}
142
- width={isMobile ? '16' : '36'}
143
- borderRadius="xl"
144
130
  >
145
131
  <Image
146
- src={strapiMediaUrl(logo.img.img, 'large')}
147
- alt={logo.img.alt}
132
+ src={strapiMediaUrl(logo.img, 'large')}
133
+ alt={logo.alt}
148
134
  fill
149
135
  style={{
150
- objectFit: logo.img.objectFit || 'contain',
151
- borderRadius: 'var(--boemly-radii-xl)',
136
+ objectFit: logo.objectFit || 'contain',
137
+ filter: 'grayscale(100%)',
152
138
  }}
153
139
  />
154
140
  </Box>
@@ -180,4 +166,21 @@ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
180
166
  );
181
167
  };
182
168
 
169
+ // Lazy-rendering the child component after client-side hydration
170
+ export const CarouselMarqueeBanner: React.FC<CarouselMarqueeBannerProps> = ({
171
+ slice,
172
+ }: CarouselMarqueeBannerProps) => {
173
+ const [showChild, setShowChild] = useState(false);
174
+
175
+ useEffect(() => {
176
+ setShowChild(true); // Hydrate the component after the client-side is ready
177
+ }, []);
178
+
179
+ if (!showChild) {
180
+ return <div />;
181
+ }
182
+
183
+ return <CarouselMarqueeBannerContent slice={slice} />;
184
+ };
185
+
183
186
  export default CarouselMarqueeBanner;
@@ -12,7 +12,9 @@ export const CarouselInnerContainer = styled(
12
12
  display: flex;
13
13
  justify-content: ${(props) =>
14
14
  props.logoCount < 5 ? 'center' : 'flex-start'};
15
- gap: var(--boemly-space-6);
15
+ gap: var(--boemly-space-24);
16
+ padding-right: var(--boemly-space-24);
17
+ padding-left: var(--boemly-space-24);
16
18
 
17
19
  @media screen and (max-width: ${BREAKPOINT_MD}) {
18
20
  width: calc(
@@ -28,7 +30,7 @@ export const LogoGrid = styled(motion.div)`
28
30
  display: flex;
29
31
  flex-wrap: wrap;
30
32
  justify-content: center;
31
- gap: var(--boemly-space-6);
33
+ gap: var(--boemly-space-24);
32
34
 
33
35
  @media screen and (max-width: ${BREAKPOINT_MD}) {
34
36
  display: grid;
@@ -1,4 +1,4 @@
1
- const ALLOWED_RATIOS = [2 / 3, 1 / 1, 3 / 2];
1
+ const ALLOWED_RATIOS = [2 / 3, 1 / 1, 3 / 2, 2 / 1, 3 / 1, 4 / 1, 5 / 1]; // width / height
2
2
 
3
3
  export const getClosestRatio = (width: number, height: number): number => {
4
4
  const ratio = width / height;