cloudcommerce 0.1.7 → 0.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 (177) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/action.yml +4 -0
  3. package/ecomplus-stores/monocard/functions/core/package.json +1 -1
  4. package/ecomplus-stores/monocard/functions/events/package.json +2 -2
  5. package/ecomplus-stores/monocard/functions/modules/package.json +2 -2
  6. package/ecomplus-stores/monocard/functions/passport/package.json +2 -2
  7. package/ecomplus-stores/monocard/functions/ssr/package.json +6 -6
  8. package/ecomplus-stores/monocard/package.json +1 -1
  9. package/ecomplus-stores/tia-sonia/functions/core/package.json +1 -1
  10. package/ecomplus-stores/tia-sonia/functions/events/package.json +2 -2
  11. package/ecomplus-stores/tia-sonia/functions/modules/package.json +2 -2
  12. package/ecomplus-stores/tia-sonia/functions/passport/package.json +2 -2
  13. package/ecomplus-stores/tia-sonia/functions/ssr/package.json +8 -7
  14. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-acucares.webp +0 -0
  15. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-barras.webp +0 -0
  16. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-bebidas-em-po.webp +0 -0
  17. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-cookies.webp +0 -0
  18. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-granola-tia-sonia.webp +0 -0
  19. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-integrais.webp +0 -0
  20. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-naturais.webp +0 -0
  21. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-pastas-tia-sonia.webp +0 -0
  22. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-snacks.webp +0 -0
  23. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/categoria-ultrabar.webp +0 -0
  24. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/daniel-cady.webp +0 -0
  25. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/granola-tradicional-lata-verso.webp +0 -0
  26. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/granola-tradicional-lata.webp +0 -0
  27. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/machu-picchu-1500.jpg +0 -0
  28. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/selo-ibd-120-80.webp +0 -0
  29. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/selo-organico-120-80.webp +0 -0
  30. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/selo-usda-120-80.webp +0 -0
  31. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/selo-vegano-120-80.webp +0 -0
  32. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/tia-sonia-real.png +0 -0
  33. package/ecomplus-stores/tia-sonia/functions/ssr/public/img/uploads/trustvox.png +0 -0
  34. package/ecomplus-stores/tia-sonia/functions/ssr/src/components/AboutUs.astro +77 -0
  35. package/ecomplus-stores/tia-sonia/functions/ssr/src/components/BrandTestimonials.vue +134 -0
  36. package/ecomplus-stores/tia-sonia/functions/ssr/src/components/CategoriesGrid.vue +32 -0
  37. package/ecomplus-stores/tia-sonia/functions/ssr/src/components/CategoriesSlider.vue +105 -7
  38. package/ecomplus-stores/tia-sonia/functions/ssr/src/components/HeroBanner.vue +2 -2
  39. package/ecomplus-stores/tia-sonia/functions/ssr/src/layouts/Base.astro +5 -1
  40. package/ecomplus-stores/tia-sonia/functions/ssr/src/layouts/Pages.astro +1 -1
  41. package/ecomplus-stores/tia-sonia/functions/ssr/src/main/Home.astro +116 -25
  42. package/ecomplus-stores/tia-sonia/package.json +1 -1
  43. package/package.json +12 -12
  44. package/packages/api/package.json +1 -1
  45. package/packages/apps/correios/package.json +1 -1
  46. package/packages/apps/custom-payment/package.json +1 -1
  47. package/packages/apps/custom-shipping/package.json +1 -1
  48. package/packages/apps/datafrete/CHANGELOG.md +1 -0
  49. package/packages/apps/datafrete/README.md +1 -0
  50. package/packages/apps/datafrete/lib/datafrete-webhook.d.ts +4 -0
  51. package/packages/apps/datafrete/lib/datafrete-webhook.js +108 -0
  52. package/packages/apps/datafrete/lib/datafrete-webhook.js.map +1 -0
  53. package/packages/apps/datafrete/lib/datafrete.d.ts +2 -0
  54. package/packages/apps/datafrete/lib/datafrete.js +6 -0
  55. package/packages/apps/datafrete/lib/datafrete.js.map +1 -0
  56. package/packages/apps/datafrete/lib/index.d.ts +1 -0
  57. package/packages/apps/datafrete/lib/index.js +2 -0
  58. package/packages/apps/datafrete/lib/index.js.map +1 -0
  59. package/packages/apps/datafrete/lib-mjs/calculate-datafrete.mjs +277 -0
  60. package/packages/apps/datafrete/package.json +37 -0
  61. package/packages/apps/datafrete/src/datafrete-webhook.ts +131 -0
  62. package/packages/apps/datafrete/src/datafrete.ts +7 -0
  63. package/packages/apps/datafrete/src/index.ts +1 -0
  64. package/packages/apps/datafrete/tsconfig.json +6 -0
  65. package/packages/apps/datafrete/webhook.js +1 -0
  66. package/packages/apps/discounts/package.json +1 -1
  67. package/packages/apps/emails/package.json +1 -1
  68. package/packages/apps/fb-conversions/package.json +2 -2
  69. package/packages/apps/frenet/package.json +1 -1
  70. package/packages/apps/galaxpay/lib/functions-lib/galaxpay/webhook.js +3 -2
  71. package/packages/apps/galaxpay/lib/functions-lib/galaxpay/webhook.js.map +1 -1
  72. package/packages/apps/galaxpay/package.json +1 -1
  73. package/packages/apps/galaxpay/src/functions-lib/galaxpay/webhook.ts +3 -2
  74. package/packages/apps/google-analytics/CHANGELOG.md +1 -0
  75. package/packages/apps/google-analytics/README.md +1 -0
  76. package/packages/apps/google-analytics/lib/google-analytics-events.js +113 -0
  77. package/packages/apps/google-analytics/lib/google-analytics-events.js.map +1 -0
  78. package/packages/apps/google-analytics/lib/index.js +2 -0
  79. package/packages/apps/google-analytics/lib/index.js.map +1 -0
  80. package/packages/apps/google-analytics/package.json +32 -0
  81. package/packages/apps/google-analytics/src/google-analytics-events.ts +151 -0
  82. package/packages/apps/google-analytics/src/index.ts +1 -0
  83. package/packages/apps/google-analytics/tsconfig.json +3 -0
  84. package/packages/apps/google-analytics/types.d.ts +43 -0
  85. package/packages/apps/infinitepay/package.json +1 -1
  86. package/packages/apps/jadlog/package.json +1 -1
  87. package/packages/apps/loyalty-points/package.json +1 -1
  88. package/packages/apps/mercadopago/lib/mp-create-transaction.js +1 -1
  89. package/packages/apps/mercadopago/lib/mp-create-transaction.js.map +1 -1
  90. package/packages/apps/mercadopago/lib/mp-webhook.js +2 -7
  91. package/packages/apps/mercadopago/lib/mp-webhook.js.map +1 -1
  92. package/packages/apps/mercadopago/package.json +1 -1
  93. package/packages/apps/mercadopago/src/mp-create-transaction.ts +1 -1
  94. package/packages/apps/mercadopago/src/mp-webhook.ts +3 -8
  95. package/packages/apps/pagarme/lib/pagarme-webhook.js +1 -1
  96. package/packages/apps/pagarme/lib/pagarme-webhook.js.map +1 -1
  97. package/packages/apps/pagarme/package.json +1 -1
  98. package/packages/apps/pagarme/src/pagarme-webhook.ts +1 -1
  99. package/packages/apps/pix/package.json +1 -1
  100. package/packages/apps/tiny-erp/package.json +1 -1
  101. package/packages/cli/package.json +1 -1
  102. package/packages/config/package.json +1 -1
  103. package/packages/emails/package.json +2 -2
  104. package/packages/events/lib/firebase.js +4 -0
  105. package/packages/events/lib/firebase.js.map +1 -1
  106. package/packages/events/package.json +3 -1
  107. package/packages/events/src/firebase.ts +4 -0
  108. package/packages/firebase/lib/config.d.ts +7 -0
  109. package/packages/firebase/lib/config.js +10 -0
  110. package/packages/firebase/lib/config.js.map +1 -1
  111. package/packages/firebase/package.json +1 -1
  112. package/packages/firebase/src/config.ts +11 -0
  113. package/packages/i18n/package.json +1 -1
  114. package/packages/modules/lib/firebase/call-app-module.js +5 -0
  115. package/packages/modules/lib/firebase/call-app-module.js.map +1 -1
  116. package/packages/modules/package.json +3 -2
  117. package/packages/modules/src/firebase/call-app-module.ts +5 -0
  118. package/packages/passport/package.json +1 -1
  119. package/packages/ssr/package.json +4 -3
  120. package/packages/storefront/.eslintrc.cjs +5 -1
  121. package/packages/storefront/astro.config.mjs +9 -24
  122. package/packages/storefront/client.d.ts +6 -8
  123. package/packages/storefront/dist/client/PitchBar.afe7ff5c.js +1 -0
  124. package/packages/storefront/dist/client/Prices.eaf8a32c.js +1 -0
  125. package/packages/storefront/dist/client/ProductCard.1106b153.js +1 -0
  126. package/packages/storefront/dist/client/assets/_...slug_.fea84512.css +1 -0
  127. package/packages/storefront/dist/client/assets/index.90df622b.css +1 -0
  128. package/packages/storefront/dist/client/chunks/Prices.vue_vue_type_script_setup_true_lang.781b6501.js +1 -0
  129. package/packages/storefront/dist/client/chunks/ecom-utils.63984324.js +1 -0
  130. package/packages/storefront/dist/client/chunks/runtime-core.esm-bundler.fa6cdb60.js +1 -0
  131. package/packages/storefront/dist/client/client.367a6497.js +1 -0
  132. package/packages/storefront/dist/client/hoisted.4671ed15.js +1 -0
  133. package/packages/storefront/dist/client/sw.js +1 -1
  134. package/packages/storefront/dist/client/workbox-e2ee76b5.js +1 -0
  135. package/packages/storefront/dist/server/entry.mjs +359 -537
  136. package/packages/storefront/package.json +10 -9
  137. package/packages/storefront/src/env.d.ts +9 -0
  138. package/packages/storefront/src/lib/assets/tooltip.css +6 -5
  139. package/packages/storefront/src/lib/components/Carousel.vue +259 -0
  140. package/packages/storefront/src/lib/components/CarouselControl.vue +29 -0
  141. package/packages/storefront/src/lib/components/LoginDrawer.vue +1 -1
  142. package/packages/storefront/src/lib/components/PitchBar.vue +44 -0
  143. package/packages/storefront/src/lib/components/Prices.vue +13 -17
  144. package/packages/storefront/src/lib/components/ProductCard.vue +1 -1
  145. package/packages/storefront/src/lib/components/_injection-keys.ts +9 -0
  146. package/packages/storefront/src/lib/components/globals/ALink.vue +26 -0
  147. package/packages/storefront/src/lib/layouts/BaseBody.astro +1 -5
  148. package/packages/storefront/src/lib/layouts/BaseHead.astro +7 -2
  149. package/packages/storefront/src/lib/layouts/PagesHeader.astro +38 -0
  150. package/packages/storefront/src/lib/pages/_vue.ts +3 -2
  151. package/packages/storefront/src/lib/ssr-context.ts +6 -0
  152. package/packages/storefront/src/vue-globals.d.ts +5 -5
  153. package/packages/storefront/tailwind.config.cjs +12 -6
  154. package/packages/storefront/tsconfig.json +2 -2
  155. package/packages/storefront/uno.config.cjs +4 -4
  156. package/packages/types/package.json +1 -1
  157. package/packages/storefront/dist/client/HeaderButtons.6f668467.js +0 -1
  158. package/packages/storefront/dist/client/Prices.2ada125b.js +0 -1
  159. package/packages/storefront/dist/client/ProductCard.e5bdea60.js +0 -1
  160. package/packages/storefront/dist/client/assets/_...slug_.81b9a00c.css +0 -1
  161. package/packages/storefront/dist/client/assets/index.e6a09532.css +0 -1
  162. package/packages/storefront/dist/client/chunks/HeaderButtons.cfa275db.js +0 -1
  163. package/packages/storefront/dist/client/chunks/LoginForm.1ba3ad0d.js +0 -1441
  164. package/packages/storefront/dist/client/chunks/Prices.vue_vue_type_script_setup_true_lang.9a6ab0d6.js +0 -1
  165. package/packages/storefront/dist/client/chunks/_plugin-vue_export-helper.0d33cd48.js +0 -1
  166. package/packages/storefront/dist/client/chunks/ecom-utils.b0a26608.js +0 -1
  167. package/packages/storefront/dist/client/chunks/preload-helper.1de719f8.js +0 -1
  168. package/packages/storefront/dist/client/chunks/price.ecf7fed4.js +0 -1
  169. package/packages/storefront/dist/client/chunks/runtime-core.esm-bundler.45ba83fa.js +0 -1
  170. package/packages/storefront/dist/client/client.4d2b3a73.js +0 -1
  171. package/packages/storefront/dist/client/hoisted.f6ee2883.js +0 -1
  172. package/packages/storefront/dist/client/page.5a6f3db5.js +0 -1
  173. package/packages/storefront/dist/client/workbox-abdc68aa.js +0 -1
  174. package/packages/storefront/dist/client/~partytown/partytown-atomics.js +0 -2
  175. package/packages/storefront/dist/client/~partytown/partytown-media.js +0 -2
  176. package/packages/storefront/dist/client/~partytown/partytown-sw.js +0 -2
  177. package/packages/storefront/dist/client/~partytown/partytown.js +0 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/storefront",
3
3
  "type": "module",
4
- "version": "0.1.7",
4
+ "version": "0.2.1",
5
5
  "description": "E-Com Plus Cloud Commerce storefront with Astro",
6
6
  "main": "src/index.js",
7
7
  "repository": {
@@ -38,24 +38,25 @@
38
38
  "@headlessui/vue": "^1.7.7",
39
39
  "@iconify-json/fa6-brands": "^1.1.8",
40
40
  "@iconify-json/heroicons": "^1.1.8",
41
- "@iconify-json/logos": "^1.1.21",
42
- "@vueuse/core": "^9.9.0",
43
- "astro": "^1.8.0",
41
+ "@iconify-json/logos": "^1.1.22",
42
+ "@vite-pwa/astro": "^0.0.1",
43
+ "@vueuse/core": "^9.10.0",
44
+ "astro": "^1.9.2",
44
45
  "chroma-js": "^2.4.2",
45
46
  "dotenv": "^16.0.3",
46
47
  "firebase": "^9.15.0",
47
48
  "image-size": "^1.0.2",
49
+ "lodash": "^4.17.21",
48
50
  "semver": "^7.3.8",
49
51
  "sharp": "^0.31.3",
50
52
  "tailwindcss": "^3.2.4",
51
- "unocss": "^0.48.0",
53
+ "unocss": "^0.48.4",
52
54
  "vite": "^3.2.5",
53
- "vite-plugin-pwa": "^0.14.0",
54
- "vue": "^3.2.45",
55
- "vue-bind-once": "^0.1.1"
55
+ "vite-plugin-pwa": "^0.14.1",
56
+ "vue": "^3.2.45"
56
57
  },
57
58
  "devDependencies": {
58
- "@babel/core": "^7.20.7",
59
+ "@babel/core": "^7.20.12",
59
60
  "@cloudcommerce/types": "workspace:*"
60
61
  }
61
62
  }
@@ -1,3 +1,12 @@
1
1
  /// <reference types="@astrojs/image/client" />
2
2
  /// <reference types="vite-plugin-pwa/client" />
3
+ /// <reference types="vue/ref-macros" />
3
4
  /// <reference types="../client" />
5
+
6
+ /* eslint-disable import/newline-after-import */
7
+
8
+ declare module '*.vue' {
9
+ import { type DefineComponent } from 'vue';
10
+ const component: DefineComponent<{}, {}, any>;
11
+ export default component;
12
+ }
@@ -1,8 +1,9 @@
1
1
  [data-tooltip] {
2
2
  position: relative;
3
3
  cursor: help;
4
- --c-background: var(--c-tooltip-background, rgba(44, 44, 44, 0.85));
5
- --c-foreground: var(--c-tooltip-foreground, var(--c-on-dark));
4
+ --background-color: var(--c-tooltip-background, rgba(44, 44, 44, 0.85));
5
+ --color: var(--c-tooltip-foreground, var(--c-on-dark));
6
+ --border-color: transparent transparent var(--background-color) transparent;
6
7
  }
7
8
  [data-tooltip]::before {
8
9
  content: attr(data-tooltip);
@@ -16,8 +17,8 @@
16
17
  margin-top: 5px;
17
18
  font-size: clamp(0.75rem, 90%, 1rem);
18
19
  width: max-content;
19
- background-color: var(--c-background);
20
- color: var(--c-foreground);
20
+ background-color: var(--background-color);
21
+ color: var(--color);
21
22
  text-align: center;
22
23
  @apply rounded-sm py-1 px-2 leading-snug;
23
24
  }
@@ -34,7 +35,7 @@
34
35
  margin-top: -4px;
35
36
  border-width: 5px;
36
37
  border-style: solid;
37
- border-color: transparent transparent var(--c-background) transparent;
38
+ border-color: var(--border-color);
38
39
  }
39
40
  [data-tooltip]:hover::before,
40
41
  [data-tooltip]:hover::after {
@@ -0,0 +1,259 @@
1
+ <script setup lang="ts">
2
+ /* REFERENCE: https://github.com/bartdominiak/vue-snap */
3
+ import {
4
+ onMounted,
5
+ onBeforeUnmount,
6
+ ref,
7
+ watch,
8
+ toRef,
9
+ nextTick,
10
+ provide,
11
+ } from 'vue';
12
+ import debounce from 'lodash/debounce';
13
+ import { useElementHover } from '@vueuse/core';
14
+ import { carouselKey } from './_injection-keys';
15
+ import CarouselControl from './CarouselControl.vue';
16
+
17
+ export interface Props {
18
+ as?: string;
19
+ modelValue?: number;
20
+ autoplay?: number; // milliseconds
21
+ }
22
+
23
+ const approximatelyEqual = (v1, v2, epsilon) => {
24
+ return Math.abs(v1 - v2) <= epsilon;
25
+ };
26
+ const SCROLL_DEBOUNCE = 100;
27
+ const RESIZE_DEBOUNCE = 410;
28
+
29
+ const props = withDefaults(defineProps<Props>(), {
30
+ as: 'ul',
31
+ modelValue: 1,
32
+ });
33
+ const emit = defineEmits([
34
+ 'update:modelValue',
35
+ 'bound-left',
36
+ 'bound-right',
37
+ ]);
38
+
39
+ const currentPage = ref(props.modelValue - 1);
40
+ watch(toRef(props, 'modelValue'), (modelValue) => {
41
+ currentPage.value = modelValue - 1;
42
+ });
43
+ watch(currentPage, (current, previous) => {
44
+ if (current !== previous) {
45
+ emit('update:modelValue', current + 1);
46
+ }
47
+ });
48
+ const wrapper = ref<HTMLElement>(null);
49
+ const isBoundLeft = ref(true);
50
+ const isBoundRight = ref(false);
51
+ const slidesWidth = ref([]);
52
+ const wrapperScrollWidth = ref(0);
53
+ const wrapperVisibleWidth = ref(0);
54
+ const currentPos = ref(0);
55
+ const maxPages = ref(0);
56
+ const onResizeFn = ref(null);
57
+ const onScrollFn = ref(null);
58
+ const calcBounds = () => {
59
+ // Find the closest point, with 5px approximate.
60
+ const _isBoundLeft = approximatelyEqual(currentPos.value, 0, 5);
61
+ const _isBoundRight = approximatelyEqual(
62
+ wrapperScrollWidth.value - wrapperVisibleWidth.value,
63
+ currentPos.value,
64
+ 5,
65
+ );
66
+ if (_isBoundLeft) {
67
+ emit('bound-left', true);
68
+ }
69
+ isBoundLeft.value = _isBoundLeft;
70
+ if (_isBoundRight) {
71
+ emit('bound-right', true);
72
+ }
73
+ isBoundRight.value = _isBoundRight;
74
+ };
75
+ const calcWrapperWidth = () => {
76
+ wrapperScrollWidth.value = wrapper.value.scrollWidth;
77
+ wrapperVisibleWidth.value = wrapper.value.offsetWidth;
78
+ };
79
+ const calcSlidesWidth = () => {
80
+ const childNodes = [...wrapper.value.children];
81
+ slidesWidth.value = childNodes.map((node: HTMLElement) => ({
82
+ offsetLeft: node.offsetLeft,
83
+ width: node.offsetWidth,
84
+ }));
85
+ };
86
+ const calcNextWidth = (direction) => {
87
+ const nextSlideIndex = direction > 0 ? currentPage.value : currentPage.value + direction;
88
+ const width = slidesWidth.value[nextSlideIndex].width || 0;
89
+ if (!width) {
90
+ return 0;
91
+ }
92
+ return width * direction;
93
+ };
94
+ const calcCurrentPage = () => {
95
+ const getCurrentPage = slidesWidth.value.findIndex((slide) => {
96
+ // Find the closest point, with 5px approximate.
97
+ return approximatelyEqual(slide.offsetLeft, currentPos.value, 5);
98
+ });
99
+ if (getCurrentPage !== -1 && getCurrentPage !== -2) {
100
+ currentPage.value = getCurrentPage || 0;
101
+ }
102
+ };
103
+ const calcCurrentPosition = () => {
104
+ currentPos.value = wrapper.value.scrollLeft || 0;
105
+ };
106
+ const calcMaxPages = () => {
107
+ const maxPos = wrapperScrollWidth.value - wrapperVisibleWidth.value;
108
+ maxPages.value = slidesWidth.value
109
+ .findIndex(({ offsetLeft }) => (offsetLeft >= maxPos));
110
+ };
111
+ const calcOnInit = () => {
112
+ if (!wrapper.value) {
113
+ return;
114
+ }
115
+ calcWrapperWidth();
116
+ calcSlidesWidth();
117
+ calcCurrentPosition();
118
+ calcCurrentPage();
119
+ calcBounds();
120
+ calcMaxPages();
121
+ };
122
+ const calcOnScroll = () => {
123
+ if (!wrapper.value) {
124
+ return;
125
+ }
126
+ calcCurrentPosition();
127
+ calcCurrentPage();
128
+ calcBounds();
129
+ };
130
+ let autoplayTimer = null;
131
+ const restartAutoplay = () => {
132
+ if (props.autoplay) {
133
+ clearTimeout(autoplayTimer);
134
+ autoplayTimer = setTimeout(() => {
135
+ // eslint-disable-next-line no-use-before-define
136
+ changeSlide(1);
137
+ }, props.autoplay);
138
+ }
139
+ };
140
+ const changeSlide = (direction: number) => {
141
+ if (direction < 0) {
142
+ if (isBoundLeft.value) {
143
+ calcMaxPages();
144
+ currentPage.value = maxPages.value - 1;
145
+ changeSlide(1);
146
+ return;
147
+ }
148
+ } else if (isBoundRight.value) {
149
+ currentPage.value = 1;
150
+ changeSlide(-1);
151
+ return;
152
+ }
153
+ const nextSlideWidth = calcNextWidth(direction);
154
+ if (nextSlideWidth) {
155
+ wrapper.value.scrollBy({ left: nextSlideWidth, behavior: 'smooth' });
156
+ restartAutoplay();
157
+ }
158
+ };
159
+ const carousel = ref(null);
160
+ const isHovered = useElementHover(carousel);
161
+ watch(isHovered, (_isHovered) => {
162
+ if (_isHovered) {
163
+ clearTimeout(autoplayTimer);
164
+ } else {
165
+ restartAutoplay();
166
+ }
167
+ });
168
+ onMounted(() => {
169
+ calcOnInit();
170
+ if (!import.meta.env.SSR) {
171
+ // Assign to new variable and keep reference for removeEventListener (Avoid Memory Leaks)
172
+ onScrollFn.value = debounce(calcOnScroll, SCROLL_DEBOUNCE);
173
+ onResizeFn.value = debounce(calcOnInit, RESIZE_DEBOUNCE);
174
+ wrapper.value.addEventListener('scroll', onScrollFn.value);
175
+ window.addEventListener('resize', onResizeFn.value);
176
+ nextTick(() => {
177
+ [...wrapper.value.children].forEach((slide: HTMLElement) => {
178
+ slide.setAttribute('tabindex', '0');
179
+ });
180
+ });
181
+ restartAutoplay();
182
+ }
183
+ });
184
+ onBeforeUnmount(() => {
185
+ if (!import.meta.env.SSR) {
186
+ wrapper.value.removeEventListener('scroll', onScrollFn.value);
187
+ window.removeEventListener('resize', onResizeFn.value);
188
+ clearTimeout(autoplayTimer);
189
+ }
190
+ });
191
+ provide(carouselKey, {
192
+ autoplay: toRef(props, 'autoplay'),
193
+ changeSlide,
194
+ isBoundLeft,
195
+ isBoundRight,
196
+ });
197
+ </script>
198
+
199
+ <template>
200
+ <div ref="carousel" data-carousel>
201
+ <component :is="as" ref="wrapper" data-carousel-wrapper>
202
+ <slot />
203
+ </component>
204
+ <!-- @slot Slot for Arrows -->
205
+ <slot
206
+ name="controls"
207
+ v-bind="{ changeSlide, isBoundLeft, isBoundRight }"
208
+ >
209
+ <CarouselControl :direction="-1">
210
+ <slot name="previous" />
211
+ </CarouselControl>
212
+ <CarouselControl>
213
+ <slot name="next" />
214
+ </CarouselControl>
215
+ </slot>
216
+ </div>
217
+ </template>
218
+
219
+ <style>
220
+ [data-carousel] {
221
+ position: relative;
222
+ }
223
+ [data-carousel-wrapper] {
224
+ display: flex;
225
+ overflow-x: scroll;
226
+ overflow-y: hidden;
227
+ scroll-snap-type: x mandatory;
228
+ scroll-behavior: smooth;
229
+ scrollbar-width: none;
230
+ -webkit-overflow-scrolling: touch;
231
+ -ms-overflow-style: none;
232
+ list-style: none;
233
+ margin: 0;
234
+ padding: 0;
235
+ }
236
+ [data-carousel-wrapper]::-webkit-scrollbar {
237
+ display: none;
238
+ }
239
+ [data-carousel-wrapper] > * {
240
+ flex: 0 0 100%;
241
+ height: 100%;
242
+ scroll-snap-align: start;
243
+ display: flex;
244
+ justify-content: center;
245
+ align-items: center;
246
+ outline: none;
247
+ }
248
+ [data-carousel-control] {
249
+ position: absolute;
250
+ top: 0;
251
+ bottom: 0;
252
+ }
253
+ [data-carousel-control=previous] {
254
+ left: 0;
255
+ }
256
+ [data-carousel-control=next] {
257
+ right: 0;
258
+ }
259
+ </style>
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import { inject } from 'vue';
3
+ import { carouselKey } from './_injection-keys';
4
+
5
+ export interface Props {
6
+ direction?: number;
7
+ }
8
+
9
+ withDefaults(defineProps<Props>(), {
10
+ direction: 1,
11
+ });
12
+ const { changeSlide } = inject(carouselKey);
13
+ </script>
14
+
15
+ <template>
16
+ <button
17
+ type="button"
18
+ :aria-label="direction > 0 ? $t.i19next : $t.i19previous"
19
+ @click="changeSlide(direction)"
20
+ :data-carousel-control="direction > 0 ? 'next' : 'previous'"
21
+ >
22
+ <slot>
23
+ <i
24
+ class="mb-0 z-10"
25
+ :class="direction > 0 ? 'i-chevron-right' : 'i-chevron-left'"
26
+ ></i>
27
+ </slot>
28
+ </button>
29
+ </template>
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import { ref, defineAsyncComponent } from 'vue';
3
3
  import { i19myAccount, i19myOrders } from '@@i18n';
4
- import ADrawer from '@@components/ADrawer.vue';
4
+ import ADrawer from '@@sf/components/ADrawer.vue';
5
5
 
6
6
  export interface Props {
7
7
  accountUrl?: string;
@@ -0,0 +1,44 @@
1
+ <script setup lang="ts">
2
+ import Carousel from '@@sf/components/Carousel.vue';
3
+ import CarouselControl from '@@sf/components/CarouselControl.vue';
4
+
5
+ export interface Props {
6
+ slides: Array<{
7
+ href?: string;
8
+ target?: string;
9
+ html: string;
10
+ }>;
11
+ }
12
+
13
+ defineProps<Props>();
14
+ </script>
15
+
16
+ <template>
17
+ <div data-pitch-bar class="bg-base-100">
18
+ <div class="container md:w-2/3 mx-auto px-3 py-1">
19
+ <Carousel :autoplay="7000">
20
+ <li v-for="({ href, target, html }, i) in slides" :key="i">
21
+ <component
22
+ :is="href ? 'ALink' : 'span'"
23
+ :href="href"
24
+ :target="target"
25
+ :class="href ? 'hover:underline' : null"
26
+ >
27
+ <slot name="slide">
28
+ <span v-html="html" class="prose text-sm text-base-800"></span>
29
+ </slot>
30
+ </component>
31
+ </li>
32
+ <template #controls>
33
+ <div class="text-xl leading-none text-base-400">
34
+ <CarouselControl
35
+ :direction="-1"
36
+ class="pr-2 bg-base-100 hover:text-base-700"
37
+ />
38
+ <CarouselControl class="pl-2 bg-base-100 hover:text-base-700" />
39
+ </div>
40
+ </template>
41
+ </Carousel>
42
+ </div>
43
+ </div>
44
+ </template>
@@ -37,9 +37,9 @@ const componentVariant = useComponentVariant(props);
37
37
  </script>
38
38
 
39
39
  <template>
40
- <div :data-sf-prices="componentVariant" class="text-base-600">
40
+ <div :data-prices="componentVariant" class="text-base-600">
41
41
  <slot v-if="comparePrice" name="compare" v-bind="{ salePrice, comparePrice }">
42
- <span :data-sf-prices-compare="comparePrice" class="text-base-500 mr-1">
42
+ <span data-prices-compare class="text-base-500 mr-1">
43
43
  <slot name="compare-pre">
44
44
  <small v-if="isLiteral">
45
45
  {{ `${$t.i19from} ` }}
@@ -56,7 +56,7 @@ const componentVariant = useComponentVariant(props);
56
56
  </span>
57
57
  </slot>
58
58
  <slot name="sale" v-bind="{ salePrice }">
59
- <strong :data-sf-prices-sale="salePrice" class="inline-block text-base-800">
59
+ <strong data-prices-sale class="inline-block text-base-800">
60
60
  <slot name="sale-pre">
61
61
  <small v-if="hasVariedPrices">
62
62
  {{ `${$t.i19asOf} ` }}
@@ -74,11 +74,7 @@ const componentVariant = useComponentVariant(props);
74
74
  v-bind="{ salePrice, cashbackValue, cashbackPercentage }"
75
75
  >
76
76
  <Fade slide="down">
77
- <div
78
- v-if="hasCashback"
79
- :data-sf-prices-cashback="cashbackValue"
80
- class="relative z-10"
81
- >
77
+ <div v-if="hasCashback" data-prices-cashback class="relative z-10">
82
78
  <span :data-tooltip="$t.i19get$1back
83
79
  .replace('$1', $percentage(cashbackPercentage))">
84
80
  <slot name="cashback-pre">
@@ -105,7 +101,7 @@ const componentVariant = useComponentVariant(props);
105
101
  v-bind="{ salePrice, installmentValue, installmentsNumber, monthlyInterest }"
106
102
  >
107
103
  <Fade slide="down">
108
- <div v-if="hasPriceOptions" :data-sf-prices-installment="installmentValue">
104
+ <div v-if="hasPriceOptions" data-prices-installment>
109
105
  <slot name="installment-pre">
110
106
  <small v-if="isLiteral">
111
107
  {{ `${$t.i19upTo} ` }}
@@ -135,7 +131,7 @@ const componentVariant = useComponentVariant(props);
135
131
  v-bind="{ salePrice, priceWithDiscount, discountLabel }"
136
132
  >
137
133
  <Fade slide="down">
138
- <div v-if="hasPriceOptions" :data-sf-prices-discount="priceWithDiscount">
134
+ <div v-if="hasPriceOptions" data-prices-discount>
139
135
  <slot name="discount-pre">
140
136
  <small v-if="!discountLabel">
141
137
  {{ `${$t.i19asOf} ` }}
@@ -159,22 +155,22 @@ const componentVariant = useComponentVariant(props);
159
155
  </template>
160
156
 
161
157
  <style>
162
- [data-sf-prices-compare] {
158
+ [data-prices-compare] {
163
159
  font-size: 87%;
164
160
  }
165
- [data-sf-prices-cashback],
166
- [data-sf-prices-installment],
167
- [data-sf-prices-discount] {
161
+ [data-prices-cashback],
162
+ [data-prices-installment],
163
+ [data-prices-discount] {
168
164
  font-size: 90%;
169
165
  }
170
- [data-sf-prices] small {
166
+ [data-prices] small {
171
167
  @apply lowercase;
172
168
  font-size: 92%;
173
169
  }
174
- [data-sf-prices~=Big] {
170
+ [data-prices~=Big] {
175
171
  @apply text-lg;
176
172
  }
177
- [data-sf-prices~=Big] [data-sf-prices-sale] {
173
+ [data-prices~=Big] [data-prices-sale] {
178
174
  @apply text-5xl block;
179
175
  }
180
176
  </style>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue';
3
- import Prices from '@@components/Prices.vue';
3
+ import Prices from '@@sf/components/Prices.vue';
4
4
 
5
5
  export interface Props {
6
6
  as?: string;
@@ -0,0 +1,9 @@
1
+ /* eslint-disable import/prefer-default-export */
2
+ import type { Ref, InjectionKey } from 'vue';
3
+
4
+ export const carouselKey = Symbol('carousel') as InjectionKey<{
5
+ autoplay: Ref<number>,
6
+ changeSlide: (direction: number) => void,
7
+ isBoundLeft: Ref<boolean>,
8
+ isBoundRight: Ref<boolean>,
9
+ }>;
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue';
3
+
4
+ export interface Props {
5
+ href: string;
6
+ target?: string;
7
+ }
8
+
9
+ const props = defineProps<Props>();
10
+ const linkTarget = computed(() => {
11
+ if (props.target) return props.target;
12
+ if (props.href.startsWith('http') && globalThis.storefront.settings) {
13
+ const domain = globalThis.storefront.settings.domain || window.location.host;
14
+ if (props.href.startsWith(`https://${domain}`)) return null;
15
+ }
16
+ return null;
17
+ });
18
+ </script>
19
+
20
+ <template>
21
+ <a
22
+ :href="href"
23
+ :target="linkTarget"
24
+ :rel="linkTarget === '_blank' ? 'noopener' : null"
25
+ ><slot /></a>
26
+ </template>
@@ -13,10 +13,6 @@ export interface Props {
13
13
 
14
14
  <body>
15
15
  <slot />
16
- <script>
17
- import { registerSW } from 'virtual:pwa-register';
18
- import '../scripts/session-utm';
19
- registerSW();
20
- </script>
16
+ <script src="../scripts/session-utm"></script>
21
17
  <slot name="before-body-end" />
22
18
  </body>
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  import type CmsSocial from '@@sf/types/cms-social';
3
- import { img as getImg } from '@ecomplus/utils';
4
3
  import type { PageContext } from '@@sf/ssr-context';
4
+ import { pwaInfo } from 'virtual:pwa-info';
5
+ import { img as getImg } from '@ecomplus/utils';
5
6
  import { getImage as transformImage } from '@@sf/ssr/image';
6
7
 
7
8
  export interface Props {
@@ -53,7 +54,6 @@ if (!ogImage) {
53
54
  <meta name="viewport" content="width=device-width">
54
55
  <meta name="theme-color" content={primaryColor}>
55
56
  <link rel="icon" href={favicon} />
56
- {import.meta.env.PROD && <link rel="manifest" href="/manifest.webmanifest" />}
57
57
  <title>{title}</title>
58
58
  <meta name="description" content={description}>
59
59
  <meta name="author" content={settings.name}>
@@ -73,3 +73,8 @@ if (!ogImage) {
73
73
  <meta name="twitter:card" content="summary">
74
74
  {cmsSocial.twitter_username && <meta name="twitter:site" content={cmsSocial.twitter_username} />}
75
75
  <meta name="ecom-store-id" content={String(storeId)}>
76
+ {pwaInfo && <Fragment set:html={pwaInfo.webManifest.linkTag} />}
77
+ <script>
78
+ import { registerSW } from 'virtual:pwa-register';
79
+ registerSW({ immediate: true });
80
+ </script>
@@ -0,0 +1,38 @@
1
+ ---
2
+ import type { Categories } from '@cloudcommerce/api/types';
3
+ import type CmsHeader from '@@sf/types/cms-header';
4
+ import type CmsContacts from '@@sf/types/cms-contacts';
5
+ import type { PageContext } from '@@sf/ssr-context';
6
+ import { i19buyOnWhatsApp } from '@@i18n';
7
+ import { getImage } from '@@sf/ssr/image';
8
+ import PitchBar, { Props as PitchBarProps } from '@@sf/components/PitchBar.vue';
9
+
10
+ export interface Props {
11
+ pageContext: PageContext;
12
+ }
13
+
14
+ const {
15
+ pageContext: {
16
+ apiState,
17
+ settings,
18
+ cms,
19
+ },
20
+ } = Astro.props as Props;
21
+ const header = cms('header') as CmsHeader &
22
+ { marketing_stripe?: { text: string, link: string } };
23
+ const pitchBar: PitchBarProps = { slides: [] };
24
+ if (header.pitch_bar) {
25
+ pitchBar.slides = header.pitch_bar;
26
+ } else if (header.marketing_stripe) {
27
+ pitchBar.slides = [{
28
+ href: header.marketing_stripe.link,
29
+ html: header.marketing_stripe.text,
30
+ }];
31
+ }
32
+ ---
33
+
34
+ <Fragment>
35
+ <slot name="pitch-bar">
36
+ {pitchBar.slides.length && <PitchBar {...pitchBar} client:idle />}
37
+ </slot>
38
+ </Fragment>
@@ -1,7 +1,7 @@
1
1
  import type { App } from 'vue';
2
2
  import { i18n, formatMoney } from '@ecomplus/utils';
3
- // @ts-ignore
4
- import Fade from '@@components/globals/Fade.vue';
3
+ import Fade from '@@sf/components/globals/Fade.vue';
4
+ import ALink from '@@sf/components/globals/ALink.vue';
5
5
 
6
6
  const formatPercentage = (value: number, digits = 1) => {
7
7
  return Number.isInteger(value) ? `${value}%` : `${value.toFixed(digits)}%`;
@@ -21,6 +21,7 @@ export default (app: App) => {
21
21
  },
22
22
  });
23
23
  app.component('Fade', Fade);
24
+ app.component('ALink', ALink);
24
25
  };
25
26
 
26
27
  export type FormatPercentage = typeof formatPercentage;
@@ -26,10 +26,15 @@ const getConfig: () => StorefrontConfig = _getConfig;
26
26
  declare global {
27
27
  // eslint-disable-next-line
28
28
  var api_prefetch_endpoints: ApiEndpoint[];
29
+ // eslint-disable-next-line
30
+ var storefront: { settings: Partial<CmsSettings> };
29
31
  }
30
32
  if (!globalThis.api_prefetch_endpoints) {
31
33
  globalThis.api_prefetch_endpoints = ['categories'];
32
34
  }
35
+ if (!globalThis.storefront) {
36
+ globalThis.storefront = { settings: {} };
37
+ }
33
38
 
34
39
  type ApiPrefetchEndpoints = Array<ApiEndpoint>;
35
40
 
@@ -53,6 +58,7 @@ const loadPageContext = async (Astro: AstroGlobal, {
53
58
  const urlPath = Astro.url.pathname;
54
59
  const { slug } = Astro.params;
55
60
  const config = getConfig();
61
+ globalThis.storefront.settings = config.settings;
56
62
  let cmsContent: Record<string, any> | undefined;
57
63
  let apiResource: string | undefined;
58
64
  let apiDoc: Record<string, any> | undefined;