cloudcommerce 0.2.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/ecomplus-stores/monocard/functions/ssr/package.json +0 -2
  3. package/ecomplus-stores/tia-sonia/functions/ssr/package.json +0 -2
  4. package/package.json +6 -6
  5. package/packages/api/package.json +1 -1
  6. package/packages/apps/correios/package.json +2 -2
  7. package/packages/apps/custom-payment/package.json +1 -1
  8. package/packages/apps/custom-shipping/package.json +1 -1
  9. package/packages/apps/datafrete/package.json +2 -2
  10. package/packages/apps/discounts/package.json +1 -1
  11. package/packages/apps/emails/package.json +1 -1
  12. package/packages/apps/fb-conversions/package.json +1 -1
  13. package/packages/apps/frenet/package.json +2 -2
  14. package/packages/apps/galaxpay/package.json +2 -2
  15. package/packages/apps/google-analytics/package.json +2 -2
  16. package/packages/apps/infinitepay/package.json +2 -2
  17. package/packages/apps/jadlog/package.json +2 -2
  18. package/packages/apps/loyalty-points/package.json +1 -1
  19. package/packages/apps/melhor-envio/CHANGELOG.md +1 -0
  20. package/packages/apps/melhor-envio/README.md +1 -0
  21. package/packages/apps/melhor-envio/events.js +1 -0
  22. package/packages/apps/melhor-envio/lib/functions-lib/database.d.ts +18 -0
  23. package/packages/apps/melhor-envio/lib/functions-lib/database.js +115 -0
  24. package/packages/apps/melhor-envio/lib/functions-lib/database.js.map +1 -0
  25. package/packages/apps/melhor-envio/lib/functions-lib/events-to-melhor-envio.d.ts +7 -0
  26. package/packages/apps/melhor-envio/lib/functions-lib/events-to-melhor-envio.js +112 -0
  27. package/packages/apps/melhor-envio/lib/functions-lib/events-to-melhor-envio.js.map +1 -0
  28. package/packages/apps/melhor-envio/lib/functions-lib/new-label.d.ts +42 -0
  29. package/packages/apps/melhor-envio/lib/functions-lib/new-label.js +185 -0
  30. package/packages/apps/melhor-envio/lib/functions-lib/new-label.js.map +1 -0
  31. package/packages/apps/melhor-envio/lib/functions-lib/order-is-valid.d.ts +5 -0
  32. package/packages/apps/melhor-envio/lib/functions-lib/order-is-valid.js +40 -0
  33. package/packages/apps/melhor-envio/lib/functions-lib/order-is-valid.js.map +1 -0
  34. package/packages/apps/melhor-envio/lib/functions-lib/tracking-codes.d.ts +2 -0
  35. package/packages/apps/melhor-envio/lib/functions-lib/tracking-codes.js +164 -0
  36. package/packages/apps/melhor-envio/lib/functions-lib/tracking-codes.js.map +1 -0
  37. package/packages/apps/melhor-envio/lib/index.d.ts +1 -0
  38. package/packages/apps/melhor-envio/lib/index.js +2 -0
  39. package/packages/apps/melhor-envio/lib/index.js.map +1 -0
  40. package/packages/apps/melhor-envio/lib/melhor-envio-events.d.ts +6 -0
  41. package/packages/apps/melhor-envio/lib/melhor-envio-events.js +17 -0
  42. package/packages/apps/melhor-envio/lib/melhor-envio-events.js.map +1 -0
  43. package/packages/apps/melhor-envio/lib/melhor-envio.d.ts +2 -0
  44. package/packages/apps/melhor-envio/lib/melhor-envio.js +6 -0
  45. package/packages/apps/melhor-envio/lib/melhor-envio.js.map +1 -0
  46. package/packages/apps/melhor-envio/lib-mjs/calculate-melhor-envio.mjs +341 -0
  47. package/packages/apps/melhor-envio/lib-mjs/functions/client-melhor-envio.mjs +14 -0
  48. package/packages/apps/melhor-envio/lib-mjs/functions/error-handling.mjs +62 -0
  49. package/packages/apps/melhor-envio/lib-mjs/functions/new-shipment.mjs +119 -0
  50. package/packages/apps/melhor-envio/package.json +36 -0
  51. package/packages/apps/melhor-envio/src/functions-lib/database.ts +140 -0
  52. package/packages/apps/melhor-envio/src/functions-lib/events-to-melhor-envio.ts +137 -0
  53. package/packages/apps/melhor-envio/src/functions-lib/new-label.ts +214 -0
  54. package/packages/apps/melhor-envio/src/functions-lib/order-is-valid.ts +51 -0
  55. package/packages/apps/melhor-envio/src/functions-lib/tracking-codes.ts +191 -0
  56. package/packages/apps/melhor-envio/src/index.ts +1 -0
  57. package/packages/apps/melhor-envio/src/melhor-envio-events.ts +24 -0
  58. package/packages/apps/melhor-envio/src/melhor-envio.ts +7 -0
  59. package/packages/apps/melhor-envio/tsconfig.json +6 -0
  60. package/packages/apps/mercadopago/package.json +2 -2
  61. package/packages/apps/pagarme/package.json +2 -2
  62. package/packages/apps/paghiper/package.json +3 -3
  63. package/packages/apps/pix/package.json +2 -2
  64. package/packages/apps/tiny-erp/package.json +2 -2
  65. package/packages/cli/package.json +1 -1
  66. package/packages/config/package.json +1 -1
  67. package/packages/emails/package.json +3 -3
  68. package/packages/events/lib/firebase.js +2 -0
  69. package/packages/events/lib/firebase.js.map +1 -1
  70. package/packages/events/package.json +2 -1
  71. package/packages/events/src/firebase.ts +2 -0
  72. package/packages/firebase/lib/config.d.ts +4 -0
  73. package/packages/firebase/lib/config.js +7 -0
  74. package/packages/firebase/lib/config.js.map +1 -1
  75. package/packages/firebase/package.json +2 -2
  76. package/packages/firebase/src/config.ts +8 -0
  77. package/packages/i18n/lib/en_us/i19buyTogether.txt +1 -0
  78. package/packages/i18n/lib/en_us/i19buyTogetherWith.txt +1 -0
  79. package/packages/i18n/lib/en_us/i19report.txt +1 -0
  80. package/packages/i18n/lib/en_us/i19toggleMenu.txt +1 -0
  81. package/packages/i18n/lib/en_us/i19uponRequest.txt +1 -0
  82. package/packages/i18n/lib/en_us/i19usedPoints.txt +1 -0
  83. package/packages/i18n/lib/en_us.d.ts +6 -0
  84. package/packages/i18n/lib/en_us.js +6 -0
  85. package/packages/i18n/lib/en_us.js.map +1 -1
  86. package/packages/i18n/lib/pt_br/i19buyTogether.txt +1 -0
  87. package/packages/i18n/lib/pt_br/i19buyTogetherWith.txt +1 -0
  88. package/packages/i18n/lib/pt_br/i19report.txt +1 -0
  89. package/packages/i18n/lib/pt_br/i19toggleMenu.txt +1 -0
  90. package/packages/i18n/lib/pt_br/i19uponRequest.txt +1 -0
  91. package/packages/i18n/lib/pt_br/i19usedPoints.txt +1 -0
  92. package/packages/i18n/lib/pt_br.d.ts +6 -0
  93. package/packages/i18n/lib/pt_br.js +6 -0
  94. package/packages/i18n/lib/pt_br.js.map +1 -1
  95. package/packages/i18n/package.json +1 -1
  96. package/packages/i18n/src/en_us.ts +6 -0
  97. package/packages/i18n/src/pt_br.ts +6 -0
  98. package/packages/modules/lib/firebase/call-app-module.js +5 -0
  99. package/packages/modules/lib/firebase/call-app-module.js.map +1 -1
  100. package/packages/modules/package.json +3 -2
  101. package/packages/modules/src/firebase/call-app-module.ts +5 -0
  102. package/packages/passport/package.json +1 -1
  103. package/packages/ssr/package.json +3 -4
  104. package/packages/storefront/.eslintrc.cjs +1 -1
  105. package/packages/storefront/astro.config.mjs +8 -1
  106. package/packages/storefront/dist/client/_astro/PitchBar.103168e6.js +1 -0
  107. package/packages/storefront/dist/client/_astro/Prices.b75d44d6.js +1 -0
  108. package/packages/storefront/dist/client/_astro/Prices.vue_vue_type_script_setup_true_lang.054033ef.js +1 -0
  109. package/packages/storefront/dist/client/_astro/{ProductCard.6d8b6d86.js → ProductCard.9138ec25.js} +1 -1
  110. package/packages/storefront/dist/client/_astro/ShopHeader.65213f83.js +1 -0
  111. package/packages/storefront/dist/client/_astro/_...slug_.39c46f54.css +1 -0
  112. package/packages/storefront/dist/client/_astro/client.eba0daa7.js +1 -0
  113. package/packages/storefront/dist/client/_astro/index.0c833781.css +1 -0
  114. package/packages/storefront/dist/client/_astro/index.7577af70.js +1 -0
  115. package/packages/storefront/dist/client/_astro/{modules-info.dde776b4.js → modules-info.0c999f60.js} +1 -1
  116. package/packages/storefront/dist/client/_astro/runtime-core.esm-bundler.4da3640b.js +1 -0
  117. package/packages/storefront/dist/client/_astro/runtime-dom.esm-bundler.0869e112.js +1 -0
  118. package/packages/storefront/dist/client/_astro/server.60de185d.css +1 -0
  119. package/packages/storefront/dist/client/fallback/index.html +12 -7
  120. package/packages/storefront/dist/client/sw.js +1 -1
  121. package/packages/storefront/dist/server/chunks/pages/{all.c27193d6.mjs → all.6379e666.mjs} +494 -373
  122. package/packages/storefront/dist/server/chunks/{prerender.89f63027.mjs → prerender.a1ec39e0.mjs} +0 -0
  123. package/packages/storefront/dist/server/entry.mjs +39 -4452
  124. package/packages/storefront/package.json +4 -5
  125. package/packages/storefront/src/lib/assets/base.css +16 -11
  126. package/packages/storefront/src/lib/components/Carousel.vue +52 -82
  127. package/packages/storefront/src/lib/components/Drawer.vue +97 -0
  128. package/packages/storefront/src/lib/components/ProductCard.vue +1 -1
  129. package/packages/storefront/src/lib/components/ShopHeader.vue +110 -0
  130. package/packages/storefront/src/lib/components/ShopSidenav.vue +26 -0
  131. package/packages/storefront/src/lib/components/globals/Fade.vue +10 -14
  132. package/packages/storefront/src/lib/composables/use-pitch-bar.ts +27 -0
  133. package/packages/storefront/src/lib/composables/use-prices.ts +4 -2
  134. package/packages/storefront/src/lib/composables/use-sticky-header.ts +111 -0
  135. package/packages/storefront/src/lib/layouts/BaseBody.astro +2 -0
  136. package/packages/storefront/src/lib/layouts/PagesHeader.astro +23 -17
  137. package/packages/storefront/tailwind.config.cjs +4 -0
  138. package/packages/storefront/uno.config.cjs +1 -1
  139. package/packages/types/package.json +1 -1
  140. package/packages/storefront/dist/client/_astro/PitchBar.f3579a5b.js +0 -1
  141. package/packages/storefront/dist/client/_astro/Prices.8e5cead5.js +0 -1
  142. package/packages/storefront/dist/client/_astro/Prices.vue_vue_type_script_setup_true_lang.b8cbeb54.js +0 -1
  143. package/packages/storefront/dist/client/_astro/StickyHeader.7b0f3963.js +0 -1
  144. package/packages/storefront/dist/client/_astro/_...slug_.97285eba.css +0 -1
  145. package/packages/storefront/dist/client/_astro/client.3e777d4c.js +0 -1
  146. package/packages/storefront/dist/client/_astro/index.90df622b.css +0 -1
  147. package/packages/storefront/dist/client/_astro/runtime-core.esm-bundler.7cf33881.js +0 -1
  148. package/packages/storefront/dist/client/_astro/runtime-dom.esm-bundler.1a4c7407.js +0 -1
  149. package/packages/storefront/dist/client/_astro/server.4d9646d8.css +0 -1
  150. package/packages/storefront/src/lib/components/PitchBar.vue +0 -61
  151. package/packages/storefront/src/lib/components/Prices.vue +0 -176
  152. package/packages/storefront/src/lib/components/StickyHeader.vue +0 -56
  153. package/packages/storefront/src/lib/composables/use-component-variant.ts +0 -13
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/storefront",
3
3
  "type": "module",
4
- "version": "0.2.3",
4
+ "version": "0.4.0",
5
5
  "description": "E-Com Plus Cloud Commerce storefront with Astro",
6
6
  "main": "src/index.js",
7
7
  "repository": {
@@ -35,22 +35,21 @@
35
35
  "@cloudcommerce/i18n": "workspace:*",
36
36
  "@ecomplus/utils": "1.5.0-rc.3",
37
37
  "@fastify/deepmerge": "^1.3.0",
38
- "@headlessui/vue": "^1.7.7",
38
+ "@headlessui/vue": "^1.7.8",
39
39
  "@iconify-json/fa6-brands": "^1.1.8",
40
40
  "@iconify-json/heroicons": "^1.1.8",
41
41
  "@iconify-json/logos": "^1.1.22",
42
42
  "@vite-pwa/astro": "^0.0.1",
43
- "@vueuse/core": "^9.11.1",
43
+ "@vueuse/core": "^9.12.0",
44
44
  "astro": "^2.0.2",
45
45
  "chroma-js": "^2.4.2",
46
46
  "dotenv": "^16.0.3",
47
47
  "firebase": "^9.16.0",
48
48
  "image-size": "^1.0.2",
49
- "lodash": "^4.17.21",
50
49
  "semver": "^7.3.8",
51
50
  "sharp": "^0.31.3",
52
51
  "tailwindcss": "^3.2.4",
53
- "unocss": "^0.48.4",
52
+ "unocss": "^0.49.1",
54
53
  "vite": "^4.0.4",
55
54
  "vite-plugin-pwa": "^0.14.1",
56
55
  "vue": "^3.2.45"
@@ -1,5 +1,4 @@
1
1
  :root {
2
- --content-max-width: 80rem;
3
2
  --font-size: 14.5px;
4
3
  --font-sans: var(--custom-font-sans, ui-sans-serif),
5
4
  system-ui, -apple-system, BlinkMacSystemFont,
@@ -8,6 +7,7 @@
8
7
  --font-mono: var(--custom-font-mono, ui-monospace),
9
8
  SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
10
9
  --font-family: var(--font-sans);
10
+ --transition-fast: 75ms linear;
11
11
  --transition: .15s ease-in-out;
12
12
  --transition-slow: .25s ease-in-out;
13
13
  --transition-slower: .45s ease-in-out;
@@ -28,6 +28,7 @@
28
28
 
29
29
  @media (prefers-reduced-motion: reduce) {
30
30
  :root {
31
+ --transition-fast: 0s;
31
32
  --transition: 0s;
32
33
  --transition-slow: 0s;
33
34
  --transition-slower: .15s linear;
@@ -63,16 +64,6 @@ html {
63
64
  }
64
65
  }
65
66
 
66
- body > header,
67
- body > main,
68
- body > footer {
69
- margin-left: auto;
70
- margin-right: auto;
71
- }
72
- body > main {
73
- max-width: var(--content-max-width);
74
- }
75
-
76
67
  :focus-visible {
77
68
  outline-color: var(--c-outline, rgba(var(--rgb-secondary), .1));
78
69
  }
@@ -95,3 +86,17 @@ body {
95
86
  background: var(--c-background);
96
87
  color: var(--c-on-background);
97
88
  }
89
+
90
+ /*
91
+ Custom elements for responsive tricks in /content JSON.
92
+ Avoids the need of escape \" for class names with common elements.
93
+ */
94
+
95
+ d-md {
96
+ display: none;
97
+ }
98
+ @screen md {
99
+ d-md {
100
+ display: inline;
101
+ }
102
+ }
@@ -4,13 +4,13 @@ import {
4
4
  onMounted,
5
5
  onBeforeUnmount,
6
6
  ref,
7
+ computed,
7
8
  watch,
8
9
  toRef,
9
10
  nextTick,
10
11
  provide,
11
12
  } from 'vue';
12
- import debounce from 'lodash/debounce';
13
- import { useElementHover } from '@vueuse/core';
13
+ import { useDebounceFn, useElementHover, useScroll } from '@vueuse/core';
14
14
  import { carouselKey } from './_injection-keys';
15
15
  import CarouselControl from './CarouselControl.vue';
16
16
 
@@ -20,58 +20,30 @@ export interface Props {
20
20
  autoplay?: number; // milliseconds
21
21
  }
22
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
23
  const props = withDefaults(defineProps<Props>(), {
30
24
  as: 'ul',
31
25
  modelValue: 1,
32
26
  });
33
27
  const emit = defineEmits([
34
28
  'update:modelValue',
35
- 'bound-left',
36
- 'bound-right',
37
29
  ]);
38
-
39
- const currentPage = ref(props.modelValue - 1);
30
+ const currentIndex = ref(props.modelValue - 1);
40
31
  watch(toRef(props, 'modelValue'), (modelValue) => {
41
- currentPage.value = modelValue - 1;
32
+ currentIndex.value = modelValue - 1;
42
33
  });
43
- watch(currentPage, (current, previous) => {
34
+ watch(currentIndex, (current, previous) => {
44
35
  if (current !== previous) {
45
36
  emit('update:modelValue', current + 1);
46
37
  }
47
38
  });
48
39
  const wrapper = ref<HTMLElement>(null);
49
- const isBoundLeft = ref(true);
50
- const isBoundRight = ref(false);
40
+ const { x: currentPos, isScrolling, arrivedState } = useScroll(wrapper);
41
+ const isBoundLeft = computed(() => arrivedState.left);
42
+ const isBoundRight = computed(() => arrivedState.right);
51
43
  const slidesWidth = ref([]);
52
44
  const wrapperScrollWidth = ref(0);
53
45
  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
- };
46
+ const indexCount = ref(0);
75
47
  const calcWrapperWidth = () => {
76
48
  wrapperScrollWidth.value = wrapper.value.scrollWidth;
77
49
  wrapperVisibleWidth.value = wrapper.value.offsetWidth;
@@ -84,48 +56,27 @@ const calcSlidesWidth = () => {
84
56
  }));
85
57
  };
86
58
  const calcNextWidth = (direction) => {
87
- const nextSlideIndex = direction > 0 ? currentPage.value : currentPage.value + direction;
88
- const width = slidesWidth.value[nextSlideIndex].width || 0;
59
+ const nextSlideIndex = direction > 0
60
+ ? currentIndex.value : currentIndex.value + direction;
61
+ const width = slidesWidth.value[nextSlideIndex]?.width || 0;
89
62
  if (!width) {
90
63
  return 0;
91
64
  }
92
65
  return width * direction;
93
66
  };
94
- const calcCurrentPage = () => {
95
- const getCurrentPage = slidesWidth.value.findIndex((slide) => {
67
+ const calcCurrentIndex = () => {
68
+ const getCurrentIndex = slidesWidth.value.findIndex((slide: HTMLElement) => {
96
69
  // Find the closest point, with 5px approximate.
97
- return approximatelyEqual(slide.offsetLeft, currentPos.value, 5);
70
+ return Math.abs(slide.offsetLeft - currentPos.value) <= 5;
98
71
  });
99
- if (getCurrentPage !== -1 && getCurrentPage !== -2) {
100
- currentPage.value = getCurrentPage || 0;
72
+ if (getCurrentIndex > -1) {
73
+ currentIndex.value = getCurrentIndex || 0;
101
74
  }
102
75
  };
103
- const calcCurrentPosition = () => {
104
- currentPos.value = wrapper.value.scrollLeft || 0;
105
- };
106
- const calcMaxPages = () => {
76
+ const calcIndexCount = () => {
107
77
  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();
78
+ indexCount.value = slidesWidth.value
79
+ .findIndex(({ offsetLeft }) => (offsetLeft >= maxPos - 5));
129
80
  };
130
81
  let autoplayTimer = null;
131
82
  const restartAutoplay = () => {
@@ -140,13 +91,13 @@ const restartAutoplay = () => {
140
91
  const changeSlide = (direction: number) => {
141
92
  if (direction < 0) {
142
93
  if (isBoundLeft.value) {
143
- calcMaxPages();
144
- currentPage.value = maxPages.value - 1;
94
+ calcIndexCount();
95
+ currentIndex.value = indexCount.value - 1;
145
96
  changeSlide(1);
146
97
  return;
147
98
  }
148
99
  } else if (isBoundRight.value) {
149
- currentPage.value = 1;
100
+ currentIndex.value = 1;
150
101
  changeSlide(-1);
151
102
  return;
152
103
  }
@@ -156,37 +107,50 @@ const changeSlide = (direction: number) => {
156
107
  restartAutoplay();
157
108
  }
158
109
  };
110
+ watch(isScrolling, (_isScrolling: boolean) => {
111
+ if (_isScrolling) {
112
+ clearTimeout(autoplayTimer);
113
+ } else {
114
+ calcCurrentIndex();
115
+ restartAutoplay();
116
+ }
117
+ });
159
118
  const carousel = ref(null);
160
119
  const isHovered = useElementHover(carousel);
161
- watch(isHovered, (_isHovered) => {
120
+ watch(isHovered, (_isHovered: boolean) => {
162
121
  if (_isHovered) {
163
122
  clearTimeout(autoplayTimer);
164
123
  } else {
165
124
  restartAutoplay();
166
125
  }
167
126
  });
127
+ const calcOnInit = () => {
128
+ if (!wrapper.value) {
129
+ return;
130
+ }
131
+ calcWrapperWidth();
132
+ calcSlidesWidth();
133
+ calcCurrentIndex();
134
+ calcIndexCount();
135
+ };
136
+ const onResize = useDebounceFn(calcOnInit, 400);
168
137
  onMounted(() => {
169
138
  calcOnInit();
170
139
  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
140
  nextTick(() => {
177
141
  [...wrapper.value.children].forEach((slide: HTMLElement) => {
178
142
  slide.setAttribute('tabindex', '0');
179
143
  });
180
144
  });
181
145
  restartAutoplay();
146
+ window.addEventListener('resize', onResize);
182
147
  }
183
148
  });
184
149
  onBeforeUnmount(() => {
185
150
  if (!import.meta.env.SSR) {
186
- wrapper.value.removeEventListener('scroll', onScrollFn.value);
187
- window.removeEventListener('resize', onResizeFn.value);
188
- clearTimeout(autoplayTimer);
151
+ window.removeEventListener('resize', onResize);
189
152
  }
153
+ clearTimeout(autoplayTimer);
190
154
  });
191
155
  provide(carouselKey, {
192
156
  autoplay: toRef(props, 'autoplay'),
@@ -204,7 +168,13 @@ provide(carouselKey, {
204
168
  <!-- @slot Slot for Arrows -->
205
169
  <slot
206
170
  name="controls"
207
- v-bind="{ changeSlide, isBoundLeft, isBoundRight }"
171
+ v-bind="{
172
+ changeSlide,
173
+ isBoundLeft,
174
+ isBoundRight,
175
+ currentPage: currentIndex + 1,
176
+ pageCount: indexCount + 1,
177
+ }"
208
178
  >
209
179
  <CarouselControl :direction="-1">
210
180
  <slot name="previous" />
@@ -0,0 +1,97 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ toRef,
4
+ ref,
5
+ computed,
6
+ watch,
7
+ } from 'vue';
8
+
9
+ export interface Props {
10
+ modelValue?: boolean;
11
+ placement?: 'start' | 'end' | 'top' | 'bottom';
12
+ position?: 'fixed' | 'absolute';
13
+ hasCloseButton?: boolean;
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ modelValue: false,
18
+ placement: 'start',
19
+ position: 'fixed',
20
+ hasCloseButton: true,
21
+ });
22
+ const emit = defineEmits([
23
+ 'update:modelValue',
24
+ ]);
25
+ const close = () => emit('update:modelValue', false);
26
+ const drawer = ref(null);
27
+ const outsideClickListener = (ev: MouseEvent) => {
28
+ if (!drawer.value?.contains(ev.target)) {
29
+ close();
30
+ }
31
+ };
32
+ const escClickListener = (ev: KeyboardEvent) => {
33
+ if (ev.key === 'Escape') {
34
+ close();
35
+ }
36
+ };
37
+ watch(toRef(props, 'modelValue'), async (isOpen) => {
38
+ if (isOpen) {
39
+ document.body.style.overflow = 'hidden';
40
+ setTimeout(() => {
41
+ document.addEventListener('click', outsideClickListener, { passive: true });
42
+ document.addEventListener('keydown', escClickListener, { passive: true });
43
+ }, 500);
44
+ } else {
45
+ document.body.style.overflow = null;
46
+ document.removeEventListener('click', outsideClickListener);
47
+ document.removeEventListener('keydown', escClickListener);
48
+ }
49
+ });
50
+ const slideTo = computed(() => {
51
+ switch (props.placement) {
52
+ case 'start': return 'left';
53
+ case 'end': return 'right';
54
+ case 'top': return 'up';
55
+ default: return 'down';
56
+ }
57
+ });
58
+ const isFixed = computed(() => {
59
+ return props.position === 'fixed';
60
+ });
61
+ const isPlacementX = computed(() => {
62
+ return props.placement === 'start' || props.placement === 'end';
63
+ });
64
+ </script>
65
+
66
+ <template>
67
+ <Fade :slide="slideTo" speed="slow" is-floating>
68
+ <dialog
69
+ v-if="modelValue"
70
+ ref="drawer"
71
+ class="w-screen max-w-sm shadow p-0 m-0 z-50"
72
+ :class="[
73
+ position,
74
+ isFixed ? `top-0 left-0 ${(isPlacementX ? 'h-screen' : '')}` : null,
75
+ ]"
76
+ :open="modelValue"
77
+ :data-drawer="placement"
78
+ >
79
+ <div class="relative">
80
+ <button
81
+ v-if="hasCloseButton"
82
+ type="button"
83
+ :aria-label="$t.i19close"
84
+ @click.prevent="close"
85
+ class="absolute top-2"
86
+ :class="placement === 'end' ? 'left-2' : 'right-2'"
87
+ data-drawer-close
88
+ >
89
+ <slot name="close">
90
+ <i class="i-close text-base-400 text-3xl"></i>
91
+ </slot>
92
+ </button>
93
+ <slot />
94
+ </div>
95
+ </dialog>
96
+ </Fade>
97
+ </template>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue';
3
- import Prices from '@@sf/components/Prices.vue';
3
+ import Prices from '~/components/Prices.vue';
4
4
 
5
5
  export interface Props {
6
6
  as?: string;
@@ -0,0 +1,110 @@
1
+ <script setup lang="ts">
2
+ import type { CategoriesList } from '@cloudcommerce/api/types';
3
+ import { ref, computed } from 'vue';
4
+ import { i19myAccount, i19openCart, i19searchProducts } from '@@i18n';
5
+ import useStickyHeader from '@@sf/composables/use-sticky-header';
6
+ import Drawer from '@@sf/components/Drawer.vue';
7
+ import ShopSidenav from '@@sf/components/ShopSidenav.vue';
8
+
9
+ export interface Props {
10
+ categories: CategoriesList;
11
+ }
12
+
13
+ defineProps<Props>();
14
+ const buttons = ref({
15
+ search: {
16
+ icon: 'i-search',
17
+ onClick: () => {},
18
+ label: i19searchProducts,
19
+ },
20
+ account: {
21
+ icon: 'i-account',
22
+ onClick: () => {},
23
+ label: i19myAccount,
24
+ },
25
+ cart: {
26
+ icon: 'i-shopping-cart',
27
+ onClick: () => {},
28
+ label: i19openCart,
29
+ },
30
+ });
31
+ const isSidenavOpen = ref(false);
32
+ const header = ref<HTMLElement | null>(null);
33
+ const {
34
+ isSticky,
35
+ staticHeight,
36
+ staticY,
37
+ } = useStickyHeader({ header });
38
+ const sidenavHeight = computed(() => {
39
+ return isSticky.value ? staticHeight.value : staticY.value;
40
+ });
41
+ </script>
42
+
43
+ <template>
44
+ <header
45
+ ref="header"
46
+ class="top-0 z-50"
47
+ :class="isSticky
48
+ ? 'bg-white/80 backdrop-blur-md shadow py-2 md:py-3'
49
+ : 'bg-white py-3 sm:py-4 md:py-5'"
50
+ >
51
+ <div class="container lg:max-w-7xl mx-auto px-1 lg:pl-3
52
+ grid grid-flow-col grid-cols-3 justify-between items-center
53
+ md:grid-cols-none md:auto-cols-max">
54
+ <slot name="sidenav-toggle">
55
+ <div class="md:hidden" data-sidenav-toggle>
56
+ <button
57
+ class="px-2 my-1"
58
+ :aria-label="$t.i19toggleMenu"
59
+ @click="isSidenavOpen = !isSidenavOpen"
60
+ >
61
+ <slot name="sidenav-toggle-content">
62
+ <i
63
+ class="text-base-500 text-3xl"
64
+ :class="isSidenavOpen ? 'i-close' : 'i-menu'"
65
+ ></i>
66
+ </slot>
67
+ </button>
68
+ </div>
69
+ </slot>
70
+ <slot name="logo" />
71
+ <slot name="nav" />
72
+ <slot name="buttons">
73
+ <div
74
+ class="px-2 flex justify-end items-center gap-3 lg:gap-4 text-base-800"
75
+ data-header-buttons
76
+ >
77
+ <slot
78
+ name="button"
79
+ v-for="({ icon, onClick, label }, name) in buttons"
80
+ :key="name"
81
+ v-bind="{ name, icon, onClick }"
82
+ >
83
+ <button
84
+ :class="name === 'account' ? 'hidden sm:block' : null"
85
+ :aria-label="label"
86
+ @click="onClick"
87
+ :data-header-button="name"
88
+ >
89
+ <slot name="button-content" v-bind="{ name, icon }">
90
+ <i
91
+ :class="icon"
92
+ class="hover:text-primary w-7 h-7 hover:scale-110 active:scale-125"
93
+ ></i>
94
+ </slot>
95
+ </button>
96
+ </slot>
97
+ </div>
98
+ </slot>
99
+ </div>
100
+ <Drawer
101
+ v-model="isSidenavOpen"
102
+ :has-close-button="false"
103
+ position="absolute"
104
+ class="mt-3"
105
+ :style="{ height: `calc(100vh - ${sidenavHeight}px)` }"
106
+ >
107
+ <ShopSidenav class="pt-6" :categories="categories" />
108
+ </Drawer>
109
+ </header>
110
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import { CategoriesList } from '@cloudcommerce/api/types';
3
+
4
+ export interface Props {
5
+ categories: CategoriesList;
6
+ }
7
+
8
+ const props = defineProps<Props>();
9
+ const mainCategories = props.categories.filter(({ slug, parent }) => {
10
+ return slug && !parent;
11
+ });
12
+ </script>
13
+
14
+ <template>
15
+ <aside data-sidenav>
16
+ <nav class="py-5" data-sidenav-nav>
17
+ <ul>
18
+ <li v-for="mainCategory in mainCategories" :key="mainCategory._id">
19
+ <a :href="`/${mainCategory.slug}`">
20
+ {{ mainCategory.name }}
21
+ </a>
22
+ </li>
23
+ </ul>
24
+ </nav>
25
+ </aside>
26
+ </template>
@@ -4,12 +4,14 @@ import { computed } from 'vue';
4
4
  export interface Props {
5
5
  speed?: 'default' | 'slow' | 'slower',
6
6
  slide?: 'down' | 'left' | 'right' | 'up',
7
+ isFloating?: boolean,
7
8
  isLeaveTo?: boolean,
8
9
  isEnterFrom?: boolean,
9
10
  }
10
11
 
11
12
  const props = withDefaults(defineProps<Props>(), {
12
13
  speed: 'default',
14
+ isFloating: false,
13
15
  isLeaveTo: true,
14
16
  isEnterFrom: true,
15
17
  });
@@ -50,32 +52,28 @@ const isSlideY = computed(() => {
50
52
  return props.slide === 'down' || props.slide === 'up';
51
53
  });
52
54
  const height = computed(() => {
55
+ if (props.isFloating) return null;
53
56
  return isSlideY.value ? 0 : 'auto';
54
57
  });
55
58
  const width = computed(() => {
59
+ if (props.isFloating) return null;
56
60
  return props.slide && !isSlideY.value ? 0 : 'auto';
57
61
  });
58
62
  const enterFromHeight = computed(() => {
59
63
  return props.isEnterFrom ? height.value : 'auto';
60
64
  });
61
- const leaveToHeight = computed(() => {
62
- return props.isLeaveTo ? height.value : 'auto';
63
- });
64
65
  const enterFromWidth = computed(() => {
65
66
  return props.isEnterFrom ? width.value : 'auto';
66
67
  });
67
- const leaveToWidth = computed(() => {
68
- return props.isLeaveTo ? width.value : 'auto';
69
- });
70
68
  const willChange = computed(() => {
71
69
  let properties = 'opacity';
72
70
  if (transform.value !== 'none') properties += ', transform';
73
- if (height.value !== 'auto') properties += ', height';
74
- if (width.value !== 'auto') properties += ', width';
71
+ if (height.value === 0) properties += ', height';
72
+ if (width.value === 0) properties += ', width';
75
73
  return properties;
76
74
  });
77
75
  const onEnter = (el: HTMLElement) => {
78
- if (props.slide) {
76
+ if (props.slide && !props.isFloating && props.isEnterFrom) {
79
77
  if (isSlideY.value) {
80
78
  el.style.width = getComputedStyle(el).width;
81
79
  el.style.height = 'auto';
@@ -104,12 +102,12 @@ const onEnter = (el: HTMLElement) => {
104
102
  }
105
103
  };
106
104
  const onAfterEnter = (el: HTMLElement) => {
107
- if (props.slide) {
108
- el.style[isSlideY.value ? 'height' : 'width'] = 'auto';
105
+ if (props.slide && !props.isFloating && props.isEnterFrom) {
106
+ el.style[isSlideY.value ? 'height' : 'width'] = null;
109
107
  }
110
108
  };
111
109
  const onLeave = (el: HTMLElement) => {
112
- if (props.slide) {
110
+ if (props.slide && !props.isFloating && props.isLeaveTo) {
113
111
  if (isSlideY.value) {
114
112
  el.style.height = getComputedStyle(el).height;
115
113
  } else {
@@ -165,7 +163,5 @@ const onLeave = (el: HTMLElement) => {
165
163
  .sf-fade-leave-to {
166
164
  opacity: v-bind(leaveToOpacity);
167
165
  transform: v-bind(leaveToTransform);
168
- height: v-bind(leaveToHeight);
169
- width: v-bind(leaveToWidth);
170
166
  }
171
167
  </style>
@@ -0,0 +1,27 @@
1
+ import { computed } from 'vue';
2
+ import { parseShippingPhrase } from '@@sf/state/modules-info';
3
+
4
+ export interface Props {
5
+ slides: Array<{
6
+ href?: string;
7
+ target?: string;
8
+ html: string;
9
+ }>;
10
+ }
11
+
12
+ const usePitchBar = (props: Props) => {
13
+ const parsedContents = computed(() => {
14
+ return props.slides.map(({ html }) => {
15
+ return parseShippingPhrase(html).value;
16
+ });
17
+ });
18
+ const countValidSlides = computed(() => {
19
+ return parsedContents.value.filter((html) => html).length;
20
+ });
21
+ return {
22
+ parsedContents,
23
+ countValidSlides,
24
+ };
25
+ };
26
+
27
+ export default usePitchBar;
@@ -7,7 +7,7 @@ export interface Props {
7
7
  product?: Partial<Products> & { price: number, final_price?: number };
8
8
  price?: number;
9
9
  basePrice?: number;
10
- isAmountTotal?: boolean,
10
+ isAmountTotal?: boolean;
11
11
  installmentsOption?: ListPaymentsResponse['installments_option'];
12
12
  discountOption?: ListPaymentsResponse['discount_option'];
13
13
  loyaltyPointsProgram?: ListPaymentsResponse['loyalty_points_programs']['k'];
@@ -27,7 +27,7 @@ const getPriceWithDiscount = (price: number, discount: Props['discountOption'])
27
27
  return price;
28
28
  };
29
29
 
30
- export default (props: Props) => {
30
+ const usePrices = (props: Props) => {
31
31
  const _product = computed(() => {
32
32
  return props.product || {
33
33
  price: props.price || 0,
@@ -177,3 +177,5 @@ export default (props: Props) => {
177
177
  cashbackValue,
178
178
  };
179
179
  };
180
+
181
+ export default usePrices;