zz-shopify-components 0.24.1-beta.2 → 0.24.1-beta.4
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/assets/loading.png +0 -0
- package/assets/zz-components.css +2 -1
- package/package.json +1 -1
- package/snippets/zz-accessories-preview-swiper.liquid +109 -57
- package/snippets/zz-gallery-tab.liquid +181 -136
- package/snippets/zz-product-preview.liquid +2 -2
- package/snippets/zz-product-swiper.liquid +7 -3
- package/snippets/zz-product-video.liquid +179 -54
|
Binary file
|
package/assets/zz-components.css
CHANGED
package/package.json
CHANGED
|
@@ -16,35 +16,53 @@
|
|
|
16
16
|
{% for block in accessories_points %}
|
|
17
17
|
{% if block.settings.swiper_index == accessories_points_index %}
|
|
18
18
|
<div
|
|
19
|
-
onclick='window.accessoriesPointClickHandler({{ block.settings.accessories_product.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
>
|
|
24
|
-
<svg
|
|
25
|
-
width='36'
|
|
26
|
-
height='36'
|
|
27
|
-
viewBox='0 0 36 36'
|
|
28
|
-
fill='none'
|
|
29
|
-
xmlns='http://www.w3.org/2000/svg'
|
|
19
|
+
onclick='window.accessoriesPointClickHandler(event, {{ block.settings.accessories_product.variants[0].id }})'
|
|
20
|
+
data-point-swiper-index='{{ block.settings.swiper_index }}'
|
|
21
|
+
class='product-accessories-point-item tw-absolute tw-rounded-full tw-backdrop-blur-[20px] tw-gap-[12px] tw-flex tw-items-center tw-justify-center tw-bg-[rgba(255,255,255,0.8)] lg:tw-py-[6px] tw-py-[4px] lg:tw-pl-[8px] tw-pl-[4px] tw-pr-[20px] tw-z-50 tw-cursor-pointer'
|
|
22
|
+
style='left: {{ block.settings.point_x }}%; top: {{ block.settings.point_y }}%;'
|
|
30
23
|
>
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
24
|
+
<svg
|
|
25
|
+
width='36'
|
|
26
|
+
height='36'
|
|
27
|
+
viewBox='0 0 36 36'
|
|
28
|
+
fill='none'
|
|
29
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
30
|
+
class="tw-block buy-icon tw-w-[36px] tw-h-[36px]"
|
|
31
|
+
>
|
|
32
|
+
<rect width="36" height="36" rx="18" fill="#FC6C0F"/>
|
|
33
|
+
<path d="M8 10H9.51521C10.2098 10 10.8135 10.4769 10.9744 11.1526L11.4143 13M11.4143 13L13.3341 21.0632C13.5486 21.9642 14.3536 22.6 15.2797 22.6H23.786C24.7278 22.6 25.542 21.943 25.7409 21.0225L26.9511 15.4225C27.2204 14.1765 26.2709 13 24.9962 13H11.4143Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
34
|
+
<circle cx="24.584" cy="26" r="0.6" fill="white" stroke="white" stroke-width="0.8"/>
|
|
35
|
+
<circle cx="14.916" cy="26" r="0.6" fill="white" stroke="white" stroke-width="0.8"/>
|
|
36
|
+
<path d="M17.4746 17.7998H21.4746" stroke="white" stroke-width="1.3" stroke-linecap="round"/>
|
|
37
|
+
<path d="M19.4746 19.7998V15.7998" stroke="white" stroke-width="1.3" stroke-linecap="round"/>
|
|
38
|
+
</svg>
|
|
39
|
+
|
|
40
|
+
<svg
|
|
41
|
+
width='30'
|
|
42
|
+
height='30'
|
|
43
|
+
viewBox='0 0 30 30'
|
|
44
|
+
fill='none'
|
|
45
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
46
|
+
class="tw-hidden buy-done-icon tw-w-[36px] tw-h-[36px]"
|
|
47
|
+
>
|
|
48
|
+
<rect width="30" height="30" rx="15" fill="#FC6C0F"/>
|
|
49
|
+
<rect x="1" y="1" width="28" height="28" rx="14" stroke="white" stroke-opacity="0.3" stroke-width="2"/>
|
|
50
|
+
<path d="M10.4168 15.0586L13.9523 18.5941L19.8449 12.7016" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
|
51
|
+
</svg>
|
|
52
|
+
|
|
53
|
+
<div class=' tw-flex tw-flex-col '>
|
|
54
|
+
<div class='lg:tw-text-[16px] tw-text-[12px] tw-leading-[1.2] tw-font-bold'>
|
|
55
|
+
{{
|
|
56
|
+
block.settings.accessories_title
|
|
57
|
+
| default: block.settings.accessories_product.title
|
|
58
|
+
}}
|
|
59
|
+
</div>
|
|
60
|
+
<div class='lg:tw-text-[14px] tw-text-[12px] tw-leading-[1.5] tw-font-medium'>
|
|
61
|
+
{{
|
|
62
|
+
block.settings.accessories_product.price
|
|
63
|
+
| money_without_trailing_zeros
|
|
64
|
+
}}
|
|
65
|
+
</div>
|
|
48
66
|
</div>
|
|
49
67
|
</div>
|
|
50
68
|
{% endif %}
|
|
@@ -71,7 +89,7 @@
|
|
|
71
89
|
| image_url: width: 200
|
|
72
90
|
| image_tag:
|
|
73
91
|
loading: 'lazy',
|
|
74
|
-
class: 'lg:tw-w-[
|
|
92
|
+
class: 'lg:tw-w-[40px] tw-w-[30px] tw-aspect-square tw-object-cover tw-rounded-[6px] ',
|
|
75
93
|
sizes: '(min-width: 750px) 50px, calc(100vw - 30px)',
|
|
76
94
|
widths: '50, 100, 150'
|
|
77
95
|
}}
|
|
@@ -80,8 +98,6 @@
|
|
|
80
98
|
</div>
|
|
81
99
|
</div>
|
|
82
100
|
</div>
|
|
83
|
-
|
|
84
|
-
|
|
85
101
|
</div>
|
|
86
102
|
|
|
87
103
|
<style>
|
|
@@ -190,33 +206,69 @@
|
|
|
190
206
|
});
|
|
191
207
|
});
|
|
192
208
|
|
|
193
|
-
window.accessoriesPointClickHandler = async function(variantId) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
209
|
+
window.accessoriesPointClickHandler = async function(eventOrElement, variantId) {
|
|
210
|
+
const element =
|
|
211
|
+
eventOrElement?.currentTarget ||
|
|
212
|
+
(eventOrElement instanceof Event ? eventOrElement.target : eventOrElement);
|
|
213
|
+
|
|
214
|
+
if (!(element instanceof Element)) {
|
|
215
|
+
console.warn('accessoriesPointClickHandler: expected an Element but got', eventOrElement);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const buyIcon = element.querySelector('.buy-icon');
|
|
220
|
+
const buyDoneIcon = element.querySelector('.buy-done-icon');
|
|
221
|
+
if (buyIcon) buyIcon.style.display = 'none';
|
|
222
|
+
if (buyDoneIcon) buyDoneIcon.style.display = 'block';
|
|
223
|
+
const data = {
|
|
224
|
+
items: [
|
|
225
|
+
{
|
|
226
|
+
id: variantId,
|
|
227
|
+
quantity: 1,
|
|
200
228
|
},
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
229
|
+
],
|
|
230
|
+
sections: 'cart-drawer,cart-icon-bubble',
|
|
231
|
+
};
|
|
232
|
+
const cart = document.querySelector('cart-drawer');
|
|
233
|
+
|
|
234
|
+
await fetch(`${routes.cart_add_url}`, {
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: {
|
|
237
|
+
'Content-Type': 'application/json',
|
|
238
|
+
Accept: 'application/javascript',
|
|
239
|
+
},
|
|
240
|
+
body: JSON.stringify(data),
|
|
241
|
+
})
|
|
242
|
+
.then((response) => response.json())
|
|
243
|
+
.then((response) => {
|
|
244
|
+
if (response.status) {
|
|
245
|
+
publish(PUB_SUB_EVENTS.cartError, {
|
|
246
|
+
source: 'product-form',
|
|
247
|
+
productVariantId: variantId,
|
|
248
|
+
errors: response.errors || response.description,
|
|
249
|
+
message: response.message,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
publish(PUB_SUB_EVENTS.cartUpdate, {
|
|
254
|
+
source: 'product-form',
|
|
255
|
+
productVariantId: variantId,
|
|
256
|
+
cartData: response,
|
|
257
|
+
});
|
|
258
|
+
cart.renderContents(response, false);
|
|
259
|
+
zzShowToast('1 item added to Cart', { type: 'success' });
|
|
260
|
+
|
|
261
|
+
})
|
|
262
|
+
.catch((e) => {
|
|
263
|
+
console.error(e);
|
|
264
|
+
})
|
|
265
|
+
.finally(() => {
|
|
266
|
+
setTimeout(() => {
|
|
267
|
+
if (buyIcon) buyIcon.style.display = 'block';
|
|
268
|
+
if (buyDoneIcon) buyDoneIcon.style.display = 'none';
|
|
269
|
+
}, 3000);
|
|
270
|
+
if (cart && cart.classList.contains('is-empty'))
|
|
271
|
+
cart.classList.remove('is-empty');
|
|
204
272
|
});
|
|
205
|
-
const data = await res.json();
|
|
206
|
-
if (data && data.status) {
|
|
207
|
-
console.error('Add to cart error:', data);
|
|
208
|
-
alert(data.message || 'Failed to add to cart');
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
const cartDrawer = document.querySelector('cart-drawer');
|
|
212
|
-
if (cartDrawer && typeof cartDrawer.renderContents === 'function') {
|
|
213
|
-
cartDrawer.renderContents(data);
|
|
214
|
-
if (typeof cartDrawer.open === 'function') cartDrawer.open();
|
|
215
|
-
} else {
|
|
216
|
-
window.location.href = window.routes.cart_url;
|
|
217
|
-
}
|
|
218
|
-
} catch (e) {
|
|
219
|
-
console.error(e);
|
|
220
|
-
}
|
|
221
273
|
};
|
|
222
274
|
</script>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
<gallery-tab
|
|
1
|
+
<gallery-tab>
|
|
2
2
|
<div class='gallery-tab-container lg:tw-mt-[20px] tw-mt-[12px] tw-absolute bottom-0 left-0 tw-w-full tw-z-10 tw-text-center tw-flex tw-items-center tw-justify-center lg:tw-gap-[12px] tw-gap-[4px]'>
|
|
3
|
-
<div
|
|
3
|
+
<div
|
|
4
|
+
class='gallery-tab-item active'
|
|
5
|
+
data-test-locator='galleryTabItemPhoto'
|
|
6
|
+
data-test-value='photo'
|
|
7
|
+
>
|
|
4
8
|
<div class='gallery-tab-item-text'>
|
|
5
9
|
<svg
|
|
6
10
|
xmlns='http://www.w3.org/2000/svg'
|
|
@@ -18,66 +22,78 @@
|
|
|
18
22
|
</div>
|
|
19
23
|
</div>
|
|
20
24
|
{% if show_accessories_point %}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
<div
|
|
26
|
+
class='gallery-tab-item'
|
|
27
|
+
data-test-locator='galleryTabItemAccessories'
|
|
28
|
+
data-test-value='accessories'
|
|
29
|
+
>
|
|
30
|
+
<div class='gallery-tab-item-text'>
|
|
31
|
+
<svg
|
|
32
|
+
width='20'
|
|
33
|
+
height='20'
|
|
34
|
+
viewBox='0 0 20 20'
|
|
35
|
+
fill='none'
|
|
36
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
37
|
+
>
|
|
38
|
+
<path d="M6.88574 3.83398H13.1035C13.9019 3.83401 14.5757 4.42847 14.6748 5.2207L15.8027 14.249C15.9207 15.1938 15.1845 16.028 14.2324 16.0283H5.75781C4.80554 16.0283 4.06858 15.1939 4.18652 14.249L5.31445 5.2207C5.41357 4.4285 6.08736 3.83406 6.88574 3.83398Z" stroke="black"/>
|
|
39
|
+
<path d="M12.7724 7.15332C12.7724 8.68744 11.5287 9.9311 9.99457 9.9311C8.46045 9.9311 7.2168 8.68744 7.2168 7.15332" stroke="black" stroke-linecap="round"/>
|
|
40
|
+
</svg>
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
<span class='gallery-tab-item-text-span'> Accessories </span>
|
|
43
|
+
</div>
|
|
35
44
|
</div>
|
|
36
|
-
</div>
|
|
37
45
|
{% endif %}
|
|
38
46
|
{% if show_video %}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
<div
|
|
48
|
+
class='gallery-tab-item'
|
|
49
|
+
data-test-locator='galleryTabItemVideo'
|
|
50
|
+
data-test-value='video'
|
|
51
|
+
>
|
|
52
|
+
<div class='gallery-tab-item-text'>
|
|
53
|
+
<svg
|
|
54
|
+
width='16'
|
|
55
|
+
height='16'
|
|
56
|
+
viewBox='0 0 16 16'
|
|
57
|
+
fill='none'
|
|
58
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
59
|
+
>
|
|
60
|
+
<rect x="0.5" y="2.5" width="15" height="11" rx="1.5" stroke="black"/>
|
|
61
|
+
<path d="M6.26348 6.16606C6.26362 5.85833 6.59736 5.66564 6.86394 5.81938L10.1644 7.72531C10.4306 7.87943 10.4304 8.26404 10.1639 8.41793L6.86389 10.3232C6.59737 10.4771 6.2642 10.2849 6.26385 9.97726L6.26348 6.16606Z" stroke="black"/>
|
|
62
|
+
</svg>
|
|
63
|
+
<span class='gallery-tab-item-text-span'> Video </span>
|
|
64
|
+
</div>
|
|
52
65
|
</div>
|
|
53
|
-
</div>
|
|
54
66
|
{% endif %}
|
|
55
67
|
{% if show_model %}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
<div
|
|
69
|
+
class='gallery-tab-item'
|
|
70
|
+
data-test-locator='galleryTabItem3D'
|
|
71
|
+
data-test-value='3d'
|
|
72
|
+
>
|
|
73
|
+
<div class='gallery-tab-item-text'>
|
|
74
|
+
<svg
|
|
75
|
+
width='16'
|
|
76
|
+
height='16'
|
|
77
|
+
viewBox='0 0 16 16'
|
|
78
|
+
fill='none'
|
|
79
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
80
|
+
>
|
|
81
|
+
<path d="M12.6963 3.78809V8.71094L8 11.4229L3.30371 8.71094V3.78809L8 1.07617L12.6963 3.78809Z" stroke="black"/>
|
|
82
|
+
<path d="M12.6346 3.75198L8.03554 6.40723L3.43652 3.75198" stroke="black"/>
|
|
83
|
+
<path d="M8 11.375V5.875" stroke="black" stroke-linejoin="round"/>
|
|
84
|
+
<path d="M6.41406 12.5996L7.82828 14.0138L6.41406 15.428" stroke="black" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round"/>
|
|
85
|
+
<path d="M3.30431 7C1.59439 7.73314 0.5 8.858 0.5 10.1192C0.5 12.2387 3.59098 13.9732 7.5 14.1104M12.6957 7C14.4056 7.73314 15.5 8.858 15.5 10.1192C15.5 12.0543 12.9234 13.6685 9.5 14.0392" stroke="black"/>
|
|
86
|
+
</svg>
|
|
87
|
+
<span class='gallery-tab-item-text-span'> 3D </span>
|
|
88
|
+
</div>
|
|
72
89
|
</div>
|
|
73
|
-
</div>
|
|
74
90
|
{% endif %}
|
|
75
91
|
</div>
|
|
76
92
|
</gallery-tab>
|
|
77
93
|
|
|
78
94
|
<style>
|
|
79
95
|
.gallery-tab-item {
|
|
80
|
-
padding:
|
|
96
|
+
padding: 3px 16px;
|
|
81
97
|
cursor: pointer;
|
|
82
98
|
display: inline-block;
|
|
83
99
|
border-radius: 100px;
|
|
@@ -89,12 +105,13 @@
|
|
|
89
105
|
|
|
90
106
|
@media screen and (max-width: 1024px) {
|
|
91
107
|
.gallery-tab-item {
|
|
92
|
-
padding:
|
|
108
|
+
padding: 8px 10px;
|
|
93
109
|
font-size: 12px !important;
|
|
110
|
+
line-height: 12px;
|
|
94
111
|
}
|
|
95
112
|
}
|
|
96
113
|
.gallery-tab-item:hover {
|
|
97
|
-
background: #
|
|
114
|
+
background: #f5f5f5;
|
|
98
115
|
}
|
|
99
116
|
.gallery-tab-item.active {
|
|
100
117
|
color: #fff;
|
|
@@ -107,106 +124,134 @@
|
|
|
107
124
|
gap: 8px;
|
|
108
125
|
}
|
|
109
126
|
.gallery-tab-item svg {
|
|
110
|
-
transition:
|
|
111
|
-
filter 0.2s ease,
|
|
112
|
-
fill 0.2s ease,
|
|
113
|
-
stroke 0.2s ease;
|
|
127
|
+
transition: filter 0.2s ease, fill 0.2s ease, stroke 0.2s ease;
|
|
114
128
|
}
|
|
115
129
|
.gallery-tab-item.active svg {
|
|
116
130
|
filter: invert(1);
|
|
117
131
|
}
|
|
118
132
|
.gallery-tab-item-text-span {
|
|
119
133
|
}
|
|
134
|
+
@media screen and (max-width: 1024px) {
|
|
135
|
+
.gallery-tab-item-text svg {
|
|
136
|
+
width: 12px;
|
|
137
|
+
height: 12px;
|
|
138
|
+
}
|
|
139
|
+
.gallery-tab-item-text {
|
|
140
|
+
font-size: 12px;
|
|
141
|
+
gap: 6px;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
120
144
|
</style>
|
|
121
145
|
|
|
122
146
|
<script>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
140
|
-
const activeFromDom = this.querySelector('.gallery-tab-item.active');
|
|
141
|
-
const activeFromDomValue = activeFromDom ? (activeFromDom.dataset.testValue || activeFromDom.getAttribute('data-test-value')) : null;
|
|
142
|
-
const firstItemValue = this._items[0] ? (this._items[0].dataset.testValue || this._items[0].getAttribute('data-test-value')) : null;
|
|
143
|
-
const initialValue = this.getAttribute('value') || activeFromDomValue || firstItemValue || '';
|
|
144
|
-
this._suppressChange = true;
|
|
145
|
-
this.setAttribute('value', String(initialValue));
|
|
146
|
-
this._syncActive(initialValue);
|
|
147
|
-
this._suppressChange = false;
|
|
148
|
-
}
|
|
149
|
-
disconnectedCallback() {
|
|
150
|
-
this._items.forEach((item) => {
|
|
151
|
-
item.removeEventListener('click', this._onItemClick, false);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
attributeChangedCallback(name, oldValue, newValue) {
|
|
155
|
-
if (name !== 'value' || oldValue === newValue) return;
|
|
156
|
-
this._syncActive(newValue);
|
|
157
|
-
if (!this._suppressChange) {
|
|
158
|
-
this.dispatchEvent(
|
|
159
|
-
new CustomEvent('change', {
|
|
160
|
-
detail: { value: newValue },
|
|
161
|
-
bubbles: true
|
|
162
|
-
})
|
|
163
|
-
);
|
|
164
|
-
document.querySelectorAll('.product-preview-item').forEach((item) => {
|
|
165
|
-
if (item.dataset.galleryValue === newValue) {
|
|
166
|
-
item.classList.add('active');
|
|
167
|
-
} else {
|
|
168
|
-
item.classList.remove('active');
|
|
169
|
-
}
|
|
147
|
+
(() => {
|
|
148
|
+
class GalleryTab extends HTMLElement {
|
|
149
|
+
static get observedAttributes() {
|
|
150
|
+
return ['value'];
|
|
151
|
+
}
|
|
152
|
+
constructor() {
|
|
153
|
+
super();
|
|
154
|
+
this._items = [];
|
|
155
|
+
this._suppressChange = false;
|
|
156
|
+
this._onItemClick = this._onItemClick.bind(this);
|
|
157
|
+
}
|
|
158
|
+
connectedCallback() {
|
|
159
|
+
this._items = Array.from(this.querySelectorAll('.gallery-tab-item'));
|
|
160
|
+
this._items.forEach((item) => {
|
|
161
|
+
item.addEventListener('click', this._onItemClick, false);
|
|
162
|
+
item.setAttribute('role', 'tab');
|
|
170
163
|
});
|
|
164
|
+
const activeFromDom = this.querySelector('.gallery-tab-item.active');
|
|
165
|
+
const activeFromDomValue = activeFromDom
|
|
166
|
+
? activeFromDom.dataset.testValue ||
|
|
167
|
+
activeFromDom.getAttribute('data-test-value')
|
|
168
|
+
: null;
|
|
169
|
+
const firstItemValue = this._items[0]
|
|
170
|
+
? this._items[0].dataset.testValue ||
|
|
171
|
+
this._items[0].getAttribute('data-test-value')
|
|
172
|
+
: null;
|
|
173
|
+
const initialValue =
|
|
174
|
+
this.getAttribute('value') ||
|
|
175
|
+
activeFromDomValue ||
|
|
176
|
+
firstItemValue ||
|
|
177
|
+
'';
|
|
178
|
+
this._suppressChange = true;
|
|
179
|
+
this.setAttribute('value', String(initialValue));
|
|
180
|
+
this._syncActive(initialValue);
|
|
181
|
+
this._suppressChange = false;
|
|
171
182
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
set value(next) {
|
|
177
|
-
if (next == null) {
|
|
178
|
-
this.removeAttribute('value');
|
|
179
|
-
} else {
|
|
180
|
-
this.setAttribute('value', String(next));
|
|
183
|
+
disconnectedCallback() {
|
|
184
|
+
this._items.forEach((item) => {
|
|
185
|
+
item.removeEventListener('click', this._onItemClick, false);
|
|
186
|
+
});
|
|
181
187
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
188
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
189
|
+
if (name !== 'value' || oldValue === newValue) return;
|
|
190
|
+
this._syncActive(newValue);
|
|
191
|
+
if (!this._suppressChange) {
|
|
192
|
+
this.dispatchEvent(
|
|
193
|
+
new CustomEvent('change', {
|
|
194
|
+
detail: { value: newValue },
|
|
195
|
+
bubbles: true,
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
document.querySelectorAll('.product-preview-item').forEach((item) => {
|
|
199
|
+
if (item.dataset.galleryValue === newValue) {
|
|
200
|
+
item.classList.add('active');
|
|
201
|
+
} else {
|
|
202
|
+
item.classList.remove('active');
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
document
|
|
207
|
+
.querySelectorAll('product-video-tab video')
|
|
208
|
+
.forEach((video) => {
|
|
209
|
+
video.pause();
|
|
210
|
+
video.currentTime = 0;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
get value() {
|
|
214
|
+
return this.getAttribute('value');
|
|
215
|
+
}
|
|
216
|
+
set value(next) {
|
|
217
|
+
if (next == null) {
|
|
218
|
+
this.removeAttribute('value');
|
|
219
|
+
} else {
|
|
220
|
+
this.setAttribute('value', String(next));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
_onItemClick(event) {
|
|
224
|
+
const item = event.currentTarget;
|
|
225
|
+
const nextValue = item
|
|
226
|
+
? item.dataset.testValue || item.getAttribute('data-test-value')
|
|
227
|
+
: '';
|
|
228
|
+
if (!nextValue || nextValue === this.value) return;
|
|
229
|
+
this.value = nextValue;
|
|
230
|
+
}
|
|
231
|
+
_syncActive(value) {
|
|
232
|
+
const normalized = String(value || '');
|
|
233
|
+
let matched = false;
|
|
234
|
+
this._items.forEach((item) => {
|
|
235
|
+
const itemValue =
|
|
236
|
+
item.dataset.testValue ||
|
|
237
|
+
item.getAttribute('data-test-value') ||
|
|
238
|
+
'';
|
|
239
|
+
const isActive = itemValue === normalized;
|
|
202
240
|
item.classList.toggle('active', isActive);
|
|
203
241
|
item.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
|
242
|
+
if (isActive) matched = true;
|
|
204
243
|
});
|
|
244
|
+
if (!matched && this._items[0]) {
|
|
245
|
+
this._items.forEach((item, index) => {
|
|
246
|
+
const isActive = index === 0;
|
|
247
|
+
item.classList.toggle('active', isActive);
|
|
248
|
+
item.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
|
249
|
+
});
|
|
250
|
+
}
|
|
205
251
|
}
|
|
206
252
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
</script>
|
|
253
|
+
if (!customElements.get('gallery-tab')) {
|
|
254
|
+
customElements.define('gallery-tab', GalleryTab);
|
|
255
|
+
}
|
|
256
|
+
})();
|
|
257
|
+
</script>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<div class='tw-w-full
|
|
1
|
+
<div class='tw-w-full tw-mx-auto'>
|
|
2
2
|
<div class='product-container tw-flex tw-items-center tw-justify-center'>
|
|
3
3
|
{% comment %} 左侧产品预览 {% endcomment %}
|
|
4
4
|
<div
|
|
5
|
-
class='product-preview tw-w-full tw-aspect-square
|
|
5
|
+
class='product-preview tw-w-full lg:tw-max-w-[550px] 2xl:tw-max-w-[650px] tw-aspect-square lg:tw-rounded-[16px] tw-overflow-hidden'
|
|
6
6
|
data-test-locator='productPreview'
|
|
7
7
|
>
|
|
8
8
|
<div
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
</div>
|
|
24
24
|
<div class='swiper-pagination'></div>
|
|
25
25
|
<div class='product-swiper-button-prev'>
|
|
26
|
-
{% render 'zz-prev-next-
|
|
26
|
+
{% render 'zz-prev-next-blur-icon', type: 'prev', %}
|
|
27
27
|
</div>
|
|
28
28
|
<div class='product-swiper-button-next'>
|
|
29
|
-
{% render 'zz-prev-next-
|
|
29
|
+
{% render 'zz-prev-next-blur-icon', type: 'next' %}
|
|
30
30
|
</div>
|
|
31
31
|
</div>
|
|
32
32
|
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
| image_url: width: 200
|
|
41
41
|
| image_tag:
|
|
42
42
|
loading: 'lazy',
|
|
43
|
-
class: 'lg:tw-w-[
|
|
43
|
+
class: 'lg:tw-w-[40px] tw-w-[30px] tw-aspect-square tw-object-cover tw-rounded-[6px] ',
|
|
44
44
|
sizes: '(min-width: 750px) 50px, calc(100vw - 30px)',
|
|
45
45
|
widths: '50, 100, 150'
|
|
46
46
|
}}
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
</zz-product-swiper>
|
|
53
53
|
|
|
54
54
|
<style>
|
|
55
|
+
zz-product-swiper .product-swiper-button-prev path,
|
|
56
|
+
zz-product-swiper .product-swiper-button-next path {
|
|
57
|
+
fill: white;
|
|
58
|
+
}
|
|
55
59
|
.product-swiper-container .swiper-pagination {
|
|
56
60
|
--swiper-pagination-color: black;
|
|
57
61
|
--swiper-pagination-bottom: 10px;
|
|
@@ -1,44 +1,152 @@
|
|
|
1
1
|
{%- assign intro_video = product.metafields.custom.intro_video.value -%}
|
|
2
|
+
{%- assign livestream_id = product.metafields.custom.livestream_id.value -%}
|
|
2
3
|
{%- assign livestream_video = product.metafields.custom.livestream_video.value -%}
|
|
4
|
+
<script
|
|
5
|
+
async
|
|
6
|
+
type='text/javascript'
|
|
7
|
+
src='//asset.fwcdn3.com/js/integrations/shopify.js'
|
|
8
|
+
></script>
|
|
9
|
+
<script
|
|
10
|
+
async
|
|
11
|
+
type='text/javascript'
|
|
12
|
+
src='//asset.fwcdn3.com/js/fwn-async.js'
|
|
13
|
+
></script>
|
|
14
|
+
<product-video-tab
|
|
15
|
+
class=' tw-w-full tw-h-full '
|
|
16
|
+
{%- if intro_video -%}
|
|
17
|
+
data-default-tab='intro'
|
|
18
|
+
{%- elsif livestream_video -%}
|
|
19
|
+
data-default-tab='livestream'
|
|
20
|
+
{%- endif -%}
|
|
21
|
+
>
|
|
22
|
+
{%- if intro_video
|
|
23
|
+
and intro_video.sources
|
|
24
|
+
and intro_video.sources.size > 0
|
|
25
|
+
-%}
|
|
26
|
+
<video
|
|
27
|
+
id='product-video-intro-{{ product.id }}'
|
|
28
|
+
data-type='intro'
|
|
29
|
+
src='{{ intro_video.sources[0].url }}'
|
|
30
|
+
poster='{{ intro_video.preview_image | image_url: width: 1000 }}'
|
|
31
|
+
controls
|
|
32
|
+
playsinline
|
|
33
|
+
muted
|
|
34
|
+
preload='metadata'
|
|
35
|
+
class=' tw-w-full tw-h-full tw-bg-black '
|
|
36
|
+
></video>
|
|
37
|
+
{%- endif -%}
|
|
3
38
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
39
|
+
{%- if livestream_id -%}
|
|
40
|
+
<div
|
|
41
|
+
id='firework-video-{{ product.id }}'
|
|
42
|
+
data-type='livestream'
|
|
43
|
+
class='tw-w-full tw-h-full tw-bg-black'
|
|
44
|
+
role='tabpanel'
|
|
45
|
+
aria-labelledby='product-video-tab-livestream-{{ product.id }}'
|
|
46
|
+
>
|
|
47
|
+
<fw-storyblock
|
|
48
|
+
channel='hover'
|
|
49
|
+
playlist='{{ livestream_id }}'
|
|
50
|
+
autoplay='true'
|
|
51
|
+
class='tw-h-full tw-w-full'
|
|
52
|
+
>
|
|
53
|
+
</fw-storyblock>
|
|
12
54
|
</div>
|
|
13
|
-
|
|
14
|
-
|
|
55
|
+
{% elsif livestream_video %}
|
|
56
|
+
<video
|
|
57
|
+
id='product-video-intro-{{ product.id }}'
|
|
58
|
+
role='tabpanel'
|
|
59
|
+
aria-labelledby='product-video-tab-livestream-{{ product.id }}'
|
|
60
|
+
data-type='livestream'
|
|
61
|
+
src='{{ livestream_video.sources[0].url }}'
|
|
62
|
+
poster='{{ livestream_video.preview_image | image_url: width: 1000 }}'
|
|
63
|
+
controls
|
|
64
|
+
playsinline
|
|
65
|
+
muted
|
|
66
|
+
preload='metadata'
|
|
67
|
+
class=' tw-w-full tw-h-full tw-bg-black '
|
|
68
|
+
></video>
|
|
69
|
+
{%- endif -%}
|
|
70
|
+
|
|
71
|
+
{%- assign tabs_count = 0 -%}
|
|
72
|
+
{%- if intro_video
|
|
73
|
+
and intro_video.sources
|
|
74
|
+
and intro_video.sources.size > 0
|
|
75
|
+
-%}
|
|
76
|
+
{%- assign tabs_count = tabs_count | plus: 1 -%}
|
|
77
|
+
{%- endif -%}
|
|
78
|
+
{%- if livestream_video -%}
|
|
79
|
+
{%- assign tabs_count = tabs_count | plus: 1 -%}
|
|
80
|
+
{%- endif -%}
|
|
15
81
|
|
|
82
|
+
{%- if tabs_count > 1 -%}
|
|
83
|
+
<div
|
|
84
|
+
class=' product-video-tabs tw-absolute tw-left-1/2 tw--translate-x-1/2 tw-top-[30px] tw-bg-white '
|
|
85
|
+
role='tablist'
|
|
86
|
+
aria-label='Product video tabs'
|
|
87
|
+
>
|
|
88
|
+
<div class=' tw-grid tw-grid-cols-2 tw-relative'>
|
|
89
|
+
{%- if intro_video
|
|
90
|
+
and intro_video.sources
|
|
91
|
+
and intro_video.sources.size > 0
|
|
92
|
+
-%}
|
|
93
|
+
<button
|
|
94
|
+
type='button'
|
|
95
|
+
id='product-video-tab-intro-{{ product.id }}'
|
|
96
|
+
class='product-video-tab-item'
|
|
97
|
+
data-tab='intro'
|
|
98
|
+
role='tab'
|
|
99
|
+
aria-controls='product-video-intro-{{ product.id }}'
|
|
100
|
+
aria-selected='true'
|
|
101
|
+
>
|
|
102
|
+
Introduction
|
|
103
|
+
</button>
|
|
104
|
+
{%- endif -%}
|
|
105
|
+
{%- if livestream_video -%}
|
|
106
|
+
<button
|
|
107
|
+
type='button'
|
|
108
|
+
id='product-video-tab-livestream-{{ product.id }}'
|
|
109
|
+
class='product-video-tab-item'
|
|
110
|
+
data-tab='livestream'
|
|
111
|
+
role='tab'
|
|
112
|
+
aria-controls='firework-video-{{ product.id }}'
|
|
113
|
+
aria-selected='false'
|
|
114
|
+
>
|
|
115
|
+
Livestream
|
|
116
|
+
</button>
|
|
117
|
+
{%- endif -%}
|
|
118
|
+
<div
|
|
119
|
+
class='product-video-tab-slider tw-z-1 tw-rounded-full !tw-block tw-absolute tw-top-0 tw-w-1/2 tw-h-full tw-bg-white'
|
|
120
|
+
></div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
{%- endif -%}
|
|
124
|
+
</product-video-tab>
|
|
16
125
|
|
|
17
126
|
<style>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
127
|
+
.product-video-tabs {
|
|
128
|
+
border-radius: 999px;
|
|
129
|
+
background-color: rgba(255, 255, 255, 0.3);
|
|
130
|
+
backdrop-filter: blur(10px);
|
|
131
|
+
}
|
|
132
|
+
.product-video-tab-item {
|
|
133
|
+
color: #fff;
|
|
134
|
+
z-index: 10;
|
|
135
|
+
text-align: center;
|
|
136
|
+
padding: 6px 20px;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
font-size: 16px;
|
|
139
|
+
transition: all 0.3s ease;
|
|
140
|
+
}
|
|
141
|
+
@media screen and (max-width: 1024px) {
|
|
23
142
|
.product-video-tab-item {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
text-align: center;
|
|
27
|
-
padding: 6px 20px;
|
|
28
|
-
cursor: pointer;
|
|
29
|
-
font-size: 16px;
|
|
30
|
-
transition: all 0.3s ease;
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
@media screen and (max-width: 1024px) {
|
|
34
|
-
.product-video-tab-item {
|
|
35
|
-
padding: 4px 12px;
|
|
36
|
-
font-size: 10px;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
.product-video-tab-slider {
|
|
40
|
-
transition: all 0.3s ease;
|
|
143
|
+
padding: 4px 12px;
|
|
144
|
+
font-size: 10px;
|
|
41
145
|
}
|
|
146
|
+
}
|
|
147
|
+
.product-video-tab-slider {
|
|
148
|
+
transition: transform 0.3s ease;
|
|
149
|
+
}
|
|
42
150
|
</style>
|
|
43
151
|
|
|
44
152
|
<script>
|
|
@@ -46,24 +154,30 @@
|
|
|
46
154
|
class ProductVideoTab extends HTMLElement {
|
|
47
155
|
constructor() {
|
|
48
156
|
super();
|
|
49
|
-
this.currentTab = 'intro';
|
|
157
|
+
this.currentTab = this.dataset.defaultTab || 'intro';
|
|
50
158
|
}
|
|
51
159
|
|
|
52
160
|
connectedCallback() {
|
|
53
161
|
this.cacheDom();
|
|
54
|
-
if (!this.
|
|
162
|
+
if (!this.panels.length) return;
|
|
163
|
+
if (this.panels.length < 2 && this.tabsContainer) {
|
|
164
|
+
this.tabsContainer.style.display = 'none';
|
|
165
|
+
}
|
|
55
166
|
this.changeTab(true);
|
|
56
167
|
this.attachEvents();
|
|
57
168
|
}
|
|
58
169
|
|
|
59
170
|
cacheDom() {
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
171
|
+
this.tabsContainer = this.querySelector('.product-video-tabs');
|
|
172
|
+
this.buttons = Array.from(
|
|
173
|
+
this.querySelectorAll('.product-video-tab-item')
|
|
174
|
+
);
|
|
175
|
+
this.panels = Array.from(this.querySelectorAll('[data-type]'));
|
|
62
176
|
this.slider = this.querySelector('.product-video-tab-slider');
|
|
63
177
|
}
|
|
64
178
|
|
|
65
179
|
attachEvents() {
|
|
66
|
-
this.buttons.forEach(button => {
|
|
180
|
+
this.buttons.forEach((button) => {
|
|
67
181
|
button.addEventListener('click', () => {
|
|
68
182
|
const nextTab = button.dataset.tab;
|
|
69
183
|
if (!nextTab || nextTab === this.currentTab) return;
|
|
@@ -73,37 +187,48 @@
|
|
|
73
187
|
});
|
|
74
188
|
}
|
|
75
189
|
|
|
190
|
+
isMedia(el) {
|
|
191
|
+
return el && (el.tagName === 'VIDEO' || el.tagName === 'AUDIO');
|
|
192
|
+
}
|
|
193
|
+
|
|
76
194
|
changeTab(isInitial = false) {
|
|
77
|
-
this.
|
|
78
|
-
const isActive =
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
195
|
+
this.panels.forEach((panel) => {
|
|
196
|
+
const isActive = panel.dataset.type === this.currentTab;
|
|
197
|
+
panel.style.display = isActive ? 'block' : 'none';
|
|
198
|
+
if (this.isMedia(panel)) {
|
|
199
|
+
try {
|
|
200
|
+
if (isActive) {
|
|
201
|
+
panel.muted = true;
|
|
202
|
+
const playPromise = panel.play && panel.play();
|
|
203
|
+
if (
|
|
204
|
+
playPromise &&
|
|
205
|
+
typeof playPromise.catch === 'function' &&
|
|
206
|
+
!isInitial
|
|
207
|
+
) {
|
|
208
|
+
playPromise.catch(() => {});
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
panel.pause && panel.pause();
|
|
212
|
+
}
|
|
213
|
+
} catch (e) {}
|
|
87
214
|
}
|
|
88
215
|
});
|
|
89
216
|
|
|
90
|
-
this.buttons.forEach(button => {
|
|
217
|
+
this.buttons.forEach((button) => {
|
|
91
218
|
const isActive = button.dataset.tab === this.currentTab;
|
|
92
219
|
button.style.color = isActive ? '#000' : '#fff';
|
|
220
|
+
button.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
|
93
221
|
});
|
|
94
222
|
|
|
95
223
|
if (!this.slider) return;
|
|
96
224
|
if (this.currentTab === 'intro') {
|
|
97
|
-
this.slider.style.
|
|
98
|
-
this.slider.style.right = 'auto';
|
|
225
|
+
this.slider.style.transform = 'translateX(0%)';
|
|
99
226
|
} else {
|
|
100
|
-
this.slider.style.
|
|
101
|
-
this.slider.style.left = 'auto';
|
|
227
|
+
this.slider.style.transform = 'translateX(100%)';
|
|
102
228
|
}
|
|
103
229
|
}
|
|
104
230
|
}
|
|
105
231
|
|
|
106
232
|
customElements.define('product-video-tab', ProductVideoTab);
|
|
107
233
|
})();
|
|
108
|
-
|
|
109
|
-
</script>
|
|
234
|
+
</script>
|