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.
- package/CHANGELOG.md +54 -0
- package/ecomplus-stores/monocard/functions/ssr/package.json +0 -2
- package/ecomplus-stores/tia-sonia/functions/ssr/package.json +0 -2
- package/package.json +6 -6
- package/packages/api/package.json +1 -1
- package/packages/apps/correios/package.json +2 -2
- package/packages/apps/custom-payment/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/datafrete/package.json +2 -2
- package/packages/apps/discounts/package.json +1 -1
- package/packages/apps/emails/package.json +1 -1
- package/packages/apps/fb-conversions/package.json +1 -1
- package/packages/apps/frenet/package.json +2 -2
- package/packages/apps/galaxpay/package.json +2 -2
- package/packages/apps/google-analytics/package.json +2 -2
- package/packages/apps/infinitepay/package.json +2 -2
- package/packages/apps/jadlog/package.json +2 -2
- package/packages/apps/loyalty-points/package.json +1 -1
- package/packages/apps/melhor-envio/CHANGELOG.md +1 -0
- package/packages/apps/melhor-envio/README.md +1 -0
- package/packages/apps/melhor-envio/events.js +1 -0
- package/packages/apps/melhor-envio/lib/functions-lib/database.d.ts +18 -0
- package/packages/apps/melhor-envio/lib/functions-lib/database.js +115 -0
- package/packages/apps/melhor-envio/lib/functions-lib/database.js.map +1 -0
- package/packages/apps/melhor-envio/lib/functions-lib/events-to-melhor-envio.d.ts +7 -0
- package/packages/apps/melhor-envio/lib/functions-lib/events-to-melhor-envio.js +112 -0
- package/packages/apps/melhor-envio/lib/functions-lib/events-to-melhor-envio.js.map +1 -0
- package/packages/apps/melhor-envio/lib/functions-lib/new-label.d.ts +42 -0
- package/packages/apps/melhor-envio/lib/functions-lib/new-label.js +185 -0
- package/packages/apps/melhor-envio/lib/functions-lib/new-label.js.map +1 -0
- package/packages/apps/melhor-envio/lib/functions-lib/order-is-valid.d.ts +5 -0
- package/packages/apps/melhor-envio/lib/functions-lib/order-is-valid.js +40 -0
- package/packages/apps/melhor-envio/lib/functions-lib/order-is-valid.js.map +1 -0
- package/packages/apps/melhor-envio/lib/functions-lib/tracking-codes.d.ts +2 -0
- package/packages/apps/melhor-envio/lib/functions-lib/tracking-codes.js +164 -0
- package/packages/apps/melhor-envio/lib/functions-lib/tracking-codes.js.map +1 -0
- package/packages/apps/melhor-envio/lib/index.d.ts +1 -0
- package/packages/apps/melhor-envio/lib/index.js +2 -0
- package/packages/apps/melhor-envio/lib/index.js.map +1 -0
- package/packages/apps/melhor-envio/lib/melhor-envio-events.d.ts +6 -0
- package/packages/apps/melhor-envio/lib/melhor-envio-events.js +17 -0
- package/packages/apps/melhor-envio/lib/melhor-envio-events.js.map +1 -0
- package/packages/apps/melhor-envio/lib/melhor-envio.d.ts +2 -0
- package/packages/apps/melhor-envio/lib/melhor-envio.js +6 -0
- package/packages/apps/melhor-envio/lib/melhor-envio.js.map +1 -0
- package/packages/apps/melhor-envio/lib-mjs/calculate-melhor-envio.mjs +341 -0
- package/packages/apps/melhor-envio/lib-mjs/functions/client-melhor-envio.mjs +14 -0
- package/packages/apps/melhor-envio/lib-mjs/functions/error-handling.mjs +62 -0
- package/packages/apps/melhor-envio/lib-mjs/functions/new-shipment.mjs +119 -0
- package/packages/apps/melhor-envio/package.json +36 -0
- package/packages/apps/melhor-envio/src/functions-lib/database.ts +140 -0
- package/packages/apps/melhor-envio/src/functions-lib/events-to-melhor-envio.ts +137 -0
- package/packages/apps/melhor-envio/src/functions-lib/new-label.ts +214 -0
- package/packages/apps/melhor-envio/src/functions-lib/order-is-valid.ts +51 -0
- package/packages/apps/melhor-envio/src/functions-lib/tracking-codes.ts +191 -0
- package/packages/apps/melhor-envio/src/index.ts +1 -0
- package/packages/apps/melhor-envio/src/melhor-envio-events.ts +24 -0
- package/packages/apps/melhor-envio/src/melhor-envio.ts +7 -0
- package/packages/apps/melhor-envio/tsconfig.json +6 -0
- package/packages/apps/mercadopago/package.json +2 -2
- package/packages/apps/pagarme/package.json +2 -2
- package/packages/apps/paghiper/package.json +3 -3
- package/packages/apps/pix/package.json +2 -2
- package/packages/apps/tiny-erp/package.json +2 -2
- package/packages/cli/package.json +1 -1
- package/packages/config/package.json +1 -1
- package/packages/emails/package.json +3 -3
- package/packages/events/lib/firebase.js +2 -0
- package/packages/events/lib/firebase.js.map +1 -1
- package/packages/events/package.json +2 -1
- package/packages/events/src/firebase.ts +2 -0
- package/packages/firebase/lib/config.d.ts +4 -0
- package/packages/firebase/lib/config.js +7 -0
- package/packages/firebase/lib/config.js.map +1 -1
- package/packages/firebase/package.json +2 -2
- package/packages/firebase/src/config.ts +8 -0
- package/packages/i18n/lib/en_us/i19buyTogether.txt +1 -0
- package/packages/i18n/lib/en_us/i19buyTogetherWith.txt +1 -0
- package/packages/i18n/lib/en_us/i19report.txt +1 -0
- package/packages/i18n/lib/en_us/i19toggleMenu.txt +1 -0
- package/packages/i18n/lib/en_us/i19uponRequest.txt +1 -0
- package/packages/i18n/lib/en_us/i19usedPoints.txt +1 -0
- package/packages/i18n/lib/en_us.d.ts +6 -0
- package/packages/i18n/lib/en_us.js +6 -0
- package/packages/i18n/lib/en_us.js.map +1 -1
- package/packages/i18n/lib/pt_br/i19buyTogether.txt +1 -0
- package/packages/i18n/lib/pt_br/i19buyTogetherWith.txt +1 -0
- package/packages/i18n/lib/pt_br/i19report.txt +1 -0
- package/packages/i18n/lib/pt_br/i19toggleMenu.txt +1 -0
- package/packages/i18n/lib/pt_br/i19uponRequest.txt +1 -0
- package/packages/i18n/lib/pt_br/i19usedPoints.txt +1 -0
- package/packages/i18n/lib/pt_br.d.ts +6 -0
- package/packages/i18n/lib/pt_br.js +6 -0
- package/packages/i18n/lib/pt_br.js.map +1 -1
- package/packages/i18n/package.json +1 -1
- package/packages/i18n/src/en_us.ts +6 -0
- package/packages/i18n/src/pt_br.ts +6 -0
- package/packages/modules/lib/firebase/call-app-module.js +5 -0
- package/packages/modules/lib/firebase/call-app-module.js.map +1 -1
- package/packages/modules/package.json +3 -2
- package/packages/modules/src/firebase/call-app-module.ts +5 -0
- package/packages/passport/package.json +1 -1
- package/packages/ssr/package.json +3 -4
- package/packages/storefront/.eslintrc.cjs +1 -1
- package/packages/storefront/astro.config.mjs +8 -1
- package/packages/storefront/dist/client/_astro/PitchBar.103168e6.js +1 -0
- package/packages/storefront/dist/client/_astro/Prices.b75d44d6.js +1 -0
- package/packages/storefront/dist/client/_astro/Prices.vue_vue_type_script_setup_true_lang.054033ef.js +1 -0
- package/packages/storefront/dist/client/_astro/{ProductCard.6d8b6d86.js → ProductCard.9138ec25.js} +1 -1
- package/packages/storefront/dist/client/_astro/ShopHeader.65213f83.js +1 -0
- package/packages/storefront/dist/client/_astro/_...slug_.39c46f54.css +1 -0
- package/packages/storefront/dist/client/_astro/client.eba0daa7.js +1 -0
- package/packages/storefront/dist/client/_astro/index.0c833781.css +1 -0
- package/packages/storefront/dist/client/_astro/index.7577af70.js +1 -0
- package/packages/storefront/dist/client/_astro/{modules-info.dde776b4.js → modules-info.0c999f60.js} +1 -1
- package/packages/storefront/dist/client/_astro/runtime-core.esm-bundler.4da3640b.js +1 -0
- package/packages/storefront/dist/client/_astro/runtime-dom.esm-bundler.0869e112.js +1 -0
- package/packages/storefront/dist/client/_astro/server.60de185d.css +1 -0
- package/packages/storefront/dist/client/fallback/index.html +12 -7
- package/packages/storefront/dist/client/sw.js +1 -1
- package/packages/storefront/dist/server/chunks/pages/{all.c27193d6.mjs → all.6379e666.mjs} +494 -373
- package/packages/storefront/dist/server/chunks/{prerender.89f63027.mjs → prerender.a1ec39e0.mjs} +0 -0
- package/packages/storefront/dist/server/entry.mjs +39 -4452
- package/packages/storefront/package.json +4 -5
- package/packages/storefront/src/lib/assets/base.css +16 -11
- package/packages/storefront/src/lib/components/Carousel.vue +52 -82
- package/packages/storefront/src/lib/components/Drawer.vue +97 -0
- package/packages/storefront/src/lib/components/ProductCard.vue +1 -1
- package/packages/storefront/src/lib/components/ShopHeader.vue +110 -0
- package/packages/storefront/src/lib/components/ShopSidenav.vue +26 -0
- package/packages/storefront/src/lib/components/globals/Fade.vue +10 -14
- package/packages/storefront/src/lib/composables/use-pitch-bar.ts +27 -0
- package/packages/storefront/src/lib/composables/use-prices.ts +4 -2
- package/packages/storefront/src/lib/composables/use-sticky-header.ts +111 -0
- package/packages/storefront/src/lib/layouts/BaseBody.astro +2 -0
- package/packages/storefront/src/lib/layouts/PagesHeader.astro +23 -17
- package/packages/storefront/tailwind.config.cjs +4 -0
- package/packages/storefront/uno.config.cjs +1 -1
- package/packages/types/package.json +1 -1
- package/packages/storefront/dist/client/_astro/PitchBar.f3579a5b.js +0 -1
- package/packages/storefront/dist/client/_astro/Prices.8e5cead5.js +0 -1
- package/packages/storefront/dist/client/_astro/Prices.vue_vue_type_script_setup_true_lang.b8cbeb54.js +0 -1
- package/packages/storefront/dist/client/_astro/StickyHeader.7b0f3963.js +0 -1
- package/packages/storefront/dist/client/_astro/_...slug_.97285eba.css +0 -1
- package/packages/storefront/dist/client/_astro/client.3e777d4c.js +0 -1
- package/packages/storefront/dist/client/_astro/index.90df622b.css +0 -1
- package/packages/storefront/dist/client/_astro/runtime-core.esm-bundler.7cf33881.js +0 -1
- package/packages/storefront/dist/client/_astro/runtime-dom.esm-bundler.1a4c7407.js +0 -1
- package/packages/storefront/dist/client/_astro/server.4d9646d8.css +0 -1
- package/packages/storefront/src/lib/components/PitchBar.vue +0 -61
- package/packages/storefront/src/lib/components/Prices.vue +0 -176
- package/packages/storefront/src/lib/components/StickyHeader.vue +0 -56
- 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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
32
|
+
currentIndex.value = modelValue - 1;
|
|
42
33
|
});
|
|
43
|
-
watch(
|
|
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
|
|
50
|
-
const
|
|
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
|
|
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
|
|
88
|
-
|
|
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
|
|
95
|
-
const
|
|
67
|
+
const calcCurrentIndex = () => {
|
|
68
|
+
const getCurrentIndex = slidesWidth.value.findIndex((slide: HTMLElement) => {
|
|
96
69
|
// Find the closest point, with 5px approximate.
|
|
97
|
-
return
|
|
70
|
+
return Math.abs(slide.offsetLeft - currentPos.value) <= 5;
|
|
98
71
|
});
|
|
99
|
-
if (
|
|
100
|
-
|
|
72
|
+
if (getCurrentIndex > -1) {
|
|
73
|
+
currentIndex.value = getCurrentIndex || 0;
|
|
101
74
|
}
|
|
102
75
|
};
|
|
103
|
-
const
|
|
104
|
-
currentPos.value = wrapper.value.scrollLeft || 0;
|
|
105
|
-
};
|
|
106
|
-
const calcMaxPages = () => {
|
|
76
|
+
const calcIndexCount = () => {
|
|
107
77
|
const maxPos = wrapperScrollWidth.value - wrapperVisibleWidth.value;
|
|
108
|
-
|
|
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
|
-
|
|
144
|
-
|
|
94
|
+
calcIndexCount();
|
|
95
|
+
currentIndex.value = indexCount.value - 1;
|
|
145
96
|
changeSlide(1);
|
|
146
97
|
return;
|
|
147
98
|
}
|
|
148
99
|
} else if (isBoundRight.value) {
|
|
149
|
-
|
|
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
|
-
|
|
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="{
|
|
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>
|
|
@@ -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
|
|
74
|
-
if (width.value
|
|
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'] =
|
|
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
|
-
|
|
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;
|