tee3apps-cms-sdk-react 0.0.20 → 0.0.23
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/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Page.tsx +2 -2
- package/src/PageComponents/BoxComponent.tsx +123 -25
- package/src/PageComponents/Visual-Components/CarouselComponent.tsx +300 -167
- package/src/PageComponents/Visual-Components/GroupBrandComponent.tsx +396 -390
- package/src/PageComponents/Visual-Components/GroupCategoryComponent.tsx +21 -13
- package/src/PageComponents/Visual-Components/GroupImageList.tsx +642 -668
- package/src/PageComponents/Visual-Components/GroupProductComponent.tsx +46 -20
- package/src/PageComponents/Visual-Components/GroupVideoList.tsx +693 -589
- package/src/PageComponents/Visual-Components/ImageComponent.tsx +74 -18
- package/src/PageComponents/Visual-Components/LottieComponent.tsx +14 -8
- package/src/PageComponents/Visual-Components/NavigationComponent.tsx +74 -27
- package/src/PageComponents/Visual-Components/RichTextComponent.tsx +1 -1
- package/src/PageComponents/Visual-Components/TabComponent.tsx +1624 -876
- package/src/PageComponents/Visual-Components/TextComponent.tsx +24 -10
- package/src/PageComponents/Visual-Components/VideoComponent.tsx +33 -11
- package/src/PageComponents/Visual-Components/tab.css +645 -611
- package/src/index.css +126 -81
- package/src/Components/BoxRenderer.tsx +0 -108
- package/src/Components/ComponentRenderer.tsx +0 -29
- package/src/Components/ImageComponent.tsx +0 -68
- package/src/Components/RowComponent.tsx +0 -66
- package/src/Components/TextComponent.tsx +0 -47
|
@@ -13,7 +13,7 @@ interface Slide {
|
|
|
13
13
|
width: number | null;
|
|
14
14
|
height: number | null;
|
|
15
15
|
};
|
|
16
|
-
video
|
|
16
|
+
video?: {
|
|
17
17
|
url?: string;
|
|
18
18
|
alt?: string;
|
|
19
19
|
};
|
|
@@ -24,7 +24,7 @@ interface Slide {
|
|
|
24
24
|
external_link: {
|
|
25
25
|
url: string;
|
|
26
26
|
target: string;
|
|
27
|
-
};
|
|
27
|
+
} | null;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
interface SlideMode {
|
|
@@ -60,7 +60,7 @@ export interface CarouselProps {
|
|
|
60
60
|
sliderArrowVisible: boolean;
|
|
61
61
|
pagingDotVisible: boolean;
|
|
62
62
|
objectFit: string;
|
|
63
|
-
slides: SlidesData[];
|
|
63
|
+
slides: SlidesData[] | Slide[][]; // Support both formats: SlidesData[] or nested array Slide[][]
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
interface CarouselComponentMainProps {
|
|
@@ -75,10 +75,62 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
75
75
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
76
76
|
const [isPlaying, setIsPlaying] = useState(props.autoplay);
|
|
77
77
|
const [isHovered, setIsHovered] = useState(false);
|
|
78
|
+
const [prevButtonHovered, setPrevButtonHovered] = useState(false);
|
|
79
|
+
const [nextButtonHovered, setNextButtonHovered] = useState(false);
|
|
80
|
+
|
|
81
|
+
// Detect data structure and safely get slides with fallback
|
|
82
|
+
// Check if slides[0] is an array of Slide objects (new format) or has 'all' property (old format)
|
|
83
|
+
const firstSlideItem = props.slides && props.slides[0] ? props.slides[0] : null;
|
|
84
|
+
|
|
85
|
+
// Check if it's the new nested array format (array of Slide objects)
|
|
86
|
+
const isNestedArrayFormat = Array.isArray(firstSlideItem) &&
|
|
87
|
+
firstSlideItem.length > 0 &&
|
|
88
|
+
typeof firstSlideItem[0] === 'object' &&
|
|
89
|
+
'sl_id' in (firstSlideItem[0] as any);
|
|
90
|
+
|
|
91
|
+
let slides: Slide[] = [];
|
|
92
|
+
let slidesData: SlidesData | null = null;
|
|
93
|
+
|
|
94
|
+
if (isNestedArrayFormat) {
|
|
95
|
+
// New format: slides is Slide[][] - first element is an array of Slide objects
|
|
96
|
+
slides = (firstSlideItem as Slide[]) || [];
|
|
97
|
+
} else if (firstSlideItem && typeof firstSlideItem === 'object' && 'all' in firstSlideItem) {
|
|
98
|
+
// Old format: slides is SlidesData[] - has 'all' property
|
|
99
|
+
slidesData = firstSlideItem as SlidesData;
|
|
100
|
+
slides = slidesData?.all || [];
|
|
101
|
+
} else {
|
|
102
|
+
// Fallback: empty array
|
|
103
|
+
slides = [];
|
|
104
|
+
}
|
|
78
105
|
|
|
79
|
-
const slides = props.slides[0].all;
|
|
80
106
|
const totalSlides = slides.length;
|
|
81
107
|
|
|
108
|
+
// Get current mode settings
|
|
109
|
+
const getCurrentMode = () => {
|
|
110
|
+
// If using nested array format, mode data doesn't exist, use defaults
|
|
111
|
+
if (isNestedArrayFormat || !slidesData || !slidesData.mode) {
|
|
112
|
+
// Return default mode based on device
|
|
113
|
+
const defaultSlidesToShow = deviceMode === 'mobileweb' || deviceMode === 'mobileapp' ? 1 :
|
|
114
|
+
deviceMode === 'tablet' ? 2 : 1;
|
|
115
|
+
return { slidesToShow: defaultSlidesToShow };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
switch(deviceMode) {
|
|
119
|
+
case 'mobileweb':
|
|
120
|
+
return slidesData.mode.mobileweb || { slidesToShow: 1 };
|
|
121
|
+
case 'mobileapp':
|
|
122
|
+
return slidesData.mode.mobileapp || { slidesToShow: 1 };
|
|
123
|
+
case 'tablet':
|
|
124
|
+
return slidesData.mode.tablet || { slidesToShow: 1 };
|
|
125
|
+
case 'web':
|
|
126
|
+
default:
|
|
127
|
+
return slidesData.mode.web || { slidesToShow: 1 };
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const currentMode = getCurrentMode();
|
|
132
|
+
const slidesToShow = Math.max(1, currentMode.slidesToShow || 1);
|
|
133
|
+
|
|
82
134
|
// Function to go to next slide (advance by 1 to support wrap pairs)
|
|
83
135
|
const nextSlide = useCallback(() => {
|
|
84
136
|
setCurrentSlide((prev) => (prev + 1) % totalSlides);
|
|
@@ -96,14 +148,16 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
96
148
|
|
|
97
149
|
// Handle autoplay
|
|
98
150
|
useEffect(() => {
|
|
99
|
-
|
|
151
|
+
// Only pause on hover if pauseOnHover is enabled
|
|
152
|
+
const shouldPause = props.pauseOnHover && isHovered;
|
|
153
|
+
if (!props.autoplay || !isPlaying || shouldPause) return;
|
|
100
154
|
|
|
101
155
|
const interval = setInterval(() => {
|
|
102
156
|
nextSlide();
|
|
103
157
|
}, props.autoplayInterval);
|
|
104
158
|
|
|
105
159
|
return () => clearInterval(interval);
|
|
106
|
-
}, [props.autoplay, props.autoplayInterval, isPlaying, isHovered, nextSlide]);
|
|
160
|
+
}, [props.autoplay, props.autoplayInterval, props.pauseOnHover, isPlaying, isHovered, nextSlide]);
|
|
107
161
|
|
|
108
162
|
// Handle pause on hover
|
|
109
163
|
const handleMouseEnter = () => {
|
|
@@ -120,24 +174,6 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
120
174
|
}
|
|
121
175
|
};
|
|
122
176
|
|
|
123
|
-
// Get current mode settings
|
|
124
|
-
const getCurrentMode = () => {
|
|
125
|
-
switch(deviceMode) {
|
|
126
|
-
case 'mobileweb':
|
|
127
|
-
return props.slides[0].mode.mobileweb;
|
|
128
|
-
case 'mobileapp':
|
|
129
|
-
return props.slides[0].mode.mobileapp;
|
|
130
|
-
case 'tablet':
|
|
131
|
-
return props.slides[0].mode.tablet;
|
|
132
|
-
case 'web':
|
|
133
|
-
default:
|
|
134
|
-
return props.slides[0].mode.web;
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const currentMode = getCurrentMode();
|
|
139
|
-
const slidesToShow = currentMode.slidesToShow;
|
|
140
|
-
|
|
141
177
|
const resolveAssetUrl = (url?: string) => {
|
|
142
178
|
if (!url) return '';
|
|
143
179
|
if (url.startsWith('http://') || url.startsWith('https://')) return url;
|
|
@@ -145,7 +181,7 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
145
181
|
};
|
|
146
182
|
|
|
147
183
|
const buildLinkForSlide = (slide: Slide) => {
|
|
148
|
-
console.warn(slide)
|
|
184
|
+
console.warn(slide);
|
|
149
185
|
switch (slide.link_type) {
|
|
150
186
|
case 'NONE':
|
|
151
187
|
return null;
|
|
@@ -155,11 +191,11 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
155
191
|
const product: any = slide.product || {};
|
|
156
192
|
const pdType = product?.pd_type || product?.product_type;
|
|
157
193
|
const code = product?.code || '';
|
|
158
|
-
|
|
194
|
+
if (!code) return null;
|
|
159
195
|
|
|
160
196
|
return pdType === 'VARIANT'
|
|
161
|
-
|
|
162
|
-
|
|
197
|
+
? `/${code}`
|
|
198
|
+
: `/model/${code}`;
|
|
163
199
|
}
|
|
164
200
|
case 'TAG': {
|
|
165
201
|
const tag: any = slide.tag || {};
|
|
@@ -168,8 +204,8 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
168
204
|
}
|
|
169
205
|
case 'PAGE': {
|
|
170
206
|
const page: any = slide.page || {};
|
|
171
|
-
const pageId = page._id
|
|
172
|
-
const pgType=page.page_type
|
|
207
|
+
const pageId = page._id;
|
|
208
|
+
const pgType = page.page_type;
|
|
173
209
|
return `/page/${pageId}?type=${pgType}`;
|
|
174
210
|
}
|
|
175
211
|
default:
|
|
@@ -179,20 +215,42 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
179
215
|
|
|
180
216
|
const handleSlideClick = (slide: Slide) => {
|
|
181
217
|
const link = buildLinkForSlide(slide);
|
|
182
|
-
if (link === null)
|
|
218
|
+
if (link === null) {
|
|
219
|
+
// If no link, navigate to next slide
|
|
220
|
+
nextSlide();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
183
223
|
if (typeof link === 'string') {
|
|
184
224
|
if (link.startsWith('http')) {
|
|
185
|
-
window.open(link, '_blank');
|
|
225
|
+
window.open(link, slide.external_link?.target || '_blank');
|
|
186
226
|
} else {
|
|
187
227
|
window.location.href = link;
|
|
188
228
|
}
|
|
189
229
|
return;
|
|
190
230
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// Calculate which group the current slide belongs to
|
|
234
|
+
const getCurrentGroupIndex = () => {
|
|
235
|
+
return Math.floor(currentSlide / slidesToShow);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Calculate total number of groups needed
|
|
239
|
+
const getTotalGroups = () => {
|
|
240
|
+
return Math.ceil(totalSlides / slidesToShow);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Calculate transform offset for slide animation
|
|
244
|
+
// Transform based on group index, not slide index
|
|
245
|
+
const calculateTransform = () => {
|
|
246
|
+
const groupIndex = getCurrentGroupIndex();
|
|
247
|
+
if (props.vertical) {
|
|
248
|
+
// Vertical sliding: moves up and down
|
|
249
|
+
return `translateY(-${groupIndex * 100}%)`;
|
|
250
|
+
} else {
|
|
251
|
+
// Horizontal sliding: moves left and right
|
|
252
|
+
return `translateX(-${groupIndex * 100}%)`;
|
|
253
|
+
}
|
|
196
254
|
};
|
|
197
255
|
|
|
198
256
|
return (
|
|
@@ -200,165 +258,240 @@ const CarouselComponent: React.FC<CarouselComponentMainProps> = ({
|
|
|
200
258
|
className="carousel-container"
|
|
201
259
|
style={{
|
|
202
260
|
position: 'relative',
|
|
203
|
-
|
|
204
|
-
overflow: 'hidden'
|
|
261
|
+
height: props.height,
|
|
262
|
+
overflow: 'hidden',
|
|
263
|
+
width: '100%'
|
|
205
264
|
}}
|
|
206
265
|
onMouseEnter={handleMouseEnter}
|
|
207
266
|
onMouseLeave={handleMouseLeave}
|
|
208
267
|
>
|
|
209
268
|
{/* Slides container */}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
269
|
+
{totalSlides > 0 ? (
|
|
270
|
+
<div
|
|
271
|
+
className="carousel-slides"
|
|
272
|
+
style={{
|
|
273
|
+
display: 'flex',
|
|
274
|
+
height: '100%',
|
|
275
|
+
width: '100%',
|
|
276
|
+
// vertical = true: slides move up/down (column direction)
|
|
277
|
+
// vertical = false: slides move left/right (row direction)
|
|
278
|
+
flexDirection: props.vertical ? 'column' : 'row',
|
|
279
|
+
transition: `transform ${props.speed}ms ease-in-out`,
|
|
280
|
+
transform: calculateTransform(),
|
|
281
|
+
willChange: 'transform'
|
|
282
|
+
}}
|
|
283
|
+
>
|
|
284
|
+
{Array.from({ length: getTotalGroups() }).map((_, groupIndex) => {
|
|
285
|
+
// Calculate starting slide index for this group
|
|
286
|
+
const startIndex = groupIndex * slidesToShow;
|
|
287
|
+
// Calculate how many slides are in this group (last group may have fewer)
|
|
288
|
+
const slidesInGroup = Math.min(slidesToShow, totalSlides - startIndex);
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<div
|
|
292
|
+
key={groupIndex}
|
|
293
|
+
className="carousel-group"
|
|
294
|
+
style={{
|
|
295
|
+
flexShrink: 0,
|
|
296
|
+
display: 'flex',
|
|
297
|
+
// Items within each slide are ALWAYS in a horizontal row
|
|
298
|
+
flexDirection: 'row',
|
|
299
|
+
width: '100%',
|
|
300
|
+
height: '100%',
|
|
301
|
+
gap: '0px'
|
|
302
|
+
}}
|
|
303
|
+
>
|
|
304
|
+
{Array.from({ length: slidesToShow }).map((_, offset) => {
|
|
305
|
+
const slideIndex = startIndex + offset;
|
|
306
|
+
|
|
307
|
+
// If this position is beyond available slides, render empty space
|
|
308
|
+
if (slideIndex >= totalSlides) {
|
|
309
|
+
return (
|
|
310
|
+
<div
|
|
311
|
+
key={`empty-${offset}`}
|
|
312
|
+
className="carousel-slide-empty"
|
|
313
|
+
style={{
|
|
314
|
+
flexShrink: 0,
|
|
315
|
+
width: `${100 / slidesToShow}%`,
|
|
316
|
+
height: '100%',
|
|
317
|
+
// Empty space, no content
|
|
318
|
+
}}
|
|
319
|
+
/>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const slide = slides[slideIndex];
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<div
|
|
327
|
+
key={`${slide.sl_id}-${offset}`}
|
|
328
|
+
className="carousel-slide"
|
|
329
|
+
style={{
|
|
330
|
+
flexShrink: 0,
|
|
331
|
+
// Items always take equal width in horizontal row
|
|
332
|
+
width: `${100 / slidesToShow}%`,
|
|
333
|
+
height: '100%',
|
|
334
|
+
overflow: 'hidden',
|
|
335
|
+
display: 'flex',
|
|
336
|
+
alignItems: 'center',
|
|
337
|
+
justifyContent: 'center',
|
|
338
|
+
position: 'relative',
|
|
339
|
+
cursor: 'pointer'
|
|
340
|
+
}}
|
|
341
|
+
onClick={() => handleSlideClick(slide)}
|
|
342
|
+
>
|
|
343
|
+
{slide.sl_type === 'video' ? (
|
|
344
|
+
<video
|
|
345
|
+
src={resolveAssetUrl(slide.video?.url)}
|
|
346
|
+
style={{
|
|
347
|
+
width: '100%',
|
|
348
|
+
height: '100%',
|
|
349
|
+
objectFit: props.objectFit as any,
|
|
350
|
+
display: 'block',
|
|
351
|
+
pointerEvents: 'none'
|
|
352
|
+
}}
|
|
353
|
+
autoPlay={props.autoplay}
|
|
354
|
+
muted
|
|
355
|
+
loop
|
|
356
|
+
controls={!props.autoplay}
|
|
357
|
+
/>
|
|
358
|
+
) : (
|
|
359
|
+
<img
|
|
360
|
+
src={resolveAssetUrl(slide.image?.url)}
|
|
361
|
+
alt={slide.image?.alt || ''}
|
|
362
|
+
style={{
|
|
363
|
+
width: '100%',
|
|
364
|
+
height: '100%',
|
|
365
|
+
objectFit: props.objectFit as any,
|
|
366
|
+
display: 'block',
|
|
367
|
+
pointerEvents: 'none'
|
|
368
|
+
}}
|
|
369
|
+
/>
|
|
370
|
+
)}
|
|
371
|
+
</div>
|
|
372
|
+
);
|
|
373
|
+
})}
|
|
374
|
+
</div>
|
|
375
|
+
);
|
|
376
|
+
})}
|
|
377
|
+
</div>
|
|
378
|
+
) : (
|
|
379
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%', color: '#999' }}>
|
|
380
|
+
No slides added yet
|
|
381
|
+
</div>
|
|
382
|
+
)}
|
|
256
383
|
|
|
257
384
|
{/* Navigation arrows */}
|
|
258
385
|
{props.sliderArrowVisible && totalSlides > slidesToShow && (
|
|
259
386
|
<>
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
<button
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
>
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
387
|
+
<button
|
|
388
|
+
onClick={prevSlide}
|
|
389
|
+
onMouseEnter={() => setPrevButtonHovered(true)}
|
|
390
|
+
onMouseLeave={() => setPrevButtonHovered(false)}
|
|
391
|
+
style={{
|
|
392
|
+
position: 'absolute',
|
|
393
|
+
...(props.vertical
|
|
394
|
+
? { top: '8px', right: '16px' }
|
|
395
|
+
: { left: '8px', top: '50%', transform: 'translateY(-50%)' }
|
|
396
|
+
),
|
|
397
|
+
background: prevButtonHovered ? 'rgba(255, 255, 255, 0.5)' : 'transparent',
|
|
398
|
+
transition: 'all 0.2s ease',
|
|
399
|
+
padding: '8px',
|
|
400
|
+
borderRadius: '4px',
|
|
401
|
+
boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
|
|
402
|
+
zIndex: 10,
|
|
403
|
+
border: 'none',
|
|
404
|
+
cursor: 'pointer',
|
|
405
|
+
display: 'flex',
|
|
406
|
+
alignItems: 'center',
|
|
407
|
+
justifyContent: 'center'
|
|
408
|
+
}}
|
|
409
|
+
>
|
|
410
|
+
{props.vertical ? (
|
|
411
|
+
<span style={{ color: '#374151', fontSize: '16px', fontWeight: 'bold' }}>^</span>
|
|
412
|
+
) : (
|
|
413
|
+
<span style={{ color: '#374151', fontSize: '20px', fontWeight: 'bold' }}><</span>
|
|
414
|
+
)}
|
|
415
|
+
</button>
|
|
416
|
+
<button
|
|
417
|
+
onClick={nextSlide}
|
|
418
|
+
onMouseEnter={() => setNextButtonHovered(true)}
|
|
419
|
+
onMouseLeave={() => setNextButtonHovered(false)}
|
|
420
|
+
style={{
|
|
421
|
+
position: 'absolute',
|
|
422
|
+
...(props.vertical
|
|
423
|
+
? { bottom: '8px', right: '16px' }
|
|
424
|
+
: { right: '8px', top: '50%', transform: 'translateY(-50%)' }
|
|
425
|
+
),
|
|
426
|
+
background: nextButtonHovered ? 'rgba(255, 255, 255, 0.5)' : 'transparent',
|
|
427
|
+
transition: 'all 0.2s ease',
|
|
428
|
+
padding: '8px',
|
|
429
|
+
borderRadius: '4px',
|
|
430
|
+
boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
|
|
431
|
+
zIndex: 10,
|
|
432
|
+
border: 'none',
|
|
433
|
+
cursor: 'pointer',
|
|
434
|
+
display: 'flex',
|
|
435
|
+
alignItems: 'center',
|
|
436
|
+
justifyContent: 'center'
|
|
437
|
+
}}
|
|
438
|
+
>
|
|
439
|
+
{props.vertical ? (
|
|
440
|
+
<span style={{ color: '#374151', fontSize: '16px', fontWeight: 'bold' }}>v</span>
|
|
441
|
+
) : (
|
|
442
|
+
<span style={{ color: '#374151', fontSize: '20px', fontWeight: 'bold' }}>></span>
|
|
443
|
+
)}
|
|
444
|
+
</button>
|
|
317
445
|
</>
|
|
318
446
|
)}
|
|
319
447
|
|
|
320
448
|
{/* Pagination dots */}
|
|
321
|
-
{props.pagingDotVisible &&
|
|
449
|
+
{props.pagingDotVisible && getTotalGroups() > 1 && (
|
|
322
450
|
<div
|
|
323
451
|
className="carousel-dots"
|
|
324
452
|
style={{
|
|
325
453
|
position: 'absolute',
|
|
326
454
|
...(props.vertical
|
|
327
|
-
? { top: '50%', right: '
|
|
328
|
-
: { bottom: '
|
|
455
|
+
? { top: '50%', right: '16px', transform: 'translateY(-50%)' }
|
|
456
|
+
: { bottom: '16px', left: '50%', transform: 'translateX(-50%)' }
|
|
329
457
|
),
|
|
330
458
|
display: 'flex',
|
|
331
459
|
justifyContent: 'center',
|
|
332
460
|
alignItems: 'center',
|
|
333
461
|
flexDirection: props.vertical ? 'column' : 'row',
|
|
334
462
|
gap: '8px',
|
|
335
|
-
zIndex: 100
|
|
336
|
-
padding: props.vertical ? '8px 6px' : '6px 10px',
|
|
337
|
-
|
|
338
|
-
borderRadius: props.vertical ? '12px' : '16px'
|
|
463
|
+
zIndex: 100
|
|
339
464
|
}}
|
|
340
465
|
>
|
|
341
|
-
{Array.from({ length:
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
466
|
+
{Array.from({ length: getTotalGroups() }).map((_, groupIndex) => {
|
|
467
|
+
const currentGroupIndex = getCurrentGroupIndex();
|
|
468
|
+
// Navigate to the first slide of the selected group
|
|
469
|
+
const goToGroup = () => {
|
|
470
|
+
const firstSlideInGroup = groupIndex * slidesToShow;
|
|
471
|
+
goToSlide(firstSlideInGroup);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
return (
|
|
475
|
+
<button
|
|
476
|
+
key={groupIndex}
|
|
477
|
+
aria-label={`Go to group ${groupIndex + 1}`}
|
|
478
|
+
onClick={goToGroup}
|
|
479
|
+
style={{
|
|
480
|
+
width: currentGroupIndex === groupIndex ? '12px' : '10px',
|
|
481
|
+
height: currentGroupIndex === groupIndex ? '12px' : '10px',
|
|
482
|
+
borderRadius: '50%',
|
|
483
|
+
border: 'none',
|
|
484
|
+
background: currentGroupIndex === groupIndex ? '#000' : '#ccc',
|
|
485
|
+
cursor: 'pointer',
|
|
486
|
+
transition: 'all 200ms ease'
|
|
487
|
+
}}
|
|
488
|
+
/>
|
|
489
|
+
);
|
|
490
|
+
})}
|
|
358
491
|
</div>
|
|
359
492
|
)}
|
|
360
493
|
</div>
|
|
361
494
|
);
|
|
362
495
|
};
|
|
363
496
|
|
|
364
|
-
export default CarouselComponent;
|
|
497
|
+
export default CarouselComponent;
|