jeawin-astro 3.0.90 → 3.0.91

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jeawin-astro",
3
- "version": "3.0.90",
3
+ "version": "3.0.91",
4
4
  "author": "chaegumi <chaegumi@qq.com>",
5
5
  "description": "",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@ let num = 0;
46
46
  if(nodepics && nodepics.length > 1){
47
47
  num=num+nodepics.length;
48
48
  }
49
- if(video){
49
+ if(video && video.poster){
50
50
  num = num + 1;
51
51
  }
52
52
  if(view360){
@@ -68,6 +68,11 @@ if(num > 1){
68
68
  if(iframe){
69
69
  iframe.src = iframe.src;
70
70
  }
71
+
72
+ const video = this.$refs.video.querySelector('video');
73
+ if(video){
74
+ video.pause();
75
+ }
71
76
  }
72
77
  this.isVideoPoppedUp = false;
73
78
  },
@@ -110,7 +115,7 @@ if(num > 1){
110
115
  }
111
116
 
112
117
  {
113
- video ? (
118
+ video && video.poster ? (
114
119
  <swiper-slide class="swiper-slide lg:flex-0 lg:h-[60px] lg:w-[60px] hidden">
115
120
  <div class="content-wrapper border border-white min-h-[100px] lg:min-h-[60px] p-1 cursor-pointer flex items-center justify-center">
116
121
  <Icon name="fa6-solid:file-video" class="size-10" />
@@ -155,7 +160,7 @@ if(num > 1){
155
160
  }
156
161
 
157
162
  {
158
- video ? (
163
+ video && video.poster ? (
159
164
  <swiper-slide class="swiper-slide hidden" lazy="true">
160
165
  <div class="flex min-h-[343px] xl:min-h-[605px] w-full">
161
166
  <img src={video.poster} alt={video.title ? video.title : node_title} />
@@ -188,7 +193,7 @@ if(num > 1){
188
193
 
189
194
  </swiper-container>
190
195
  {
191
- video ? (
196
+ video && video.poster ? (
192
197
  <div x-ref="video"
193
198
  x-bind:class="{ 'flex': isVideoPoppedUp, 'hidden': !isVideoPoppedUp }"
194
199
  class="fixed inset-0 w-full h-full flex items-center justify-center hidden z-[100000]"
@@ -0,0 +1,413 @@
1
+ ---
2
+ /**
3
+ * 产品详情页图片展示组件-splide版
4
+ *
5
+ * jeawin-astro/src/components/detail_images_splide.astro
6
+ *
7
+ * @package jeawin-astro
8
+ * @author Chaegumi
9
+ * @copyright Copyright (c) 2025-2099 jeawin.com
10
+ * @email chaegumi@jeawin.com
11
+ * @filesource
12
+ */
13
+ import { Icon } from "astro-icon/components";
14
+ import Youtube from "./youtube.astro";
15
+ import Vimeo from "./vimeo.astro";
16
+ import { img_add_link, render_value,img_change_attrs } from "../scripts/util.js";
17
+ import view360img from "../assets/images/360_view.svg";
18
+ import IframeVideo from "./iframe_video.astro";
19
+ import JeawinImage from "./image.astro";
20
+
21
+ type JWVIDEO = {
22
+ poster: string; // 图片
23
+ type: string; // [local, remote, code]
24
+ local_url?: string; // 本地视频地址
25
+ platform?: string; // 平台youtube,vimeo
26
+ id?: string; // 平台上的视频id或者远程地址
27
+ params?: any; // 参数
28
+ title?: any; // 标题
29
+ code?: any; // 视频的代码,如<iframe>
30
+ };
31
+ interface Props {
32
+ node_title?: any;
33
+ nodepics?: any[]; // 产品图片
34
+ video?: JWVIDEO; // 产品视频
35
+ view360?: any; // 360 view
36
+ thumbs_position?: string;
37
+ }
38
+ const { node_title, nodepics = [], video, view360 } = Astro.props;
39
+
40
+ const thumbs_position: string = 'bottom';
41
+
42
+ let show_thumbs = false;
43
+
44
+ let num = 0;
45
+
46
+ if(nodepics && nodepics.length > 1){
47
+ num=num+nodepics.length;
48
+ }
49
+ if(video && video.poster){
50
+ num = num + 1;
51
+ }
52
+ if(view360){
53
+ num = num + 1;
54
+ }
55
+
56
+ if(num > 1){
57
+ show_thumbs = true;
58
+ }
59
+ ---
60
+
61
+ <custom-detail-images
62
+ data-nodepics={nodepics}
63
+ data-video={video}
64
+ data-view360={view360}
65
+ data-thumbs_position={thumbs_position}
66
+ data-show_thumbs={show_thumbs}
67
+ >
68
+ <div
69
+ x-data={`{
70
+ isVideoPoppedUp:false,
71
+ closeVideo(){
72
+ if(this.$refs.video){
73
+ const iframe = this.$refs.video.querySelector('iframe');
74
+ if(iframe){
75
+ iframe.src = iframe.src;
76
+ }
77
+
78
+ const video = this.$refs.video.querySelector('video');
79
+ if(video){
80
+ video.pause();
81
+ }
82
+ }
83
+ this.isVideoPoppedUp = false;
84
+ },
85
+ openVideo(){
86
+ this.isVideoPoppedUp = true;
87
+ }
88
+ }`}
89
+ >
90
+ <div class:list={["flex flex-col", {"lg:flex-row":thumbs_position=='left'}, "gap-4"]}>
91
+
92
+
93
+ <section class="mainSplide splide" aria-label={node_title}>
94
+ <div class="splide__track">
95
+ <ul class="splide__list">
96
+ {
97
+ nodepics.map((pic: any, idx: number) => (
98
+ <li class:list={["splide__slide"]}>
99
+ <div class="magnifier">
100
+ <JeawinImage img_html={pic} loading={idx > 0 ? "lazy" : "eager"} fetchpriority={idx > 0 ? 'low' : 'high'} />
101
+ </div>
102
+
103
+ </li>
104
+ ))
105
+ }
106
+
107
+ {
108
+ video && video.poster ? (
109
+ <li class="splide__slide">
110
+ <div class="flex min-h-[343px] xl:min-h-[605px] w-full">
111
+ <img src={video.poster} alt={video.title ? video.title : node_title} />
112
+ <button
113
+ class="absolute cursor-pointer w-16 h-16 rounded-full inset-0 m-auto duration-150 bg-blue-500 hover:bg-blue-600 ring-offset-2 focus:ring-3 focus:ring-blue-500 text-white"
114
+ x-on:click="openVideo()"
115
+ >
116
+ <svg
117
+ xmlns="http://www.w3.org/2000/svg"
118
+ viewBox="0 0 20 20"
119
+ fill="currentColor"
120
+ class="w-6 h-6 m-auto"
121
+ >
122
+ <path d="M6.3 2.841A1.5 1.5 0 004 4.11V15.89a1.5 1.5 0 002.3 1.269l9.344-5.89a1.5 1.5 0 000-2.538L6.3 2.84z" />
123
+ </svg>
124
+ </button>
125
+ </div>
126
+ </li>
127
+ ) : null
128
+ }
129
+
130
+ {
131
+ view360 ? (
132
+ <li class="splide__slide no-drag">
133
+ <div class="cloudimage-360 swiper-no-swiping no-drag" data-image-list-x={`${JSON.stringify(view360)}`} data-magnifier="2" data-fullscreen>
134
+ </div>
135
+ </li>
136
+ ) : null
137
+ }
138
+ </ul>
139
+ </div>
140
+ </section>
141
+ {show_thumbs ? (
142
+ <section class="thumbnailSplide splide w-full px-8" aria-label={node_title}>
143
+ <div class="splide__track">
144
+ <ul class="splide__list">
145
+ {
146
+ nodepics.map((pic: any, idx: number) => (
147
+ <li class="splide__slide">
148
+ <div class="content-wrapper border border-white p-1 h-full cursor-pointer overflow-hidden flex items-center justify-center">
149
+ <JeawinImage img_html={pic} add_classes="lazyload" />
150
+ </div>
151
+ </li>
152
+ ))
153
+ }
154
+
155
+ {
156
+ video && video.poster ? (
157
+ <li class="splide__slide">
158
+ <div class="content-wrapper border border-white p-1 h-full cursor-pointer flex items-center justify-center">
159
+ <Icon name="fa6-solid:file-video" class="size-10" />
160
+ </div>
161
+ </li>
162
+ ) : null
163
+ }
164
+
165
+ {
166
+ view360 ? (
167
+ <li class="splide__slide">
168
+ <div class="content-wrapper border border-white p-1 h-full cursor-pointer">
169
+ <img src={view360img.src} alt="360° viewer" />
170
+ </div>
171
+ </li>
172
+ ) : null
173
+ }
174
+ </ul>
175
+ </div>
176
+ </section>
177
+ ) : null}
178
+
179
+ {
180
+ video && video.poster ? (
181
+ <div x-ref="video"
182
+ x-bind:class="{ 'flex': isVideoPoppedUp, 'hidden': !isVideoPoppedUp }"
183
+ class="fixed inset-0 w-full h-full flex items-center justify-center hidden z-[100000]"
184
+ >
185
+ <div
186
+ class="absolute inset-0 w-full h-full bg-black/50"
187
+ x-on:click="closeVideo()"
188
+ >
189
+ </div>
190
+ <div class="px-4 relative">
191
+ <button
192
+ class="w-12 h-12 mb-5 rounded-full duration-150 bg-gray-800 hover:bg-gray-700 text-white cursor-pointer"
193
+ x-on:click="closeVideo()"
194
+ >
195
+ <svg
196
+ xmlns="http://www.w3.org/2000/svg"
197
+ viewBox="0 0 20 20"
198
+ fill="currentColor"
199
+ class="w-5 h-5 m-auto"
200
+ >
201
+ <path
202
+ d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
203
+ ></path>
204
+ </svg>
205
+ </button>
206
+ {
207
+ video.type == 'remote' ? (
208
+ <Fragment>
209
+ {render_value(video, 'id') ? (
210
+ <Fragment>
211
+ {
212
+ video.platform == 'youtube' ? (
213
+ <Youtube id={render_value(video, 'id')} />
214
+ ) : video.platform == 'vimeo' ? (
215
+ <Vimeo id={render_value(video, 'id')} />
216
+ ) : (
217
+ <IframeVideo id={render_value(video, 'id')} />
218
+ )
219
+ }
220
+ </Fragment>
221
+ ) : null}
222
+
223
+ </Fragment>
224
+ ) : video.type == 'code' ? (
225
+ <Fragment set:html={video.code} />
226
+ ) : (
227
+ <video class="rounded-lg w-full max-w-2xl" controls>
228
+ <source src={video.local_url} type="video/mp4" />
229
+ </video>
230
+ )
231
+ }
232
+ </div>
233
+ </div>
234
+ ) : null
235
+ }
236
+ </div>
237
+ </div>
238
+ </custom-detail-images>
239
+ <script
240
+ is:inline
241
+ src="/js-cloudimage-360-view/build/js-cloudimage-360-view.min.js" async defer
242
+ ></script>
243
+ {
244
+ view360 ? (
245
+ <Fragment>
246
+ <script is:inline>
247
+ window.CI360 = { notInitOnLoad: true };
248
+ </script>
249
+
250
+ </Fragment>
251
+ ) : null
252
+ }
253
+ <style is:inline>
254
+ .mainSplide{
255
+ width:100%;
256
+ height:10%;
257
+ }
258
+ .splide{
259
+ margin:0 auto;
260
+ }
261
+ .splide__slide img{
262
+ width:100%;
263
+ /* height: auto; */
264
+ height:100%;
265
+ object-fit: cover;
266
+ }
267
+ .splide__slide {
268
+ opacity: 0.6;
269
+ }
270
+
271
+ .splide__slide.is-active {
272
+ opacity: 1;
273
+ }
274
+ .splide__arrows{
275
+ /* position: relative; */
276
+ }
277
+ .splide__arrow--prev{
278
+ left:-0.5rem;
279
+ /* transform: scaleX(-1) translateY(-50%); */
280
+ /* top: 50%; */
281
+ /* transform: translate3d(0, -50%, 0); */
282
+ }
283
+ .splide__arrow--next{
284
+ right:-0.5rem;
285
+ /* transform: translateY(-50%); */
286
+ }
287
+ </style>
288
+ <style is:inline>
289
+ .cloudimage-360-fullscreen-modal{
290
+ z-index:100000!important;
291
+ }
292
+ </style>
293
+
294
+ <script>
295
+ import _ from 'lodash';
296
+ import Splide from "@splidejs/splide";
297
+ import { magnify} from "../scripts/magnify.js";
298
+
299
+ class CustomDetailImages extends HTMLElement {
300
+ isMagnifyOpen = false;
301
+ glass: any = null;
302
+
303
+ container: any = null;
304
+
305
+ magnify(event:any, currentOriginalImage: any){
306
+ event.stopPropagation();
307
+
308
+ if(this.isMagnifyOpen) return;
309
+
310
+ this.isMagnifyOpen = true;
311
+
312
+ currentOriginalImage.onload = () => {
313
+ if(this.glass){
314
+ this.glass.style.cursor = 'none';
315
+ }
316
+ }
317
+
318
+ this.glass = document.createElement('div');
319
+
320
+ this.glass.addEventListener('click', (e:any) => {
321
+ e.stopPropagation();
322
+ this.closeMagnifier();
323
+ })
324
+
325
+ this.container.style.overflow = 'hidden';
326
+
327
+ magnify(this.container, {x:0,y:0}, currentOriginalImage, this.glass, 3);
328
+
329
+ }
330
+
331
+ closeMagnifier(){
332
+
333
+ if(!this.glass) return;
334
+
335
+ this.container.style.overflow = 'visible';
336
+ this.container.style.zIndex = 100000;
337
+ this.container.removeChild(this.glass);
338
+
339
+ this.glass = null;
340
+ this.isMagnifyOpen = false;
341
+ }
342
+
343
+ constructor() {
344
+ super();
345
+
346
+ const magnifiers = this.querySelectorAll('.magnifier');
347
+ magnifiers.forEach((elem) => {
348
+ elem.addEventListener('click', (e) =>{
349
+ this.container = elem;
350
+ this.magnify(e, elem.querySelector('img'));
351
+ });
352
+ })
353
+
354
+ const view360 = this.dataset.view360;
355
+
356
+ const elemMain: any = this.querySelector('.mainSplide');
357
+ const main = new Splide(elemMain, {
358
+ type: 'fade',
359
+ rewind: true,
360
+ pagination: false,
361
+ arrows: false,
362
+ noDrag: 'input, textarea, .no-drag',
363
+ drag: false
364
+ });
365
+ const show_thumbs = this.dataset.show_thumbs;
366
+ // console.log(show_thumbs);
367
+ if(show_thumbs == 'true'){
368
+ const elemThumbnail: any = this.querySelector('.thumbnailSplide');
369
+ const thumbnails = new Splide(elemThumbnail,{
370
+ // width:'100vw',
371
+ // height:'100vh',
372
+ fixedWidth:100,
373
+ fixedHeight: 100,
374
+ gap:10,
375
+ rewind:true,
376
+ pagination: false,
377
+ cover: true,
378
+ // heightRatio: 0.5,
379
+ // focus: 'center',
380
+ // perPage: 2,
381
+ isNavigation: true,
382
+ breakpoints:{
383
+ 640:{
384
+ perPage:1,
385
+ fixedWidth: 60,
386
+ fixedHeight: 60
387
+ }
388
+ }
389
+ });
390
+ main.sync(thumbnails);
391
+ main.mount();
392
+ thumbnails.mount();
393
+ }else{
394
+ main.mount();
395
+ }
396
+
397
+ const thisSelf = this;
398
+
399
+ main.on("move", (e: any) => {
400
+
401
+ this.closeMagnifier();
402
+
403
+ if(view360){
404
+ // @ts-ignore
405
+ window.CI360.init();
406
+ }
407
+
408
+ });
409
+ }
410
+ }
411
+
412
+ customElements.define("custom-detail-images", CustomDetailImages);
413
+ </script>
@@ -13,6 +13,7 @@ export {default as CommentForm} from "./comment_form.astro";
13
13
  export {default as CommonCard} from "./common_card.astro";
14
14
  export {default as DefaultImage} from "./default_image.astro";
15
15
  export {default as DetailImages} from "./detail_images.astro";
16
+ export {default as DetailImagesSplide} from "./detail_images_splide.astro";
16
17
  export {default as FilterLinksHtml} from "./filter_links_html.astro";
17
18
  export {default as FilterLinks} from "./filter_links.astro";
18
19
  export {default as Form} from "./form.astro";
@@ -0,0 +1,66 @@
1
+ ---
2
+ import '@splidejs/splide/css';
3
+ ---
4
+ <image-carousel>
5
+ <section class="splide" aria-label="Beautiful Images">
6
+ <div class="splide__track">
7
+ <ul class="splide__list">
8
+ <li class="splide__slide">
9
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="" />
10
+ <div>
11
+ Description 01
12
+ </div>
13
+ </li>
14
+ <li class="splide__slide">
15
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="" />
16
+ <div>
17
+ Description 02
18
+ </div>
19
+ </li>
20
+ <li class="splide__slide">
21
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="" />
22
+ <div>
23
+ Description 03
24
+ </div>
25
+ </li>
26
+ </ul>
27
+ </div>
28
+ </section>
29
+ </image-carousel>
30
+
31
+ <style>
32
+ .splide__slide img{
33
+ width:100%;
34
+ /* height: auto; */
35
+ height:100%;
36
+ object-fit: cover;
37
+ }
38
+ </style>
39
+ <script>
40
+ import Splide from "@splidejs/splide";
41
+
42
+ class ImageCarousel extends HTMLElement{
43
+ constructor(){
44
+ super()
45
+ }
46
+
47
+ connectedCallback() {
48
+ const elem: any = this.querySelector('.splide');
49
+ const splide = new Splide(elem,{
50
+ // width:'100vw',
51
+ // height:'100vh',
52
+ cover: true,
53
+ heightRatio: 0.3,
54
+ // perPage: 2,
55
+ // breakpoints:{
56
+ // 640:{
57
+ // perPage:1
58
+ // }
59
+ // }
60
+ });
61
+ splide.mount();
62
+ }
63
+ }
64
+
65
+ customElements.define('image-carousel', ImageCarousel);
66
+ </script>
@@ -0,0 +1,126 @@
1
+ ---
2
+ import '@splidejs/splide/css';
3
+ ---
4
+ <splide-gallery>
5
+ <section class="main-splide splide" aria-label="My Awesome Gallery">
6
+ <div class="splide__track">
7
+ <ul class="splide__list">
8
+ <li class="splide__slide">
9
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="">
10
+ </li>
11
+ <li class="splide__slide">
12
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="">
13
+ </li>
14
+ <li class="splide__slide">
15
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="">
16
+ </li>
17
+ <li class="splide__slide">
18
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="">
19
+ </li>
20
+ </ul>
21
+ </div>
22
+ </section>
23
+
24
+ <ul class="thumbnails">
25
+ <li class="thumbnail">
26
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="">
27
+ </li>
28
+ <li class="thumbnail">
29
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="">
30
+ </li>
31
+ <li class="thumbnail">
32
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="">
33
+ </li>
34
+ <li class="thumbnail">
35
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="">
36
+ </li>
37
+ </ul>
38
+ </splide-gallery>
39
+
40
+ <style>
41
+ .splide{
42
+ margin:0 auto;
43
+ }
44
+
45
+ .splide__slide img{
46
+ width:100%;
47
+ /* height: auto; */
48
+ height:100%;
49
+ object-fit: cover;
50
+ }
51
+
52
+ .thumbnails {
53
+ display: flex;
54
+ margin: 1rem auto 0;
55
+ padding: 0;
56
+ justify-content: center;
57
+ }
58
+
59
+ .thumbnail {
60
+ width: 70px;
61
+ height: 70px;
62
+ overflow: hidden;
63
+ list-style: none;
64
+ margin: 0 0.2rem;
65
+ cursor: pointer;
66
+ opacity: 0.3;
67
+ }
68
+
69
+ .thumbnail img {
70
+ width: 100%;
71
+ height: 100%;
72
+ object-fit: cover;
73
+ }
74
+
75
+ .thumbnail.is-active {
76
+ opacity: 1;
77
+ }
78
+ </style>
79
+ <script>
80
+ import Splide from "@splidejs/splide";
81
+
82
+ class SplideGallery extends HTMLElement{
83
+ constructor(){
84
+ super();
85
+ }
86
+
87
+ connectedCallback() {
88
+ // @ts-ignore
89
+ const splide = new Splide( this.querySelector('.main-splide'), {
90
+ width:600,
91
+ height:300,
92
+ pagination: false,
93
+ cover: true
94
+ } );
95
+
96
+ const thumbnails = this.querySelectorAll( '.thumbnail' );
97
+ let current: any;
98
+
99
+ for ( let i = 0; i < thumbnails.length; i++ ) {
100
+ initThumbnail( thumbnails[ i ], i );
101
+ }
102
+
103
+ function initThumbnail( thumbnail: any, index: number ) {
104
+ thumbnail.addEventListener( 'click', function () {
105
+ splide.go( index );
106
+ } );
107
+ }
108
+
109
+ splide.on( 'mounted move', function () {
110
+ const thumbnail: any = thumbnails[ splide.index ];
111
+
112
+ if ( thumbnail ) {
113
+ if ( current ) {
114
+ current.classList.remove( 'is-active' );
115
+ }
116
+
117
+ thumbnail.classList.add( 'is-active' );
118
+ current = thumbnail;
119
+ }
120
+ } );
121
+
122
+ splide.mount();
123
+ }
124
+ }
125
+ customElements.define('splide-gallery', SplideGallery);
126
+ </script>
@@ -0,0 +1,141 @@
1
+ ---
2
+ import '@splidejs/splide/css';
3
+ ---
4
+ <thumbnail-carousel>
5
+ <section class="flex flex-col gap-4">
6
+ <section class="mainSplide splide" aria-label="Beautiful Images">
7
+ <div class="splide__track">
8
+ <ul class="splide__list">
9
+ <li class="splide__slide">
10
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="" />
11
+ <div>
12
+ Description 01
13
+ </div>
14
+ </li>
15
+ <li class="splide__slide">
16
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="" />
17
+ <div>
18
+ Description 02
19
+ </div>
20
+ </li>
21
+ <li class="splide__slide">
22
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="" />
23
+ <div>
24
+ Description 03
25
+ </div>
26
+ </li>
27
+ <li class="splide__slide">
28
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="" />
29
+ <div>
30
+ Description 01
31
+ </div>
32
+ </li>
33
+ <li class="splide__slide">
34
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="" />
35
+ <div>
36
+ Description 02
37
+ </div>
38
+ </li>
39
+ <li class="splide__slide">
40
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="" />
41
+ <div>
42
+ Description 03
43
+ </div>
44
+ </li>
45
+ </ul>
46
+ </div>
47
+ </section>
48
+ <section class="thumbnailSplide splide" aria-label="Beautiful Images">
49
+ <div class="splide__track">
50
+ <ul class="splide__list">
51
+ <li class="splide__slide">
52
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="" />
53
+ </li>
54
+ <li class="splide__slide">
55
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="" />
56
+ </li>
57
+ <li class="splide__slide">
58
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="" />
59
+ </li>
60
+ <li class="splide__slide">
61
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/c5090173eec68cbaccb1e6b0576de70a/google-seo-guideline-2025_OGx6L4-1643x1062.webp" alt="" />
62
+ </li>
63
+ <li class="splide__slide">
64
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/818bfcbea4bb3fe5d3f641fb06337661/google-seo-2025_VuQ5Ea-1920x1097.webp" alt="" />
65
+ </li>
66
+ <li class="splide__slide">
67
+ <img src="https://img.jeawincdn.com/resource/upfiles/245/images/resize/586833e9e667e28f577b2b6b30486a3f/choosing-the-right-google-seo-company_Qwixn6-960x540.webp" alt="" />
68
+ </li>
69
+ </ul>
70
+ </div>
71
+ </section>
72
+ </section>
73
+
74
+ </thumbnail-carousel>
75
+
76
+ <style>
77
+ .splide{
78
+ margin:0 auto;
79
+ }
80
+ .splide__slide img{
81
+ width:100%;
82
+ /* height: auto; */
83
+ height:100%;
84
+ object-fit: cover;
85
+ }
86
+ .splide__slide {
87
+ opacity: 0.6;
88
+ }
89
+
90
+ .splide__slide.is-active {
91
+ opacity: 1;
92
+ }
93
+ </style>
94
+ <script>
95
+ import Splide from "@splidejs/splide";
96
+
97
+ class ThumbnailCarousel extends HTMLElement{
98
+ constructor(){
99
+ super()
100
+ }
101
+
102
+ connectedCallback() {
103
+ const elemMain: any = this.querySelector('.mainSplide');
104
+ const main = new Splide(elemMain, {
105
+ type: 'fade',
106
+ rewind: true,
107
+ pagination: false,
108
+ arrows: false
109
+ });
110
+ const elemThumbnail: any = this.querySelector('.thumbnailSplide');
111
+ const thumbnails = new Splide(elemThumbnail,{
112
+ // width:'100vw',
113
+ // height:'100vh',
114
+ fixedWidth:100,
115
+ fixedHeight: 60,
116
+ gap:10,
117
+ rewind:true,
118
+ pagination: false,
119
+ cover: true,
120
+ heightRatio: 0.5,
121
+ // focus: 'center',
122
+ // perPage: 2,
123
+ isNavigation: true,
124
+ breakpoints:{
125
+ 640:{
126
+ perPage:1,
127
+ fixedWidth: 60,
128
+ fixedHeight: 44
129
+ }
130
+ }
131
+ });
132
+
133
+
134
+ main.sync(thumbnails)
135
+ main.mount();
136
+ thumbnails.mount();
137
+ }
138
+ }
139
+
140
+ customElements.define('thumbnail-carousel', ThumbnailCarousel);
141
+ </script>