zz-shopify-components 0.25.0 → 0.25.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/loading.png +0 -0
- package/assets/zz-components.css +2 -1
- package/blocks/zz-bundle-compare-item.liquid +36 -0
- package/blocks/zz-bundle-compare.liquid +33 -0
- package/package.json +1 -1
- package/snippets/zz-accessories-preview-swiper.liquid +331 -0
- package/snippets/zz-gallery-tab.liquid +257 -0
- package/snippets/zz-model-viewer.liquid +124 -0
- package/snippets/zz-product-model.liquid +447 -0
- package/snippets/zz-product-preview.liquid +51 -0
- package/snippets/zz-product-swiper.liquid +255 -0
- package/snippets/zz-product-video.liquid +240 -0
|
Binary file
|
package/assets/zz-components.css
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{% schema %}
|
|
2
|
+
{
|
|
3
|
+
"name": "Compare Tab Item",
|
|
4
|
+
"settings": [
|
|
5
|
+
{
|
|
6
|
+
"type": "text",
|
|
7
|
+
"id": "title",
|
|
8
|
+
"label": "Tab标题"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"type": "image_picker",
|
|
12
|
+
"id": "image",
|
|
13
|
+
"label": "图片"
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
"presets": [
|
|
17
|
+
{
|
|
18
|
+
"name": "Compare Tab Item",
|
|
19
|
+
"settings": {
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
{% endschema %}
|
|
25
|
+
|
|
26
|
+
<input
|
|
27
|
+
type="radio"
|
|
28
|
+
name="zz-bundle-compare-item-{{ block.id }}"
|
|
29
|
+
role="tab"
|
|
30
|
+
class="tw-daisy-tab"
|
|
31
|
+
aria-label= {{ block.settings.title }}
|
|
32
|
+
checked="checked" />
|
|
33
|
+
<div role="tabpanel" class="tw-daisy-tab-content tw-w-full tw-p-10">
|
|
34
|
+
|
|
35
|
+
<img src="{{ block.settings.image | image_url }}" alt="{{ block.settings.title }}" class="tw-w-full tw-h-full" />
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{% schema %}
|
|
2
|
+
{
|
|
3
|
+
"name": "Bundle Compare",
|
|
4
|
+
"class": "zz-bundle-compare",
|
|
5
|
+
"settings": [
|
|
6
|
+
{
|
|
7
|
+
"type": "image_picker",
|
|
8
|
+
"id": "pc_image",
|
|
9
|
+
"label": "PC端图片"
|
|
10
|
+
},
|
|
11
|
+
],
|
|
12
|
+
"blocks": [
|
|
13
|
+
{
|
|
14
|
+
"type": "zz-bundle-compare-item",
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"presets": [
|
|
18
|
+
{
|
|
19
|
+
"name": "Bundle Compare",
|
|
20
|
+
"settings": {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
{% endschema %}
|
|
26
|
+
{% comment %} <div class="zz-bundle-compare-container">
|
|
27
|
+
{% content_for 'block', block %}
|
|
28
|
+
</div> {% endcomment %}
|
|
29
|
+
|
|
30
|
+
<div role="tablist" class="tw-daisy-tabs tw-daisy-tabs-bordered">
|
|
31
|
+
{% content_for 'blocks' %}
|
|
32
|
+
</div>
|
|
33
|
+
|
package/package.json
CHANGED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
<zz-accessories-preview-swiper class=' tw-w-full product-accessories-swiper-container tw-h-full tw-relative'>
|
|
2
|
+
<div class='swiper product-accessories-swiper-list tw-w-full tw-h-full tw-relative'>
|
|
3
|
+
<div class='swiper-wrapper'>
|
|
4
|
+
{% for image in product.metafields.custom.acc_images.value %}
|
|
5
|
+
{% assign accessories_points_index = forloop.index %}
|
|
6
|
+
<div class='swiper-slide tw-flex tw-justify-center tw-relative'>
|
|
7
|
+
{{
|
|
8
|
+
image
|
|
9
|
+
| image_url: width: 3000
|
|
10
|
+
| image_tag:
|
|
11
|
+
loading: 'lazy',
|
|
12
|
+
class: 'tw-w-auto tw-h-full tw-max-w-full tw-object-cover tw-m-auto',
|
|
13
|
+
sizes: '(min-width: 750px) 700px, calc(100vw - 30px)',
|
|
14
|
+
widths: '3000, 4000, 5000'
|
|
15
|
+
}}
|
|
16
|
+
{% for block in accessories_points %}
|
|
17
|
+
{% if block.settings.swiper_index == accessories_points_index %}
|
|
18
|
+
<div
|
|
19
|
+
onclick='window.accessoriesPointClickHandler(event, {{ block.settings.accessories_product.selected_or_first_available_variant.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 }}%;'
|
|
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'
|
|
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.selected_or_first_available_variant.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.selected_or_first_available_variant.price
|
|
63
|
+
| money_without_trailing_zeros
|
|
64
|
+
}}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
{% endif %}
|
|
69
|
+
{% endfor %}
|
|
70
|
+
</div>
|
|
71
|
+
{% endfor %}
|
|
72
|
+
</div>
|
|
73
|
+
<div class='swiper-pagination'></div>
|
|
74
|
+
<div class='product-accessories-swiper-button-prev'>
|
|
75
|
+
{% render 'zz-prev-next-blur-icon', type: 'prev' %}
|
|
76
|
+
</div>
|
|
77
|
+
<div class='product-accessories-swiper-button-next'>
|
|
78
|
+
{% render 'zz-prev-next-blur-icon', type: 'next' %}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div class=' tw-absolute tw-bottom-[20px] tw-left-1/2 tw-transform tw-translate-x-[-50%] tw-z-10 tw-w-[80%] '>
|
|
83
|
+
<div class='swiper product-accessories-swiper-list-thumbs tw-opacity-0'>
|
|
84
|
+
<div class='swiper-wrapper tw-flex tw-justify-center'>
|
|
85
|
+
{% for image in product.metafields.custom.acc_images.value %}
|
|
86
|
+
<div class='swiper-slide !tw-w-auto tw-opacity-30 tw-relative'>
|
|
87
|
+
{{
|
|
88
|
+
image
|
|
89
|
+
| image_url: width: 200
|
|
90
|
+
| image_tag:
|
|
91
|
+
loading: 'lazy',
|
|
92
|
+
class: 'lg:tw-w-[40px] tw-w-[30px] tw-aspect-square tw-object-cover tw-rounded-[6px] ',
|
|
93
|
+
sizes: '(min-width: 750px) 50px, calc(100vw - 30px)',
|
|
94
|
+
widths: '50, 100, 150'
|
|
95
|
+
}}
|
|
96
|
+
</div>
|
|
97
|
+
{% endfor %}
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</zz-accessories-preview-swiper>
|
|
102
|
+
|
|
103
|
+
<style>
|
|
104
|
+
zz-accessories-preview-swiper {
|
|
105
|
+
display: block;
|
|
106
|
+
}
|
|
107
|
+
zz-accessories-preview-swiper .product-accessories-swiper-button-prev path,
|
|
108
|
+
zz-accessories-preview-swiper .product-accessories-swiper-button-next path {
|
|
109
|
+
fill: white;
|
|
110
|
+
}
|
|
111
|
+
.product-accessories-swiper-container .swiper-pagination {
|
|
112
|
+
--swiper-pagination-color: black;
|
|
113
|
+
--swiper-pagination-bottom: 10px;
|
|
114
|
+
}
|
|
115
|
+
.product-accessories-swiper-container .swiper-pagination,
|
|
116
|
+
.product-accessories-swiper-list-thumbs {
|
|
117
|
+
transition: opacity 0.2s ease-in-out;
|
|
118
|
+
}
|
|
119
|
+
.product-accessories-swiper-list-thumbs {
|
|
120
|
+
transform: translateY(12px) scale(0.96);
|
|
121
|
+
transform-origin: bottom center;
|
|
122
|
+
will-change: opacity, transform;
|
|
123
|
+
transition:
|
|
124
|
+
opacity 0.25s ease,
|
|
125
|
+
transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
126
|
+
}
|
|
127
|
+
.product-accessories-swiper-container:hover
|
|
128
|
+
.product-accessories-swiper-list-thumbs {
|
|
129
|
+
opacity: 1;
|
|
130
|
+
transform: translateY(0) scale(1);
|
|
131
|
+
}
|
|
132
|
+
.product-accessories-swiper-container:hover .swiper-pagination {
|
|
133
|
+
display: none;
|
|
134
|
+
transition: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.product-accessories-swiper-list-thumbs .swiper-slide {
|
|
138
|
+
border: 1px solid black;
|
|
139
|
+
border-radius: 6px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.product-accessories-swiper-list-thumbs .swiper-slide-thumb-active {
|
|
143
|
+
opacity: 1;
|
|
144
|
+
border: 1px solid black;
|
|
145
|
+
border-radius: 6px;
|
|
146
|
+
}
|
|
147
|
+
.product-accessories-swiper-button-prev,
|
|
148
|
+
.product-accessories-swiper-button-next {
|
|
149
|
+
position: absolute;
|
|
150
|
+
top: 50%;
|
|
151
|
+
transform: translateY(-50%);
|
|
152
|
+
z-index: 10;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
pointer-events: auto;
|
|
155
|
+
}
|
|
156
|
+
@media screen and (max-width: 1024px) {
|
|
157
|
+
.product-accessories-swiper-button-prev {
|
|
158
|
+
display: none;
|
|
159
|
+
}
|
|
160
|
+
.product-accessories-swiper-button-next {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
.product-accessories-swiper-button-prev {
|
|
165
|
+
left: 20px;
|
|
166
|
+
}
|
|
167
|
+
.product-accessories-swiper-button-next {
|
|
168
|
+
right: 20px;
|
|
169
|
+
}
|
|
170
|
+
</style>
|
|
171
|
+
<script>
|
|
172
|
+
;(() => {
|
|
173
|
+
class ZZAccessoriesPreviewSwiper extends HTMLElement {
|
|
174
|
+
constructor() {
|
|
175
|
+
super();
|
|
176
|
+
this._thumbs = null;
|
|
177
|
+
this._swiper = null;
|
|
178
|
+
this._listEl = null;
|
|
179
|
+
this._thumbsEl = null;
|
|
180
|
+
this._paginationEl = null;
|
|
181
|
+
this._btnPrev = null;
|
|
182
|
+
this._btnNext = null;
|
|
183
|
+
this._initialized = false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
connectedCallback() {
|
|
187
|
+
const init = () => {
|
|
188
|
+
if (this._initialized) return;
|
|
189
|
+
if (typeof Swiper === 'undefined') return;
|
|
190
|
+
this._ensureElements();
|
|
191
|
+
this._initSwipers();
|
|
192
|
+
this._initialized = true;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (document.readyState === 'loading') {
|
|
196
|
+
document.addEventListener('DOMContentLoaded', init, { once: true });
|
|
197
|
+
} else {
|
|
198
|
+
init();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
disconnectedCallback() {
|
|
203
|
+
this._destroySwipers();
|
|
204
|
+
this._initialized = false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
_ensureElements() {
|
|
208
|
+
this._listEl = this.querySelector('.product-accessories-swiper-list');
|
|
209
|
+
this._thumbsEl = this.querySelector('.product-accessories-swiper-list-thumbs');
|
|
210
|
+
if (!this._listEl || !this._thumbsEl) return;
|
|
211
|
+
this._paginationEl = this._listEl.querySelector('.swiper-pagination');
|
|
212
|
+
this._btnPrev = this._listEl.querySelector('.product-accessories-swiper-button-prev');
|
|
213
|
+
this._btnNext = this._listEl.querySelector('.product-accessories-swiper-button-next');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
_initSwipers() {
|
|
217
|
+
if (!this._listEl || !this._thumbsEl) return;
|
|
218
|
+
|
|
219
|
+
this._thumbs = new Swiper(this._thumbsEl, {
|
|
220
|
+
slidesPerView: 5,
|
|
221
|
+
spaceBetween: 8,
|
|
222
|
+
watchSlidesProgress: true,
|
|
223
|
+
slideToClickedSlide: true,
|
|
224
|
+
breakpoints: {
|
|
225
|
+
0: { slidesPerView: 4, spaceBetween: 6 },
|
|
226
|
+
768: { slidesPerView: 5, spaceBetween: 8 },
|
|
227
|
+
1024: { slidesPerView: 6, spaceBetween: 10 },
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const loopedSlides = {{ product.metafields.custom.acc_images.value.size | default: 0 }};
|
|
232
|
+
this._swiper = new Swiper(this._listEl, {
|
|
233
|
+
loop: true,
|
|
234
|
+
navigation: {
|
|
235
|
+
nextEl: this._btnNext,
|
|
236
|
+
prevEl: this._btnPrev,
|
|
237
|
+
},
|
|
238
|
+
effect: 'fade',
|
|
239
|
+
loopedSlides: loopedSlides,
|
|
240
|
+
slidesPerView: 1,
|
|
241
|
+
spaceBetween: 10,
|
|
242
|
+
pagination: {
|
|
243
|
+
el: this._paginationEl,
|
|
244
|
+
clickable: true,
|
|
245
|
+
},
|
|
246
|
+
thumbs: { swiper: this._thumbs },
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
_destroySwipers() {
|
|
251
|
+
try {
|
|
252
|
+
this._swiper && this._swiper.destroy(true, true);
|
|
253
|
+
} catch (e) {}
|
|
254
|
+
try {
|
|
255
|
+
this._thumbs && this._thumbs.destroy(true, true);
|
|
256
|
+
} catch (e) {}
|
|
257
|
+
this._swiper = null;
|
|
258
|
+
this._thumbs = null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!customElements.get('zz-accessories-preview-swiper')) {
|
|
263
|
+
customElements.define('zz-accessories-preview-swiper', ZZAccessoriesPreviewSwiper);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
window.accessoriesPointClickHandler = async function(eventOrElement, variantId) {
|
|
267
|
+
const element =
|
|
268
|
+
eventOrElement?.currentTarget ||
|
|
269
|
+
(eventOrElement instanceof Event ? eventOrElement.target : eventOrElement);
|
|
270
|
+
|
|
271
|
+
if (!(element instanceof Element)) {
|
|
272
|
+
console.warn('accessoriesPointClickHandler: expected an Element but got', eventOrElement);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const buyIcon = element.querySelector('.buy-icon');
|
|
277
|
+
const buyDoneIcon = element.querySelector('.buy-done-icon');
|
|
278
|
+
if (buyIcon) buyIcon.style.display = 'none';
|
|
279
|
+
if (buyDoneIcon) buyDoneIcon.style.display = 'block';
|
|
280
|
+
const data = {
|
|
281
|
+
items: [
|
|
282
|
+
{
|
|
283
|
+
id: variantId,
|
|
284
|
+
quantity: 1,
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
sections: 'cart-drawer,cart-icon-bubble',
|
|
288
|
+
};
|
|
289
|
+
const cart = document.querySelector('cart-drawer');
|
|
290
|
+
|
|
291
|
+
await fetch(`${routes.cart_add_url}`, {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
headers: {
|
|
294
|
+
'Content-Type': 'application/json',
|
|
295
|
+
Accept: 'application/javascript',
|
|
296
|
+
},
|
|
297
|
+
body: JSON.stringify(data),
|
|
298
|
+
})
|
|
299
|
+
.then((response) => response.json())
|
|
300
|
+
.then((response) => {
|
|
301
|
+
if (response.status) {
|
|
302
|
+
publish(PUB_SUB_EVENTS.cartError, {
|
|
303
|
+
source: 'product-form',
|
|
304
|
+
productVariantId: variantId,
|
|
305
|
+
errors: response.errors || response.description,
|
|
306
|
+
message: response.message,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
publish(PUB_SUB_EVENTS.cartUpdate, {
|
|
311
|
+
source: 'product-form',
|
|
312
|
+
productVariantId: variantId,
|
|
313
|
+
cartData: response,
|
|
314
|
+
});
|
|
315
|
+
cart.renderContents(response, false);
|
|
316
|
+
zzShowToast('1 item added to Cart', { type: 'success' });
|
|
317
|
+
})
|
|
318
|
+
.catch((e) => {
|
|
319
|
+
console.error(e);
|
|
320
|
+
})
|
|
321
|
+
.finally(() => {
|
|
322
|
+
setTimeout(() => {
|
|
323
|
+
if (buyIcon) buyIcon.style.display = 'block';
|
|
324
|
+
if (buyDoneIcon) buyDoneIcon.style.display = 'none';
|
|
325
|
+
}, 3000);
|
|
326
|
+
if (cart && cart.classList.contains('is-empty'))
|
|
327
|
+
cart.classList.remove('is-empty');
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
})();
|
|
331
|
+
</script>
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
<gallery-tab>
|
|
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
|
|
4
|
+
class='gallery-tab-item active'
|
|
5
|
+
data-test-locator='galleryTabItemPhoto'
|
|
6
|
+
data-test-value='photo'
|
|
7
|
+
>
|
|
8
|
+
<div class='gallery-tab-item-text'>
|
|
9
|
+
<svg
|
|
10
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
11
|
+
width='16'
|
|
12
|
+
height='16'
|
|
13
|
+
viewBox='0 0 16 16'
|
|
14
|
+
fill='none'
|
|
15
|
+
>
|
|
16
|
+
<path d="M1 4.5V12.5C1 13.0523 1.44772 13.5 2 13.5H14" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
|
|
17
|
+
<rect x="3" y="3.5" width="12" height="8" rx="0.5" stroke="black"/>
|
|
18
|
+
<path d="M3 11L6 8L8 9.5L10.5 7L14.5 11" stroke="black" stroke-linejoin="round"/>
|
|
19
|
+
<circle cx="5.75" cy="5.75" r="0.75" fill="black"/>
|
|
20
|
+
</svg>
|
|
21
|
+
<span class='gallery-tab-item-text-span'> Photo </span>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
{% if show_accessories_point %}
|
|
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>
|
|
41
|
+
|
|
42
|
+
<span class='gallery-tab-item-text-span'> Accessories </span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
{% endif %}
|
|
46
|
+
{% if show_video %}
|
|
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>
|
|
65
|
+
</div>
|
|
66
|
+
{% endif %}
|
|
67
|
+
{% if show_model %}
|
|
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>
|
|
89
|
+
</div>
|
|
90
|
+
{% endif %}
|
|
91
|
+
</div>
|
|
92
|
+
</gallery-tab>
|
|
93
|
+
|
|
94
|
+
<style>
|
|
95
|
+
.gallery-tab-item {
|
|
96
|
+
padding: 3px 16px;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
display: inline-block;
|
|
99
|
+
border-radius: 100px;
|
|
100
|
+
background: #fff;
|
|
101
|
+
color: #000;
|
|
102
|
+
font-size: 14px;
|
|
103
|
+
font-weight: 400;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@media screen and (max-width: 1024px) {
|
|
107
|
+
.gallery-tab-item {
|
|
108
|
+
padding: 8px 10px;
|
|
109
|
+
font-size: 12px !important;
|
|
110
|
+
line-height: 12px;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
.gallery-tab-item:hover {
|
|
114
|
+
background: #f5f5f5;
|
|
115
|
+
}
|
|
116
|
+
.gallery-tab-item.active {
|
|
117
|
+
color: #fff;
|
|
118
|
+
background: #000;
|
|
119
|
+
}
|
|
120
|
+
.gallery-tab-item-text {
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
gap: 8px;
|
|
125
|
+
}
|
|
126
|
+
.gallery-tab-item svg {
|
|
127
|
+
transition: filter 0.2s ease, fill 0.2s ease, stroke 0.2s ease;
|
|
128
|
+
}
|
|
129
|
+
.gallery-tab-item.active svg {
|
|
130
|
+
filter: invert(1);
|
|
131
|
+
}
|
|
132
|
+
.gallery-tab-item-text-span {
|
|
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
|
+
}
|
|
144
|
+
</style>
|
|
145
|
+
|
|
146
|
+
<script>
|
|
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');
|
|
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;
|
|
182
|
+
}
|
|
183
|
+
disconnectedCallback() {
|
|
184
|
+
this._items.forEach((item) => {
|
|
185
|
+
item.removeEventListener('click', this._onItemClick, false);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
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;
|
|
240
|
+
item.classList.toggle('active', isActive);
|
|
241
|
+
item.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
|
242
|
+
if (isActive) matched = true;
|
|
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
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (!customElements.get('gallery-tab')) {
|
|
254
|
+
customElements.define('gallery-tab', GalleryTab);
|
|
255
|
+
}
|
|
256
|
+
})();
|
|
257
|
+
</script>
|