cloudcommerce 0.0.96 → 0.0.98

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 (84) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +3 -3
  3. package/packages/api/package.json +1 -1
  4. package/packages/apps/correios/lib-mjs/correios-ws.mjs +2 -1
  5. package/packages/apps/correios/package.json +1 -1
  6. package/packages/apps/custom-shipping/package.json +1 -1
  7. package/packages/apps/discounts/package.json +1 -1
  8. package/packages/apps/frenet/package.json +1 -1
  9. package/packages/apps/tiny-erp/lib/event-to-tiny.js +94 -94
  10. package/packages/apps/tiny-erp/lib/index.js +1 -1
  11. package/packages/apps/tiny-erp/lib/integration/after-tiny-queue.js +74 -71
  12. package/packages/apps/tiny-erp/lib/integration/export-order-to-tiny.js +73 -70
  13. package/packages/apps/tiny-erp/lib/integration/export-product-to-tiny.js +53 -49
  14. package/packages/apps/tiny-erp/lib/integration/helpers/format-tiny-date.js +3 -3
  15. package/packages/apps/tiny-erp/lib/integration/import-order-from-tiny.js +75 -76
  16. package/packages/apps/tiny-erp/lib/integration/import-product-from-tiny.js +140 -137
  17. package/packages/apps/tiny-erp/lib/integration/parsers/order-from-tiny.js +39 -40
  18. package/packages/apps/tiny-erp/lib/integration/parsers/order-to-tiny.js +178 -173
  19. package/packages/apps/tiny-erp/lib/integration/parsers/product-from-tiny.js +171 -173
  20. package/packages/apps/tiny-erp/lib/integration/parsers/product-to-tiny.js +127 -123
  21. package/packages/apps/tiny-erp/lib/integration/parsers/status-from-tiny.js +32 -32
  22. package/packages/apps/tiny-erp/lib/integration/parsers/status-to-tiny.js +37 -37
  23. package/packages/apps/tiny-erp/lib/integration/post-tiny-erp.js +43 -42
  24. package/packages/apps/tiny-erp/lib/tiny-erp.js +6 -8
  25. package/packages/apps/tiny-erp/lib/tiny-webhook.js +73 -76
  26. package/packages/apps/tiny-erp/package.json +2 -2
  27. package/packages/cli/package.json +1 -1
  28. package/packages/config/package.json +1 -1
  29. package/packages/events/package.json +2 -2
  30. package/packages/firebase/package.json +3 -3
  31. package/packages/modules/lib/firebase/ajv.js +19 -24
  32. package/packages/modules/lib/firebase/call-app-module.js +116 -110
  33. package/packages/modules/lib/firebase/checkout.js +151 -152
  34. package/packages/modules/lib/firebase/functions-checkout/fix-items.js +194 -187
  35. package/packages/modules/lib/firebase/functions-checkout/get-custumerId.js +25 -26
  36. package/packages/modules/lib/firebase/functions-checkout/handle-order-transaction.js +110 -109
  37. package/packages/modules/lib/firebase/functions-checkout/new-order.js +177 -177
  38. package/packages/modules/lib/firebase/functions-checkout/request-to-module.js +59 -59
  39. package/packages/modules/lib/firebase/functions-checkout/utils.js +195 -197
  40. package/packages/modules/lib/firebase/handle-module.js +144 -146
  41. package/packages/modules/lib/firebase/proxy-apps.js +2 -1
  42. package/packages/modules/lib/firebase/serve-modules-api.js +52 -53
  43. package/packages/modules/lib/firebase.js +4 -6
  44. package/packages/modules/lib/index.js +12 -15
  45. package/packages/modules/package.json +2 -2
  46. package/packages/passport/package.json +2 -2
  47. package/packages/ssr/package.json +2 -2
  48. package/packages/storefront/.eslintrc.cjs +1 -0
  49. package/packages/storefront/astro.config.mjs +11 -1
  50. package/packages/storefront/dist/client/LoginOffcanvas.daf3f717.js +1 -0
  51. package/packages/storefront/dist/client/assets/_...522e6bf2.css +4 -0
  52. package/packages/storefront/dist/client/assets/{_...ee104f19.css → _...a48b75c7.css} +1 -1
  53. package/packages/storefront/dist/client/chunks/LoginForm.d9251274.js +1066 -0
  54. package/packages/storefront/dist/client/chunks/LoginOffcanvas.07fe6492.js +1 -0
  55. package/packages/storefront/dist/client/{hoisted.46e058d2.js → chunks/index.esm.84a649c7.js} +77 -17
  56. package/packages/storefront/dist/client/chunks/preload-helper.f15ab524.js +1 -0
  57. package/packages/storefront/dist/client/chunks/runtime-dom.esm-bundler.738639ee.js +1 -0
  58. package/packages/storefront/dist/client/client.b552d86a.js +1 -0
  59. package/packages/storefront/dist/client/hoisted.054c36ac.js +1 -0
  60. package/packages/storefront/dist/client/manifest.webmanifest +1 -1
  61. package/packages/storefront/dist/client/sw.js +1 -1
  62. package/packages/storefront/dist/server/entry.mjs +370 -180
  63. package/packages/storefront/dist/server/manifest.webmanifest +1 -1
  64. package/packages/storefront/package.json +6 -5
  65. package/packages/storefront/src/assets/pico.css +0 -1
  66. package/packages/storefront/src/env.d.ts +1 -1
  67. package/packages/storefront/src/lib/components/AOffcanvas.vue +98 -0
  68. package/packages/storefront/src/lib/components/LoginForm.vue +54 -0
  69. package/packages/storefront/src/lib/components/LoginOffcanvas.vue +41 -0
  70. package/packages/storefront/src/lib/components/TheHeader.vue +37 -3
  71. package/packages/storefront/src/lib/components/TopBar.vue +13 -21
  72. package/packages/storefront/src/lib/layouts/BaseBody.astro +41 -38
  73. package/packages/storefront/src/lib/layouts/BaseHead.astro +0 -5
  74. package/packages/storefront/src/lib/layouts/BaseStateJson.astro +12 -11
  75. package/packages/storefront/src/lib/layouts/PagesHeader.astro +29 -20
  76. package/packages/storefront/src/lib/scripts/firebase-app.ts +16 -0
  77. package/packages/storefront/src/lib/{helpers → ssr}/image.ts +1 -1
  78. package/packages/storefront/src/pages/app/account.astro +0 -0
  79. package/packages/storefront/storefront.config.mjs +1 -1
  80. package/packages/storefront/tsconfig.json +4 -1
  81. package/packages/types/package.json +1 -1
  82. package/packages/storefront/dist/client/assets/_...73e01db2.css +0 -4
  83. package/packages/storefront/dist/client/client.80baece3.js +0 -1
  84. package/packages/storefront/src/lib/components/LoginModal.vue +0 -82
@@ -1 +1 @@
1
- {"name":"My Shop","short_name":"MyShop","start_url":"/","display":"standalone","background_color":"#f5f6fa","lang":"en","scope":"/","description":"My PWA Shop","theme_color":"#20c997","crossorigin":"use-credentials","icons":[{"src":"/img/icon.png","sizes":"192x192","type":"image/png"},{"src":"/img/large-icon.png","sizes":"512x512","type":"image/png"},{"src":"/img/large-icon.png","sizes":"512x512","type":"image/png","purpose":"any maskable"}]}
1
+ {"name":"My Shop","short_name":"MyShop","start_url":"/","display":"standalone","background_color":"#f5f6fa","lang":"en","scope":"/","description":"My PWA Shop","theme_color":"#137c5c","crossorigin":"use-credentials","icons":[{"src":"/img/icon.png","sizes":"192x192","type":"image/png"},{"src":"/img/large-icon.png","sizes":"512x512","type":"image/png"},{"src":"/img/large-icon.png","sizes":"512x512","type":"image/png","purpose":"any maskable"}]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/storefront",
3
3
  "type": "module",
4
- "version": "0.0.96",
4
+ "version": "0.0.98",
5
5
  "description": "E-Com Plus Cloud Commerce storefront with Astro",
6
6
  "main": "src/index.js",
7
7
  "repository": {
@@ -17,7 +17,7 @@
17
17
  "homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/storefront#readme",
18
18
  "scripts": {
19
19
  "dev": "astro dev",
20
- "start": "astro dev",
20
+ "start": "astro dev --host",
21
21
  "build": "astro build",
22
22
  "preview": "astro preview",
23
23
  "astro": "astro",
@@ -32,12 +32,13 @@
32
32
  "@astrojs/vue": "^1.0.2",
33
33
  "@cloudcommerce/api": "workspace:*",
34
34
  "@cloudcommerce/config": "workspace:*",
35
+ "@ecomplus/i18n": "^1.32.0",
35
36
  "@ecomplus/utils": "^1.4.1",
36
37
  "@iconify-json/bxl": "^1.1.4",
37
38
  "@iconify-json/heroicons": "^1.1.4",
38
39
  "@iconify-json/logos": "^1.1.16",
39
40
  "@nanostores/vue": "^0.6.0",
40
- "@unocss/preset-icons": "^0.45.22",
41
+ "@unocss/preset-icons": "^0.45.23",
41
42
  "astro": "^1.3.0",
42
43
  "color": "^4.2.3",
43
44
  "dotenv": "^16.0.2",
@@ -45,9 +46,9 @@
45
46
  "image-size": "^1.0.2",
46
47
  "nanostores": "^0.7.0",
47
48
  "rollup": "^2.79.1",
48
- "unocss": "^0.45.22",
49
+ "unocss": "^0.45.23",
49
50
  "vite": "^3.1.3",
50
- "vite-plugin-pwa": "^0.12.8",
51
+ "vite-plugin-pwa": "^0.13.1",
51
52
  "vue": "^3.2.39"
52
53
  }
53
54
  }
@@ -558,7 +558,6 @@ a:is([aria-current], :hover, :active, :focus),
558
558
  --color: var(--primary-hover);
559
559
  --text-decoration: underline;
560
560
  }
561
- a:focus,
562
561
  [role=link]:focus {
563
562
  --background-color: var(--primary-focus);
564
563
  }
@@ -1,3 +1,3 @@
1
- /// <reference types="@astrojs/image/client" />
1
+ /// <reference types="astro/client" />
2
2
  /// <reference types="vite-plugin-pwa/client" />
3
3
  /// <reference types="../client" />
@@ -0,0 +1,98 @@
1
+ <script lang="ts" setup>
2
+ import {
3
+ toRef,
4
+ ref,
5
+ computed,
6
+ watch,
7
+ } from 'vue';
8
+ import { i19close } from '@i18n';
9
+
10
+ export interface Props {
11
+ modelValue?: boolean;
12
+ placement?: 'start' | 'end';
13
+ }
14
+
15
+ const props = withDefaults(defineProps<Props>(), {
16
+ modelValue: false,
17
+ placement: 'end',
18
+ });
19
+ const emit = defineEmits(['update:modelValue']);
20
+ const close = () => emit('update:modelValue', false);
21
+ const article = ref(null);
22
+ const outsideClickListener = (ev: MouseEvent) => {
23
+ if (!article.value?.contains(ev.target)) {
24
+ close();
25
+ }
26
+ };
27
+ const escClickListener = (ev: KeyboardEvent) => {
28
+ if (ev.key === 'Escape') {
29
+ close();
30
+ }
31
+ };
32
+ watch(toRef(props, 'modelValue'), async (isOpen) => {
33
+ if (isOpen) {
34
+ document.body.style.maxWidth = `${document.body.offsetWidth}px`;
35
+ document.body.style.overflow = 'hidden';
36
+ setTimeout(() => {
37
+ document.addEventListener('click', outsideClickListener, { passive: true });
38
+ document.addEventListener('keydown', escClickListener, { passive: true });
39
+ }, 500);
40
+ } else {
41
+ document.removeEventListener('click', outsideClickListener);
42
+ document.removeEventListener('keydown', escClickListener);
43
+ }
44
+ });
45
+ const transition3dTx = computed(() => {
46
+ return props.placement === 'end' ? '100%' : '-100%';
47
+ });
48
+ </script>
49
+
50
+ <template>
51
+ <Transition>
52
+ <dialog
53
+ v-if="modelValue"
54
+ class="offcanvas p-0"
55
+ :class="placement === 'end' ? 'justify-end' : 'justify-start'"
56
+ :open="modelValue"
57
+ >
58
+ <article
59
+ ref="article"
60
+ class="rounded-none h-full max-h-screen m-0"
61
+ >
62
+ <a
63
+ href="#close"
64
+ :aria-label="i19close"
65
+ class="close"
66
+ data-target="modal-example"
67
+ @click.prevent="close"
68
+ ></a>
69
+ <slot />
70
+ </article>
71
+ </dialog>
72
+ </Transition>
73
+ </template>
74
+
75
+ <style>
76
+ .offcanvas.v-enter-active,
77
+ .offcanvas.v-leave-active {
78
+ transition: opacity 0.25s linear;
79
+ }
80
+ .offcanvas.v-enter-from,
81
+ .offcanvas.v-leave-to {
82
+ opacity: 0;
83
+ }
84
+ .offcanvas.v-enter-active article,
85
+ .offcanvas.v-leave-active article {
86
+ transition: transform 0.3s ease-out;
87
+ }
88
+ .offcanvas.v-enter-from article,
89
+ .offcanvas.v-leave-to article {
90
+ transform: translate3d(var(--transition-3d-tx), 0, 0);
91
+ }
92
+ </style>
93
+
94
+ <style scoped>
95
+ .offcanvas {
96
+ --transition-3d-tx: v-bind(transition3dTx);
97
+ }
98
+ </style>
@@ -0,0 +1,54 @@
1
+ <script lang="ts" setup>
2
+ import { ref } from 'vue';
3
+ import {
4
+ i19login,
5
+ } from '@i18n';
6
+ import '../scripts/firebase-app';
7
+ // eslint-disable-next-line import/order
8
+ import {
9
+ getAuth,
10
+ signInWithEmailAndPassword,
11
+ // isSignInWithEmailLink,
12
+ // signInWithEmailLink,
13
+ } from 'firebase/auth';
14
+
15
+ const auth = getAuth();
16
+ const email = ref('');
17
+ const password = ref('');
18
+ const loginWithPassord = () => {
19
+ signInWithEmailAndPassword(auth, email.value, password.value)
20
+ .then((userCredential) => {
21
+ const { user } = userCredential;
22
+ console.log(user);
23
+ })
24
+ .catch((error) => {
25
+ console.warn(error.code);
26
+ console.error(error);
27
+ });
28
+ };
29
+ </script>
30
+
31
+ <template>
32
+ <form @submit.prevent="loginWithPassord">
33
+ <input
34
+ ref="input"
35
+ type="email"
36
+ placeholder="email@mail.com"
37
+ v-model="email"
38
+ required
39
+ >
40
+ <input
41
+ ref="input"
42
+ type="password"
43
+ placeholder="***"
44
+ v-model="password"
45
+ required
46
+ >
47
+ <button
48
+ type="submit"
49
+ class="btn btn-block btn-primary"
50
+ >
51
+ {{ i19login }}
52
+ </button>
53
+ </form>
54
+ </template>
@@ -0,0 +1,41 @@
1
+ <script lang="ts" setup>
2
+ import { ref, defineAsyncComponent } from 'vue';
3
+ import { i19myAccountAndOrders } from '@i18n';
4
+ import AOffcanvas from './AOffcanvas.vue';
5
+
6
+ export interface Props {
7
+ accountUrl?: string;
8
+ accountIconClass?: string;
9
+ }
10
+
11
+ withDefaults(defineProps<Props>(), {
12
+ accountUrl: '/app/account',
13
+ accountIconClass: 'i-user-circle',
14
+ });
15
+ const isVisible = ref(false);
16
+ const loadingLoginForm = !import.meta.env.SSR
17
+ ? import('./LoginForm.vue')
18
+ : Promise.resolve() as Promise<any>;
19
+ const LoginForm = defineAsyncComponent(() => loadingLoginForm);
20
+ const toggle = (ev: MouseEvent) => {
21
+ loadingLoginForm.then(() => {
22
+ isVisible.value = !isVisible.value;
23
+ ev.preventDefault();
24
+ });
25
+ };
26
+ </script>
27
+
28
+ <template>
29
+ <div @click="toggle">
30
+ <slot name="toggle" v-bind="{ isVisible }">
31
+ <a :href="accountUrl" :title="i19myAccountAndOrders">
32
+ <div :class="accountIconClass"></div>
33
+ </a>
34
+ </slot>
35
+ </div>
36
+ <AOffcanvas v-model="isVisible" class="login-offcanvas">
37
+ <slot name="form">
38
+ <LoginForm class="max-w-xs" />
39
+ </slot>
40
+ </AOffcanvas>
41
+ </template>
@@ -1,15 +1,49 @@
1
1
  <script lang="ts" setup>
2
+ import { toRefs, ImgHTMLAttributes } from 'vue';
3
+
2
4
  export interface Props {
5
+ logo?: ImgHTMLAttributes;
6
+ gridClass?: string;
7
+ actionsGridClass?: string;
3
8
  }
9
+
10
+ const props = withDefaults(defineProps<Props>(), {
11
+ gridClass: 'grid grid-flow-col auto-cols-max justify-between items-center',
12
+ actionsGridClass: 'grid items-center text-2xl',
13
+ });
14
+ const { logo } = toRefs(props);
4
15
  </script>
5
16
 
6
17
  <template>
7
18
  <header class="header bg-surface bg-opacity-70 sticky py-1 sm:py-2">
8
19
  <div class="container">
9
- <div class="grid items-center">
10
- <div class="i-bars-3-bottom-left md:hidden"></div>
11
- <slot name="logo"></slot>
20
+ <div :class="gridClass">
21
+ <slot name="aside">
22
+ <div class="header__aside md:hidden">
23
+ <div class="i-bars-3-bottom-left"></div>
24
+ </div>
25
+ </slot>
26
+ <slot name="logo" v-bind="{ logo }">
27
+ <a v-if="logo" href="/" class="header__logo">
28
+ <component :is="logo.alt ? 'h1' : 'span'" class="m-0">
29
+ <img v-bind="logo" />
30
+ </component>
31
+ </a>
32
+ </slot>
33
+ <slot name="actions-grid">
34
+ <div :class="actionsGridClass">
35
+ <slot name="nav" />
36
+ <slot name="search" />
37
+ <slot name="buttons" />
38
+ </div>
39
+ </slot>
12
40
  </div>
13
41
  </div>
14
42
  </header>
15
43
  </template>
44
+
45
+ <style>
46
+ .header a:not(:hover) {
47
+ color: var(--gray-accent);
48
+ }
49
+ </style>
@@ -10,10 +10,6 @@ export interface Props {
10
10
  hasPhoneLinks?: boolean;
11
11
  hasNetworkLinks?: boolean;
12
12
  socialNetworks?: string[];
13
- countdownClass?: string;
14
- pageLinksClass?: string;
15
- contactLinksClass?: string;
16
- socialNetworksClass?: string;
17
13
  }
18
14
 
19
15
  withDefaults(defineProps<Props>(), {
@@ -28,23 +24,19 @@ withDefaults(defineProps<Props>(), {
28
24
 
29
25
  <template>
30
26
  <div class="top-bar w-full bg-surface">
31
- <slot
32
- name="countdown"
33
- v-bind="{ marketingStripe, countdownClass }"
34
- >
27
+ <slot name="countdown" v-bind="{ marketingStripe }">
35
28
  <template v-if="marketingStripe && marketingStripe.text">
36
29
  <component
37
30
  :is="marketingStripe.link ? 'a' : 'div'"
38
31
  class="top-bar__countdown block text-sm text-center p-1
39
32
  whitespace-nowrap overflow-x-auto"
40
- :class="[countdownClass, marketingStripe.link ? 'primary' : 'secondary']"
33
+ :class="marketingStripe.link ? 'primary' : 'secondary'"
41
34
  :href="marketingStripe.link"
42
35
  >
43
36
  {{ marketingStripe.text }}
44
37
  </component>
45
38
  </template>
46
39
  </slot>
47
-
48
40
  <div
49
41
  v-if="hasNavbar"
50
42
  class="top-bar__nav hidden md:block py-2"
@@ -52,14 +44,10 @@ withDefaults(defineProps<Props>(), {
52
44
  <div class="container">
53
45
  <div class="flex items-center lg:px-2 xl:px-4">
54
46
  <div class="grow text-xs">
55
- <slot
56
- name="contacts-container"
57
- v-bind="{ pageLinks, pageLinksClass }"
58
- >
47
+ <slot name="page-links" v-bind="{ pageLinks }">
59
48
  <nav
60
49
  v-if="pageLinks"
61
50
  class="top-bar__page-links inline-block mr-4 font-semibold"
62
- :class="pageLinksClass"
63
51
  >
64
52
  <a
65
53
  v-for="({ link, title }, i) in pageLinks"
@@ -71,15 +59,13 @@ withDefaults(defineProps<Props>(), {
71
59
  </a>
72
60
  </nav>
73
61
  </slot>
74
-
75
62
  <slot
76
63
  name="contact-links"
77
- v-bind="{ contacts, hasPhoneLinks, contactLinksClass }"
64
+ v-bind="{ contacts, hasPhoneLinks }"
78
65
  >
79
66
  <div
80
67
  v-if="hasPhoneLinks"
81
68
  class="top-bar__contact-links inline-block"
82
- :class="contactLinksClass"
83
69
  >
84
70
  <a
85
71
  v-if="contacts.whatsapp"
@@ -93,7 +79,7 @@ withDefaults(defineProps<Props>(), {
93
79
  {{ contacts.whatsapp }}
94
80
  </a>
95
81
  <a
96
- v-if="contacts.phone"
82
+ v-if="contacts.phone && contacts.phone !== contacts.whatsapp"
97
83
  :href="`tel:+${contacts.phone.replace(/\D/g, '')}`"
98
84
  target="_blank"
99
85
  rel="noopener"
@@ -105,10 +91,9 @@ withDefaults(defineProps<Props>(), {
105
91
  </div>
106
92
  </slot>
107
93
  </div>
108
-
109
94
  <slot
110
95
  name="social-networks"
111
- v-bind="{ contacts, hasNetworkLinks, socialNetworksClass }"
96
+ v-bind="{ contacts, hasNetworkLinks }"
112
97
  >
113
98
  <div
114
99
  v-if="hasNetworkLinks"
@@ -122,6 +107,7 @@ withDefaults(defineProps<Props>(), {
122
107
  target="_blank"
123
108
  rel="noopener"
124
109
  class="ml-1"
110
+ :aria-label="`Follow on ${network}`"
125
111
  >
126
112
  <i v-if="network === 'facebook'" class="i-facebook"></i>
127
113
  <i v-else-if="network === 'youtube'" class="i-youtube"></i>
@@ -139,3 +125,9 @@ withDefaults(defineProps<Props>(), {
139
125
  </div>
140
126
  </div>
141
127
  </template>
128
+
129
+ <style>
130
+ .top-bar__nav a:not(:hover) {
131
+ color: var(--gray);
132
+ }
133
+ </style>
@@ -9,7 +9,6 @@ export interface Props {
9
9
 
10
10
  const { pageContext } = Astro.props as Props;
11
11
  const { primaryColor, secondaryColor } = pageContext;
12
-
13
12
  const brandColors = {
14
13
  primary: primaryColor,
15
14
  secondary: secondaryColor,
@@ -65,44 +64,48 @@ Object.keys(brandColors).forEach((colorName) => {
65
64
  </body>
66
65
 
67
66
  <style is:global define:vars={colorCSSVars}>
68
- :root {
69
- --content-max-width: 80rem;
70
- --white: #fff;
71
- --gray-50: #f9fafb;
72
- --gray-200: #e5e7eb;
73
- --gray-700: #374151;
74
- --gray-800: #1f2937;
75
- --gray-900: #111827;
76
- --surface-color: var(--gray-50);
77
- --surface-border-color: var(--gray-200);
78
- --yiq-text-light: var(--white);
79
- --yiq-text-dark: var(--gray-900);
67
+ :root {
68
+ --content-max-width: 80rem;
69
+ --white: #fff;
70
+ --gray-50: #f9fafb;
71
+ --gray-200: #e5e7eb;
72
+ --gray-400: #94a3b8;
73
+ --gray-600: #4b5563;
74
+ --gray-700: #374151;
75
+ --gray-800: #1f2937;
76
+ --gray-900: #111827;
77
+ --gray: var(--gray-600);
78
+ --gray-accent: var(--gray-800);
79
+ --surface-color: var(--gray-50);
80
+ --surface-border-color: var(--gray-200);
81
+ --yiq-text-light: var(--white);
82
+ --yiq-text-dark: var(--gray-900);
83
+ }
84
+ body {
85
+ --primary: var(--primary-500);
86
+ --primary-hover: var(--primary-700);
87
+ --primary-focus: rgba(var(--primary-200-rgb), 0.2);
88
+ --primary-inverse: var(--primary-500-yiq);
89
+ --secondary: var(--secondary-500);
90
+ --secondary-hover: var(--secondary-700);
91
+ --secondary-focus: rgba(var(--secondary-200-rgb), 0.2);
92
+ --secondary-inverse: var(--secondary-500-yiq);
93
+ }
94
+ @media only screen and (prefers-color-scheme: dark) {
95
+ :root:not([data-theme=light]) {
96
+ --gray: var(--gray-400);
97
+ --gray-accent: var(--gray-200);
98
+ --surface-color: var(--gray-800);
99
+ --surface-border-color: var(--gray-700);
80
100
  }
81
- body,
82
- body [data-theme=light],
83
- body [data-theme=dark] {
84
- --primary: var(--primary-500);
85
- --primary-hover: var(--primary-700);
86
- --primary-focus: rgba(var(--primary-200-rgb), 0.2);
87
- --primary-inverse: var(--primary-500-yiq);
88
- --secondary: var(--secondary-500);
89
- --secondary-hover: var(--secondary-700);
90
- --secondary-focus: rgba(var(--secondary-200-rgb), 0.2);
91
- --secondary-inverse: var(--secondary-500-yiq);
101
+ :root:not([data-theme=light]) a:not([role=button]) {
102
+ --color: var(--primary-100);
92
103
  }
93
- @media only screen and (prefers-color-scheme: dark) {
94
- :root:not([data-theme=light]) {
95
- --surface-color: var(--gray-800);
96
- --surface-border-color: var(--gray-700);
97
- }
98
- :root:not([data-theme=light]) a {
99
- --color: var(--primary-200);
100
- }
101
- :root:not([data-theme=light]) a:is([aria-current], :hover, :active, :focus) {
102
- --color: var(--primary-400);
103
- }
104
- }
105
- body {
106
- overflow-x: hidden;
104
+ :root:not([data-theme=light]) a:not([role=button]):is([aria-current], :hover, :active, :focus) {
105
+ --color: var(--primary-300);
107
106
  }
107
+ }
108
+ body {
109
+ overflow-x: hidden;
110
+ }
108
111
  </style>
@@ -21,7 +21,6 @@ const {
21
21
  const state = apiDoc || cmsContent || {};
22
22
  const title = state.meta_title || state.name || state.title || Astro.props.title || settings.name;
23
23
  const description = state.meta_description || state.short_description || settings.description;
24
-
25
24
  const canonicalUrl = new URL(Astro.url.pathname, Astro.site || `https://${domain}`);
26
25
  const cmsSocial = cms('social') as CmsSocial;
27
26
  const ogLocale = lang.length === 2 ? lang : lang.substring(0, 2) + lang.slice(3).toUpperCase();
@@ -53,7 +52,6 @@ if (!ogImage) {
53
52
  <link rel="apple-touch-icon" href={settings.icon} />
54
53
  <meta name="apple-mobile-web-app-capable" content="yes">
55
54
  <meta name="apple-mobile-web-app-status-bar-style" content="default">
56
-
57
55
  <meta property="og:site_name" content={settings.name}>
58
56
  <meta property="og:url" content={canonicalUrl}>
59
57
  <meta property="og:title" content={title}>
@@ -64,7 +62,4 @@ if (!ogImage) {
64
62
  {cmsSocial.fb_app_id && <meta property="fb:app_id" content={cmsSocial.fb_app_id} />}
65
63
  <meta name="twitter:card" content="summary">
66
64
  {cmsSocial.twitter_username && <meta name="twitter:site" content={cmsSocial.twitter_username} />}
67
-
68
- <link rel="preconnect" href="https://ecomplus.io/" crossorigin />
69
- <link rel="dns-prefetch" href="https://ecomplus.io/" />
70
65
  <meta name="ecom-store-id" content={String(storeId)}>
@@ -6,18 +6,19 @@ export interface Props {
6
6
  pageContext: PageContext;
7
7
  }
8
8
 
9
- const { pageContext } = Astro.props as Props;
10
9
  const {
11
- storeId,
12
- apiResource,
13
- apiDoc,
14
- lang,
15
- countryCode,
16
- currency,
17
- currencySymbol,
18
- domain,
19
- settings,
20
- } = pageContext;
10
+ pageContext: {
11
+ storeId,
12
+ apiResource,
13
+ apiDoc,
14
+ lang,
15
+ countryCode,
16
+ currency,
17
+ currencySymbol,
18
+ domain,
19
+ settings,
20
+ },
21
+ } = Astro.props as Props;
21
22
 
22
23
  let inlineClientJS = `
23
24
  window.storefront = ${JSON.stringify({
@@ -3,22 +3,16 @@ import type { Categories } from '@cloudcommerce/api/types';
3
3
  import type CmsHeader from '../../types/cms-header';
4
4
  import type CmsContacts from '../../types/cms-contacts';
5
5
  import type { PageContext } from '../ssr-context';
6
- import { getImageAttrs } from '../helpers/image';
6
+ import { getImageAttrs } from '../ssr/image';
7
7
  import TopBar, { Props as TopBarProps } from '../components/TopBar.vue';
8
- import TheHeader from '../components/TheHeader.vue';
8
+ import TheHeader, { Props as TheHeaderProps } from '../components/TheHeader.vue';
9
+ import LoginOffcanvas, { Props as LoginOffcanvasProps } from '../components/LoginOffcanvas.vue';
9
10
 
10
11
  export interface Props {
11
12
  pageContext: PageContext;
12
13
  topBarProps?: Partial<TopBarProps>;
13
- logoTransform?: {
14
- width?: number;
15
- height?: number;
16
- quality?: number;
17
- };
18
- }
19
-
20
- declare global {
21
- var TopBarProps: TopBarProps;
14
+ theHeaderProps?: Partial<TheHeaderProps>;
15
+ loginOffcanvasProps?: Partial<LoginOffcanvasProps>;
22
16
  }
23
17
 
24
18
  const {
@@ -28,12 +22,12 @@ const {
28
22
  cms,
29
23
  },
30
24
  topBarProps,
31
- logoTransform,
25
+ theHeaderProps,
26
+ loginOffcanvasProps,
32
27
  } = Astro.props as Props;
33
28
  const header = cms('header') as CmsHeader;
34
29
  const contacts = cms('contacts') as CmsContacts;
35
30
  const customThemeName = settings.theme.custom || '';
36
-
37
31
  let headerCategories: Array<{ slug: string, name: string }> = [];
38
32
  let isCategoriesNavFull: boolean | undefined;
39
33
  if (header.categories_list) {
@@ -64,6 +58,11 @@ const hasMegamenu: boolean | undefined = header.desktop_megamenu;
64
58
  const isAlphabeticalOrderSubmenu: boolean | undefined = header.alphabetical_order_submenu;
65
59
  const isFullWidthSubmenu: boolean | undefined = header.full_width_submenu;
66
60
 
61
+ declare global {
62
+ var TopBarProps: TopBarProps;
63
+ var TheHeaderProps: TheHeaderProps;
64
+ var LoginOffcanvasProps: LoginOffcanvasProps;
65
+ }
67
66
  globalThis.TopBarProps = {
68
67
  marketingStripe: header.marketing_stripe,
69
68
  pageLinks: header.contacts_stripe.pages,
@@ -72,18 +71,28 @@ globalThis.TopBarProps = {
72
71
  contacts,
73
72
  ...topBarProps,
74
73
  };
75
-
76
- const logoWebpAttrs = await getImageAttrs({
77
- src: settings.logo,
78
- width: 150,
79
- });
74
+ globalThis.TheHeaderProps = {
75
+ logo: {
76
+ ...getImageAttrs({
77
+ src: settings.logo,
78
+ width: 150,
79
+ }),
80
+ alt: settings.name,
81
+ },
82
+ ...theHeaderProps,
83
+ };
84
+ globalThis.LoginOffcanvasProps = {
85
+ ...loginOffcanvasProps,
86
+ };
80
87
  ---
81
88
 
82
89
  <slot name="top-bar">
83
90
  <TopBar {...globalThis.TopBarProps} />
84
91
  </slot>
85
92
  <slot name="header">
86
- <TheHeader>
87
- <img slot="logo" {...logoWebpAttrs} alt={`${settings.name} (logo)`} />
93
+ <TheHeader {...globalThis.TheHeaderProps}>
94
+ <Fragment slot="buttons">
95
+ <LoginOffcanvas client:idle {...globalThis.LoginOffcanvasProps} />
96
+ </Fragment>
88
97
  </TheHeader>
89
98
  </slot>
@@ -0,0 +1,16 @@
1
+ import { initializeApp } from 'firebase/app';
2
+
3
+ const firebaseConfig = window.firebaseConfig || {
4
+ apiKey: 'AIzaSyCrVzemDgpyp9i6ni7Yc5ZuEVfXYwl-4J0',
5
+ authDomain: 'ecom2-002.firebaseapp.com',
6
+ projectId: 'ecom2-002',
7
+ storageBucket: 'ecom2-002.appspot.com',
8
+ messagingSenderId: '402807248219',
9
+ appId: '1:402807248219:web:cf7d57759751e74776367e',
10
+ measurementId: 'G-SC592CE0GB',
11
+ };
12
+ const app = initializeApp(firebaseConfig);
13
+
14
+ export default app;
15
+
16
+ export const firebaseApp = app;