zz-shopify-components 0.24.1-beta.3 → 0.25.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.
@@ -1,248 +0,0 @@
1
- <zz-product-swiper class=' tw-w-full product-swiper-container tw-h-full tw-relative'>
2
- <div class='swiper product-swiper-list tw-w-full tw-h-full tw-relative'>
3
- <div class='swiper-wrapper'>
4
- {% assign product_images = product.selected_or_first_available_variant.metafields.custom.images.value | default: product.images %}
5
- {% for image in product_images %}
6
- <div class='swiper-slide tw-flex tw-justify-center'>
7
- {% assign fetchpriority = 'auto' %}
8
- {% if forloop.first %}
9
- {% assign fetchpriority = 'high' %}
10
- {% endif %}
11
- {{
12
- image
13
- | image_url: width: 3000
14
- | image_tag:
15
- loading: 'lazy',
16
- class: 'tw-w-auto tw-h-full tw-max-w-full tw-object-cover tw-m-auto',
17
- sizes: '(min-width: 750px) 700px, calc(100vw - 30px)',
18
- widths: '3000, 4000, 5000',
19
- fetchpriority: fetchpriority
20
- }}
21
- </div>
22
- {% endfor %}
23
- </div>
24
- <div class='swiper-pagination'></div>
25
- <div class='product-swiper-button-prev'>
26
- {% render 'zz-prev-next-btn', type: 'prev', color_type: 'dark' %}
27
- </div>
28
- <div class='product-swiper-button-next'>
29
- {% render 'zz-prev-next-btn', type: 'next', color_type: 'dark' %}
30
- </div>
31
- </div>
32
-
33
- <div class=' tw-absolute tw-bottom-[20px] tw-left-1/2 tw-transform tw-translate-x-[-50%] tw-z-10 tw-w-[80%] '>
34
- <div class='swiper product-swiper-list-thumbs tw-opacity-0'>
35
- <div class='swiper-wrapper tw-flex tw-justify-center'>
36
- {% for image in product_images %}
37
- <div class='swiper-slide !tw-w-auto tw-opacity-30'>
38
- {{
39
- image
40
- | image_url: width: 200
41
- | image_tag:
42
- loading: 'lazy',
43
- class: 'lg:tw-w-[50px] tw-w-[40px] tw-aspect-square tw-object-cover tw-rounded-[6px] ',
44
- sizes: '(min-width: 750px) 50px, calc(100vw - 30px)',
45
- widths: '50, 100, 150'
46
- }}
47
- </div>
48
- {% endfor %}
49
- </div>
50
- </div>
51
- </div>
52
- </zz-product-swiper>
53
-
54
- <style>
55
- .product-swiper-container .swiper-pagination {
56
- --swiper-pagination-color: black;
57
- --swiper-pagination-bottom: 10px;
58
- }
59
- .product-swiper-container .swiper-pagination,
60
- .product-swiper-list-thumbs {
61
- transition: opacity 0.2s ease-in-out;
62
- }
63
- .product-swiper-list-thumbs {
64
- transform: translateY(12px) scale(0.96);
65
- transform-origin: bottom center;
66
- will-change: opacity, transform;
67
- transition:
68
- opacity 0.25s ease,
69
- transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
70
- }
71
- .product-swiper-container:hover .product-swiper-list-thumbs {
72
- opacity: 1;
73
- transform: translateY(0) scale(1);
74
- }
75
- .product-swiper-container:hover .swiper-pagination {
76
- display: none;
77
- transition: none;
78
- }
79
-
80
- .product-swiper-list-thumbs .swiper-slide {
81
- border: 1px solid black;
82
- border-radius: 6px;
83
- }
84
-
85
- .product-swiper-list-thumbs .swiper-slide-thumb-active {
86
- opacity: 1;
87
- border: 1px solid black;
88
- border-radius: 6px;
89
- }
90
- .product-swiper-button-prev,
91
- .product-swiper-button-next {
92
- position: absolute;
93
- top: 50%;
94
- transform: translateY(-50%);
95
- z-index: 10;
96
- cursor: pointer;
97
- pointer-events: auto;
98
- }
99
- @media screen and (max-width: 1024px) {
100
- .product-swiper-button-prev { display: none; }
101
- .product-swiper-button-next { display: none; }
102
- }
103
- .product-swiper-button-prev { left: 20px; }
104
- .product-swiper-button-next { right: 20px; }
105
- </style>
106
- <script>
107
- ;(() => {
108
- class ZZProductSwiper extends HTMLElement {
109
- constructor() {
110
- super();
111
- this._swiper = null;
112
- this._thumbs = null;
113
- this._listEl = null;
114
- this._thumbsEl = null;
115
- this._paginationEl = null;
116
- this._btnPrev = null;
117
- this._btnNext = null;
118
- }
119
-
120
- connectedCallback() {
121
- console.log(typeof Swiper,121212121);
122
- if (typeof Swiper !== 'undefined') {
123
- this._ensureStructure();
124
- this._initSwipers();
125
- } else {
126
- document.addEventListener('DOMContentLoaded', () => {
127
- this._ensureStructure();
128
- this._initSwipers();
129
- });}
130
- }
131
-
132
- disconnectedCallback() {
133
- this._destroySwipers();
134
- }
135
-
136
- setImages(imageUrls) {
137
- const newImages = {{product.selected_or_first_available_variant.metafields.custom.images.value | json}};
138
- console.log(newImages);
139
- if (!Array.isArray(imageUrls)) return;
140
- this._rebuildSlides(imageUrls);
141
- this._reinitSwipers(imageUrls.length);
142
- }
143
-
144
- _ensureStructure() {
145
- this._listEl = this.querySelector('.product-swiper-list');
146
- if (!this._listEl) {
147
- const list = document.createElement('div');
148
- list.className = 'swiper product-swiper-list tw-w-full tw-h-full tw-relative';
149
- list.innerHTML = `
150
- <div class="swiper-wrapper"></div>
151
- <div class="swiper-pagination"></div>
152
- <div class="product-swiper-button-prev"></div>
153
- <div class="product-swiper-button-next"></div>
154
- `;
155
- this.appendChild(list);
156
- this._listEl = list;
157
- }
158
- this._thumbsEl = this.querySelector('.product-swiper-list-thumbs');
159
- if (!this._thumbsEl) {
160
- const wrap = document.createElement('div');
161
- wrap.className = ' tw-absolute tw-bottom-[20px] tw-left-1/2 tw-transform tw-translate-x-[-50%] tw-z-10 tw-w-[80%] ';
162
- const thumbs = document.createElement('div');
163
- thumbs.className = 'swiper product-swiper-list-thumbs tw-opacity-0';
164
- thumbs.innerHTML = `<div class="swiper-wrapper tw-flex tw-justify-center"></div>`;
165
- wrap.appendChild(thumbs);
166
- this.appendChild(wrap);
167
- this._thumbsEl = thumbs;
168
- }
169
- this._paginationEl = this._listEl.querySelector('.swiper-pagination');
170
- this._btnPrev = this._listEl.querySelector('.product-swiper-button-prev');
171
- this._btnNext = this._listEl.querySelector('.product-swiper-button-next');
172
- }
173
-
174
- _initSwipers() {
175
- if (typeof Swiper === 'undefined') return;
176
- // Thumbs
177
- this._thumbs = new Swiper(this._thumbsEl, {
178
- slidesPerView: 5,
179
- spaceBetween: 8,
180
- watchSlidesProgress: true,
181
- slideToClickedSlide: true,
182
- breakpoints: {
183
- 0: { slidesPerView: 4, spaceBetween: 6 },
184
- 768: { slidesPerView: 5, spaceBetween: 8 },
185
- 1024:{ slidesPerView: 6, spaceBetween: 10 }
186
- }
187
- });
188
- // Main
189
- const initialCount = this._listEl.querySelectorAll('.swiper-slide').length;
190
- this._swiper = new Swiper(this._listEl, {
191
- loop: true,
192
- effect: 'slide',
193
- loopedSlides: initialCount,
194
- slidesPerView: 1,
195
- spaceBetween: 10,
196
- pagination: {
197
- el: this._paginationEl,
198
- clickable: true
199
- },
200
- navigation: {
201
- nextEl: this._btnNext,
202
- prevEl: this._btnPrev
203
- },
204
- thumbs: { swiper: this._thumbs }
205
- });
206
- }
207
-
208
- _destroySwipers() {
209
- try { this._swiper && this._swiper.destroy(true, true); } catch(_) {}
210
- try { this._thumbs && this._thumbs.destroy(true, true); } catch(_) {}
211
- this._swiper = null;
212
- this._thumbs = null;
213
- }
214
-
215
- _rebuildSlides(imageUrls) {
216
- const listWrapper = this._listEl.querySelector('.swiper-wrapper');
217
- const thumbsWrapper = this._thumbsEl.querySelector('.swiper-wrapper');
218
- if (!listWrapper || !thumbsWrapper) return;
219
- // Clear
220
- listWrapper.innerHTML = '';
221
- thumbsWrapper.innerHTML = '';
222
- // Build
223
- imageUrls.forEach((url) => {
224
- const slide = document.createElement('div');
225
- slide.className = 'swiper-slide tw-flex tw-justify-center';
226
- slide.innerHTML =
227
- `<img src="${url}" alt="product image" class="tw-w-auto tw-h-full tw-max-w-full tw-object-cover tw-m-auto">`;
228
- listWrapper.appendChild(slide);
229
-
230
- const tSlide = document.createElement('div');
231
- tSlide.className = 'swiper-slide !tw-w-auto tw-opacity-30';
232
- tSlide.innerHTML =
233
- `<img src="${url}" alt="thumb" class="lg:tw-w-[50px] tw-w-[40px] tw-aspect-square tw-object-cover tw-rounded-[6px]">`;
234
- thumbsWrapper.appendChild(tSlide);
235
- });
236
- }
237
-
238
- _reinitSwipers(count) {
239
- this._destroySwipers();
240
- this._initSwipers();
241
- }
242
- }
243
-
244
- if (!customElements.get('zz-product-swiper')) {
245
- customElements.define('zz-product-swiper', ZZProductSwiper);
246
- }
247
- })();
248
- </script>
@@ -1,109 +0,0 @@
1
- {%- assign intro_video = product.metafields.custom.intro_video.value -%}
2
- {%- assign livestream_video = product.metafields.custom.livestream_video.value -%}
3
-
4
- <product-video-tab class=" tw-w-full tw-h-full ">
5
- <video data-type="intro" src='{{ intro_video.sources[0].url }}' poster='{{intro_video.preview_image | image_url: width: 1000}}' controls class=" tw-w-full tw-h-full tw-bg-black tw-hidden"></video>
6
- <video data-type="livestream" src='{{ livestream_video.sources[0].url }}' poster='{{intro_video.preview_image | image_url: width: 1000}}' controls class=" tw-w-full tw-h-full tw-bg-black tw-hidden"></video>
7
- <div class=" product-video-tabs tw-absolute tw-left-1/2 tw--translate-x-1/2 tw-top-[30px] tw-bg-white ">
8
- <div class=" tw-grid tw-grid-cols-2 tw-relative">
9
- <button type="button" class="product-video-tab-item" data-tab="intro">Introduction</button>
10
- <button type="button" class="product-video-tab-item" data-tab="livestream">Livestream</button>
11
- <div 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"></div>
12
- </div>
13
- </div>
14
- </product-video-tab>
15
-
16
-
17
- <style>
18
- .product-video-tabs {
19
- border-radius: 999px;
20
- background-color: rgba(255, 255, 255, 0.3);
21
- backdrop-filter: blur(10px);
22
- }
23
- .product-video-tab-item {
24
- color: #fff;
25
- z-index: 10;
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;
41
- }
42
- </style>
43
-
44
- <script>
45
- (() => {
46
- class ProductVideoTab extends HTMLElement {
47
- constructor() {
48
- super();
49
- this.currentTab = 'intro';
50
- }
51
-
52
- connectedCallback() {
53
- this.cacheDom();
54
- if (!this.buttons.length || !this.videos.length) return;
55
- this.changeTab(true);
56
- this.attachEvents();
57
- }
58
-
59
- cacheDom() {
60
- this.buttons = Array.from(this.querySelectorAll('.product-video-tab-item'));
61
- this.videos = Array.from(this.querySelectorAll('video[data-type]'));
62
- this.slider = this.querySelector('.product-video-tab-slider');
63
- }
64
-
65
- attachEvents() {
66
- this.buttons.forEach(button => {
67
- button.addEventListener('click', () => {
68
- const nextTab = button.dataset.tab;
69
- if (!nextTab || nextTab === this.currentTab) return;
70
- this.currentTab = nextTab;
71
- this.changeTab();
72
- });
73
- });
74
- }
75
-
76
- changeTab(isInitial = false) {
77
- this.videos.forEach(video => {
78
- const isActive = video.dataset.type === this.currentTab;
79
- video.style.display = isActive ? 'block' : 'none';
80
- if (isActive) {
81
- const playPromise = video.play();
82
- if (playPromise && typeof playPromise.catch === 'function' && !isInitial) {
83
- playPromise.catch(() => {});
84
- }
85
- } else {
86
- video.pause();
87
- }
88
- });
89
-
90
- this.buttons.forEach(button => {
91
- const isActive = button.dataset.tab === this.currentTab;
92
- button.style.color = isActive ? '#000' : '#fff';
93
- });
94
-
95
- if (!this.slider) return;
96
- if (this.currentTab === 'intro') {
97
- this.slider.style.left = '0';
98
- this.slider.style.right = 'auto';
99
- } else {
100
- this.slider.style.right = '0';
101
- this.slider.style.left = 'auto';
102
- }
103
- }
104
- }
105
-
106
- customElements.define('product-video-tab', ProductVideoTab);
107
- })();
108
-
109
- </script>