cloudcommerce 0.0.82 → 0.0.84

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 (138) hide show
  1. package/.vscode/extensions.json +1 -1
  2. package/.vscode/settings.json +2 -3
  3. package/CHANGELOG.md +33 -0
  4. package/package.json +9 -9
  5. package/packages/api/lib/api.d.ts +8 -0
  6. package/packages/api/lib/api.js +24 -3
  7. package/packages/api/lib/api.js.map +1 -1
  8. package/packages/api/lib/types.d.ts +2 -0
  9. package/packages/api/package.json +5 -1
  10. package/packages/api/src/api.ts +31 -3
  11. package/packages/api/src/types.ts +2 -0
  12. package/packages/api/types.ts +2 -0
  13. package/packages/apps/correios/package.json +1 -1
  14. package/packages/apps/custom-shipping/package.json +1 -1
  15. package/packages/apps/discounts/package.json +1 -1
  16. package/packages/apps/frenet/package.json +1 -1
  17. package/packages/apps/tiny-erp/package.json +1 -1
  18. package/packages/cli/package.json +1 -1
  19. package/packages/config/package.json +1 -1
  20. package/packages/events/package.json +1 -1
  21. package/packages/firebase/package.json +2 -2
  22. package/packages/modules/package.json +1 -1
  23. package/packages/passport/package.json +1 -1
  24. package/packages/ssr/package.json +1 -1
  25. package/packages/storefront/astro.config.mjs +122 -5
  26. package/packages/storefront/client.d.ts +27 -0
  27. package/packages/storefront/content/header.json +3 -1
  28. package/packages/storefront/dist/client/admin/config.json +1 -0
  29. package/packages/storefront/dist/client/assets/_...2fc8f657.css +1 -0
  30. package/packages/storefront/dist/client/assets/{_...11681504.css → _...7af61807.css} +1 -1
  31. package/packages/storefront/dist/client/assets/cms-preview.css +274 -0
  32. package/packages/storefront/dist/client/assets/cms.css +114 -0
  33. package/packages/storefront/dist/client/assets/cvv.png +0 -0
  34. package/packages/storefront/dist/client/assets/icons/bootstrap-icons/font/storefront-icons.woff2 +0 -0
  35. package/packages/storefront/dist/client/assets/icons/feather-icons/font/storefront-icons.woff2 +0 -0
  36. package/packages/storefront/dist/client/assets/icons/font-awesome/font/storefront-icons.woff2 +0 -0
  37. package/packages/storefront/dist/client/assets/icons/line-awesome/font/storefront-icons.woff2 +0 -0
  38. package/packages/storefront/dist/client/assets/icons/tabler-icons/font/storefront-icons.woff2 +0 -0
  39. package/packages/storefront/dist/client/assets/img-placeholder.png +0 -0
  40. package/packages/storefront/dist/client/assets/payments.png +0 -0
  41. package/packages/storefront/dist/client/assets/ssl-safe.png +0 -0
  42. package/packages/storefront/dist/client/chunks/workbox-window.prod.es5.4b654ae6.js +2 -0
  43. package/packages/storefront/dist/client/hoisted.46e058d2.js +271 -0
  44. package/packages/storefront/dist/client/img/icon.png +0 -0
  45. package/packages/storefront/dist/client/img/large-icon.png +0 -0
  46. package/packages/storefront/dist/client/img/uploads/banner1.png +0 -0
  47. package/packages/storefront/dist/client/img/uploads/banner2.png +0 -0
  48. package/packages/storefront/dist/client/img/uploads/banner2.webp +0 -0
  49. package/packages/storefront/dist/client/img/uploads/favicon.png +0 -0
  50. package/packages/storefront/dist/client/img/uploads/headless.png +0 -0
  51. package/packages/storefront/dist/client/img/uploads/headphone.png +0 -0
  52. package/packages/storefront/dist/client/img/uploads/headphone.webp +0 -0
  53. package/packages/storefront/dist/client/img/uploads/icon.png +0 -0
  54. package/packages/storefront/dist/client/img/uploads/large-icon.png +0 -0
  55. package/packages/storefront/dist/client/img/uploads/logo.png +0 -0
  56. package/packages/storefront/dist/client/img/uploads/logo.webp +0 -0
  57. package/packages/storefront/dist/client/img/uploads/og-image.png +0 -0
  58. package/packages/storefront/dist/client/img/uploads/passion.png +0 -0
  59. package/packages/storefront/dist/client/img/uploads/passion.webp +0 -0
  60. package/packages/storefront/dist/client/img/uploads/pwa-reliable.png +0 -0
  61. package/packages/storefront/dist/client/img/uploads/rect8589.png +0 -0
  62. package/packages/storefront/dist/client/img/uploads/rect859.png +0 -0
  63. package/packages/storefront/dist/client/img/uploads/rect89.png +0 -0
  64. package/packages/storefront/dist/client/img/uploads/rect89.webp +0 -0
  65. package/packages/storefront/dist/client/img/uploads/ssl-safe.png +0 -0
  66. package/packages/storefront/dist/client/manifest.webmanifest +1 -1
  67. package/packages/storefront/dist/client/robots.txt +8 -0
  68. package/packages/storefront/dist/client/sw.js +1 -1
  69. package/packages/storefront/dist/client/workbox-361aba39.js +1 -0
  70. package/packages/storefront/dist/server/entry.mjs +608 -103
  71. package/packages/storefront/dist/server/manifest.webmanifest +1 -1
  72. package/packages/storefront/package.json +13 -12
  73. package/packages/storefront/public/admin/config.json +1 -0
  74. package/packages/storefront/public/assets/cms-preview.css +274 -0
  75. package/packages/storefront/public/assets/cms.css +114 -0
  76. package/packages/storefront/public/assets/cvv.png +0 -0
  77. package/packages/storefront/public/assets/icons/bootstrap-icons/font/storefront-icons.woff2 +0 -0
  78. package/packages/storefront/public/assets/icons/feather-icons/font/storefront-icons.woff2 +0 -0
  79. package/packages/storefront/public/assets/icons/font-awesome/font/storefront-icons.woff2 +0 -0
  80. package/packages/storefront/public/assets/icons/line-awesome/font/storefront-icons.woff2 +0 -0
  81. package/packages/storefront/public/assets/icons/tabler-icons/font/storefront-icons.woff2 +0 -0
  82. package/packages/storefront/public/assets/img-placeholder.png +0 -0
  83. package/packages/storefront/public/assets/payments.png +0 -0
  84. package/packages/storefront/public/assets/ssl-safe.png +0 -0
  85. package/packages/storefront/public/img/icon.png +0 -0
  86. package/packages/storefront/public/img/large-icon.png +0 -0
  87. package/packages/storefront/public/img/uploads/banner1.png +0 -0
  88. package/packages/storefront/public/img/uploads/banner2.png +0 -0
  89. package/packages/storefront/public/img/uploads/banner2.webp +0 -0
  90. package/packages/storefront/public/img/uploads/favicon.png +0 -0
  91. package/packages/storefront/public/img/uploads/headless.png +0 -0
  92. package/packages/storefront/public/img/uploads/headphone.png +0 -0
  93. package/packages/storefront/public/img/uploads/headphone.webp +0 -0
  94. package/packages/storefront/public/img/uploads/icon.png +0 -0
  95. package/packages/storefront/public/img/uploads/large-icon.png +0 -0
  96. package/packages/storefront/public/img/uploads/logo.png +0 -0
  97. package/packages/storefront/public/img/uploads/logo.webp +0 -0
  98. package/packages/storefront/public/img/uploads/og-image.png +0 -0
  99. package/packages/storefront/public/img/uploads/passion.png +0 -0
  100. package/packages/storefront/public/img/uploads/passion.webp +0 -0
  101. package/packages/storefront/public/img/uploads/pwa-reliable.png +0 -0
  102. package/packages/storefront/public/img/uploads/rect8589.png +0 -0
  103. package/packages/storefront/public/img/uploads/rect859.png +0 -0
  104. package/packages/storefront/public/img/uploads/rect89.png +0 -0
  105. package/packages/storefront/public/img/uploads/rect89.webp +0 -0
  106. package/packages/storefront/public/img/uploads/ssl-safe.png +0 -0
  107. package/packages/storefront/public/robots.txt +8 -0
  108. package/packages/storefront/scripts/prepare-monorepo.sh +4 -0
  109. package/packages/storefront/scripts/prerelease.sh +4 -0
  110. package/packages/storefront/src/env.d.ts +3 -1
  111. package/packages/storefront/src/lib/components/TheHeader.vue +15 -0
  112. package/packages/storefront/src/lib/components/TopBar.vue +141 -0
  113. package/packages/storefront/src/lib/helpers/image.ts +36 -0
  114. package/packages/storefront/src/lib/layouts/Base.astro +26 -25
  115. package/packages/storefront/src/lib/layouts/{meta/Head.astro → BaseHead.astro} +5 -3
  116. package/packages/storefront/src/lib/layouts/{meta/Json.astro → BaseStateJson.astro} +1 -1
  117. package/packages/storefront/src/lib/layouts/Pages.astro +2 -7
  118. package/packages/storefront/src/lib/layouts/PagesHeader.astro +92 -0
  119. package/packages/storefront/src/lib/ssr-context.ts +6 -4
  120. package/packages/storefront/src/pages/[...slug].astro +4 -0
  121. package/packages/storefront/src/types/cms-code.d.ts +5 -0
  122. package/packages/storefront/src/types/cms-contacts.d.ts +5 -0
  123. package/packages/storefront/src/types/cms-header.d.ts +5 -0
  124. package/packages/storefront/src/types/cms-settings.d.ts +5 -0
  125. package/packages/storefront/src/types/cms-social.d.ts +5 -0
  126. package/packages/storefront/tailwind.config.cjs +78 -0
  127. package/packages/storefront/uno.config.ts +55 -30
  128. package/packages/types/index.ts +1 -1
  129. package/packages/types/package.json +1 -1
  130. package/tsconfig.json +2 -1
  131. package/packages/storefront/dist/client/assets/_...65ca64e2.css +0 -1
  132. package/packages/storefront/dist/client/favicon.ico +0 -0
  133. package/packages/storefront/dist/client/hoisted.f0efb207.js +0 -272
  134. package/packages/storefront/dist/client/workbox-70b8fbb9.js +0 -1
  135. package/packages/storefront/public/favicon.ico +0 -0
  136. package/packages/storefront/src/html.d.ts +0 -23
  137. package/packages/storefront/src/vite-env.d.ts +0 -13
  138. package/packages/storefront/tailwind.config.ts +0 -30
@@ -0,0 +1,141 @@
1
+ <script lang="ts" setup>
2
+ import type CmsHeader from '../../types/cms-header';
3
+ import type CmsContacts from '../../types/cms-contacts';
4
+
5
+ export interface Props {
6
+ marketingStripe: CmsHeader['marketing_stripe'];
7
+ hasNavbar?: boolean;
8
+ pageLinks: CmsHeader['contacts_stripe']['pages'];
9
+ contacts: CmsContacts;
10
+ hasPhoneLinks?: boolean;
11
+ hasNetworkLinks?: boolean;
12
+ socialNetworks?: string[];
13
+ countdownClass?: string;
14
+ pageLinksClass?: string;
15
+ contactLinksClass?: string;
16
+ socialNetworksClass?: string;
17
+ }
18
+
19
+ withDefaults(defineProps<Props>(), {
20
+ hasNavbar: true,
21
+ hasPhoneLinks: true,
22
+ hasNetworksLinks: true,
23
+ socialNetworks() {
24
+ return ['facebook', 'twitter', 'youtube', 'pinterest', 'instagram', 'tiktok'];
25
+ },
26
+ });
27
+ </script>
28
+
29
+ <template>
30
+ <div class="top-bar w-full bg-surface">
31
+ <slot
32
+ name="countdown"
33
+ v-bind="{ marketingStripe, countdownClass }"
34
+ >
35
+ <template v-if="marketingStripe && marketingStripe.text">
36
+ <component
37
+ :is="marketingStripe.link ? 'a' : 'div'"
38
+ class="top-bar__countdown block text-sm text-center p-1
39
+ whitespace-nowrap overflow-x-auto"
40
+ :class="[countdownClass, marketingStripe.link ? 'primary' : 'secondary']"
41
+ :href="marketingStripe.link"
42
+ >
43
+ {{ marketingStripe.text }}
44
+ </component>
45
+ </template>
46
+ </slot>
47
+
48
+ <div
49
+ v-if="hasNavbar"
50
+ class="top-bar__nav hidden md:block py-2"
51
+ >
52
+ <div class="container">
53
+ <div class="flex items-center lg:px-2 xl:px-4">
54
+ <div class="grow text-xs">
55
+ <slot
56
+ name="contacts-container"
57
+ v-bind="{ pageLinks, pageLinksClass }"
58
+ >
59
+ <nav
60
+ v-if="pageLinks"
61
+ class="top-bar__page-links inline-block mr-4 font-semibold"
62
+ :class="pageLinksClass"
63
+ >
64
+ <a
65
+ v-for="({ link, title }, i) in pageLinks"
66
+ class="mr-2 lg:mr-3"
67
+ :key="i"
68
+ :href="link"
69
+ >
70
+ {{ title }}
71
+ </a>
72
+ </nav>
73
+ </slot>
74
+
75
+ <slot
76
+ name="contact-links"
77
+ v-bind="{ contacts, hasPhoneLinks, contactLinksClass }"
78
+ >
79
+ <div
80
+ v-if="hasPhoneLinks"
81
+ class="top-bar__contact-links inline-block"
82
+ :class="contactLinksClass"
83
+ >
84
+ <a
85
+ v-if="contacts.whatsapp"
86
+ href="javascript:;"
87
+ target="_blank"
88
+ rel="noopener"
89
+ :data-whatsapp-tel="contacts.whatsapp.replace(/\D/g, '')"
90
+ class="mr-2"
91
+ >
92
+ <i class="i-whatsapp"></i>
93
+ {{ contacts.whatsapp }}
94
+ </a>
95
+ <a
96
+ v-if="contacts.phone"
97
+ :href="`tel:+${contacts.phone.replace(/\D/g, '')}`"
98
+ target="_blank"
99
+ rel="noopener"
100
+ class="mr-2"
101
+ >
102
+ <i class="i-phone"></i>
103
+ {{ contacts.phone }}
104
+ </a>
105
+ </div>
106
+ </slot>
107
+ </div>
108
+
109
+ <slot
110
+ name="social-networks"
111
+ v-bind="{ contacts, hasNetworkLinks, socialNetworksClass }"
112
+ >
113
+ <div
114
+ v-if="hasNetworkLinks"
115
+ class="top-bar__social-networks leading-none"
116
+ >
117
+ <template v-for="network in socialNetworks">
118
+ <template v-if="contacts[network]">
119
+ <a
120
+ :key="network"
121
+ :href="contacts[network]"
122
+ target="_blank"
123
+ rel="noopener"
124
+ class="ml-1"
125
+ >
126
+ <i v-if="network === 'facebook'" class="i-facebook"></i>
127
+ <i v-else-if="network === 'youtube'" class="i-youtube"></i>
128
+ <i v-else-if="network === 'twitter'" class="i-twitter"></i>
129
+ <i v-else-if="network === 'pinterest'" class="i-pinterest"></i>
130
+ <i v-else-if="network === 'instagram'" class="i-instagram"></i>
131
+ <i v-else-if="network === 'tiktok'" class="i-tiktok"></i>
132
+ </a>
133
+ </template>
134
+ </template>
135
+ </div>
136
+ </slot>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </template>
@@ -0,0 +1,36 @@
1
+ import imageSize from 'image-size';
2
+ // eslint-disable-next-line import/no-unresolved
3
+ import { getImage as _getImage } from '@astrojs/image';
4
+
5
+ const tryImageSize = (src: string) => {
6
+ let dimensions: { width?: number, height?: number } = {};
7
+ if (typeof src === 'string' && src.startsWith('/')) {
8
+ try {
9
+ dimensions = imageSize(`public${src}`);
10
+ } catch (e) {
11
+ dimensions = {};
12
+ }
13
+ }
14
+ return dimensions;
15
+ };
16
+
17
+ const getImage = (options: Parameters<typeof _getImage>[0]) => {
18
+ const { src } = options;
19
+ if (
20
+ typeof src === 'string'
21
+ && !options.aspectRatio
22
+ && (!options.width || !options.height)
23
+ ) {
24
+ const { width, height } = tryImageSize(src);
25
+ return _getImage({
26
+ width,
27
+ ...options,
28
+ aspectRatio: width && height ? width / height : 1,
29
+ });
30
+ }
31
+ return _getImage(options);
32
+ };
33
+
34
+ export default getImage;
35
+
36
+ export { tryImageSize, getImage };
@@ -1,8 +1,9 @@
1
1
  ---
2
+ import type CmsCode from '../../types/cms-code';
2
3
  import type { PageContext } from '../ssr-context';
3
4
  import Color from 'color';
4
- import MetaHead from './meta/Head.astro';
5
- import MetaJson from './meta/Json.astro';
5
+ import BaseHead from './BaseHead.astro';
6
+ import BaseStateJson from './BaseStateJson.astro';
6
7
  import '@picocss/pico/css/pico.min.css';
7
8
 
8
9
  export interface Props {
@@ -17,7 +18,7 @@ const {
17
18
  secondaryColor,
18
19
  cms,
19
20
  } = pageContext;
20
- const cmsCustomCode = cms('code') as typeof import('../../../content/code.json');
21
+ const cmsCustomCode = cms('code') as CmsCode;
21
22
 
22
23
  const brandColors = {
23
24
  primary: primaryColor,
@@ -44,7 +45,7 @@ Object.keys(brandColors).forEach((colorName) => {
44
45
  const colorShift = colorVariants[colorVariant];
45
46
  const colorLabel = `${colorName}-${colorVariant}`;
46
47
  colorCSSVars[colorLabel] = color.darken(colorShift).hex();
47
- if (Number(colorLabel) > 100 && Number(colorLabel) < 900) {
48
+ if (Number(colorVariant) > 100 && Number(colorVariant) < 900) {
48
49
  colorCSSVars[`${colorLabel}-yiq`] = color.isLight()
49
50
  ? 'var(--yiq-text-dark)' : 'var(--yiq-text-light)';
50
51
  colorCSSVars[`${colorLabel}-rgb`] = `${color.red()}, ${color.green()}, ${color.blue()}`;
@@ -56,8 +57,8 @@ Object.keys(brandColors).forEach((colorName) => {
56
57
  <!DOCTYPE html>
57
58
  <html lang={lang.replace('_', '-')}>
58
59
  <head>
59
- <MetaHead pageContext={pageContext} title={title} />
60
- <MetaJson pageContext={pageContext} />
60
+ <BaseHead pageContext={pageContext} title={title} />
61
+ <BaseStateJson pageContext={pageContext} />
61
62
  <slot name="before-head-end">
62
63
  {cmsCustomCode.css && <style>{cmsCustomCode.css}</style>}
63
64
  {cmsCustomCode.html_head && <Fragment set:html={cmsCustomCode.html_head} />}
@@ -67,9 +68,9 @@ Object.keys(brandColors).forEach((colorName) => {
67
68
  <body>
68
69
  <slot />
69
70
  <script>
70
- import { initializeApp } from 'firebase/app';
71
71
  import { registerSW } from 'virtual:pwa-register';
72
- // @ts-ignore
72
+ import { initializeApp } from 'firebase/app';
73
+ registerSW();
73
74
  const firebaseConfig = window.firebaseConfig || {
74
75
  apiKey: "AIzaSyCrVzemDgpyp9i6ni7Yc5ZuEVfXYwl-4J0",
75
76
  authDomain: "ecom2-002.firebaseapp.com",
@@ -80,13 +81,6 @@ Object.keys(brandColors).forEach((colorName) => {
80
81
  measurementId: "G-SC592CE0GB"
81
82
  };
82
83
  initializeApp(firebaseConfig);
83
- const updateSW = registerSW({
84
- onNeedRefresh() {},
85
- onOfflineReady() {
86
- console.log('Offline ready');
87
- },
88
- });
89
- updateSW();
90
84
  </script>
91
85
  <slot name="before-body-end">
92
86
  {cmsCustomCode.html_body && <Fragment set:html={cmsCustomCode.html_body} />}
@@ -96,25 +90,35 @@ Object.keys(brandColors).forEach((colorName) => {
96
90
 
97
91
  <style is:global define:vars={colorCSSVars}>
98
92
  :root {
93
+ --content-max-width: 80rem;
99
94
  --white: #fff;
100
- --gray: #6c757d;
101
- --gray-dark: #343a40;
95
+ --gray-50: theme('colors.gray.50');
96
+ --gray-200: theme('colors.gray.200');
97
+ --gray-700: theme('colors.gray.700');
98
+ --gray-800: theme('colors.gray.800');
99
+ --gray-900: theme('colors.gray.900');
100
+ --surface-color: var(--gray-50);
101
+ --surface-border-color: var(--gray-200);
102
102
  --yiq-text-light: var(--white);
103
- --yiq-text-dark: var(--gray-dark);
103
+ --yiq-text-dark: var(--gray-900);
104
104
  }
105
105
  body,
106
106
  body [data-theme=light],
107
107
  body [data-theme=dark] {
108
108
  --primary: var(--primary-500);
109
109
  --primary-hover: var(--primary-700);
110
- --primary-focus: var(--primary-50);
110
+ --primary-focus: rgba(var(--primary-200-rgb), 0.2);
111
111
  --primary-inverse: var(--primary-500-yiq);
112
112
  --secondary: var(--secondary-500);
113
113
  --secondary-hover: var(--secondary-700);
114
- --secondary-focus: var(--secondary-50);
114
+ --secondary-focus: rgba(var(--secondary-200-rgb), 0.2);
115
115
  --secondary-inverse: var(--secondary-500-yiq);
116
116
  }
117
117
  @media only screen and (prefers-color-scheme: dark) {
118
+ :root:not([data-theme=light]) {
119
+ --surface-color: var(--gray-800);
120
+ --surface-border-color: var(--gray-700);
121
+ }
118
122
  :root:not([data-theme=light]) a {
119
123
  --color: var(--primary-200);
120
124
  }
@@ -122,10 +126,7 @@ Object.keys(brandColors).forEach((colorName) => {
122
126
  --color: var(--primary-400);
123
127
  }
124
128
  }
125
- [data-theme=light] a {
126
- --color: var(--primary) !important;
127
- }
128
- [data-theme=light] a:is([aria-current], :hover, :active, :focus) {
129
- --color: var(--primary-hover) !important;
129
+ body {
130
+ overflow-x: hidden;
130
131
  }
131
132
  </style>
@@ -1,5 +1,6 @@
1
1
  ---
2
- import type { PageContext } from '../../ssr-context';
2
+ import type CmsSocial from '../../types/cms-social';
3
+ import type { PageContext } from '../ssr-context';
3
4
  import ecomUtils from '@ecomplus/utils';
4
5
 
5
6
  export interface Props {
@@ -22,7 +23,7 @@ const title = state.meta_title || state.name || state.title || Astro.props.title
22
23
  const description = state.meta_description || state.short_description || settings.description;
23
24
 
24
25
  const canonicalUrl = new URL(Astro.url.pathname, Astro.site || `https://${domain}`);
25
- const cmsSocial = cms('social') as typeof import('../../../../content/social.json');
26
+ const cmsSocial = cms('social') as CmsSocial;
26
27
  const ogLocale = lang.length === 2 ? lang : lang.substring(0, 2) + lang.slice(3).toUpperCase();
27
28
  let ogImage: string | undefined;
28
29
  if (apiDoc) {
@@ -43,10 +44,11 @@ if (!ogImage) {
43
44
  <meta name="viewport" content="width=device-width">
44
45
  <meta name="theme-color" content={primaryColor}>
45
46
  <link rel="icon" href={settings.favicon || '/favicon.ico'} />
47
+ {import.meta.env.PROD && <link rel="manifest" href="/manifest.webmanifest" />}
46
48
  <title>{title}</title>
47
49
  <meta name="description" content={description}>
48
50
  <meta name="author" content={settings.name}>
49
- <meta name="generator" content="E-Com Plus Cloud Commerce">
51
+ <meta name="generator" content={Astro.generator} />
50
52
  <link rel="canonical" href={canonicalUrl} />
51
53
  <link rel="apple-touch-icon" href={settings.icon} />
52
54
  <meta name="apple-mobile-web-app-capable" content="yes">
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { PageContext } from '../../ssr-context';
2
+ import type { PageContext } from '../ssr-context';
3
3
  import ecomUtils from '@ecomplus/utils';
4
4
 
5
5
  export interface Props {
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  import type { PageContext } from '../ssr-context';
3
3
  import Base from './Base.astro';
4
+ import Header from './PagesHeader.astro';
4
5
 
5
6
  export interface Props {
6
7
  pageContext: PageContext;
@@ -15,13 +16,7 @@ const { pageContext, title } = Astro.props as Props;
15
16
  <slot name="before-head-end" />
16
17
  </Fragment>
17
18
  <slot name="header">
18
- <div class="i-shopping-cart" text="sky-400" />
19
- <div class="i-google-pay w-32" />
20
- <div class="i-logos:apple bg-primary" />
21
- <div class="i-heroicons:user bg-primary-300" />
22
- <div class="i-user bg-primary-700" />
23
- <div class="i-user bg-secondary-hover" />
24
- <div class="i-user bg-contrast" />
19
+ <Header pageContext={pageContext} />
25
20
  </slot>
26
21
  <slot />
27
22
  <Fragment slot="before-body-end">
@@ -0,0 +1,92 @@
1
+ ---
2
+ import type { Categories } from '@cloudcommerce/api/types';
3
+ import type CmsHeader from '../../types/cms-header';
4
+ import type CmsContacts from '../../types/cms-contacts';
5
+ import type { PageContext } from '../ssr-context';
6
+ import getImage from '../helpers/image';
7
+ import TopBar, { Props as TopBarProps } from '../components/TopBar.vue';
8
+ import TheHeader from '../components/TheHeader.vue';
9
+
10
+ export interface Props {
11
+ pageContext: PageContext;
12
+ topBarProps?: Partial<TopBarProps>;
13
+ logoTransform?: {
14
+ width?: number;
15
+ height?: number;
16
+ quality?: number;
17
+ };
18
+ }
19
+
20
+ declare global {
21
+ var TopBarProps: TopBarProps;
22
+ }
23
+
24
+ const {
25
+ pageContext: {
26
+ apiState,
27
+ settings,
28
+ cms,
29
+ },
30
+ topBarProps,
31
+ logoTransform,
32
+ } = Astro.props as Props;
33
+ const header = cms('header') as CmsHeader;
34
+ const contacts = cms('contacts') as CmsContacts;
35
+ const customThemeName = settings.theme.custom || '';
36
+
37
+ let headerCategories: Array<{ slug: string, name: string }> = [];
38
+ let isCategoriesNavFull: boolean | undefined;
39
+ if (header.categories_list) {
40
+ if (header.categories_list.featured.length) {
41
+ // Selected categories/collections/brands
42
+ headerCategories = header.categories_list.featured.map((pathAndName) => {
43
+ const [path, name] = pathAndName.split('?');
44
+ return { slug: path.slice(1), name };
45
+ });
46
+ }
47
+ if (header.categories_list.random) {
48
+ const mainCategories: Categories[] | undefined = apiState
49
+ .categories?.filter(({ parent }) => (!parent || !parent.slug));
50
+ if (mainCategories) {
51
+ for (let i = 0; i < header.categories_list.random && i < mainCategories.length; i++) {
52
+ if (!headerCategories.find(({ slug }) => mainCategories[i].slug === slug)) {
53
+ headerCategories.push({
54
+ slug: mainCategories[i].slug,
55
+ name: mainCategories[i].name,
56
+ });
57
+ }
58
+ }
59
+ }
60
+ }
61
+ isCategoriesNavFull = header.categories_list.full_width;
62
+ }
63
+ const hasMegamenu: boolean | undefined = header.desktop_megamenu;
64
+ const isAlphabeticalOrderSubmenu: boolean | undefined = header.alphabetical_order_submenu;
65
+ const isFullWidthSubmenu: boolean | undefined = header.full_width_submenu;
66
+
67
+ globalThis.TopBarProps = {
68
+ marketingStripe: header.marketing_stripe,
69
+ pageLinks: header.contacts_stripe.pages,
70
+ hasPhoneLinks: header.contacts_stripe.phone_wpp,
71
+ hasNetworkLinks: header.contacts_stripe.socials,
72
+ contacts,
73
+ ...Astro.props.topBarProps,
74
+ };
75
+
76
+ const logoWebpAttrs = await getImage({
77
+ src: settings.logo,
78
+ width: 150,
79
+ format: 'webp',
80
+ quality: 100,
81
+ ...logoTransform,
82
+ });
83
+ ---
84
+
85
+ <slot name="top-bar">
86
+ <TopBar {...globalThis.TopBarProps} />
87
+ </slot>
88
+ <slot name="header">
89
+ <TheHeader>
90
+ <img slot="logo" {...logoWebpAttrs} alt={`${settings.name} (logo)`} />
91
+ </TheHeader>
92
+ </slot>
@@ -1,10 +1,8 @@
1
1
  import type { AstroGlobal } from 'astro';
2
2
  import type { BaseConfig } from '@cloudcommerce/config';
3
+ import type CmsSettings from '../types/cms-settings';
3
4
  import api, { ApiError, ApiEndpoint } from '@cloudcommerce/api';
4
5
  import _getConfig from '../../storefront.config.mjs';
5
- import settings from '../../content/settings.json';
6
-
7
- type CmsSettings = typeof settings;
8
6
 
9
7
  type StorefrontConfig = {
10
8
  storeId: BaseConfig['storeId'],
@@ -24,6 +22,10 @@ type StorefrontConfig = {
24
22
 
25
23
  const getConfig: () => StorefrontConfig = _getConfig;
26
24
 
25
+ declare global {
26
+ // eslint-disable-next-line
27
+ var api_prefetch_endpoints: ApiEndpoint[];
28
+ }
27
29
  if (!globalThis.api_prefetch_endpoints) {
28
30
  globalThis.api_prefetch_endpoints = ['categories'];
29
31
  }
@@ -76,7 +78,7 @@ const loadPageContext = async (Astro: AstroGlobal, {
76
78
  apiState[`${apiResource}/${apiDoc._id}`] = apiDoc;
77
79
  }
78
80
  prefetchResponses.forEach(({ config: { endpoint }, data }) => {
79
- apiState[endpoint] = data;
81
+ apiState[endpoint] = data.result || data;
80
82
  });
81
83
  } catch (err: any) {
82
84
  const error: ApiError = err;
@@ -2,6 +2,10 @@
2
2
  import ViewWildcard from '../lib/views/[...slug].astro';
3
3
  import loadPageContext, { PageContext } from '../lib/ssr-context';
4
4
 
5
+ if (String(Astro.params.slug).endsWith('.css.map')) {
6
+ return new Response(null, { status: 404 });
7
+ }
8
+
5
9
  let pageContext: PageContext;
6
10
  let loadError: any;
7
11
  try {
@@ -0,0 +1,5 @@
1
+ type CmsCode = typeof import('../../content/code.json');
2
+
3
+ export default CmsCode;
4
+
5
+ export type { CmsCode };
@@ -0,0 +1,5 @@
1
+ type CmsContacts = typeof import('../../content/contacts.json');
2
+
3
+ export default CmsContacts;
4
+
5
+ export type { CmsContacts };
@@ -0,0 +1,5 @@
1
+ type CmsHeader = typeof import('../../content/header.json');
2
+
3
+ export default CmsHeader;
4
+
5
+ export type { CmsHeader };
@@ -0,0 +1,5 @@
1
+ type CmsSettings = typeof import('../../content/settings.json');
2
+
3
+ export default CmsSettings;
4
+
5
+ export type { CmsSettings };
@@ -0,0 +1,5 @@
1
+ type CmsSocial = typeof import('../../content/social.json');
2
+
3
+ export default CmsSocial;
4
+
5
+ export type { CmsSocial };
@@ -0,0 +1,78 @@
1
+ const genTailwindConfig = ({
2
+ colorVariants = [
3
+ '50',
4
+ ...[...Array(9).keys()].map((i) => String((i + 1) * 100)),
5
+ ],
6
+ } = {}) => ({
7
+ theme: {
8
+ extend: {
9
+ colors: {
10
+ // Color vars from Base.astro styles
11
+ ...['primary', 'secondary', 'contrast'].reduce((colors, color) => {
12
+ const colorVariations = ['hover', 'focus', 'inverse'];
13
+ if (color !== 'contrast') {
14
+ colorVariations.push(...colorVariants);
15
+ }
16
+ colors[color] = colorVariations.reduce((colorPalette, variant) => {
17
+ colorPalette[variant] = `var(--${color}-${variant})`;
18
+ return colorPalette;
19
+ }, {
20
+ DEFAULT: `var(--${color})`,
21
+ });
22
+ return colors;
23
+ }, {}),
24
+ ...['surface', 'muted'].reduce((colors, color) => ({
25
+ [color]: {
26
+ DEFAULT: `var(--${color}-color)`,
27
+ border: `var(--${color}-border-color)`,
28
+ },
29
+ ...colors,
30
+ }), {}),
31
+ },
32
+ },
33
+ },
34
+ plugins: [
35
+ ({ addUtilities }) => {
36
+ addUtilities({
37
+ // https://picocss.com/docs/containers.html
38
+ '.container-fluid': {
39
+ 'max-width': 'var(--content-max-width)',
40
+ },
41
+ // https://picocss.com/docs/buttons.html
42
+ ...['primary', 'secondary', 'contrast'].reduce((utilities, color) => ({
43
+ ...utilities,
44
+ [`.${color}`]: {
45
+ '--background-color': `var(--${color})`,
46
+ 'background-color': 'var(--background-color)',
47
+ color: `var(--${color}-inverse)`,
48
+ },
49
+ }), {}),
50
+ ...['primary', 'secondary'].reduce((utilities, color) => {
51
+ colorVariants.forEach((variant) => {
52
+ const colorLabel = `${color}-${variant}`;
53
+ let textColor;
54
+ if (Number(variant) <= 100) {
55
+ textColor = 'var(--yiq-text-dark)';
56
+ } else if (Number(variant) >= 900) {
57
+ textColor = 'var(--yiq-text-light)';
58
+ } else {
59
+ textColor = `var(--${colorLabel}-yiq)`;
60
+ }
61
+ utilities[`.${colorLabel}`] = {
62
+ 'background-color': `var(--${colorLabel})`,
63
+ color: textColor,
64
+ };
65
+ });
66
+ return utilities;
67
+ }, {}),
68
+ });
69
+ },
70
+ ],
71
+ });
72
+
73
+ const tailwindConfig = genTailwindConfig();
74
+
75
+ module.exports = { ...tailwindConfig, genTailwindConfig };
76
+
77
+ exports.genTailwindConfig = genTailwindConfig;
78
+ exports.tailwindConfig = tailwindConfig;