@treely/strapi-slices 7.4.1 → 7.5.0

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 (57) hide show
  1. package/dist/components/PreviewAlert/PreviewAlert.stories.d.ts +2 -2
  2. package/dist/integrations/strapi/getAvailableLocalesFromStrapi.d.ts +2 -0
  3. package/dist/slices/BlogCards/BlogCards.stories.d.ts +4 -4
  4. package/dist/slices/CarouselMarqueeBanner/CarouselMarqueeBanner.stories.d.ts +3 -3
  5. package/dist/slices/Comparison/Comparison.stories.d.ts +5 -5
  6. package/dist/slices/Cta/Cta.stories.d.ts +8 -8
  7. package/dist/slices/CtaOnly/CtaOnly.stories.d.ts +2 -2
  8. package/dist/slices/CustomerStories/CustomerStories.stories.d.ts +5 -5
  9. package/dist/slices/Events/Events.stories.d.ts +3 -3
  10. package/dist/slices/Facts/Facts.stories.d.ts +6 -6
  11. package/dist/slices/FullWidthHighlightQuote/FullWidthHighlightQuote.stories.d.ts +3 -3
  12. package/dist/slices/FullWidthImage/FullWidthImage.stories.d.ts +4 -4
  13. package/dist/slices/FullWidthImageSlider/FullWidthImageSlider.stories.d.ts +2 -2
  14. package/dist/slices/Glossary/Glossary.stories.d.ts +2 -2
  15. package/dist/slices/Hero/Hero.stories.d.ts +8 -8
  16. package/dist/slices/IconGrid/IconGrid.stories.d.ts +4 -4
  17. package/dist/slices/ImageGrid/ImageGrid.stories.d.ts +4 -4
  18. package/dist/slices/ImageTextSequence/ImageTextSequence.stories.d.ts +6 -6
  19. package/dist/slices/LeftTextRightCard/LeftTextRightCard.stories.d.ts +7 -7
  20. package/dist/slices/LinkCardsGrid/LinkCardsGrid.stories.d.ts +4 -4
  21. package/dist/slices/LogoGridWithText/LogoGridWithText.stories.d.ts +5 -5
  22. package/dist/slices/MapHero/MapHero.stories.d.ts +7 -7
  23. package/dist/slices/ProjectFacts/ProjectFacts.stories.d.ts +7 -7
  24. package/dist/slices/ProjectsGrid/ProjectsGrid.stories.d.ts +4 -4
  25. package/dist/slices/ProjectsMap/ProjectsMap.stories.d.ts +5 -5
  26. package/dist/slices/QAndA/QAndA.stories.d.ts +6 -6
  27. package/dist/slices/QuoteCards/QuoteCards.stories.d.ts +7 -7
  28. package/dist/slices/RichTextSection/RichTextSection.stories.d.ts +2 -2
  29. package/dist/slices/ShopCheckout/ShopCheckout.stories.d.ts +7 -7
  30. package/dist/slices/SideBySideImages/SideBySideImages.stories.d.ts +2 -2
  31. package/dist/slices/SmallHero/SmallHero.stories.d.ts +10 -10
  32. package/dist/slices/Steps/Steps.stories.d.ts +6 -6
  33. package/dist/slices/TextCardGrid/TextCardGrid.stories.d.ts +7 -7
  34. package/dist/slices/TextCarousel/TextCarousel.stories.d.ts +7 -7
  35. package/dist/slices/TextWithCard/TextWithCard.stories.d.ts +9 -9
  36. package/dist/slices/TextWithTextCards/TextWithTextCards.stories.d.ts +6 -6
  37. package/dist/slices/Timeline/Timeline.stories.d.ts +8 -8
  38. package/dist/slices/Video/Video.stories.d.ts +2 -2
  39. package/dist/strapi-slices.cjs.development.js +196 -128
  40. package/dist/strapi-slices.cjs.development.js.map +1 -1
  41. package/dist/strapi-slices.cjs.production.min.js +1 -1
  42. package/dist/strapi-slices.cjs.production.min.js.map +1 -1
  43. package/dist/strapi-slices.esm.js +196 -128
  44. package/dist/strapi-slices.esm.js.map +1 -1
  45. package/package.json +17 -12
  46. package/src/integrations/strapi/getAllSlugsFromStrapi.test.ts +42 -5
  47. package/src/integrations/strapi/getAllSlugsFromStrapi.ts +39 -26
  48. package/src/integrations/strapi/getAvailableLocalesFromStrapi.test.ts +22 -0
  49. package/src/integrations/strapi/getAvailableLocalesFromStrapi.ts +8 -0
  50. package/src/integrations/strapi/getPortfolioProjects.ts +1 -1
  51. package/src/integrations/strapi/getStrapiCollectionType.test.ts +36 -10
  52. package/src/integrations/strapi/getStrapiCollectionType.ts +33 -26
  53. package/src/integrations/strapi/getStrapiSingleType.ts +1 -1
  54. package/src/integrations/strapi/strapiClient.ts +1 -0
  55. package/src/slices/Events/Events.tsx +8 -3
  56. package/src/slices/TextCarousel/TextCarousel.tsx +46 -44
  57. package/src/stories/{Introduction.stories.mdx → Introduction.mdx} +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treely/strapi-slices",
3
- "version": "7.4.1",
3
+ "version": "7.5.0",
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.",
@@ -99,22 +99,27 @@
99
99
  }
100
100
  ],
101
101
  "devDependencies": {
102
+ "@chromatic-com/storybook": "^3.2.5",
102
103
  "@size-limit/preset-small-lib": "^11.0.0",
103
- "@storybook/addon-essentials": "^7.5.3",
104
- "@storybook/addon-interactions": "^7.5.3",
105
- "@storybook/addon-links": "^7.5.3",
106
- "@storybook/addon-onboarding": "^1.0.8",
107
- "@storybook/addons": "^7.5.3",
108
- "@storybook/blocks": "^7.5.3",
109
- "@storybook/nextjs": "^7.5.3",
110
- "@storybook/react": "^7.5.3",
111
- "@storybook/testing-library": "^0.2.2",
104
+ "@storybook/addon-essentials": "^8.6.4",
105
+ "@storybook/addon-interactions": "^8.6.4",
106
+ "@storybook/addon-links": "^8.6.4",
107
+ "@storybook/addon-onboarding": "^8.6.4",
108
+ "@storybook/blocks": "^8.6.4",
109
+ "@storybook/manager-api": "^8.6.4",
110
+ "@storybook/nextjs": "^8.6.4",
111
+ "@storybook/preview-api": "^8.6.4",
112
+ "@storybook/react": "^8.6.4",
113
+ "@storybook/test": "^8.6.4",
114
+ "@storybook/theming": "^8.6.4",
115
+ "@storybook/types": "^8.6.4",
112
116
  "@testing-library/jest-dom": "^6.1.4",
113
117
  "@testing-library/react": "^14.1.2",
114
118
  "@testing-library/user-event": "^14.5.1",
115
119
  "@tsconfig/recommended": "^1.0.3",
116
120
  "@tsconfig/vite-react": "^2.0.1",
117
121
  "@types/mapbox-gl": "^2.7.19",
122
+ "@types/qs": "^6.9.18",
118
123
  "@types/react": "^18.2.38",
119
124
  "@types/react-dom": "^18.2.17",
120
125
  "@typescript-eslint/eslint-plugin": "^7.9.0",
@@ -133,7 +138,7 @@
133
138
  "react-dom": "^18.2.0",
134
139
  "semantic-release": "^22.0.8",
135
140
  "size-limit": "^11.0.0",
136
- "storybook": "^7.5.3",
141
+ "storybook": "^8.6.4",
137
142
  "typescript": "^5.3.2"
138
143
  },
139
144
  "dependencies": {
@@ -141,7 +146,7 @@
141
146
  "adblock-detect-react": "^1.1.0",
142
147
  "axios": "^1.7.2",
143
148
  "axios-cache-interceptor": "^1.5.3",
144
- "boemly": "^7.5.0",
149
+ "boemly": "^7.6.0",
145
150
  "embla-carousel-auto-scroll": "^8.5.1",
146
151
  "embla-carousel-autoplay": "^8.5.1",
147
152
  "embla-carousel-react": "^8.5.1",
@@ -2,24 +2,61 @@ import MockAxios from 'jest-mock-axios';
2
2
  import getAllSlugsFromStrapi from './getAllSlugsFromStrapi';
3
3
  import StrapiPage from '../../models/strapi/StrapiPage';
4
4
  import { strapiPageMock } from '../../test/strapiMocks/strapiPage';
5
+ import getAvailableLocalesFromStrapi from './getAvailableLocalesFromStrapi';
6
+
7
+ jest.mock('./getAvailableLocalesFromStrapi', () => ({
8
+ __esModule: true,
9
+ default: jest.fn(),
10
+ }));
5
11
 
6
12
  describe('The getAllSlugsFromStrapi function', () => {
7
13
  afterEach(() => {
8
14
  MockAxios.reset();
15
+ jest.clearAllMocks();
9
16
  });
10
17
 
11
18
  it('returns all slugs and creates a fallback for locales that dont have a translation', async () => {
19
+ (getAvailableLocalesFromStrapi as jest.Mock).mockResolvedValue([
20
+ 'en',
21
+ 'de',
22
+ 'hu',
23
+ ]);
24
+
12
25
  const slugsPromise = getAllSlugsFromStrapi<StrapiPage>('/api/pages', [
13
26
  'en',
14
27
  'de',
15
28
  'hu',
16
29
  ]);
17
30
 
18
- // This page is avaliable in 'de' and 'en'
19
- MockAxios.mockResponseFor(
20
- { url: '/api/pages' },
21
- { data: { data: [strapiPageMock] } }
22
- );
31
+ // This page is available in 'de', 'en', and 'hu'
32
+ MockAxios.get
33
+ .mockResolvedValueOnce({ data: { data: [strapiPageMock] } }) // english
34
+ .mockResolvedValueOnce({
35
+ data: {
36
+ data: [
37
+ {
38
+ ...strapiPageMock,
39
+ attributes: {
40
+ ...strapiPageMock.attributes,
41
+ locale: 'de',
42
+ },
43
+ },
44
+ ],
45
+ },
46
+ })
47
+ .mockResolvedValueOnce({
48
+ data: {
49
+ data: [
50
+ {
51
+ ...strapiPageMock,
52
+ attributes: {
53
+ ...strapiPageMock.attributes,
54
+ locale: 'hu',
55
+ },
56
+ },
57
+ ],
58
+ },
59
+ });
23
60
 
24
61
  const slugs = await slugsPromise;
25
62
 
@@ -6,6 +6,7 @@ import {
6
6
  import IStrapiResponse from '../../models/strapi/IStrapiResponse';
7
7
  import IStrapiData from '../../models/strapi/IStrapiData';
8
8
  import LocalizedEntity from '../../models/LocalizedEntity';
9
+ import getAvailableLocalesFromStrapi from './getAvailableLocalesFromStrapi';
9
10
 
10
11
  interface Options {
11
12
  filters?: Record<string, any>;
@@ -18,33 +19,45 @@ const getAllSlugsFromStrapi = async <T extends LocalizedEntity<'slug'>>(
18
19
  locales: string[],
19
20
  { filters = {} }: Options = { filters: {} }
20
21
  ): Promise<Slug[]> => {
21
- const params: Record<string, any> = {
22
- locale: 'all',
23
- 'pagination[pageSize]': STRAPI_DEFAULT_PAGE_SIZE,
24
- filters,
25
- };
26
-
27
- const { data } = await strapiClient.get<IStrapiResponse<IStrapiData<T>[]>>(
28
- path,
29
- { params }
30
- );
31
-
32
- const slugs: Slug[] = data.data.map((page) => ({
33
- slug: page.attributes.slug,
34
- locale: page.attributes.locale,
35
- }));
36
-
37
- const fallBackSlugs: Slug[] = locales.flatMap((locale) =>
38
- slugs
22
+ const allLocales = await getAvailableLocalesFromStrapi();
23
+
24
+ const slugPromises = allLocales.map((locale) => {
25
+ const params: Record<string, any> = {
26
+ locale,
27
+ 'pagination[pageSize]': STRAPI_DEFAULT_PAGE_SIZE,
28
+ filters,
29
+ };
30
+
31
+ return strapiClient.get<IStrapiResponse<IStrapiData<T>[]>>(path, {
32
+ params,
33
+ });
34
+ });
35
+
36
+ const slugResults = await Promise.all(slugPromises);
37
+
38
+ let allSlugs = slugResults
39
+ .map((result) =>
40
+ result.data.data.map((page) => ({
41
+ slug: page.attributes.slug,
42
+ locale: page.attributes.locale,
43
+ }))
44
+ )
45
+ .flat();
46
+
47
+ // Identify missing locales for each slug
48
+ const missingLocales = locales.flatMap((locale) => {
49
+ return allSlugs
39
50
  .filter((slug) => slug.locale === STRAPI_FALLBACK_LOCALE)
40
- .map((slug) => ({ ...slug, locale }))
41
- );
42
-
43
- const nonFallbackSlugs = slugs.filter(
44
- (p) => p.locale !== STRAPI_FALLBACK_LOCALE
45
- );
46
-
47
- return [...fallBackSlugs, ...nonFallbackSlugs];
51
+ .filter(
52
+ (fallbackSlug) =>
53
+ !allSlugs.some(
54
+ (slug) => slug.slug === fallbackSlug.slug && slug.locale === locale
55
+ )
56
+ )
57
+ .map((fallbackSlug) => ({ ...fallbackSlug, locale })); // Clone only for missing locales
58
+ });
59
+
60
+ return [...allSlugs, ...missingLocales]; // Merge original and missing slugs
48
61
  };
49
62
 
50
63
  export default getAllSlugsFromStrapi;
@@ -0,0 +1,22 @@
1
+ import getAvailableLocalesFromStrapi from './getAvailableLocalesFromStrapi';
2
+ import strapiClient from './strapiClient';
3
+
4
+ jest.mock('./strapiClient', () => ({
5
+ get: jest.fn(),
6
+ }));
7
+
8
+ describe('getAvailableLocales function', () => {
9
+ it('should fetch available locales and return them correctly', async () => {
10
+ const mockResponse = {
11
+ data: [{ code: 'en' }, { code: 'de' }, { code: 'hu' }],
12
+ };
13
+
14
+ (strapiClient.get as jest.Mock).mockResolvedValue(mockResponse);
15
+
16
+ const locales = await getAvailableLocalesFromStrapi();
17
+
18
+ expect(locales).toEqual(['en', 'de', 'hu']);
19
+ expect(strapiClient.get).toHaveBeenCalledWith('/i18n/locales');
20
+ expect(strapiClient.get).toHaveBeenCalledTimes(1);
21
+ });
22
+ });
@@ -0,0 +1,8 @@
1
+ import strapiClient from './strapiClient';
2
+
3
+ const getAvailableLocalesFromStrapi = async (): Promise<string[]> => {
4
+ const { data } = await strapiClient.get('/i18n/locales');
5
+ return data.map((locale: { code: string }) => locale.code);
6
+ };
7
+
8
+ export default getAvailableLocalesFromStrapi;
@@ -17,7 +17,7 @@ const getPortfolioProjects = async (
17
17
  ): Promise<PortfolioProject[]> => {
18
18
  const cache = preview ? false : undefined;
19
19
  const params: Record<string, any> = {
20
- populate: 'deep,6',
20
+ pLevel: '6',
21
21
  locale,
22
22
  'pagination[pageSize]': STRAPI_DEFAULT_PAGE_SIZE,
23
23
  };
@@ -2,6 +2,17 @@ import MockAxios from 'jest-mock-axios';
2
2
  import getStrapiCollectionType from './getStrapiCollectionType';
3
3
  import StrapiPage from '../../models/strapi/StrapiPage';
4
4
  import { strapiPageMock } from '../../test/strapiMocks/strapiPage';
5
+ import getAvailableLocalesFromStrapi from './getAvailableLocalesFromStrapi';
6
+ import strapiClient from './strapiClient';
7
+
8
+ jest.mock('./strapiClient', () => ({
9
+ get: jest.fn(),
10
+ }));
11
+
12
+ jest.mock('./getAvailableLocalesFromStrapi', () => ({
13
+ __esModule: true,
14
+ default: jest.fn(),
15
+ }));
5
16
 
6
17
  describe('The getStrapiCollectionType function', () => {
7
18
  const germanStrapiPageMock = {
@@ -15,20 +26,28 @@ describe('The getStrapiCollectionType function', () => {
15
26
 
16
27
  afterEach(() => {
17
28
  MockAxios.reset();
29
+ jest.clearAllMocks();
18
30
  });
19
31
 
20
32
  it('returns the localized versions if available', async () => {
33
+ (getAvailableLocalesFromStrapi as jest.Mock).mockResolvedValue([
34
+ 'en',
35
+ 'de',
36
+ 'hu',
37
+ ]);
38
+
39
+ (strapiClient.get as jest.Mock).mockResolvedValue({
40
+ data: {
41
+ data: [strapiPageMock, germanStrapiPageMock],
42
+ },
43
+ });
44
+
21
45
  const pages = getStrapiCollectionType<StrapiPage, 'slug'>(
22
46
  '/api/pages',
23
47
  'slug',
24
48
  { locale: 'de' }
25
49
  );
26
50
 
27
- MockAxios.mockResponseFor(
28
- { url: '/api/pages' },
29
- { data: { data: [strapiPageMock, germanStrapiPageMock] } }
30
- );
31
-
32
51
  const page = await pages;
33
52
 
34
53
  expect(page).toStrictEqual([
@@ -41,17 +60,24 @@ describe('The getStrapiCollectionType function', () => {
41
60
  });
42
61
 
43
62
  it('returns the english versions if no localized version is available', async () => {
63
+ (getAvailableLocalesFromStrapi as jest.Mock).mockResolvedValue([
64
+ 'en',
65
+ 'de',
66
+ 'hu',
67
+ ]);
68
+
69
+ (strapiClient.get as jest.Mock).mockResolvedValue({
70
+ data: {
71
+ data: [strapiPageMock],
72
+ },
73
+ });
74
+
44
75
  const pages = getStrapiCollectionType<StrapiPage, 'slug'>(
45
76
  '/api/pages',
46
77
  'slug',
47
78
  { locale: 'de' }
48
79
  );
49
80
 
50
- MockAxios.mockResponseFor(
51
- { url: '/api/pages' },
52
- { data: { data: [strapiPageMock] } }
53
- );
54
-
55
81
  const page = await pages;
56
82
 
57
83
  expect(page).toStrictEqual([
@@ -6,6 +6,7 @@ import {
6
6
  import IStrapiData from '../../models/strapi/IStrapiData';
7
7
  import IStrapiResponse from '../../models/strapi/IStrapiResponse';
8
8
  import LocalizedEntity from '../../models/LocalizedEntity';
9
+ import getAvailableLocalesFromStrapi from './getAvailableLocalesFromStrapi';
9
10
 
10
11
  interface Options {
11
12
  locale?: string;
@@ -23,40 +24,46 @@ const getStrapiCollectionType = async <
23
24
  { locale = 'en', preview = false, filters = {} }: Options
24
25
  ): Promise<IStrapiData<T>[]> => {
25
26
  const cache = preview ? false : undefined;
26
- const params: Record<string, any> = {
27
- populate: 'deep,6',
28
- locale: 'all',
29
- 'pagination[pageSize]': STRAPI_DEFAULT_PAGE_SIZE,
30
- filters,
31
- };
32
-
33
- if (preview) {
34
- params.publicationState = 'preview';
27
+ const allLocales = await getAvailableLocalesFromStrapi();
28
+
29
+ if (!allLocales.includes(STRAPI_FALLBACK_LOCALE)) {
30
+ allLocales.push(STRAPI_FALLBACK_LOCALE);
35
31
  }
36
32
 
37
- const { data } = await strapiClient.get<IStrapiResponse<IStrapiData<T>[]>>(
38
- path,
39
- { params, cache }
40
- );
33
+ const responses: IStrapiData<T>[] = [];
41
34
 
42
- const localizedResponses = data.data.filter(
43
- (d) => d.attributes.locale === locale
44
- );
35
+ for (const loc of allLocales) {
36
+ const params: Record<string, any> = {
37
+ pLevel: '6',
38
+ loc,
39
+ 'pagination[pageSize]': STRAPI_DEFAULT_PAGE_SIZE,
40
+ filters,
41
+ };
45
42
 
46
- const fallbackResponses = data.data.filter(
47
- (d) => d.attributes.locale === STRAPI_FALLBACK_LOCALE
48
- );
43
+ if (preview) {
44
+ params.publicationState = 'preview';
45
+ }
49
46
 
50
- const responses = fallbackResponses.map((fallbackResponse) => {
51
- const localizedResponse = localizedResponses.find(
52
- (localized) =>
53
- localized.attributes[key] === fallbackResponse.attributes[key]
47
+ const { data } = await strapiClient.get<IStrapiResponse<IStrapiData<T>[]>>(
48
+ path,
49
+ { params, cache }
54
50
  );
55
51
 
56
- return localizedResponse || fallbackResponse;
57
- });
52
+ responses.push(...data.data);
53
+ }
54
+
55
+ const groupedResponses = responses.reduce<Record<string, IStrapiData<T>>>(
56
+ (acc, response) => {
57
+ const keyValue = response.attributes[key];
58
+ if (!acc[keyValue] || response.attributes.locale === locale) {
59
+ acc[keyValue] = response;
60
+ }
61
+ return acc;
62
+ },
63
+ {}
64
+ );
58
65
 
59
- return responses;
66
+ return Object.values(groupedResponses);
60
67
  };
61
68
 
62
69
  export default getStrapiCollectionType;
@@ -19,7 +19,7 @@ const getStrapiSingleType = async <T>(
19
19
  ): Promise<IStrapiData<T>> => {
20
20
  const cache = preview ? false : undefined;
21
21
  const params: Record<string, any> = {
22
- populate: 'deep,6',
22
+ pLevel: '6',
23
23
  locale,
24
24
  'pagination[pageSize]': STRAPI_DEFAULT_PAGE_SIZE,
25
25
  filters,
@@ -6,6 +6,7 @@ import { STRAPI_URI } from '../../constants/strapi';
6
6
  const strapiClient = setupCache(
7
7
  axios.create({
8
8
  baseURL: `${STRAPI_URI}/api`,
9
+ headers: { 'Strapi-Response-Format': 'v4' },
9
10
  paramsSerializer: (p) => qs.stringify(p, { encodeValuesOnly: true }),
10
11
  timeout: 60_000,
11
12
  }),
@@ -90,7 +90,7 @@ export const Events: React.FC<EventsProps> = ({ slice }: EventsProps) => {
90
90
  url.searchParams.append('pagination[limit]', batchSize.toString());
91
91
  url.searchParams.append(startFilter, now);
92
92
  url.searchParams.append('locale', locale);
93
- url.searchParams.append('populate', 'deep,6');
93
+ url.searchParams.append('pLevel', '6');
94
94
 
95
95
  if (sort[0] === Sort.OLDEST_FIRST) {
96
96
  url.searchParams.append('sort', 'start:asc');
@@ -165,10 +165,15 @@ export const Events: React.FC<EventsProps> = ({ slice }: EventsProps) => {
165
165
  const fetchAllOptions = useCallback(async () => {
166
166
  const url = new URL(`/treely-events`, STRAPI_URI);
167
167
  url.searchParams.append('locale', locale);
168
- url.searchParams.append('populate', 'deep,6');
168
+ url.searchParams.append('pLevel', '6');
169
169
 
170
170
  const response = await fetch(
171
- `${STRAPI_URI}/api/treely-events${url.search}`
171
+ `${STRAPI_URI}/api/treely-events${url.search}`,
172
+ {
173
+ headers: {
174
+ 'Strapi-Response-Format': 'v4',
175
+ },
176
+ }
172
177
  );
173
178
  const data = await response.json();
174
179
 
@@ -105,54 +105,56 @@ export const TextCarousel: React.FC<TextCarouselProps> = ({
105
105
 
106
106
  <CarouselContainer ref={containerRef}>
107
107
  <Box position="relative" width="full">
108
- <CarouselInnerContainer
109
- numberOfItems={slice.slides.length}
110
- animate={{
111
- x: offsetLeft,
112
- }}
113
- transition={{
114
- duration: 0.3,
115
- ease: 'easeInOut',
116
- }}
117
- >
118
- {displaySlides.map(({ id, title, text, icon, image, button }) => (
119
- <CardContainer key={id} ref={itemRef}>
120
- <TextCardWithIcon
121
- title={title}
122
- text={text}
123
- height="full"
124
- icon={
125
- <Image
126
- src={strapiMediaUrl(icon.img, 'small')}
127
- alt={icon.alt}
128
- fill
129
- style={{ objectFit: icon.objectFit || 'contain' }}
130
- />
131
- }
132
- image={
133
- image && (
108
+ <Wrapper>
109
+ <CarouselInnerContainer
110
+ numberOfItems={slice.slides.length}
111
+ animate={{
112
+ x: offsetLeft,
113
+ }}
114
+ transition={{
115
+ duration: 0.3,
116
+ ease: 'easeInOut',
117
+ }}
118
+ >
119
+ {displaySlides.map(({ id, title, text, icon, image, button }) => (
120
+ <CardContainer key={id} ref={itemRef}>
121
+ <TextCardWithIcon
122
+ title={title}
123
+ text={text}
124
+ height="full"
125
+ icon={
134
126
  <Image
135
- src={strapiMediaUrl(image?.img, 'medium')}
136
- alt={image?.alt}
127
+ src={strapiMediaUrl(icon.img, 'small')}
128
+ alt={icon.alt}
137
129
  fill
138
- style={{
139
- objectFit: image?.objectFit || 'cover',
140
- borderRadius: 'var(--boemly-radii-xl)',
141
- }}
130
+ style={{ objectFit: icon.objectFit || 'contain' }}
142
131
  />
143
- )
144
- }
145
- button={
146
- button && {
147
- text: button.text,
148
- onClick: () => push(strapiLinkUrl(button)),
149
132
  }
150
- }
151
- displayAs="column"
152
- />
153
- </CardContainer>
154
- ))}
155
- </CarouselInnerContainer>
133
+ image={
134
+ image && (
135
+ <Image
136
+ src={strapiMediaUrl(image?.img, 'medium')}
137
+ alt={image?.alt}
138
+ fill
139
+ style={{
140
+ objectFit: image?.objectFit || 'cover',
141
+ borderRadius: 'var(--boemly-radii-xl)',
142
+ }}
143
+ />
144
+ )
145
+ }
146
+ button={
147
+ button && {
148
+ text: button.text,
149
+ onClick: () => push(strapiLinkUrl(button)),
150
+ }
151
+ }
152
+ displayAs="column"
153
+ />
154
+ </CardContainer>
155
+ ))}
156
+ </CarouselInnerContainer>
157
+ </Wrapper>
156
158
  <Box
157
159
  display={['none', null, null, !!allowScroll ? 'flex' : 'none']}
158
160
  pointerEvents="none"
@@ -1,4 +1,4 @@
1
- import { Meta } from '@storybook/addon-docs';
1
+ import { Meta } from '@storybook/blocks';
2
2
 
3
3
  <Meta title="Introduction" />
4
4