@gem-sdk/pages 1.0.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 (73) hide show
  1. package/README.md +7 -0
  2. package/dist/cjs/components/ErrorBoundary.js +32 -0
  3. package/dist/cjs/components/ErrorFallback.js +9 -0
  4. package/dist/cjs/components/FacebookPixel.js +41 -0
  5. package/dist/cjs/components/GoogleAnalytic.js +43 -0
  6. package/dist/cjs/components/TikTokPixel.js +20 -0
  7. package/dist/cjs/components/builder/Toolbox.js +200 -0
  8. package/dist/cjs/index.js +62 -0
  9. package/dist/cjs/layouts/main.js +15 -0
  10. package/dist/cjs/libs/api/get-builder-props.js +33 -0
  11. package/dist/cjs/libs/api/get-collection-props.js +64 -0
  12. package/dist/cjs/libs/api/get-home-page-props-v2.js +127 -0
  13. package/dist/cjs/libs/api/get-home-page-props.js +135 -0
  14. package/dist/cjs/libs/api/get-preview-props.js +18 -0
  15. package/dist/cjs/libs/api/get-product-props.js +71 -0
  16. package/dist/cjs/libs/api/get-static-page-props-preview.js +133 -0
  17. package/dist/cjs/libs/api/get-static-page-props-v2.js +130 -0
  18. package/dist/cjs/libs/api/get-static-page-props.js +132 -0
  19. package/dist/cjs/libs/fetcher.js +71 -0
  20. package/dist/cjs/libs/get-layout.js +10 -0
  21. package/dist/cjs/libs/get-storefront-api.js +12 -0
  22. package/dist/cjs/libs/getStaticPaths.js +10 -0
  23. package/dist/cjs/libs/google-fonts.js +68 -0
  24. package/dist/cjs/libs/helpers/gen-css.js +102 -0
  25. package/dist/cjs/libs/helpers/generate-manifres.js +5 -0
  26. package/dist/cjs/libs/helpers/get-fallback.js +29 -0
  27. package/dist/cjs/libs/helpers/normalize.js +87 -0
  28. package/dist/cjs/libs/helpers/parse-json.js +18 -0
  29. package/dist/cjs/pages/404.js +11 -0
  30. package/dist/cjs/pages/500.js +19 -0
  31. package/dist/cjs/pages/builder.js +26 -0
  32. package/dist/cjs/pages/collection-detail.js +21 -0
  33. package/dist/cjs/pages/preview.js +20 -0
  34. package/dist/cjs/pages/product-detail.js +21 -0
  35. package/dist/cjs/pages/static-v2.js +17 -0
  36. package/dist/cjs/pages/static.js +19 -0
  37. package/dist/esm/components/ErrorBoundary.js +30 -0
  38. package/dist/esm/components/ErrorFallback.js +7 -0
  39. package/dist/esm/components/FacebookPixel.js +39 -0
  40. package/dist/esm/components/GoogleAnalytic.js +41 -0
  41. package/dist/esm/components/TikTokPixel.js +18 -0
  42. package/dist/esm/components/builder/Toolbox.js +196 -0
  43. package/dist/esm/index.js +28 -0
  44. package/dist/esm/layouts/main.js +11 -0
  45. package/dist/esm/libs/api/get-builder-props.js +31 -0
  46. package/dist/esm/libs/api/get-collection-props.js +62 -0
  47. package/dist/esm/libs/api/get-home-page-props-v2.js +125 -0
  48. package/dist/esm/libs/api/get-home-page-props.js +133 -0
  49. package/dist/esm/libs/api/get-preview-props.js +16 -0
  50. package/dist/esm/libs/api/get-product-props.js +69 -0
  51. package/dist/esm/libs/api/get-static-page-props-preview.js +131 -0
  52. package/dist/esm/libs/api/get-static-page-props-v2.js +128 -0
  53. package/dist/esm/libs/api/get-static-page-props.js +130 -0
  54. package/dist/esm/libs/fetcher.js +68 -0
  55. package/dist/esm/libs/get-layout.js +8 -0
  56. package/dist/esm/libs/get-storefront-api.js +10 -0
  57. package/dist/esm/libs/getStaticPaths.js +8 -0
  58. package/dist/esm/libs/google-fonts.js +64 -0
  59. package/dist/esm/libs/helpers/gen-css.js +100 -0
  60. package/dist/esm/libs/helpers/generate-manifres.js +3 -0
  61. package/dist/esm/libs/helpers/get-fallback.js +27 -0
  62. package/dist/esm/libs/helpers/normalize.js +83 -0
  63. package/dist/esm/libs/helpers/parse-json.js +15 -0
  64. package/dist/esm/pages/404.js +9 -0
  65. package/dist/esm/pages/500.js +17 -0
  66. package/dist/esm/pages/builder.js +24 -0
  67. package/dist/esm/pages/collection-detail.js +17 -0
  68. package/dist/esm/pages/preview.js +18 -0
  69. package/dist/esm/pages/product-detail.js +17 -0
  70. package/dist/esm/pages/static-v2.js +15 -0
  71. package/dist/esm/pages/static.js +15 -0
  72. package/dist/types/index.d.ts +173 -0
  73. package/package.json +45 -0
@@ -0,0 +1,39 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { fpixel } from '@gem-sdk/core';
3
+ import { useRouter } from 'next/router';
4
+ import Script from 'next/script';
5
+ import { useEffect } from 'react';
6
+
7
+ const FacebookPixel = ({ pixelId }) => {
8
+ const router = useRouter();
9
+ useEffect(() => {
10
+ // This pageview only triggers the first time (it's important for Pixel to have real information)
11
+ fpixel.pageview();
12
+ const handleRouteChange = () => {
13
+ fpixel.pageview();
14
+ };
15
+ router.events.on('routeChangeComplete', handleRouteChange);
16
+ router.events.on('hashChangeComplete', handleRouteChange);
17
+ return () => {
18
+ router.events.off('routeChangeComplete', handleRouteChange);
19
+ router.events.off('hashChangeComplete', handleRouteChange);
20
+ };
21
+ }, [router.events]);
22
+ if (!pixelId)
23
+ return null;
24
+ return (jsx(Script, { id: "fb-pixel", strategy: "afterInteractive", dangerouslySetInnerHTML: {
25
+ __html: `
26
+ !function(f,b,e,v,n,t,s)
27
+ {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
28
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};
29
+ if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
30
+ n.queue=[];t=b.createElement(e);t.async=!0;
31
+ t.src=v;s=b.getElementsByTagName(e)[0];
32
+ s.parentNode.insertBefore(t,s)}(window, document,'script',
33
+ 'https://connect.facebook.net/en_US/fbevents.js');
34
+ fbq('init', ${pixelId});
35
+ `,
36
+ } }));
37
+ };
38
+
39
+ export { FacebookPixel };
@@ -0,0 +1,41 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { gtag } from '@gem-sdk/core';
3
+ import { useRouter } from 'next/router';
4
+ import Script from 'next/script';
5
+ import { useEffect } from 'react';
6
+
7
+ const GoogleAnalytic = ({ trackingId }) => {
8
+ const router = useRouter();
9
+ useEffect(() => {
10
+ const handleRouteChange = (url) => {
11
+ gtag.pageview(url, trackingId);
12
+ };
13
+ router.events.on('routeChangeComplete', handleRouteChange);
14
+ router.events.on('hashChangeComplete', handleRouteChange);
15
+ return () => {
16
+ router.events.off('routeChangeComplete', handleRouteChange);
17
+ router.events.off('hashChangeComplete', handleRouteChange);
18
+ };
19
+ }, [trackingId, router.events]);
20
+ if (!trackingId)
21
+ return null;
22
+ if (trackingId.startsWith('UA-'))
23
+ return (jsxs(Fragment, { children: [jsx(Script, { src: "https://www.google-analytics.com/analytics.js", async: true, strategy: "afterInteractive" }), jsx(Script, { strategy: "afterInteractive", id: "google-analytics", dangerouslySetInnerHTML: {
24
+ __html: `window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
25
+ ga('create', '${trackingId}', 'auto');
26
+ ga('send', 'pageview');
27
+ `,
28
+ } })] }));
29
+ return (jsxs(Fragment, { children: [jsx(Script, { strategy: "afterInteractive", src: `https://www.googletagmanager.com/gtag/js?id=${trackingId}` }), jsx(Script, { id: "gtag-init", strategy: "afterInteractive", dangerouslySetInnerHTML: {
30
+ __html: `
31
+ window.dataLayer = window.dataLayer || [];
32
+ function gtag(){dataLayer.push(arguments);}
33
+ gtag('js', new Date());
34
+ gtag('config', '${trackingId}', {
35
+ page_path: window.location.pathname,
36
+ });
37
+ `,
38
+ } })] }));
39
+ };
40
+
41
+ export { GoogleAnalytic };
@@ -0,0 +1,18 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import Script from 'next/script';
3
+
4
+ const TikTokPixel = ({ pixelId }) => {
5
+ if (!pixelId)
6
+ return null;
7
+ return (jsx(Script, { id: "tiktok-pixel", strategy: "afterInteractive", dangerouslySetInnerHTML: {
8
+ __html: `
9
+ !function (w, d, t) {
10
+ w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie"],ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for(var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e},ttq.load=function(e,n){var i="https://analytics.tiktok.com/i18n/pixel/events.js";ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=i,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};var o=document.createElement("script");o.type="text/javascript",o.async=!0,o.src=i+"?sdkid="+e+"&lib="+t;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(o,a)};
11
+ ttq.load('${pixelId}');
12
+ ttq.page();
13
+ }(window, document, 'ttq');
14
+ `,
15
+ } }));
16
+ };
17
+
18
+ export { TikTokPixel };
@@ -0,0 +1,196 @@
1
+ import { useMatchMutate, useShopStore, useBuilderPreviewStore, useSectionStore } from '@gem-sdk/core';
2
+ import { memo, useCallback, useEffect } from 'react';
3
+ import { createFontUrl } from '../../libs/google-fonts.js';
4
+ import { genCSS } from '../../libs/helpers/gen-css.js';
5
+ import { getStorefrontApi } from '../../libs/get-storefront-api.js';
6
+
7
+ const globalStyleId = 'global-style';
8
+ const globalFontId = 'google-font-builder';
9
+ const Toolbox = () => {
10
+ const matchMutate = useMatchMutate();
11
+ const provider = useShopStore((s) => s.provider);
12
+ const changeStorefrontInfo = useShopStore((s) => s.changeStorefrontInfo);
13
+ const initState = useBuilderPreviewStore((s) => s.initState);
14
+ const initNormalizeState = useBuilderPreviewStore((s) => s.forceChangeState);
15
+ const changeItemPropByKey = useBuilderPreviewStore((s) => s.changeItemPropByKey);
16
+ const addItem = useBuilderPreviewStore((s) => s.addItem);
17
+ const moveItem = useBuilderPreviewStore((s) => s.moveItem);
18
+ const removeItem = useBuilderPreviewStore((s) => s.removeItem);
19
+ const addSection = useSectionStore((s) => s.addSection);
20
+ const changeSwatches = useShopStore((s) => s.changeSwatches);
21
+ // Revalidate all query with key match query/
22
+ const onRevalidateQuery = useCallback(() => {
23
+ matchMutate(/query\//);
24
+ }, [matchMutate]);
25
+ // Update shop info
26
+ const onChangeShopInfo = useCallback((e) => {
27
+ const detail = e.detail;
28
+ changeStorefrontInfo({
29
+ url: detail.shopHandle ? getStorefrontApi(detail.shopHandle, provider) : undefined,
30
+ token: detail.shopToken,
31
+ });
32
+ }, [changeStorefrontInfo, provider]);
33
+ const onChangeGlobalStyle = useCallback((e) => {
34
+ const detail = e.detail;
35
+ try {
36
+ if (detail.data) {
37
+ const themeStyle = genCSS(detail.data, detail.mobileOnly);
38
+ const font = Object.entries(detail.data?.font).map(([, value]) => {
39
+ return value;
40
+ });
41
+ const fontUrl = createFontUrl(font);
42
+ const globalStyle = document.getElementById(globalStyleId);
43
+ const googleFont = document.getElementById(globalFontId);
44
+ if (googleFont) {
45
+ googleFont.getAttribute('href') !== fontUrl && googleFont.setAttribute('href', fontUrl);
46
+ //
47
+ }
48
+ else {
49
+ const link = document.createElement('link');
50
+ link.id = globalFontId;
51
+ link.href = fontUrl;
52
+ link.rel = 'stylesheet';
53
+ document.head.appendChild(link);
54
+ }
55
+ if (globalStyle) {
56
+ globalStyle.innerHTML = themeStyle;
57
+ }
58
+ else {
59
+ const style = document.createElement('style');
60
+ style.id = globalStyleId;
61
+ style.innerHTML = themeStyle;
62
+ document.head.appendChild(style);
63
+ }
64
+ }
65
+ }
66
+ catch {
67
+ //
68
+ }
69
+ }, []);
70
+ // Init builder data
71
+ const onInitBuilder = useCallback((e) => {
72
+ try {
73
+ const detail = e.detail;
74
+ if (detail.data) {
75
+ if (detail.type === 'flat') {
76
+ initNormalizeState(detail.data);
77
+ }
78
+ else {
79
+ initState(detail.data);
80
+ }
81
+ }
82
+ }
83
+ catch {
84
+ //
85
+ }
86
+ }, [initNormalizeState, initState]);
87
+ // Add new entity
88
+ const onAddEntity = useCallback((e) => {
89
+ try {
90
+ const detail = e.detail;
91
+ if (detail.entity) {
92
+ addItem({
93
+ data: detail.entity,
94
+ id: detail.id,
95
+ position: detail.position,
96
+ type: detail.type ?? 'component',
97
+ });
98
+ if (detail?.type === 'section' && !Array.isArray(detail.entity)) {
99
+ addSection(detail.entity.uid, detail.entity);
100
+ }
101
+ }
102
+ }
103
+ catch {
104
+ //
105
+ }
106
+ }, [addItem, addSection]);
107
+ // Update props of entity
108
+ const onUpdateEntityProp = useCallback((e) => {
109
+ try {
110
+ const detail = e.detail;
111
+ if (detail.uid && detail.propName) {
112
+ changeItemPropByKey({
113
+ id: detail.uid,
114
+ key: detail.propName,
115
+ data: detail.propValue,
116
+ group: detail.group,
117
+ });
118
+ }
119
+ }
120
+ catch {
121
+ //
122
+ }
123
+ }, [changeItemPropByKey]);
124
+ // Move entity
125
+ const onMoveEntity = useCallback((e) => {
126
+ try {
127
+ const detail = e.detail;
128
+ if (detail.to && detail.uid) {
129
+ moveItem(detail.uid, detail.to, Number(detail.position) ?? 0);
130
+ }
131
+ }
132
+ catch {
133
+ //
134
+ }
135
+ }, [moveItem]);
136
+ // Remove entity
137
+ const onRemoveEntity = useCallback((e) => {
138
+ try {
139
+ const detail = e.detail;
140
+ if (detail.uid) {
141
+ removeItem(detail.uid);
142
+ }
143
+ }
144
+ catch {
145
+ //
146
+ }
147
+ }, [removeItem]);
148
+ // Change Swatches Data
149
+ const onChangeSwatchesData = useCallback((e) => {
150
+ const detail = e.detail;
151
+ try {
152
+ if (detail.data) {
153
+ changeSwatches(detail.data);
154
+ }
155
+ }
156
+ catch {
157
+ //
158
+ }
159
+ }, [changeSwatches]);
160
+ useEffect(() => {
161
+ window.addEventListener('update-shop-info', onChangeShopInfo);
162
+ window.addEventListener('revalidate-query', onRevalidateQuery);
163
+ window.addEventListener('init-builder', onInitBuilder);
164
+ window.addEventListener('add-entity', onAddEntity);
165
+ window.addEventListener('remove-entity', onRemoveEntity);
166
+ window.addEventListener('move-entity', onMoveEntity);
167
+ window.addEventListener('update-entity-prop', onUpdateEntityProp);
168
+ window.addEventListener('set-global-style', onChangeGlobalStyle);
169
+ window.addEventListener('update-global-swatches-data', onChangeSwatchesData);
170
+ return () => {
171
+ window.removeEventListener('update-shop-info', onChangeShopInfo);
172
+ window.removeEventListener('revalidate-query', onRevalidateQuery);
173
+ window.removeEventListener('init-builder', onInitBuilder);
174
+ window.removeEventListener('add-entity', onAddEntity);
175
+ window.removeEventListener('remove-entity', onRemoveEntity);
176
+ window.removeEventListener('move-entity', onMoveEntity);
177
+ window.removeEventListener('update-entity-prop', onUpdateEntityProp);
178
+ window.removeEventListener('set-global-style', onChangeGlobalStyle);
179
+ window.removeEventListener('update-global-swatches-data', onChangeSwatchesData);
180
+ };
181
+ }, [
182
+ onAddEntity,
183
+ onUpdateEntityProp,
184
+ onInitBuilder,
185
+ onMoveEntity,
186
+ onRemoveEntity,
187
+ onChangeGlobalStyle,
188
+ onChangeSwatchesData,
189
+ onRevalidateQuery,
190
+ onChangeShopInfo,
191
+ ]);
192
+ return null;
193
+ };
194
+ var Toolbox$1 = memo(Toolbox);
195
+
196
+ export { Toolbox$1 as default };
@@ -0,0 +1,28 @@
1
+ export { getCollectionProps } from './libs/api/get-collection-props.js';
2
+ export { getHomePageProps } from './libs/api/get-home-page-props.js';
3
+ export { getHomePagePropsV2 } from './libs/api/get-home-page-props-v2.js';
4
+ export { getPreviewProps } from './libs/api/get-preview-props.js';
5
+ export { getBuilderProps } from './libs/api/get-builder-props.js';
6
+ export { getProductProps } from './libs/api/get-product-props.js';
7
+ export { getStaticPageProps } from './libs/api/get-static-page-props.js';
8
+ export { getStaticPagePropsV2 } from './libs/api/get-static-page-props-v2.js';
9
+ export { getStaticPagePropsPreview } from './libs/api/get-static-page-props-preview.js';
10
+ export { createFetcher, createShopifyFetcher } from './libs/fetcher.js';
11
+ export { getLayout } from './libs/get-layout.js';
12
+ export { genCSS } from './libs/helpers/gen-css.js';
13
+ export { default as CollectionDetailPage } from './pages/collection-detail.js';
14
+ export { PreviewPage } from './pages/preview.js';
15
+ export { default as ProductDetailPage } from './pages/product-detail.js';
16
+ export { default as StaticPage } from './pages/static.js';
17
+ export { BuilderPage } from './pages/builder.js';
18
+ export { StaticPageV2 } from './pages/static-v2.js';
19
+ export { getStaticPaths } from './libs/getStaticPaths.js';
20
+ export { getFonts } from './libs/google-fonts.js';
21
+ export { getStorefrontApi } from './libs/get-storefront-api.js';
22
+ export { ErrorBoundary } from './components/ErrorBoundary.js';
23
+ export { ErrorFallback } from './components/ErrorFallback.js';
24
+ export { Page404 } from './pages/404.js';
25
+ export { Page500 } from './pages/500.js';
26
+ export { GoogleAnalytic } from './components/GoogleAnalytic.js';
27
+ export { FacebookPixel } from './components/FacebookPixel.js';
28
+ export { TikTokPixel } from './components/TikTokPixel.js';
@@ -0,0 +1,11 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useShopStore, cls, AddOn } from '@gem-sdk/core';
3
+
4
+ const MainLayout = ({ children }) => {
5
+ const mobileOnly = useShopStore((s) => s.mobileOnly);
6
+ return (jsxs(Fragment, { children: [jsx("div", { className: cls({
7
+ 'max-w-mobile mx-auto w-full': mobileOnly,
8
+ }), children: children }), jsx(AddOn, { name: "cookie-bar" }), jsx(AddOn, { name: "cart-drawer" })] }));
9
+ };
10
+
11
+ export { MainLayout as default };
@@ -0,0 +1,31 @@
1
+ import { StorePropertyDocument } from '@gem-sdk/core';
2
+ import { ShopMetaDocument } from '@gem-sdk/adapter-shopify';
3
+ import { serializableJson, parseJson } from '../helpers/parse-json.js';
4
+
5
+ const getBuilderProps = async (fetcher, shopifyFetcher) => {
6
+ const [storeProperty, shopifyMeta] = await Promise.allSettled([
7
+ fetcher([StorePropertyDocument]),
8
+ shopifyFetcher([ShopMetaDocument]),
9
+ ]);
10
+ const shopMeta = shopifyMeta.status === 'fulfilled' ? shopifyMeta.value : undefined;
11
+ const shopData = storeProperty.status === 'fulfilled' ? storeProperty.value : undefined;
12
+ const seo = shopMeta
13
+ ? {
14
+ titleTemplate: `%s | ${shopMeta.shop.name}`,
15
+ defaultTitle: shopMeta?.shop.name,
16
+ title: 'Preview',
17
+ description: shopMeta?.shop.description,
18
+ }
19
+ : {};
20
+ return serializableJson({
21
+ currency: shopMeta?.localization.country.currency.isoCode ?? null,
22
+ locale: shopMeta?.localization.country.isoCode ?? null,
23
+ swatches: parseJson(shopData?.storeProperty?.swatchesConfig),
24
+ swr: {
25
+ revalidateOnMount: true,
26
+ },
27
+ seo,
28
+ });
29
+ };
30
+
31
+ export { getBuilderProps };
@@ -0,0 +1,62 @@
1
+ import { CollectionDocument, PublishedThemePagesDocument, prefetchQueries } from '@gem-sdk/core';
2
+ import { genCSS } from '../helpers/gen-css.js';
3
+ import { parseBuilderTemplate } from '../helpers/normalize.js';
4
+ import { serializableJson } from '../helpers/parse-json.js';
5
+
6
+ const getCollectionProps = (fetcher) => async (handle) => {
7
+ const pageType = 'COLLECTION';
8
+ const variables = {
9
+ slug: handle,
10
+ slugType: pageType,
11
+ };
12
+ const [collectionData, theme] = await Promise.all([
13
+ fetcher([
14
+ CollectionDocument,
15
+ {
16
+ handle,
17
+ },
18
+ ]),
19
+ fetcher([
20
+ PublishedThemePagesDocument,
21
+ variables,
22
+ ]),
23
+ ]);
24
+ const dataBuilder = theme.publishedThemePages?.[0];
25
+ const collectionTemplate = parseBuilderTemplate(dataBuilder);
26
+ if (!collectionData || !collectionData?.collection || !dataBuilder) {
27
+ throw new Error('Collection not found');
28
+ }
29
+ const { collection } = collectionData;
30
+ const queries = prefetchQueries(collectionTemplate);
31
+ const datas = await Promise.allSettled(queries.map(({ query, variables, func }) => {
32
+ if (func) {
33
+ return func(fetcher, variables);
34
+ }
35
+ if (query)
36
+ return fetcher([query, variables]);
37
+ return {};
38
+ }));
39
+ const fallback = queries.reduce((acc, { key }, index) => {
40
+ const res = datas[index];
41
+ if (res?.status === 'fulfilled') {
42
+ return {
43
+ ...acc,
44
+ [key]: res.value,
45
+ };
46
+ }
47
+ return acc;
48
+ }, {});
49
+ return serializableJson({
50
+ builderData: collectionTemplate,
51
+ collection,
52
+ pageType,
53
+ themeStyle: genCSS(dataBuilder.pageStyle?.data),
54
+ swr: { fallback },
55
+ seo: {
56
+ title: collection.title,
57
+ description: collection.description,
58
+ },
59
+ });
60
+ };
61
+
62
+ export { getCollectionProps };
@@ -0,0 +1,125 @@
1
+ import { PublishedThemePagesDocument, StorePropertyDocument } from '@gem-sdk/core';
2
+ import { ShopMetaDocument } from '@gem-sdk/adapter-shopify';
3
+ import { getFontFromGlobalStyle } from '../google-fonts.js';
4
+ import { genCSS } from '../helpers/gen-css.js';
5
+ import { generateManifest } from '../helpers/generate-manifres.js';
6
+ import { getFallbackV2 } from '../helpers/get-fallback.js';
7
+ import { parseBuilderTemplateV2 } from '../helpers/normalize.js';
8
+ import { parseJson, serializableJson } from '../helpers/parse-json.js';
9
+ import { captureException } from '@sentry/nextjs';
10
+
11
+ const getHomePagePropsV2 = (fetcher, shopifyFetcher) => async () => {
12
+ try {
13
+ const variables = {
14
+ slugType: 'STATIC',
15
+ };
16
+ const [theme, storeProperty, shopifyMeta] = await Promise.allSettled([
17
+ fetcher([
18
+ PublishedThemePagesDocument,
19
+ variables,
20
+ ]),
21
+ fetcher([StorePropertyDocument]),
22
+ shopifyFetcher([ShopMetaDocument]),
23
+ ]);
24
+ if (theme.status === 'rejected') {
25
+ throw new Error(theme.reason?.[0]);
26
+ }
27
+ const dataBuilder = theme.value?.publishedThemePages?.[0];
28
+ if (!dataBuilder) {
29
+ throw new Error(`No data builder found for Home page`);
30
+ }
31
+ const homeTemplate = parseBuilderTemplateV2(dataBuilder);
32
+ const [fontStyle, fallback] = await Promise.all([
33
+ getFontFromGlobalStyle(dataBuilder?.pageStyle?.data),
34
+ getFallbackV2(fetcher, homeTemplate),
35
+ ]);
36
+ const mobileOnly = dataBuilder.isMobile ?? false;
37
+ const description = dataBuilder?.themePageDataSEO?.find((item) => item?.key === 'global-meta-description')?.value;
38
+ const thumbnail = parseJson(dataBuilder?.themePageDataSEO?.find((item) => item?.key === 'global-meta-thumbnail')?.value);
39
+ const shopMeta = shopifyMeta.status === 'fulfilled' ? shopifyMeta.value : undefined;
40
+ const shopData = storeProperty.status === 'fulfilled' ? storeProperty.value : undefined;
41
+ const favicon = shopData?.storeProperty?.favicon ?? '/favicon/favicon-32x32.png';
42
+ const seo = {
43
+ defaultTitle: shopMeta?.shop.name,
44
+ title: dataBuilder?.name ?? 'Home',
45
+ description: description ?? shopMeta?.shop.description,
46
+ openGraph: {
47
+ site_name: shopMeta?.shop.name,
48
+ locale: shopMeta?.localization.country.isoCode,
49
+ title: dataBuilder?.name ?? shopMeta?.shop.name,
50
+ description: description ?? shopMeta?.shop.description,
51
+ images: thumbnail ? [thumbnail] : [],
52
+ },
53
+ additionalMetaTags: [
54
+ {
55
+ name: 'theme-color',
56
+ content: '#000000',
57
+ },
58
+ ],
59
+ canonical: '/',
60
+ additionalLinkTags: [
61
+ {
62
+ rel: 'icon',
63
+ sizes: '32x32',
64
+ href: `${favicon}-/crop/1:1/center/-/smart_resize/32x32/`,
65
+ },
66
+ {
67
+ rel: 'icon',
68
+ sizes: '16x16',
69
+ href: `${favicon}-/crop/1:1/center/-/smart_resize/16x16/`,
70
+ },
71
+ {
72
+ rel: 'apple-touch-icon',
73
+ sizes: '180x180',
74
+ href: `${favicon}-/crop/1:1/center/-/smart_resize/180x180/`,
75
+ },
76
+ {
77
+ rel: 'manifest',
78
+ href: generateManifest({
79
+ theme_color: '#000000',
80
+ background_color: '#ffffff',
81
+ display: 'standalone',
82
+ scope: '/',
83
+ start_url: '/',
84
+ name: shopMeta?.shop.name,
85
+ short_name: shopMeta?.shop.name,
86
+ description: shopMeta?.shop.description,
87
+ icons: [
88
+ {
89
+ src: `${favicon}-/crop/1:1/center/-/smart_resize/192x192/`,
90
+ sizes: '192x192',
91
+ type: 'image/png',
92
+ purpose: 'any maskable',
93
+ },
94
+ {
95
+ src: `${favicon}-/crop/1:1/center/-/smart_resize/512x512/`,
96
+ sizes: '512x512',
97
+ type: 'image/png',
98
+ },
99
+ ],
100
+ }),
101
+ },
102
+ ],
103
+ };
104
+ return serializableJson({
105
+ themeStyle: genCSS(dataBuilder?.pageStyle?.data, mobileOnly),
106
+ fontStyle,
107
+ builderData: homeTemplate,
108
+ swr: { fallback },
109
+ currency: shopMeta?.localization.country.currency.isoCode ?? null,
110
+ locale: shopMeta?.localization.country.isoCode ?? null,
111
+ swatches: parseJson(shopData?.storeProperty?.swatchesConfig),
112
+ seo,
113
+ mobileOnly,
114
+ gaTrackingId: dataBuilder.themePageAnalytic?.gaTrackingID ?? null,
115
+ facebookPixelId: dataBuilder.themePageAnalytic?.fbPixelID ?? null,
116
+ tiktokPixelId: dataBuilder.themePageAnalytic?.tiktokPixelID ?? null,
117
+ });
118
+ }
119
+ catch (err) {
120
+ captureException(err);
121
+ throw err;
122
+ }
123
+ };
124
+
125
+ export { getHomePagePropsV2 };