@treely/strapi-slices 2.1.0 → 2.2.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 (56) hide show
  1. package/dist/components/SEOTags/SEOTags.d.ts +14 -0
  2. package/dist/components/SEOTags/index.d.ts +1 -0
  3. package/dist/components/portfolio/SmallCheckout/SmallCheckout.d.ts +1 -1
  4. package/dist/constants/metadata.d.ts +2 -0
  5. package/dist/constants/sectionsConfig.d.ts +5 -0
  6. package/dist/index.d.ts +16 -1
  7. package/dist/models/HeaderType.d.ts +5 -0
  8. package/dist/models/Image.d.ts +5 -0
  9. package/dist/models/PageMetadata.d.ts +9 -0
  10. package/dist/models/PageProps.d.ts +21 -0
  11. package/dist/models/strapi/StrapiBlogPostProps.d.ts +6 -0
  12. package/dist/models/strapi/StrapiCustomerStoryProps.d.ts +6 -0
  13. package/dist/models/strapi/StrapiPageProps.d.ts +6 -0
  14. package/dist/models/strapi/StrapiProjectProps.d.ts +6 -0
  15. package/dist/slices/FullWidthImageSlider/styles.d.ts +1 -0
  16. package/dist/slices/TextCarousel/styles.d.ts +1 -0
  17. package/dist/strapi-slices.cjs.development.js +232 -11
  18. package/dist/strapi-slices.cjs.development.js.map +1 -1
  19. package/dist/strapi-slices.cjs.production.min.js +1 -1
  20. package/dist/strapi-slices.cjs.production.min.js.map +1 -1
  21. package/dist/strapi-slices.esm.js +224 -11
  22. package/dist/strapi-slices.esm.js.map +1 -1
  23. package/dist/test/mocks/getStaticPropsContext.d.ts +3 -0
  24. package/dist/utils/mergeGlobalAndStrapiBlogPostData.d.ts +5 -0
  25. package/dist/utils/mergeGlobalAndStrapiBlogPostData.test.d.ts +1 -0
  26. package/dist/utils/mergeGlobalAndStrapiCustomerStoryData.d.ts +4 -0
  27. package/dist/utils/mergeGlobalAndStrapiCustomerStoryData.test.d.ts +1 -0
  28. package/dist/utils/mergeGlobalAndStrapiPageData.d.ts +5 -0
  29. package/dist/utils/mergeGlobalAndStrapiPageData.test.d.ts +1 -0
  30. package/dist/utils/mergeGlobalAndStrapiProjectData.d.ts +5 -0
  31. package/dist/utils/mergeGlobalAndStrapiProjectData.test.d.ts +1 -0
  32. package/package.json +1 -2
  33. package/src/components/SEOTags/SEOTags.tsx +53 -0
  34. package/src/components/SEOTags/index.ts +1 -0
  35. package/src/components/portfolio/SmallCheckout/SmallCheckout.tsx +14 -15
  36. package/src/constants/metadata.ts +3 -0
  37. package/src/constants/sectionsConfig.ts +20 -0
  38. package/src/index.tsx +45 -0
  39. package/src/models/HeaderType.ts +6 -0
  40. package/src/models/Image.ts +6 -0
  41. package/src/models/PageMetadata.ts +11 -0
  42. package/src/models/PageProps.ts +32 -0
  43. package/src/models/strapi/StrapiBlogPostProps.ts +7 -0
  44. package/src/models/strapi/StrapiCustomerStoryProps.ts +9 -0
  45. package/src/models/strapi/StrapiPageProps.ts +7 -0
  46. package/src/models/strapi/StrapiProjectProps.ts +7 -0
  47. package/src/slices/ProjectFacts/ProjectFacts.stories.tsx +53 -0
  48. package/src/test/mocks/getStaticPropsContext.ts +9 -0
  49. package/src/utils/mergeGlobalAndStrapiBlogPostData.test.ts +154 -0
  50. package/src/utils/mergeGlobalAndStrapiBlogPostData.ts +68 -0
  51. package/src/utils/mergeGlobalAndStrapiCustomerStoryData.test.ts +149 -0
  52. package/src/utils/mergeGlobalAndStrapiCustomerStoryData.ts +68 -0
  53. package/src/utils/mergeGlobalAndStrapiPageData.test.ts +254 -0
  54. package/src/utils/mergeGlobalAndStrapiPageData.ts +81 -0
  55. package/src/utils/mergeGlobalAndStrapiProjectData.test.ts +243 -0
  56. package/src/utils/mergeGlobalAndStrapiProjectData.ts +79 -0
@@ -0,0 +1,68 @@
1
+ import { GetStaticPropsContext } from 'next';
2
+ import strapiMediaUrl from './strapiMediaUrl';
3
+ import {
4
+ IStrapiData,
5
+ StrapiBlogPost,
6
+ StrapiBlogPostProps,
7
+ StrapiGlobal,
8
+ } from '..';
9
+ import PortfolioProject from '../models/PortfolioProject';
10
+ import { DEFAULT_SHARE_ALT, DEFAULT_SHARE_IMAGE } from '../constants/metadata';
11
+
12
+ const mergeGlobalAndStrapiBlogPostData = (
13
+ context: GetStaticPropsContext,
14
+ global: IStrapiData<StrapiGlobal>,
15
+ post: IStrapiData<StrapiBlogPost>,
16
+ blog: IStrapiData<StrapiBlogPost>[],
17
+ projects: PortfolioProject[]
18
+ ): StrapiBlogPostProps => {
19
+ const metaShareImageUrl = post.attributes.metadata?.shareImage
20
+ ? strapiMediaUrl(
21
+ post.attributes.metadata?.shareImage.media ??
22
+ global.attributes.metadata.shareImage?.media,
23
+ 'large'
24
+ )
25
+ : DEFAULT_SHARE_IMAGE;
26
+
27
+ return {
28
+ ...post,
29
+ // Portfolio Projects
30
+ projects,
31
+ // StrapiBlogPost
32
+ attributes: {
33
+ ...post?.attributes,
34
+ metadata: post?.attributes?.metadata || global.attributes.metadata,
35
+ },
36
+ // PageProps
37
+ headerType: {
38
+ extendable: true,
39
+ theme: 'light',
40
+ },
41
+ headerNavMenus: global.attributes.navbar.navMenus || [],
42
+ headerButtons: global.attributes.navbar.buttons || [],
43
+ footerLinks: global.attributes.footer.links || [],
44
+ metadata: {
45
+ title:
46
+ post.attributes.metadata?.title ?? global.attributes.metadata.title,
47
+ description:
48
+ post.attributes.metadata?.description ??
49
+ global.attributes.metadata.description,
50
+ shareImage: {
51
+ url: metaShareImageUrl,
52
+ alt:
53
+ post.attributes.metadata?.shareImage?.alt ??
54
+ global.attributes.metadata.shareImage?.alt ??
55
+ DEFAULT_SHARE_ALT,
56
+ },
57
+ metaTitleSuffix: global.attributes.metaTitleSuffix,
58
+ favicon: strapiMediaUrl(global.attributes.favicon, 'thumbnail'),
59
+ },
60
+ slices: post?.attributes.slices,
61
+ blogPosts: blog,
62
+ banner: global.attributes.banner,
63
+ topBanner: post?.attributes.topBanner || global.attributes.topBanner,
64
+ customerStories: [],
65
+ };
66
+ };
67
+
68
+ export default mergeGlobalAndStrapiBlogPostData;
@@ -0,0 +1,149 @@
1
+ import mergeGlobalAndStrapiCustomerStoryData from './mergeGlobalAndStrapiCustomerStoryData';
2
+ import { strapiCustomerStoryMock } from '../test/strapiMocks/strapiCustomerStory';
3
+ import getStaticPropsContextMock from '../test/mocks/getStaticPropsContext';
4
+ import minimalGlobalData from '../test/strapiMocks/minimalGlobalData';
5
+ import { strapiMetadataMock } from '../test/strapiMocks/strapiMetadata';
6
+
7
+ describe('The mergeGlobalAndStrapiCustomerStoryData util', () => {
8
+ it('returns the global metadata if there is no page metadata', () => {
9
+ const pageDataWithoutMetadata = {
10
+ ...strapiCustomerStoryMock,
11
+ attributes: {
12
+ ...strapiCustomerStoryMock.attributes,
13
+ metadata: null,
14
+ },
15
+ };
16
+
17
+ const result = mergeGlobalAndStrapiCustomerStoryData(
18
+ getStaticPropsContextMock,
19
+ minimalGlobalData,
20
+ pageDataWithoutMetadata,
21
+ []
22
+ );
23
+
24
+ expect(result.attributes.metadata).toBe(
25
+ minimalGlobalData.attributes.metadata
26
+ );
27
+ expect(result.metadata.title).toBe(
28
+ minimalGlobalData.attributes.metadata.title
29
+ );
30
+ expect(result.metadata.description).toBe(
31
+ minimalGlobalData.attributes.metadata.description
32
+ );
33
+ });
34
+
35
+ it('returns the pages metadata if the page data includes metadata', () => {
36
+ const pageDataWithMetadata = {
37
+ ...strapiCustomerStoryMock,
38
+ data: {
39
+ ...strapiCustomerStoryMock,
40
+ attributes: {
41
+ ...strapiCustomerStoryMock.attributes,
42
+ metadata: strapiMetadataMock,
43
+ },
44
+ },
45
+ };
46
+
47
+ const result = mergeGlobalAndStrapiCustomerStoryData(
48
+ getStaticPropsContextMock,
49
+ minimalGlobalData,
50
+ pageDataWithMetadata,
51
+ []
52
+ );
53
+
54
+ expect(result.attributes.metadata?.title).toBe(strapiMetadataMock.title);
55
+ expect(result.metadata?.title).toBe(strapiMetadataMock.title);
56
+ });
57
+
58
+ it('returns the navbar links if there are links in the global data', () => {
59
+ const result = mergeGlobalAndStrapiCustomerStoryData(
60
+ getStaticPropsContextMock,
61
+ {
62
+ ...minimalGlobalData,
63
+ attributes: {
64
+ ...minimalGlobalData.attributes,
65
+ navbar: {
66
+ ...minimalGlobalData.attributes.navbar,
67
+ navMenus: [
68
+ {
69
+ link: {
70
+ id: Infinity,
71
+ text: 'Text',
72
+ url: '/',
73
+ },
74
+ title: 'Title',
75
+ items: [],
76
+ },
77
+ ],
78
+ },
79
+ },
80
+ },
81
+ strapiCustomerStoryMock,
82
+ []
83
+ );
84
+
85
+ expect(result.headerNavMenus).toStrictEqual([
86
+ {
87
+ title: 'Title',
88
+ items: [],
89
+ link: { id: Infinity, text: 'Text', url: '/' },
90
+ },
91
+ ]);
92
+ });
93
+
94
+ it('returns the navbar buttons if there are buttons in the global data', () => {
95
+ const result = mergeGlobalAndStrapiCustomerStoryData(
96
+ getStaticPropsContextMock,
97
+ {
98
+ ...minimalGlobalData,
99
+ attributes: {
100
+ ...minimalGlobalData.attributes,
101
+ navbar: {
102
+ ...minimalGlobalData.attributes.navbar,
103
+ buttons: [
104
+ {
105
+ id: Infinity,
106
+ text: 'Header button',
107
+ url: '/',
108
+ },
109
+ ],
110
+ },
111
+ },
112
+ },
113
+ strapiCustomerStoryMock,
114
+ []
115
+ );
116
+
117
+ expect(result.headerButtons).toStrictEqual([
118
+ { id: Infinity, text: 'Header button', url: '/' },
119
+ ]);
120
+ });
121
+
122
+ it('returns the footer links if there are links in the global data', () => {
123
+ const result = mergeGlobalAndStrapiCustomerStoryData(
124
+ getStaticPropsContextMock,
125
+ {
126
+ ...minimalGlobalData,
127
+ attributes: {
128
+ ...minimalGlobalData.attributes,
129
+ footer: {
130
+ ...minimalGlobalData.attributes.footer,
131
+ links: [
132
+ {
133
+ id: Infinity,
134
+ title: 'Title',
135
+ links: [],
136
+ },
137
+ ],
138
+ },
139
+ },
140
+ },
141
+ strapiCustomerStoryMock,
142
+ []
143
+ );
144
+
145
+ expect(result.footerLinks).toStrictEqual([
146
+ { id: Infinity, title: 'Title', links: [] },
147
+ ]);
148
+ });
149
+ });
@@ -0,0 +1,68 @@
1
+ import { GetStaticPropsContext } from 'next';
2
+ import strapiMediaUrl from './strapiMediaUrl';
3
+ import {
4
+ IStrapiData,
5
+ StrapiCustomerStory,
6
+ StrapiCustomerStoryProps,
7
+ StrapiGlobal,
8
+ } from '..';
9
+ import { DEFAULT_SHARE_ALT, DEFAULT_SHARE_IMAGE } from '../constants/metadata';
10
+
11
+ const mergeGlobalAndStrapiCustomerStoryData = (
12
+ context: GetStaticPropsContext,
13
+ global: IStrapiData<StrapiGlobal>,
14
+ customerStory: IStrapiData<StrapiCustomerStory>,
15
+ customerStories: IStrapiData<StrapiCustomerStory>[]
16
+ ): StrapiCustomerStoryProps => {
17
+ const metaShareImageUrl = customerStory.attributes.metadata?.shareImage
18
+ ? strapiMediaUrl(
19
+ customerStory.attributes.metadata?.shareImage.media ??
20
+ global.attributes.metadata.shareImage?.media,
21
+ 'large'
22
+ )
23
+ : DEFAULT_SHARE_IMAGE;
24
+
25
+ return {
26
+ ...customerStory,
27
+ // Portfolio Projects
28
+ projects: [],
29
+ attributes: {
30
+ ...customerStory?.attributes,
31
+ metadata:
32
+ customerStory?.attributes?.metadata || global.attributes.metadata,
33
+ },
34
+ // PageProps
35
+ headerType: {
36
+ extendable: true,
37
+ theme: 'light',
38
+ },
39
+ headerNavMenus: global.attributes.navbar.navMenus || [],
40
+ headerButtons: global.attributes.navbar.buttons || [],
41
+ footerLinks: global.attributes.footer.links || [],
42
+ metadata: {
43
+ title:
44
+ customerStory.attributes.metadata?.title ??
45
+ global.attributes.metadata.title,
46
+ description:
47
+ customerStory.attributes.metadata?.description ??
48
+ global.attributes.metadata.description,
49
+ shareImage: {
50
+ url: metaShareImageUrl,
51
+ alt:
52
+ customerStory.attributes.metadata?.shareImage?.alt ??
53
+ global.attributes.metadata.shareImage?.alt ??
54
+ DEFAULT_SHARE_ALT,
55
+ },
56
+ metaTitleSuffix: global.attributes.metaTitleSuffix,
57
+ favicon: strapiMediaUrl(global.attributes.favicon, 'thumbnail'),
58
+ },
59
+ slices: customerStory?.attributes.slices,
60
+ customerStories,
61
+ banner: global.attributes.banner,
62
+ topBanner:
63
+ customerStory?.attributes.topBanner || global.attributes.topBanner,
64
+ blogPosts: [],
65
+ };
66
+ };
67
+
68
+ export default mergeGlobalAndStrapiCustomerStoryData;
@@ -0,0 +1,254 @@
1
+ import minimalGlobalData from '../test/strapiMocks/minimalGlobalData';
2
+ import mergeGlobalAndStrapiPageData from './mergeGlobalAndStrapiPageData';
3
+ import { strapiPageMock } from '../test/strapiMocks/strapiPage';
4
+ import getStaticPropsContextMock from '../test/mocks/getStaticPropsContext';
5
+ import { strapiMetadataMock } from '../test/strapiMocks/strapiMetadata';
6
+
7
+ describe('The mergeGlobalAndStrapiPageData util', () => {
8
+ it('returns the global metadata if there is no page metadata', () => {
9
+ const pageDataWithoutMetadata = {
10
+ ...strapiPageMock,
11
+ attributes: {
12
+ ...strapiPageMock.attributes,
13
+ metadata: null,
14
+ },
15
+ };
16
+
17
+ const result = mergeGlobalAndStrapiPageData(
18
+ getStaticPropsContextMock,
19
+ minimalGlobalData,
20
+ pageDataWithoutMetadata,
21
+ [],
22
+ [],
23
+ []
24
+ );
25
+
26
+ expect(result.attributes.metadata).toBe(
27
+ minimalGlobalData.attributes.metadata
28
+ );
29
+ expect(result.metadata.title).toBe(
30
+ minimalGlobalData.attributes.metadata.title
31
+ );
32
+ expect(result.metadata.description).toBe(
33
+ minimalGlobalData.attributes.metadata.description
34
+ );
35
+ });
36
+
37
+ it('returns the pages metadata if the page data includes metadata', () => {
38
+ const pageDataWithMetadata = {
39
+ ...strapiPageMock,
40
+ attributes: {
41
+ ...strapiPageMock.attributes,
42
+ metadata: strapiMetadataMock,
43
+ },
44
+ };
45
+
46
+ const result = mergeGlobalAndStrapiPageData(
47
+ getStaticPropsContextMock,
48
+ minimalGlobalData,
49
+ pageDataWithMetadata,
50
+ [],
51
+ [],
52
+ []
53
+ );
54
+
55
+ expect(result.attributes.metadata?.title).toBe(strapiMetadataMock.title);
56
+ expect(result.metadata?.title).toBe(strapiMetadataMock.title);
57
+ });
58
+
59
+ it('returns a light theme header type if the first slice of the page is not a hero', () => {
60
+ const result = mergeGlobalAndStrapiPageData(
61
+ getStaticPropsContextMock,
62
+ minimalGlobalData,
63
+ {
64
+ ...strapiPageMock,
65
+ attributes: {
66
+ ...strapiPageMock.attributes,
67
+ slices: [{ __component: 'no.hero.section' }],
68
+ },
69
+ },
70
+ [],
71
+ [],
72
+ []
73
+ );
74
+
75
+ expect(result.headerType?.theme).toBe('light');
76
+ });
77
+
78
+ it('returns a light theme header type if the slices array is empty', () => {
79
+ const result = mergeGlobalAndStrapiPageData(
80
+ getStaticPropsContextMock,
81
+ minimalGlobalData,
82
+ {
83
+ ...strapiPageMock,
84
+ attributes: {
85
+ ...strapiPageMock.attributes,
86
+ slices: [],
87
+ },
88
+ },
89
+ [],
90
+ [],
91
+ []
92
+ );
93
+
94
+ expect(result.headerType?.theme).toBe('light');
95
+ });
96
+
97
+ it('returns a dark theme header type if the first slice of the page is a hero', () => {
98
+ const result = mergeGlobalAndStrapiPageData(
99
+ getStaticPropsContextMock,
100
+ minimalGlobalData,
101
+ {
102
+ ...strapiPageMock,
103
+ attributes: {
104
+ ...strapiPageMock.attributes,
105
+ slices: [{ __component: 'sections.hero' }],
106
+ },
107
+ },
108
+ [],
109
+ [],
110
+ []
111
+ );
112
+
113
+ expect(result.headerType?.theme).toBe('dark');
114
+ });
115
+
116
+ it('returns a not extendable header type if the first slice of the page is not a hero', () => {
117
+ const result = mergeGlobalAndStrapiPageData(
118
+ getStaticPropsContextMock,
119
+ minimalGlobalData,
120
+ {
121
+ ...strapiPageMock,
122
+ attributes: {
123
+ ...strapiPageMock.attributes,
124
+ slices: [{ __component: 'no.hero.section' }],
125
+ },
126
+ },
127
+ [],
128
+ [],
129
+ []
130
+ );
131
+
132
+ expect(result.headerType?.extendable).toBe(false);
133
+ });
134
+
135
+ it('returns a not extendable header type if the slices array is empty', () => {
136
+ const result = mergeGlobalAndStrapiPageData(
137
+ getStaticPropsContextMock,
138
+ minimalGlobalData,
139
+ {
140
+ ...strapiPageMock,
141
+ attributes: {
142
+ ...strapiPageMock.attributes,
143
+ slices: [],
144
+ },
145
+ },
146
+ [],
147
+ [],
148
+ []
149
+ );
150
+
151
+ expect(result.headerType?.extendable).toBe(false);
152
+ });
153
+
154
+ it('returns an extendable header type if the first slice of the page is a hero', () => {
155
+ const result = mergeGlobalAndStrapiPageData(
156
+ getStaticPropsContextMock,
157
+ minimalGlobalData,
158
+ {
159
+ ...strapiPageMock,
160
+ attributes: {
161
+ ...strapiPageMock.attributes,
162
+ slices: [{ __component: 'sections.hero' }],
163
+ },
164
+ },
165
+ [],
166
+ [],
167
+ []
168
+ );
169
+
170
+ expect(result.headerType?.extendable).toBe(true);
171
+ });
172
+
173
+ it('returns the navbar links if there are links in the global data', () => {
174
+ const result = mergeGlobalAndStrapiPageData(
175
+ getStaticPropsContextMock,
176
+ {
177
+ ...minimalGlobalData,
178
+ attributes: {
179
+ ...minimalGlobalData.attributes,
180
+ navbar: {
181
+ ...minimalGlobalData.attributes.navbar,
182
+ navMenus: [
183
+ {
184
+ link: { id: Infinity, text: 'Text', url: '/' },
185
+ title: 'Title',
186
+ items: [],
187
+ },
188
+ ],
189
+ },
190
+ },
191
+ },
192
+ strapiPageMock,
193
+ [],
194
+ [],
195
+ []
196
+ );
197
+
198
+ expect(result.headerNavMenus).toStrictEqual([
199
+ {
200
+ link: { id: Infinity, text: 'Text', url: '/' },
201
+ items: [],
202
+ title: 'Title',
203
+ },
204
+ ]);
205
+ });
206
+
207
+ it('returns the navbar buttons if there are buttons in the global data', () => {
208
+ const result = mergeGlobalAndStrapiPageData(
209
+ getStaticPropsContextMock,
210
+ {
211
+ ...minimalGlobalData,
212
+ attributes: {
213
+ ...minimalGlobalData.attributes,
214
+ navbar: {
215
+ ...minimalGlobalData.attributes.navbar,
216
+ buttons: [{ id: Infinity, text: 'Header button', url: '/' }],
217
+ },
218
+ },
219
+ },
220
+ strapiPageMock,
221
+ [],
222
+ [],
223
+ []
224
+ );
225
+
226
+ expect(result.headerButtons).toStrictEqual([
227
+ { id: Infinity, text: 'Header button', url: '/' },
228
+ ]);
229
+ });
230
+
231
+ it('returns the footer links if there are links in the global data', () => {
232
+ const result = mergeGlobalAndStrapiPageData(
233
+ getStaticPropsContextMock,
234
+ {
235
+ ...minimalGlobalData,
236
+ attributes: {
237
+ ...minimalGlobalData.attributes,
238
+ footer: {
239
+ ...minimalGlobalData.attributes.footer,
240
+ links: [{ id: Infinity, title: 'Text', links: [] }],
241
+ },
242
+ },
243
+ },
244
+ strapiPageMock,
245
+ [],
246
+ [],
247
+ []
248
+ );
249
+
250
+ expect(result.footerLinks).toStrictEqual([
251
+ { id: Infinity, title: 'Text', links: [] },
252
+ ]);
253
+ });
254
+ });
@@ -0,0 +1,81 @@
1
+ import { GetStaticPropsContext } from 'next';
2
+ import strapiMediaUrl from './strapiMediaUrl';
3
+ import {
4
+ IStrapiData,
5
+ StrapiBlogPost,
6
+ StrapiCustomerStory,
7
+ StrapiGlobal,
8
+ StrapiPage,
9
+ StrapiPageProps,
10
+ } from '..';
11
+ import PortfolioProject from '../models/PortfolioProject';
12
+ import {
13
+ DARK_THEME_HEADER_SECTIONS,
14
+ EXTENDABLE_HEADER_SECTIONS,
15
+ } from '../constants/sectionsConfig';
16
+ import { DEFAULT_SHARE_ALT, DEFAULT_SHARE_IMAGE } from '../constants/metadata';
17
+
18
+ const mergeGlobalAndStrapiPageData = (
19
+ context: GetStaticPropsContext,
20
+ global: IStrapiData<StrapiGlobal>,
21
+ page: IStrapiData<StrapiPage>,
22
+ blogPosts: IStrapiData<StrapiBlogPost>[],
23
+ customerStories: IStrapiData<StrapiCustomerStory>[],
24
+ projects: PortfolioProject[]
25
+ ): StrapiPageProps => {
26
+ const metaShareImageUrl = page.attributes.metadata?.shareImage
27
+ ? strapiMediaUrl(
28
+ page.attributes.metadata?.shareImage.media ??
29
+ global.attributes.metadata.shareImage?.media,
30
+ 'large'
31
+ )
32
+ : DEFAULT_SHARE_IMAGE;
33
+
34
+ return {
35
+ ...page,
36
+ // Portfolio Projects
37
+ projects,
38
+ // StrapiPage
39
+ attributes: {
40
+ ...page?.attributes,
41
+ metadata: page?.attributes?.metadata ?? global.attributes.metadata,
42
+ },
43
+ // PageProps
44
+ headerType: {
45
+ extendable: EXTENDABLE_HEADER_SECTIONS.includes(
46
+ page.attributes.slices[0]?.__component
47
+ ),
48
+ theme: DARK_THEME_HEADER_SECTIONS.includes(
49
+ page.attributes.slices[0]?.__component
50
+ )
51
+ ? 'dark'
52
+ : 'light',
53
+ },
54
+ headerNavMenus: global.attributes.navbar.navMenus || [],
55
+ headerButtons: global.attributes.navbar.buttons || [],
56
+ footerLinks: global.attributes.footer.links || [],
57
+ metadata: {
58
+ title:
59
+ page.attributes.metadata?.title ?? global.attributes.metadata.title,
60
+ description:
61
+ page.attributes.metadata?.description ??
62
+ global.attributes.metadata.description,
63
+ shareImage: {
64
+ url: metaShareImageUrl,
65
+ alt:
66
+ page.attributes.metadata?.shareImage?.alt ??
67
+ global.attributes.metadata.shareImage?.alt ??
68
+ DEFAULT_SHARE_ALT,
69
+ },
70
+ metaTitleSuffix: global.attributes.metaTitleSuffix,
71
+ favicon: strapiMediaUrl(global.attributes.favicon, 'thumbnail'),
72
+ },
73
+ slices: page?.attributes.slices,
74
+ blogPosts,
75
+ banner: global.attributes.banner,
76
+ topBanner: page?.attributes.topBanner || global.attributes.topBanner,
77
+ customerStories,
78
+ };
79
+ };
80
+
81
+ export default mergeGlobalAndStrapiPageData;