tee3apps-cms-sdk-react 0.0.34 → 0.0.36
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.d.ts +1 -1
- 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/rollup.config-1772797822233.cjs +48 -0
- package/src/Page.tsx +89 -69
- package/src/PageComponents/RowComponent.tsx +4 -2
- package/src/PageComponents/Visual-Components/GroupProductComponent.tsx +22 -15
- package/src/PageComponents/Visual-Components/RichTextComponent.tsx +12 -4
- package/src/PageComponents/Visual-Components/Styles/ProductListViewOne.tsx +9 -9
- package/src/PageComponents/Visual-Components/Styles/ProductListViewTwo.tsx +14 -12
- package/src/PageComponents/Visual-Components/TabComponent.tsx +1541 -1529
|
@@ -127,6 +127,8 @@ export interface TabComponentProps {
|
|
|
127
127
|
showTitle: boolean;
|
|
128
128
|
title: TitleStyle;
|
|
129
129
|
header: HeaderStyle;
|
|
130
|
+
showsp?: boolean;
|
|
131
|
+
showdiscount?: boolean;
|
|
130
132
|
tabs: TabItem[] | TabsData; // Support both array (new) and object with locale keys (old)
|
|
131
133
|
}
|
|
132
134
|
|
|
@@ -141,14 +143,14 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
141
143
|
const [hoveredTab, setHoveredTab] = useState<number | null>(null);
|
|
142
144
|
const [hasError, setHasError] = useState(false);
|
|
143
145
|
const [errorMessage, setErrorMessage] = useState<string>('');
|
|
144
|
-
|
|
146
|
+
|
|
145
147
|
// Get scroll type and objectFit from props
|
|
146
148
|
const scrollType = props.scroll || 'horizontal';
|
|
147
149
|
const objectFit = props.objectFit || 'fill';
|
|
148
150
|
|
|
149
151
|
// Extract tabs - handle both new structure (array) and old structure (object with locale keys)
|
|
150
|
-
const tabs = Array.isArray(props.tabs)
|
|
151
|
-
? props.tabs
|
|
152
|
+
const tabs = Array.isArray(props.tabs)
|
|
153
|
+
? props.tabs
|
|
152
154
|
: (props.tabs?.all || props.tabs?.['en-IN'] || []);
|
|
153
155
|
|
|
154
156
|
// Validate props structure
|
|
@@ -163,8 +165,8 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
// Check if tabs is array or object with valid structure
|
|
166
|
-
const tabs = Array.isArray(props.tabs)
|
|
167
|
-
? props.tabs
|
|
168
|
+
const tabs = Array.isArray(props.tabs)
|
|
169
|
+
? props.tabs
|
|
168
170
|
: (props.tabs?.all || props.tabs?.['en-IN'] || []);
|
|
169
171
|
|
|
170
172
|
if (!Array.isArray(tabs) || tabs.length === 0) {
|
|
@@ -301,7 +303,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
301
303
|
// Helper function to extract YouTube video ID from various URL formats
|
|
302
304
|
const getYouTubeVideoId = (url: string): string | null => {
|
|
303
305
|
if (!url) return null;
|
|
304
|
-
|
|
306
|
+
|
|
305
307
|
// Handle various YouTube URL formats
|
|
306
308
|
const patterns = [
|
|
307
309
|
/(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^&]+)/,
|
|
@@ -315,7 +317,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
315
317
|
return match[1];
|
|
316
318
|
}
|
|
317
319
|
}
|
|
318
|
-
|
|
320
|
+
|
|
319
321
|
return null;
|
|
320
322
|
};
|
|
321
323
|
|
|
@@ -324,19 +326,19 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
324
326
|
if (isDynamic) {
|
|
325
327
|
return videoData?.video?.playerType === 'Youtube' || videoData?.video?.playerType === 'youtube';
|
|
326
328
|
} else {
|
|
327
|
-
return videoData?.attr?.all?.playerType === 'Youtube' ||
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
return videoData?.attr?.all?.playerType === 'Youtube' ||
|
|
330
|
+
videoData?.attr?.all?.playerType === 'youtube' ||
|
|
331
|
+
videoData?.attr?.playerType === 'Youtube' ||
|
|
332
|
+
videoData?.attr?.playerType === 'youtube';
|
|
331
333
|
}
|
|
332
334
|
};
|
|
333
335
|
|
|
334
336
|
// Render video player (YouTube or HTML5)
|
|
335
337
|
const renderVideoPlayer = (videoData: any, isDynamic: boolean, className: string = 'media-content', style: React.CSSProperties = {}) => {
|
|
336
338
|
console.log('renderVideoPlayer called with:', { videoData, isDynamic });
|
|
337
|
-
|
|
339
|
+
|
|
338
340
|
const isYouTube = isYouTubeVideo(videoData, isDynamic);
|
|
339
|
-
|
|
341
|
+
|
|
340
342
|
// Get video URL with proper fallback - handle both dynamic and static videos
|
|
341
343
|
let videoUrl = '';
|
|
342
344
|
if (isDynamic) {
|
|
@@ -345,21 +347,21 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
345
347
|
// Static videos: check multiple possible locations
|
|
346
348
|
videoUrl = videoData?.attr?.all?.url || videoData?.attr?.url || videoData?.video?.url || videoData?.url || '';
|
|
347
349
|
}
|
|
348
|
-
|
|
350
|
+
|
|
349
351
|
console.log('Video URL extracted:', videoUrl, 'isYouTube:', isYouTube);
|
|
350
|
-
|
|
352
|
+
|
|
351
353
|
// Get video attributes - handle both dynamic and static videos
|
|
352
|
-
const videoAlt = isDynamic
|
|
354
|
+
const videoAlt = isDynamic
|
|
353
355
|
? (videoData?.video?.alt || videoData?.alt || videoData?.name || 'Video')
|
|
354
356
|
: (videoData?.attr?.all?.alt || videoData?.attr?.alt || videoData?.video?.alt || videoData?.alt || 'Video');
|
|
355
|
-
|
|
357
|
+
|
|
356
358
|
// Get controls setting with proper defaults (default to true if undefined)
|
|
357
|
-
const controls = isDynamic
|
|
359
|
+
const controls = isDynamic
|
|
358
360
|
? (videoData?.video?.controls !== undefined ? videoData.video.controls : true)
|
|
359
361
|
: (videoData?.attr?.all?.controls !== undefined ? videoData.attr.all.controls : (videoData?.attr?.controls !== undefined ? videoData.attr.controls : true));
|
|
360
|
-
|
|
362
|
+
|
|
361
363
|
// Get loop setting (default to false if undefined)
|
|
362
|
-
const loop = isDynamic
|
|
364
|
+
const loop = isDynamic
|
|
363
365
|
? (videoData?.video?.loop === true)
|
|
364
366
|
: (videoData?.attr?.all?.loop === true || videoData?.attr?.loop === true);
|
|
365
367
|
|
|
@@ -401,7 +403,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
401
403
|
// Fallback to HTML5 video - always use Linode URL
|
|
402
404
|
const finalVideoUrl = getImageUrl(videoUrl);
|
|
403
405
|
console.log('Rendering HTML5 video with URL:', finalVideoUrl);
|
|
404
|
-
|
|
406
|
+
|
|
405
407
|
// Create a video component with proper handling for no-controls videos
|
|
406
408
|
const VideoComponent = () => {
|
|
407
409
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
@@ -446,12 +448,12 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
446
448
|
muted={autoplay || !controls} // Mute if autoplay or no controls (required for autoplay in browsers)
|
|
447
449
|
playsInline={true} // Required for mobile devices
|
|
448
450
|
onClick={handleVideoClick}
|
|
449
|
-
style={{
|
|
450
|
-
width: '100%',
|
|
451
|
-
height: '100%',
|
|
452
|
-
objectFit: (props.objectFit || 'contain') as any,
|
|
451
|
+
style={{
|
|
452
|
+
width: '100%',
|
|
453
|
+
height: '100%',
|
|
454
|
+
objectFit: (props.objectFit || 'contain') as any,
|
|
453
455
|
cursor: controls ? 'default' : 'pointer',
|
|
454
|
-
...style
|
|
456
|
+
...style
|
|
455
457
|
}}
|
|
456
458
|
onError={(e) => {
|
|
457
459
|
console.error('Video failed to load:', e, 'URL:', finalVideoUrl);
|
|
@@ -541,8 +543,8 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
541
543
|
const sp = product.price?.SP;
|
|
542
544
|
const offer = calculateOffer(mrp, sp);
|
|
543
545
|
|
|
544
|
-
const cardMode = layout === '1x1' ? 'carousel-mode' : layout === '2x1' ? 'layout-2x1' : 'grid-mode';
|
|
545
|
-
|
|
546
|
+
const cardMode = layout === '1x1' ? 'carousel-mode' : layout === '2x1' ? 'layout-2x1' : 'grid-mode';
|
|
547
|
+
|
|
546
548
|
const cardContent = (
|
|
547
549
|
<>
|
|
548
550
|
{/* Product Image */}
|
|
@@ -584,7 +586,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
584
586
|
))}
|
|
585
587
|
</div>
|
|
586
588
|
)}
|
|
587
|
-
{/* {layout === '1x1' && product.variant && product.variant.length > 0 && (
|
|
589
|
+
{/* {layout === '1x1' && product.variant && product.variant.length > 0 && (
|
|
588
590
|
<div className="product-variants">
|
|
589
591
|
{product.variant.map((variant: any, index: number) => (
|
|
590
592
|
<span key={index} className="variant-tag">
|
|
@@ -595,17 +597,27 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
595
597
|
)} */}
|
|
596
598
|
{/* Pricing */}
|
|
597
599
|
<div className="product-pricing">
|
|
598
|
-
<div className="price-row">
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
600
|
+
<div className="price-row" style={{ display: 'flex', flexDirection: 'column', gap: '2px' }}>
|
|
601
|
+
{props.showsp !== false && (
|
|
602
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '6px', flexWrap: 'wrap' }}>
|
|
603
|
+
<span className="current-price" style={{ fontSize: '15px', fontWeight: 'bold' }}>
|
|
604
|
+
SP: {formatPrice(sp)} (incl of all tax)
|
|
605
|
+
</span>
|
|
606
|
+
{props.showdiscount !== false && mrp && sp && (() => {
|
|
607
|
+
const mrpValue = parseFloat(mrp?.$numberDecimal || mrp || 0);
|
|
608
|
+
const spValue = parseFloat(sp?.$numberDecimal || sp || 0);
|
|
609
|
+
return mrpValue > spValue && mrpValue > 0;
|
|
610
|
+
})() && (
|
|
611
|
+
<span className="original-price" style={{ fontSize: '12px', color: '#666', textDecoration: 'line-through' }}>
|
|
612
|
+
MRP: {formatPrice(mrp)}
|
|
613
|
+
</span>
|
|
614
|
+
)}
|
|
615
|
+
</div>
|
|
616
|
+
)}
|
|
617
|
+
{props.showdiscount !== false && offer > 0 && (
|
|
618
|
+
<span className="offer-badge" style={{ fontSize: '11px', color: '#28a745', fontWeight: 'bold', width: 'fit-content' }}>
|
|
619
|
+
{offer}% OFF
|
|
620
|
+
</span>
|
|
609
621
|
)}
|
|
610
622
|
</div>
|
|
611
623
|
</div>
|
|
@@ -622,11 +634,11 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
622
634
|
</div>
|
|
623
635
|
)}
|
|
624
636
|
|
|
625
|
-
|
|
637
|
+
|
|
626
638
|
</div>
|
|
627
639
|
</>
|
|
628
640
|
);
|
|
629
|
-
|
|
641
|
+
|
|
630
642
|
const productCode = typeof product.code === 'string' ? product.code : getDisplayText(product.code) || product.sku || '';
|
|
631
643
|
return (
|
|
632
644
|
<a href={productCode ? `/${productCode}` : '#'} className={`product-card ${cardMode}`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
|
@@ -641,34 +653,34 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
641
653
|
// Get current tab to determine max slides
|
|
642
654
|
const currentTab = tabs[activeTab];
|
|
643
655
|
if (!currentTab) return prev;
|
|
644
|
-
|
|
656
|
+
|
|
645
657
|
const layout = getCurrentLayout(currentTab);
|
|
646
658
|
const itemsPerSlide = layout === '2x2' ? 4 : (layout === '1x2' || layout === '2x1') ? 2 : 1;
|
|
647
|
-
|
|
659
|
+
|
|
648
660
|
let maxSlides = 0;
|
|
649
661
|
if (currentTab.tabContentType === 'GROUPIMAGE' && currentTab.tabContentGroupImage) {
|
|
650
662
|
const items = currentTab.tabContentGroupImage.showItems && currentTab.tabContentGroupImage.showItems.length > 0
|
|
651
663
|
? currentTab.tabContentGroupImage.showItems
|
|
652
|
-
: (currentTab.tabContentGroupImage.type === 'DYNAMIC'
|
|
653
|
-
? currentTab.tabContentGroupImage.dynamicImages
|
|
664
|
+
: (currentTab.tabContentGroupImage.type === 'DYNAMIC'
|
|
665
|
+
? currentTab.tabContentGroupImage.dynamicImages
|
|
654
666
|
: (currentTab.tabContentGroupImage.staticImages || []));
|
|
655
667
|
maxSlides = items?.length ? (layout !== '1x1' ? Math.ceil(items.length / itemsPerSlide) : items.length) : 0;
|
|
656
668
|
} else if (currentTab.tabContentType === 'GROUPVIDEO' && currentTab.tabContentGroupVideo) {
|
|
657
669
|
const items = currentTab.tabContentGroupVideo.showItems && currentTab.tabContentGroupVideo.showItems.length > 0
|
|
658
670
|
? currentTab.tabContentGroupVideo.showItems
|
|
659
|
-
: (currentTab.tabContentGroupVideo.type === 'DYNAMIC'
|
|
660
|
-
? currentTab.tabContentGroupVideo.dynamicVideos
|
|
671
|
+
: (currentTab.tabContentGroupVideo.type === 'DYNAMIC'
|
|
672
|
+
? currentTab.tabContentGroupVideo.dynamicVideos
|
|
661
673
|
: (currentTab.tabContentGroupVideo.staticVideos || []));
|
|
662
674
|
maxSlides = items?.length ? (layout !== '1x1' ? Math.ceil(items.length / itemsPerSlide) : items.length) : 0;
|
|
663
675
|
} else if (currentTab.tabContentType === 'GROUPPRODUCT' && currentTab.tabContentGroupProduct) {
|
|
664
676
|
const items = currentTab.tabContentGroupProduct.showItems && currentTab.tabContentGroupProduct.showItems.length > 0
|
|
665
677
|
? currentTab.tabContentGroupProduct.showItems
|
|
666
|
-
: (currentTab.tabContentGroupProduct.type === 'DYNAMIC'
|
|
667
|
-
? currentTab.tabContentGroupProduct.dynamic?.list
|
|
678
|
+
: (currentTab.tabContentGroupProduct.type === 'DYNAMIC'
|
|
679
|
+
? currentTab.tabContentGroupProduct.dynamic?.list
|
|
668
680
|
: currentTab.tabContentGroupProduct.staticProducts);
|
|
669
681
|
maxSlides = items?.length ? (layout !== '1x1' ? Math.ceil(items.length / itemsPerSlide) : items.length) : 0;
|
|
670
682
|
}
|
|
671
|
-
|
|
683
|
+
|
|
672
684
|
return maxSlides > 0 ? Math.min(prev + 1, maxSlides - 1) : prev;
|
|
673
685
|
});
|
|
674
686
|
}, [activeTab, tabs]);
|
|
@@ -764,618 +776,113 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
764
776
|
|
|
765
777
|
const layout = getCurrentLayout(tab);
|
|
766
778
|
console.warn(tab)
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
}
|
|
775
|
-
};
|
|
776
|
-
|
|
777
|
-
const getGridRows = () => {
|
|
778
|
-
switch (layout) {
|
|
779
|
-
case '1x1': return '1fr';
|
|
780
|
-
case '1x2': return '1fr';
|
|
781
|
-
case '2x1': return 'repeat(2, minmax(0, 1fr))';
|
|
782
|
-
case '2x2': return 'repeat(2, minmax(0, 1fr))';
|
|
783
|
-
default: return '1fr';
|
|
784
|
-
}
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
const contentStyle = {
|
|
788
|
-
display: 'grid',
|
|
789
|
-
gridTemplateColumns: getGridColumns(),
|
|
790
|
-
gridTemplateRows: getGridRows(),
|
|
791
|
-
gap: '3px',
|
|
792
|
-
height: '100%', // force tab content height
|
|
793
|
-
overflow: 'hidden'
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
switch (tab.tabContentType) {
|
|
798
|
-
case 'IMAGE':
|
|
799
|
-
if (tab.tabContentImage) {
|
|
800
|
-
return (
|
|
801
|
-
<div style={contentStyle}>
|
|
802
|
-
<div className="media-box">
|
|
803
|
-
<img
|
|
804
|
-
src={getImageUrl(tab.tabContentImage.image.url)}
|
|
805
|
-
alt={tab.tabContentImage.image.alt}
|
|
806
|
-
className="media-content"
|
|
807
|
-
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
808
|
-
/>
|
|
809
|
-
</div>
|
|
810
|
-
</div>
|
|
811
|
-
);
|
|
779
|
+
const getGridColumns = () => {
|
|
780
|
+
switch (layout) {
|
|
781
|
+
case '1x1': return '1fr';
|
|
782
|
+
case '1x2': return 'repeat(2, 1fr)';
|
|
783
|
+
case '2x1': return '1fr';
|
|
784
|
+
case '2x2': return 'repeat(2, 1fr)';
|
|
785
|
+
default: return '1fr';
|
|
812
786
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
if (!videoUrl) {
|
|
823
|
-
return <div style={{ padding: '20px', textAlign: 'center' }}>No video URL available</div>;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
// Check if it's a YouTube video (by playerType or URL)
|
|
827
|
-
const isYouTube = playerType === 'Youtube' || playerType === 'youtube' || getYouTubeVideoId(videoUrl) !== null;
|
|
828
|
-
const youtubeId = getYouTubeVideoId(videoUrl);
|
|
829
|
-
|
|
830
|
-
return (
|
|
831
|
-
<div style={contentStyle}>
|
|
832
|
-
<div className="media-box">
|
|
833
|
-
{isYouTube && youtubeId ? (
|
|
834
|
-
<iframe
|
|
835
|
-
src={`https://www.youtube.com/embed/${youtubeId}`}
|
|
836
|
-
title={videoAlt}
|
|
837
|
-
className="media-content"
|
|
838
|
-
style={{ width: '100%', height: '100%', border: 'none' }}
|
|
839
|
-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
840
|
-
allowFullScreen
|
|
841
|
-
/>
|
|
842
|
-
) : (
|
|
843
|
-
<video
|
|
844
|
-
src={getImageUrl(videoUrl)}
|
|
845
|
-
controls
|
|
846
|
-
className="media-content"
|
|
847
|
-
style={{ width: '100%', height: '100%', objectFit: objectFit as any }}
|
|
848
|
-
/>
|
|
849
|
-
)}
|
|
850
|
-
</div>
|
|
851
|
-
</div>
|
|
852
|
-
);
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
const getGridRows = () => {
|
|
790
|
+
switch (layout) {
|
|
791
|
+
case '1x1': return '1fr';
|
|
792
|
+
case '1x2': return '1fr';
|
|
793
|
+
case '2x1': return 'repeat(2, minmax(0, 1fr))';
|
|
794
|
+
case '2x2': return 'repeat(2, minmax(0, 1fr))';
|
|
795
|
+
default: return '1fr';
|
|
853
796
|
}
|
|
854
|
-
|
|
797
|
+
};
|
|
855
798
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
// 1x1 layout: use scrollbar if scroll type is set, otherwise carousel
|
|
870
|
-
if (layout === '1x1' && scrollType) {
|
|
871
|
-
// Use scrollable container with scrollbar - each item takes full width/height
|
|
872
|
-
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
873
|
-
|
|
799
|
+
const contentStyle = {
|
|
800
|
+
display: 'grid',
|
|
801
|
+
gridTemplateColumns: getGridColumns(),
|
|
802
|
+
gridTemplateRows: getGridRows(),
|
|
803
|
+
gap: '3px',
|
|
804
|
+
height: '100%', // force tab content height
|
|
805
|
+
overflow: 'hidden'
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
switch (tab.tabContentType) {
|
|
810
|
+
case 'IMAGE':
|
|
811
|
+
if (tab.tabContentImage) {
|
|
874
812
|
return (
|
|
875
|
-
<div
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
padding: 0,
|
|
885
|
-
}}
|
|
886
|
-
className="scroll-container"
|
|
887
|
-
>
|
|
888
|
-
{images.map((image, index) => (
|
|
889
|
-
<div
|
|
890
|
-
key={index}
|
|
891
|
-
className="media-box"
|
|
892
|
-
style={{
|
|
893
|
-
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
894
|
-
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
895
|
-
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
896
|
-
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
897
|
-
flexShrink: 0,
|
|
898
|
-
scrollSnapAlign: 'start',
|
|
899
|
-
}}
|
|
900
|
-
>
|
|
901
|
-
<img
|
|
902
|
-
src={getImageUrl(
|
|
903
|
-
getImageItemUrl(image, tab.tabContentGroupImage.type)
|
|
904
|
-
)}
|
|
905
|
-
alt={
|
|
906
|
-
getImageItemAlt(image, tab.tabContentGroupImage.type)
|
|
907
|
-
}
|
|
908
|
-
className="media-content"
|
|
909
|
-
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
910
|
-
/>
|
|
911
|
-
</div>
|
|
912
|
-
))}
|
|
813
|
+
<div style={contentStyle}>
|
|
814
|
+
<div className="media-box">
|
|
815
|
+
<img
|
|
816
|
+
src={getImageUrl(tab.tabContentImage.image.url)}
|
|
817
|
+
alt={tab.tabContentImage.image.alt}
|
|
818
|
+
className="media-content"
|
|
819
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
820
|
+
/>
|
|
821
|
+
</div>
|
|
913
822
|
</div>
|
|
914
823
|
);
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
alt={
|
|
928
|
-
getImageItemAlt(currentImage, tab.tabContentGroupImage.type)
|
|
929
|
-
}
|
|
930
|
-
className="media-content"
|
|
931
|
-
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
932
|
-
/>
|
|
933
|
-
</div>
|
|
934
|
-
) : null;
|
|
935
|
-
|
|
936
|
-
return (
|
|
937
|
-
<div
|
|
938
|
-
style={{
|
|
939
|
-
position: 'relative',
|
|
940
|
-
width: '100%',
|
|
941
|
-
height: '100%',
|
|
942
|
-
overflow: 'hidden',
|
|
943
|
-
display: 'flex',
|
|
944
|
-
alignItems: 'center',
|
|
945
|
-
justifyContent: 'center',
|
|
946
|
-
}}
|
|
947
|
-
>
|
|
948
|
-
{imageElement}
|
|
949
|
-
|
|
950
|
-
{/* Carousel Navigation */}
|
|
951
|
-
{images.length > 1 && (
|
|
952
|
-
<>
|
|
953
|
-
{/* Previous Button */}
|
|
954
|
-
<button
|
|
955
|
-
onClick={prevCarouselItem}
|
|
956
|
-
disabled={carouselIndex === 0}
|
|
957
|
-
style={{
|
|
958
|
-
position: 'absolute',
|
|
959
|
-
left: '10px',
|
|
960
|
-
top: '50%',
|
|
961
|
-
transform: 'translateY(-50%)',
|
|
962
|
-
background: 'rgba(0,0,0,0.5)',
|
|
963
|
-
color: 'white',
|
|
964
|
-
border: 'none',
|
|
965
|
-
borderRadius: '50%',
|
|
966
|
-
width: '40px',
|
|
967
|
-
height: '40px',
|
|
968
|
-
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
969
|
-
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
970
|
-
display: 'flex',
|
|
971
|
-
alignItems: 'center',
|
|
972
|
-
justifyContent: 'center',
|
|
973
|
-
fontSize: '18px',
|
|
974
|
-
zIndex: 10,
|
|
975
|
-
}}
|
|
976
|
-
>
|
|
977
|
-
‹
|
|
978
|
-
</button>
|
|
979
|
-
|
|
980
|
-
{/* Next Button */}
|
|
981
|
-
<button
|
|
982
|
-
onClick={nextCarouselItem}
|
|
983
|
-
disabled={carouselIndex >= images.length - 1}
|
|
984
|
-
style={{
|
|
985
|
-
position: 'absolute',
|
|
986
|
-
right: '10px',
|
|
987
|
-
top: '50%',
|
|
988
|
-
transform: 'translateY(-50%)',
|
|
989
|
-
background: 'rgba(0,0,0,0.5)',
|
|
990
|
-
color: 'white',
|
|
991
|
-
border: 'none',
|
|
992
|
-
borderRadius: '50%',
|
|
993
|
-
width: '40px',
|
|
994
|
-
height: '40px',
|
|
995
|
-
cursor: carouselIndex >= images.length - 1 ? 'not-allowed' : 'pointer',
|
|
996
|
-
opacity: carouselIndex >= images.length - 1 ? 0.5 : 1,
|
|
997
|
-
display: 'flex',
|
|
998
|
-
alignItems: 'center',
|
|
999
|
-
justifyContent: 'center',
|
|
1000
|
-
fontSize: '18px',
|
|
1001
|
-
zIndex: 10,
|
|
1002
|
-
}}
|
|
1003
|
-
>
|
|
1004
|
-
›
|
|
1005
|
-
</button>
|
|
1006
|
-
|
|
1007
|
-
{/* Dots Indicator */}
|
|
1008
|
-
<div
|
|
1009
|
-
style={{
|
|
1010
|
-
position: 'absolute',
|
|
1011
|
-
bottom: '10px',
|
|
1012
|
-
left: '50%',
|
|
1013
|
-
transform: 'translateX(-50%)',
|
|
1014
|
-
display: 'flex',
|
|
1015
|
-
gap: '8px',
|
|
1016
|
-
zIndex: 10,
|
|
1017
|
-
}}
|
|
1018
|
-
>
|
|
1019
|
-
{images.map((_, index) => (
|
|
1020
|
-
<button
|
|
1021
|
-
key={index}
|
|
1022
|
-
onClick={() => goToCarouselItem(index)}
|
|
1023
|
-
style={{
|
|
1024
|
-
width: index === carouselIndex ? '12px' : '8px',
|
|
1025
|
-
height: index === carouselIndex ? '12px' : '8px',
|
|
1026
|
-
borderRadius: '50%',
|
|
1027
|
-
border: 'none',
|
|
1028
|
-
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1029
|
-
cursor: 'pointer',
|
|
1030
|
-
transition: 'all 0.3s ease',
|
|
1031
|
-
}}
|
|
1032
|
-
/>
|
|
1033
|
-
))}
|
|
1034
|
-
</div>
|
|
1035
|
-
</>
|
|
1036
|
-
)}
|
|
1037
|
-
</div>
|
|
1038
|
-
);
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
// Other layouts: grid display with limited images
|
|
1042
|
-
const getMaxImages = () => {
|
|
1043
|
-
switch (layout) {
|
|
1044
|
-
case '1x2': return 2;
|
|
1045
|
-
case '2x1': return 2;
|
|
1046
|
-
case '2x2': return 4;
|
|
1047
|
-
default: return images.length;
|
|
1048
|
-
}
|
|
1049
|
-
};
|
|
1050
|
-
|
|
1051
|
-
// For grid layouts (1x2, 2x1, 2x2), show one grid per slide
|
|
1052
|
-
// For 1x1 layout with scroll, show one item at a time
|
|
1053
|
-
if (layout !== '1x1' && scrollType) {
|
|
1054
|
-
// Group items into slides based on layout
|
|
1055
|
-
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1056
|
-
const slides: any[][] = [];
|
|
1057
|
-
for (let i = 0; i < images.length; i += itemsPerSlide) {
|
|
1058
|
-
slides.push(images.slice(i, i + itemsPerSlide));
|
|
824
|
+
}
|
|
825
|
+
break;
|
|
826
|
+
case 'VIDEO':
|
|
827
|
+
if (tab.tabContentVideo) {
|
|
828
|
+
const videoUrl = tab.tabContentVideo.video.url;
|
|
829
|
+
const videoAlt = tab.tabContentVideo.video.alt || 'Video';
|
|
830
|
+
// Access playerType from video object (may not be in type definition but exists in runtime)
|
|
831
|
+
const videoData = tab.tabContentVideo.video as any;
|
|
832
|
+
const playerType = videoData?.playerType;
|
|
833
|
+
|
|
834
|
+
if (!videoUrl) {
|
|
835
|
+
return <div style={{ padding: '20px', textAlign: 'center' }}>No video URL available</div>;
|
|
1059
836
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
style={{
|
|
1066
|
-
width: '100%',
|
|
1067
|
-
height: '100%',
|
|
1068
|
-
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1069
|
-
display: 'flex',
|
|
1070
|
-
flexDirection: scrollDirection as any,
|
|
1071
|
-
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1072
|
-
gap: 0,
|
|
1073
|
-
padding: 0,
|
|
1074
|
-
}}
|
|
1075
|
-
className="scroll-container"
|
|
1076
|
-
>
|
|
1077
|
-
{slides.map((slideImages, slideIndex) => (
|
|
1078
|
-
<div
|
|
1079
|
-
key={slideIndex}
|
|
1080
|
-
style={{
|
|
1081
|
-
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1082
|
-
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1083
|
-
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1084
|
-
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1085
|
-
flexShrink: 0,
|
|
1086
|
-
scrollSnapAlign: 'start',
|
|
1087
|
-
display: 'grid',
|
|
1088
|
-
gridTemplateColumns: getGridColumns(),
|
|
1089
|
-
gridTemplateRows: getGridRows(),
|
|
1090
|
-
gap: '3px',
|
|
1091
|
-
overflow: 'hidden',
|
|
1092
|
-
boxSizing: 'border-box',
|
|
1093
|
-
}}
|
|
1094
|
-
>
|
|
1095
|
-
{slideImages.map((image, index) => (
|
|
1096
|
-
<div
|
|
1097
|
-
key={index}
|
|
1098
|
-
className="media-box"
|
|
1099
|
-
style={{
|
|
1100
|
-
width: '100%',
|
|
1101
|
-
height: '100%',
|
|
1102
|
-
minHeight: 0,
|
|
1103
|
-
overflow: 'hidden',
|
|
1104
|
-
display: 'flex',
|
|
1105
|
-
alignItems: 'center',
|
|
1106
|
-
justifyContent: 'center',
|
|
1107
|
-
boxSizing: 'border-box',
|
|
1108
|
-
}}
|
|
1109
|
-
>
|
|
1110
|
-
<img
|
|
1111
|
-
src={getImageUrl(
|
|
1112
|
-
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1113
|
-
? image.image?.url || image.url
|
|
1114
|
-
: image.attr?.all?.url || image.attr?.url || image.url
|
|
1115
|
-
)}
|
|
1116
|
-
alt={
|
|
1117
|
-
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1118
|
-
? image.image?.alt || image.alt || ''
|
|
1119
|
-
: image.attr?.all?.alt || image.attr?.alt || image.alt || ''
|
|
1120
|
-
}
|
|
1121
|
-
className="media-content"
|
|
1122
|
-
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1123
|
-
/>
|
|
1124
|
-
</div>
|
|
1125
|
-
))}
|
|
1126
|
-
</div>
|
|
1127
|
-
))}
|
|
1128
|
-
</div>
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
// For 1x1 layout with scroll, show one item at a time (carousel-like)
|
|
1133
|
-
if (layout === '1x1' && scrollType) {
|
|
1134
|
-
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
837
|
+
|
|
838
|
+
// Check if it's a YouTube video (by playerType or URL)
|
|
839
|
+
const isYouTube = playerType === 'Youtube' || playerType === 'youtube' || getYouTubeVideoId(videoUrl) !== null;
|
|
840
|
+
const youtubeId = getYouTubeVideoId(videoUrl);
|
|
841
|
+
|
|
1135
842
|
return (
|
|
1136
|
-
<div
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
flexDirection: scrollDirection as any,
|
|
1143
|
-
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1144
|
-
gap: 0,
|
|
1145
|
-
padding: 0,
|
|
1146
|
-
}}
|
|
1147
|
-
className="scroll-container"
|
|
1148
|
-
>
|
|
1149
|
-
{images.map((image, index) => (
|
|
1150
|
-
<div
|
|
1151
|
-
key={index}
|
|
1152
|
-
className="media-box"
|
|
1153
|
-
style={{
|
|
1154
|
-
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1155
|
-
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1156
|
-
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1157
|
-
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1158
|
-
flexShrink: 0,
|
|
1159
|
-
scrollSnapAlign: 'start',
|
|
1160
|
-
}}
|
|
1161
|
-
>
|
|
1162
|
-
<img
|
|
1163
|
-
src={getImageUrl(
|
|
1164
|
-
getImageItemUrl(image, tab.tabContentGroupImage.type)
|
|
1165
|
-
)}
|
|
1166
|
-
alt={
|
|
1167
|
-
getImageItemAlt(image, tab.tabContentGroupImage.type)
|
|
1168
|
-
}
|
|
843
|
+
<div style={contentStyle}>
|
|
844
|
+
<div className="media-box">
|
|
845
|
+
{isYouTube && youtubeId ? (
|
|
846
|
+
<iframe
|
|
847
|
+
src={`https://www.youtube.com/embed/${youtubeId}`}
|
|
848
|
+
title={videoAlt}
|
|
1169
849
|
className="media-content"
|
|
1170
|
-
style={{
|
|
850
|
+
style={{ width: '100%', height: '100%', border: 'none' }}
|
|
851
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
852
|
+
allowFullScreen
|
|
1171
853
|
/>
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
// Group items into slides based on layout
|
|
1181
|
-
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1182
|
-
const slides: any[][] = [];
|
|
1183
|
-
for (let i = 0; i < images.length; i += itemsPerSlide) {
|
|
1184
|
-
slides.push(images.slice(i, i + itemsPerSlide));
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
const currentSlide = slides[carouselIndex] || slides[0] || [];
|
|
1188
|
-
|
|
1189
|
-
const groupImageContentStyle: React.CSSProperties = {
|
|
1190
|
-
display: 'grid',
|
|
1191
|
-
gridTemplateColumns: getGridColumns(),
|
|
1192
|
-
gridTemplateRows: getGridRows(),
|
|
1193
|
-
gap: '3px',
|
|
1194
|
-
height: '100%',
|
|
1195
|
-
width: '100%',
|
|
1196
|
-
overflow: 'hidden',
|
|
1197
|
-
alignContent: 'stretch',
|
|
1198
|
-
boxSizing: 'border-box',
|
|
1199
|
-
};
|
|
1200
|
-
|
|
1201
|
-
return (
|
|
1202
|
-
<div style={{ position: 'relative', width: '100%', height: '100%', overflow: 'hidden' }}>
|
|
1203
|
-
<div style={groupImageContentStyle}>
|
|
1204
|
-
{currentSlide.map((image, index) => (
|
|
1205
|
-
<div
|
|
1206
|
-
key={index}
|
|
1207
|
-
className="media-box"
|
|
1208
|
-
style={{
|
|
1209
|
-
width: '100%',
|
|
1210
|
-
height: '100%',
|
|
1211
|
-
minHeight: 0,
|
|
1212
|
-
minWidth: 0,
|
|
1213
|
-
overflow: 'hidden',
|
|
1214
|
-
display: 'flex',
|
|
1215
|
-
alignItems: 'center',
|
|
1216
|
-
justifyContent: 'center',
|
|
1217
|
-
boxSizing: 'border-box',
|
|
1218
|
-
}}
|
|
1219
|
-
>
|
|
1220
|
-
<img
|
|
1221
|
-
src={getImageUrl(
|
|
1222
|
-
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1223
|
-
? image.image?.url || image.url
|
|
1224
|
-
: image.attr?.all?.url || image.attr?.url || image.url
|
|
1225
|
-
)}
|
|
1226
|
-
alt={
|
|
1227
|
-
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1228
|
-
? image.image?.alt || image.alt || ''
|
|
1229
|
-
: image.attr?.all?.alt || image.attr?.alt || image.alt || ''
|
|
1230
|
-
}
|
|
1231
|
-
className="media-content"
|
|
1232
|
-
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1233
|
-
/>
|
|
1234
|
-
</div>
|
|
1235
|
-
))}
|
|
854
|
+
) : (
|
|
855
|
+
<video
|
|
856
|
+
src={getImageUrl(videoUrl)}
|
|
857
|
+
controls
|
|
858
|
+
className="media-content"
|
|
859
|
+
style={{ width: '100%', height: '100%', objectFit: objectFit as any }}
|
|
860
|
+
/>
|
|
861
|
+
)}
|
|
1236
862
|
</div>
|
|
1237
|
-
|
|
1238
|
-
{/* Carousel Navigation for grid slides */}
|
|
1239
|
-
{slides.length > 1 && (
|
|
1240
|
-
<>
|
|
1241
|
-
<button
|
|
1242
|
-
onClick={prevCarouselItem}
|
|
1243
|
-
disabled={carouselIndex === 0}
|
|
1244
|
-
style={{
|
|
1245
|
-
position: 'absolute',
|
|
1246
|
-
left: '10px',
|
|
1247
|
-
top: '50%',
|
|
1248
|
-
transform: 'translateY(-50%)',
|
|
1249
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1250
|
-
color: 'white',
|
|
1251
|
-
border: 'none',
|
|
1252
|
-
borderRadius: '50%',
|
|
1253
|
-
width: '40px',
|
|
1254
|
-
height: '40px',
|
|
1255
|
-
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1256
|
-
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1257
|
-
display: 'flex',
|
|
1258
|
-
alignItems: 'center',
|
|
1259
|
-
justifyContent: 'center',
|
|
1260
|
-
fontSize: '18px',
|
|
1261
|
-
zIndex: 10,
|
|
1262
|
-
}}
|
|
1263
|
-
>
|
|
1264
|
-
‹
|
|
1265
|
-
</button>
|
|
1266
|
-
<button
|
|
1267
|
-
onClick={nextCarouselItem}
|
|
1268
|
-
disabled={carouselIndex >= slides.length - 1}
|
|
1269
|
-
style={{
|
|
1270
|
-
position: 'absolute',
|
|
1271
|
-
right: '10px',
|
|
1272
|
-
top: '50%',
|
|
1273
|
-
transform: 'translateY(-50%)',
|
|
1274
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1275
|
-
color: 'white',
|
|
1276
|
-
border: 'none',
|
|
1277
|
-
borderRadius: '50%',
|
|
1278
|
-
width: '40px',
|
|
1279
|
-
height: '40px',
|
|
1280
|
-
cursor: carouselIndex >= slides.length - 1 ? 'not-allowed' : 'pointer',
|
|
1281
|
-
opacity: carouselIndex >= slides.length - 1 ? 0.5 : 1,
|
|
1282
|
-
display: 'flex',
|
|
1283
|
-
alignItems: 'center',
|
|
1284
|
-
justifyContent: 'center',
|
|
1285
|
-
fontSize: '18px',
|
|
1286
|
-
zIndex: 10,
|
|
1287
|
-
}}
|
|
1288
|
-
>
|
|
1289
|
-
›
|
|
1290
|
-
</button>
|
|
1291
|
-
<div
|
|
1292
|
-
style={{
|
|
1293
|
-
position: 'absolute',
|
|
1294
|
-
bottom: '10px',
|
|
1295
|
-
left: '50%',
|
|
1296
|
-
transform: 'translateX(-50%)',
|
|
1297
|
-
display: 'flex',
|
|
1298
|
-
gap: '8px',
|
|
1299
|
-
zIndex: 10,
|
|
1300
|
-
}}
|
|
1301
|
-
>
|
|
1302
|
-
{slides.map((_, index) => (
|
|
1303
|
-
<button
|
|
1304
|
-
key={index}
|
|
1305
|
-
onClick={() => goToCarouselItem(index)}
|
|
1306
|
-
style={{
|
|
1307
|
-
width: index === carouselIndex ? '12px' : '8px',
|
|
1308
|
-
height: index === carouselIndex ? '12px' : '8px',
|
|
1309
|
-
borderRadius: '50%',
|
|
1310
|
-
border: 'none',
|
|
1311
|
-
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1312
|
-
cursor: 'pointer',
|
|
1313
|
-
transition: 'all 0.3s ease',
|
|
1314
|
-
}}
|
|
1315
|
-
/>
|
|
1316
|
-
))}
|
|
1317
|
-
</div>
|
|
1318
|
-
</>
|
|
1319
|
-
)}
|
|
1320
863
|
</div>
|
|
1321
864
|
);
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
};
|
|
1337
|
-
|
|
1338
|
-
return (
|
|
1339
|
-
<div style={groupImageContentStyle}>
|
|
1340
|
-
{displayImages.map((image, index) => (
|
|
1341
|
-
<div key={index} className="media-box" style={{ width: '100%', height: '100%', minHeight: 0, minWidth: 0 }}>
|
|
1342
|
-
<img
|
|
1343
|
-
src={getImageUrl(
|
|
1344
|
-
getImageItemUrl(image, tab.tabContentGroupImage.type)
|
|
1345
|
-
)}
|
|
1346
|
-
alt={
|
|
1347
|
-
getImageItemAlt(image, tab.tabContentGroupImage.type)
|
|
1348
|
-
}
|
|
1349
|
-
className="media-content"
|
|
1350
|
-
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1351
|
-
/>
|
|
1352
|
-
</div>
|
|
1353
|
-
))}
|
|
1354
|
-
</div>
|
|
1355
|
-
);
|
|
1356
|
-
|
|
865
|
+
}
|
|
866
|
+
break;
|
|
867
|
+
|
|
868
|
+
case 'GROUPIMAGE':
|
|
869
|
+
if (tab.tabContentGroupImage) {
|
|
870
|
+
// Prioritize showItems, fallback to dynamic/static arrays
|
|
871
|
+
const images = tab.tabContentGroupImage.showItems && tab.tabContentGroupImage.showItems.length > 0
|
|
872
|
+
? tab.tabContentGroupImage.showItems
|
|
873
|
+
: (tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
874
|
+
? tab.tabContentGroupImage.dynamicImages
|
|
875
|
+
: (tab.tabContentGroupImage.staticImages || []));
|
|
876
|
+
|
|
877
|
+
if (!images || images.length === 0) {
|
|
878
|
+
return <div>No images available</div>;
|
|
1357
879
|
}
|
|
1358
|
-
break;
|
|
1359
880
|
|
|
1360
|
-
|
|
1361
|
-
if (
|
|
1362
|
-
// Prioritize showItems, fallback to dynamic/static arrays
|
|
1363
|
-
const videos = tab.tabContentGroupVideo.showItems && tab.tabContentGroupVideo.showItems.length > 0
|
|
1364
|
-
? tab.tabContentGroupVideo.showItems
|
|
1365
|
-
: (tab.tabContentGroupVideo.type === 'DYNAMIC'
|
|
1366
|
-
? tab.tabContentGroupVideo.dynamicVideos
|
|
1367
|
-
: (tab.tabContentGroupVideo.staticVideos || []));
|
|
1368
|
-
|
|
1369
|
-
if (!videos || videos.length === 0) {
|
|
1370
|
-
return <div>No videos available</div>;
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
// 1x1 layout: use scrollbar if scroll type is set, otherwise carousel
|
|
1374
|
-
if (layout === '1x1' && scrollType) {
|
|
881
|
+
// 1x1 layout: use scrollbar if scroll type is set, otherwise carousel
|
|
882
|
+
if (layout === '1x1' && scrollType) {
|
|
1375
883
|
// Use scrollable container with scrollbar - each item takes full width/height
|
|
1376
884
|
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1377
|
-
|
|
1378
|
-
|
|
885
|
+
|
|
1379
886
|
return (
|
|
1380
887
|
<div
|
|
1381
888
|
style={{
|
|
@@ -1390,7 +897,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
1390
897
|
}}
|
|
1391
898
|
className="scroll-container"
|
|
1392
899
|
>
|
|
1393
|
-
{
|
|
900
|
+
{images.map((image, index) => (
|
|
1394
901
|
<div
|
|
1395
902
|
key={index}
|
|
1396
903
|
className="media-box"
|
|
@@ -1403,722 +910,1176 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
1403
910
|
scrollSnapAlign: 'start',
|
|
1404
911
|
}}
|
|
1405
912
|
>
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
913
|
+
<img
|
|
914
|
+
src={getImageUrl(
|
|
915
|
+
getImageItemUrl(image, tab.tabContentGroupImage.type)
|
|
916
|
+
)}
|
|
917
|
+
alt={
|
|
918
|
+
getImageItemAlt(image, tab.tabContentGroupImage.type)
|
|
919
|
+
}
|
|
920
|
+
className="media-content"
|
|
921
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
922
|
+
/>
|
|
1411
923
|
</div>
|
|
1412
924
|
))}
|
|
1413
925
|
</div>
|
|
1414
926
|
);
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// 1x1 layout: carousel display (fallback when scroll is not set)
|
|
930
|
+
if (layout === '1x1') {
|
|
931
|
+
const currentImage = images[carouselIndex] || images[0];
|
|
932
|
+
|
|
933
|
+
const imageElement = currentImage ? (
|
|
934
|
+
<div className="media-box" style={{ width: '100%', height: '100%' }}>
|
|
935
|
+
<img
|
|
936
|
+
src={getImageUrl(
|
|
937
|
+
getImageItemUrl(currentImage, tab.tabContentGroupImage.type)
|
|
938
|
+
)}
|
|
939
|
+
alt={
|
|
940
|
+
getImageItemAlt(currentImage, tab.tabContentGroupImage.type)
|
|
941
|
+
}
|
|
942
|
+
className="media-content"
|
|
943
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
944
|
+
/>
|
|
945
|
+
</div>
|
|
1430
946
|
) : null;
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
947
|
+
|
|
948
|
+
return (
|
|
949
|
+
<div
|
|
1434
950
|
style={{
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
951
|
+
position: 'relative',
|
|
952
|
+
width: '100%',
|
|
953
|
+
height: '100%',
|
|
954
|
+
overflow: 'hidden',
|
|
955
|
+
display: 'flex',
|
|
956
|
+
alignItems: 'center',
|
|
957
|
+
justifyContent: 'center',
|
|
1442
958
|
}}
|
|
1443
|
-
|
|
1444
|
-
{
|
|
1445
|
-
|
|
1446
|
-
{videoElement}
|
|
1447
|
-
</div>
|
|
1448
|
-
)}
|
|
1449
|
-
|
|
959
|
+
>
|
|
960
|
+
{imageElement}
|
|
961
|
+
|
|
1450
962
|
{/* Carousel Navigation */}
|
|
1451
|
-
{
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
<button
|
|
1455
|
-
onClick={prevCarouselItem}
|
|
1456
|
-
disabled={carouselIndex === 0}
|
|
1457
|
-
style={{
|
|
1458
|
-
position: 'absolute',
|
|
1459
|
-
left: '10px',
|
|
1460
|
-
top: '50%',
|
|
1461
|
-
transform: 'translateY(-50%)',
|
|
1462
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1463
|
-
color: 'white',
|
|
1464
|
-
border: 'none',
|
|
1465
|
-
borderRadius: '50%',
|
|
1466
|
-
width: '40px',
|
|
1467
|
-
height: '40px',
|
|
1468
|
-
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1469
|
-
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1470
|
-
display: 'flex',
|
|
1471
|
-
alignItems: 'center',
|
|
1472
|
-
justifyContent: 'center',
|
|
1473
|
-
fontSize: '18px',
|
|
1474
|
-
zIndex: 10,
|
|
1475
|
-
}}
|
|
1476
|
-
>
|
|
1477
|
-
‹
|
|
1478
|
-
</button>
|
|
1479
|
-
|
|
1480
|
-
{/* Next Button */}
|
|
1481
|
-
<button
|
|
1482
|
-
onClick={nextCarouselItem}
|
|
1483
|
-
disabled={carouselIndex >= videos.length - 1}
|
|
1484
|
-
style={{
|
|
1485
|
-
position: 'absolute',
|
|
1486
|
-
right: '10px',
|
|
1487
|
-
top: '50%',
|
|
1488
|
-
transform: 'translateY(-50%)',
|
|
1489
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1490
|
-
color: 'white',
|
|
1491
|
-
border: 'none',
|
|
1492
|
-
borderRadius: '50%',
|
|
1493
|
-
width: '40px',
|
|
1494
|
-
height: '40px',
|
|
1495
|
-
cursor: carouselIndex >= videos.length - 1 ? 'not-allowed' : 'pointer',
|
|
1496
|
-
opacity: carouselIndex >= videos.length - 1 ? 0.5 : 1,
|
|
1497
|
-
display: 'flex',
|
|
1498
|
-
alignItems: 'center',
|
|
1499
|
-
justifyContent: 'center',
|
|
1500
|
-
fontSize: '18px',
|
|
1501
|
-
zIndex: 10,
|
|
1502
|
-
}}
|
|
1503
|
-
>
|
|
1504
|
-
›
|
|
1505
|
-
</button>
|
|
1506
|
-
|
|
1507
|
-
{/* Dots Indicator */}
|
|
1508
|
-
<div
|
|
1509
|
-
style={{
|
|
1510
|
-
position: 'absolute',
|
|
1511
|
-
bottom: '10px',
|
|
1512
|
-
left: '50%',
|
|
1513
|
-
transform: 'translateX(-50%)',
|
|
1514
|
-
display: 'flex',
|
|
1515
|
-
gap: '8px',
|
|
1516
|
-
zIndex: 10,
|
|
1517
|
-
}}
|
|
1518
|
-
>
|
|
1519
|
-
{videos.map((_, index) => (
|
|
963
|
+
{images.length > 1 && (
|
|
964
|
+
<>
|
|
965
|
+
{/* Previous Button */}
|
|
1520
966
|
<button
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
)}
|
|
1537
|
-
</div>
|
|
1538
|
-
);
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
// Other layouts: grid display with limited videos
|
|
1542
|
-
const getMaxVideos = () => {
|
|
1543
|
-
switch (layout) {
|
|
1544
|
-
case '1x2': return 2;
|
|
1545
|
-
case '2x1': return 2;
|
|
1546
|
-
case '2x2': return 4;
|
|
1547
|
-
default: return videos.length;
|
|
1548
|
-
}
|
|
1549
|
-
};
|
|
1550
|
-
|
|
1551
|
-
const isDynamic = tab.tabContentGroupVideo.type === 'DYNAMIC';
|
|
1552
|
-
|
|
1553
|
-
// For grid layouts (1x2, 2x1, 2x2), show one grid per slide
|
|
1554
|
-
// For 1x1 layout with scroll, show one item at a time
|
|
1555
|
-
if (layout !== '1x1' && scrollType) {
|
|
1556
|
-
// Group items into slides based on layout
|
|
1557
|
-
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1558
|
-
const slides: any[][] = [];
|
|
1559
|
-
for (let i = 0; i < videos.length; i += itemsPerSlide) {
|
|
1560
|
-
slides.push(videos.slice(i, i + itemsPerSlide));
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1564
|
-
|
|
1565
|
-
return (
|
|
1566
|
-
<div
|
|
1567
|
-
style={{
|
|
1568
|
-
width: '100%',
|
|
1569
|
-
height: '100%',
|
|
1570
|
-
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1571
|
-
display: 'flex',
|
|
1572
|
-
flexDirection: scrollDirection as any,
|
|
1573
|
-
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1574
|
-
gap: 0,
|
|
1575
|
-
padding: 0,
|
|
1576
|
-
}}
|
|
1577
|
-
className="scroll-container"
|
|
1578
|
-
>
|
|
1579
|
-
{slides.map((slideVideos, slideIndex) => (
|
|
1580
|
-
<div
|
|
1581
|
-
key={slideIndex}
|
|
1582
|
-
style={{
|
|
1583
|
-
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1584
|
-
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1585
|
-
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1586
|
-
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1587
|
-
flexShrink: 0,
|
|
1588
|
-
scrollSnapAlign: 'start',
|
|
1589
|
-
display: 'grid',
|
|
1590
|
-
gridTemplateColumns: getGridColumns(),
|
|
1591
|
-
gridTemplateRows: getGridRows(),
|
|
1592
|
-
gap: '3px',
|
|
1593
|
-
overflow: 'hidden',
|
|
1594
|
-
alignContent: 'stretch',
|
|
1595
|
-
boxSizing: 'border-box',
|
|
1596
|
-
}}
|
|
1597
|
-
>
|
|
1598
|
-
{slideVideos.map((video, index) => (
|
|
1599
|
-
<div
|
|
1600
|
-
key={index}
|
|
1601
|
-
className="media-box"
|
|
1602
|
-
style={{
|
|
1603
|
-
width: '100%',
|
|
1604
|
-
height: '100%',
|
|
1605
|
-
minHeight: 0,
|
|
1606
|
-
overflow: 'hidden',
|
|
967
|
+
onClick={prevCarouselItem}
|
|
968
|
+
disabled={carouselIndex === 0}
|
|
969
|
+
style={{
|
|
970
|
+
position: 'absolute',
|
|
971
|
+
left: '10px',
|
|
972
|
+
top: '50%',
|
|
973
|
+
transform: 'translateY(-50%)',
|
|
974
|
+
background: 'rgba(0,0,0,0.5)',
|
|
975
|
+
color: 'white',
|
|
976
|
+
border: 'none',
|
|
977
|
+
borderRadius: '50%',
|
|
978
|
+
width: '40px',
|
|
979
|
+
height: '40px',
|
|
980
|
+
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
981
|
+
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1607
982
|
display: 'flex',
|
|
1608
983
|
alignItems: 'center',
|
|
1609
984
|
justifyContent: 'center',
|
|
1610
|
-
|
|
985
|
+
fontSize: '18px',
|
|
986
|
+
zIndex: 10,
|
|
1611
987
|
}}
|
|
1612
988
|
>
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
989
|
+
‹
|
|
990
|
+
</button>
|
|
991
|
+
|
|
992
|
+
{/* Next Button */}
|
|
993
|
+
<button
|
|
994
|
+
onClick={nextCarouselItem}
|
|
995
|
+
disabled={carouselIndex >= images.length - 1}
|
|
996
|
+
style={{
|
|
997
|
+
position: 'absolute',
|
|
998
|
+
right: '10px',
|
|
999
|
+
top: '50%',
|
|
1000
|
+
transform: 'translateY(-50%)',
|
|
1001
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1002
|
+
color: 'white',
|
|
1003
|
+
border: 'none',
|
|
1004
|
+
borderRadius: '50%',
|
|
1005
|
+
width: '40px',
|
|
1006
|
+
height: '40px',
|
|
1007
|
+
cursor: carouselIndex >= images.length - 1 ? 'not-allowed' : 'pointer',
|
|
1008
|
+
opacity: carouselIndex >= images.length - 1 ? 0.5 : 1,
|
|
1009
|
+
display: 'flex',
|
|
1010
|
+
alignItems: 'center',
|
|
1011
|
+
justifyContent: 'center',
|
|
1012
|
+
fontSize: '18px',
|
|
1013
|
+
zIndex: 10,
|
|
1014
|
+
}}
|
|
1015
|
+
>
|
|
1016
|
+
›
|
|
1017
|
+
</button>
|
|
1018
|
+
|
|
1019
|
+
{/* Dots Indicator */}
|
|
1020
|
+
<div
|
|
1021
|
+
style={{
|
|
1022
|
+
position: 'absolute',
|
|
1023
|
+
bottom: '10px',
|
|
1024
|
+
left: '50%',
|
|
1025
|
+
transform: 'translateX(-50%)',
|
|
1026
|
+
display: 'flex',
|
|
1027
|
+
gap: '8px',
|
|
1028
|
+
zIndex: 10,
|
|
1029
|
+
}}
|
|
1030
|
+
>
|
|
1031
|
+
{images.map((_, index) => (
|
|
1032
|
+
<button
|
|
1033
|
+
key={index}
|
|
1034
|
+
onClick={() => goToCarouselItem(index)}
|
|
1035
|
+
style={{
|
|
1036
|
+
width: index === carouselIndex ? '12px' : '8px',
|
|
1037
|
+
height: index === carouselIndex ? '12px' : '8px',
|
|
1038
|
+
borderRadius: '50%',
|
|
1039
|
+
border: 'none',
|
|
1040
|
+
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1041
|
+
cursor: 'pointer',
|
|
1042
|
+
transition: 'all 0.3s ease',
|
|
1043
|
+
}}
|
|
1044
|
+
/>
|
|
1045
|
+
))}
|
|
1046
|
+
</div>
|
|
1047
|
+
</>
|
|
1048
|
+
)}
|
|
1049
|
+
</div>
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Other layouts: grid display with limited images
|
|
1054
|
+
const getMaxImages = () => {
|
|
1055
|
+
switch (layout) {
|
|
1056
|
+
case '1x2': return 2;
|
|
1057
|
+
case '2x1': return 2;
|
|
1058
|
+
case '2x2': return 4;
|
|
1059
|
+
default: return images.length;
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
// For grid layouts (1x2, 2x1, 2x2), show one grid per slide
|
|
1064
|
+
// For 1x1 layout with scroll, show one item at a time
|
|
1065
|
+
if (layout !== '1x1' && scrollType) {
|
|
1066
|
+
// Group items into slides based on layout
|
|
1067
|
+
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1068
|
+
const slides: any[][] = [];
|
|
1069
|
+
for (let i = 0; i < images.length; i += itemsPerSlide) {
|
|
1070
|
+
slides.push(images.slice(i, i + itemsPerSlide));
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1074
|
+
|
|
1075
|
+
return (
|
|
1076
|
+
<div
|
|
1077
|
+
style={{
|
|
1078
|
+
width: '100%',
|
|
1079
|
+
height: '100%',
|
|
1080
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1081
|
+
display: 'flex',
|
|
1082
|
+
flexDirection: scrollDirection as any,
|
|
1083
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1084
|
+
gap: 0,
|
|
1085
|
+
padding: 0,
|
|
1086
|
+
}}
|
|
1087
|
+
className="scroll-container"
|
|
1088
|
+
>
|
|
1089
|
+
{slides.map((slideImages, slideIndex) => (
|
|
1090
|
+
<div
|
|
1091
|
+
key={slideIndex}
|
|
1092
|
+
style={{
|
|
1093
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1094
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1095
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1096
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1097
|
+
flexShrink: 0,
|
|
1098
|
+
scrollSnapAlign: 'start',
|
|
1099
|
+
display: 'grid',
|
|
1100
|
+
gridTemplateColumns: getGridColumns(),
|
|
1101
|
+
gridTemplateRows: getGridRows(),
|
|
1102
|
+
gap: '3px',
|
|
1103
|
+
overflow: 'hidden',
|
|
1104
|
+
boxSizing: 'border-box',
|
|
1105
|
+
}}
|
|
1106
|
+
>
|
|
1107
|
+
{slideImages.map((image, index) => (
|
|
1108
|
+
<div
|
|
1109
|
+
key={index}
|
|
1110
|
+
className="media-box"
|
|
1111
|
+
style={{
|
|
1112
|
+
width: '100%',
|
|
1113
|
+
height: '100%',
|
|
1114
|
+
minHeight: 0,
|
|
1115
|
+
overflow: 'hidden',
|
|
1116
|
+
display: 'flex',
|
|
1117
|
+
alignItems: 'center',
|
|
1118
|
+
justifyContent: 'center',
|
|
1119
|
+
boxSizing: 'border-box',
|
|
1120
|
+
}}
|
|
1121
|
+
>
|
|
1122
|
+
<img
|
|
1123
|
+
src={getImageUrl(
|
|
1124
|
+
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1125
|
+
? image.image?.url || image.url
|
|
1126
|
+
: image.attr?.all?.url || image.attr?.url || image.url
|
|
1127
|
+
)}
|
|
1128
|
+
alt={
|
|
1129
|
+
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1130
|
+
? image.image?.alt || image.alt || ''
|
|
1131
|
+
: image.attr?.all?.alt || image.attr?.alt || image.alt || ''
|
|
1132
|
+
}
|
|
1133
|
+
className="media-content"
|
|
1134
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1135
|
+
/>
|
|
1136
|
+
</div>
|
|
1137
|
+
))}
|
|
1138
|
+
</div>
|
|
1139
|
+
))}
|
|
1140
|
+
</div>
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// For 1x1 layout with scroll, show one item at a time (carousel-like)
|
|
1145
|
+
if (layout === '1x1' && scrollType) {
|
|
1146
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1147
|
+
return (
|
|
1148
|
+
<div
|
|
1149
|
+
style={{
|
|
1150
|
+
width: '100%',
|
|
1151
|
+
height: '100%',
|
|
1152
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1153
|
+
display: 'flex',
|
|
1154
|
+
flexDirection: scrollDirection as any,
|
|
1155
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1156
|
+
gap: 0,
|
|
1157
|
+
padding: 0,
|
|
1158
|
+
}}
|
|
1159
|
+
className="scroll-container"
|
|
1160
|
+
>
|
|
1161
|
+
{images.map((image, index) => (
|
|
1162
|
+
<div
|
|
1163
|
+
key={index}
|
|
1164
|
+
className="media-box"
|
|
1165
|
+
style={{
|
|
1166
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1167
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1168
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1169
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1170
|
+
flexShrink: 0,
|
|
1171
|
+
scrollSnapAlign: 'start',
|
|
1172
|
+
}}
|
|
1173
|
+
>
|
|
1174
|
+
<img
|
|
1175
|
+
src={getImageUrl(
|
|
1176
|
+
getImageItemUrl(image, tab.tabContentGroupImage.type)
|
|
1177
|
+
)}
|
|
1178
|
+
alt={
|
|
1179
|
+
getImageItemAlt(image, tab.tabContentGroupImage.type)
|
|
1180
|
+
}
|
|
1181
|
+
className="media-content"
|
|
1182
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1183
|
+
/>
|
|
1184
|
+
</div>
|
|
1185
|
+
))}
|
|
1186
|
+
</div>
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// Grid layout without scroll - show one grid per slide with carousel navigation
|
|
1191
|
+
if (layout !== '1x1') {
|
|
1192
|
+
// Group items into slides based on layout
|
|
1193
|
+
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1194
|
+
const slides: any[][] = [];
|
|
1195
|
+
for (let i = 0; i < images.length; i += itemsPerSlide) {
|
|
1196
|
+
slides.push(images.slice(i, i + itemsPerSlide));
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
const currentSlide = slides[carouselIndex] || slides[0] || [];
|
|
1200
|
+
|
|
1201
|
+
const groupImageContentStyle: React.CSSProperties = {
|
|
1202
|
+
display: 'grid',
|
|
1203
|
+
gridTemplateColumns: getGridColumns(),
|
|
1204
|
+
gridTemplateRows: getGridRows(),
|
|
1205
|
+
gap: '3px',
|
|
1206
|
+
height: '100%',
|
|
1207
|
+
width: '100%',
|
|
1208
|
+
overflow: 'hidden',
|
|
1209
|
+
alignContent: 'stretch',
|
|
1210
|
+
boxSizing: 'border-box',
|
|
1211
|
+
};
|
|
1212
|
+
|
|
1213
|
+
return (
|
|
1214
|
+
<div style={{ position: 'relative', width: '100%', height: '100%', overflow: 'hidden' }}>
|
|
1215
|
+
<div style={groupImageContentStyle}>
|
|
1216
|
+
{currentSlide.map((image, index) => (
|
|
1217
|
+
<div
|
|
1218
|
+
key={index}
|
|
1219
|
+
className="media-box"
|
|
1220
|
+
style={{
|
|
1221
|
+
width: '100%',
|
|
1222
|
+
height: '100%',
|
|
1223
|
+
minHeight: 0,
|
|
1224
|
+
minWidth: 0,
|
|
1225
|
+
overflow: 'hidden',
|
|
1226
|
+
display: 'flex',
|
|
1227
|
+
alignItems: 'center',
|
|
1228
|
+
justifyContent: 'center',
|
|
1229
|
+
boxSizing: 'border-box',
|
|
1230
|
+
}}
|
|
1231
|
+
>
|
|
1232
|
+
<img
|
|
1233
|
+
src={getImageUrl(
|
|
1234
|
+
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1235
|
+
? image.image?.url || image.url
|
|
1236
|
+
: image.attr?.all?.url || image.attr?.url || image.url
|
|
1237
|
+
)}
|
|
1238
|
+
alt={
|
|
1239
|
+
tab.tabContentGroupImage.type === 'DYNAMIC'
|
|
1240
|
+
? image.image?.alt || image.alt || ''
|
|
1241
|
+
: image.attr?.all?.alt || image.attr?.alt || image.alt || ''
|
|
1242
|
+
}
|
|
1243
|
+
className="media-content"
|
|
1244
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1245
|
+
/>
|
|
1246
|
+
</div>
|
|
1247
|
+
))}
|
|
1248
|
+
</div>
|
|
1249
|
+
|
|
1250
|
+
{/* Carousel Navigation for grid slides */}
|
|
1251
|
+
{slides.length > 1 && (
|
|
1252
|
+
<>
|
|
1253
|
+
<button
|
|
1254
|
+
onClick={prevCarouselItem}
|
|
1255
|
+
disabled={carouselIndex === 0}
|
|
1256
|
+
style={{
|
|
1257
|
+
position: 'absolute',
|
|
1258
|
+
left: '10px',
|
|
1259
|
+
top: '50%',
|
|
1260
|
+
transform: 'translateY(-50%)',
|
|
1261
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1262
|
+
color: 'white',
|
|
1263
|
+
border: 'none',
|
|
1264
|
+
borderRadius: '50%',
|
|
1265
|
+
width: '40px',
|
|
1266
|
+
height: '40px',
|
|
1267
|
+
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1268
|
+
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1269
|
+
display: 'flex',
|
|
1270
|
+
alignItems: 'center',
|
|
1271
|
+
justifyContent: 'center',
|
|
1272
|
+
fontSize: '18px',
|
|
1273
|
+
zIndex: 10,
|
|
1274
|
+
}}
|
|
1275
|
+
>
|
|
1276
|
+
‹
|
|
1277
|
+
</button>
|
|
1278
|
+
<button
|
|
1279
|
+
onClick={nextCarouselItem}
|
|
1280
|
+
disabled={carouselIndex >= slides.length - 1}
|
|
1281
|
+
style={{
|
|
1282
|
+
position: 'absolute',
|
|
1283
|
+
right: '10px',
|
|
1284
|
+
top: '50%',
|
|
1285
|
+
transform: 'translateY(-50%)',
|
|
1286
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1287
|
+
color: 'white',
|
|
1288
|
+
border: 'none',
|
|
1289
|
+
borderRadius: '50%',
|
|
1290
|
+
width: '40px',
|
|
1291
|
+
height: '40px',
|
|
1292
|
+
cursor: carouselIndex >= slides.length - 1 ? 'not-allowed' : 'pointer',
|
|
1293
|
+
opacity: carouselIndex >= slides.length - 1 ? 0.5 : 1,
|
|
1294
|
+
display: 'flex',
|
|
1295
|
+
alignItems: 'center',
|
|
1296
|
+
justifyContent: 'center',
|
|
1297
|
+
fontSize: '18px',
|
|
1298
|
+
zIndex: 10,
|
|
1299
|
+
}}
|
|
1300
|
+
>
|
|
1301
|
+
›
|
|
1302
|
+
</button>
|
|
1303
|
+
<div
|
|
1304
|
+
style={{
|
|
1305
|
+
position: 'absolute',
|
|
1306
|
+
bottom: '10px',
|
|
1307
|
+
left: '50%',
|
|
1308
|
+
transform: 'translateX(-50%)',
|
|
1309
|
+
display: 'flex',
|
|
1310
|
+
gap: '8px',
|
|
1311
|
+
zIndex: 10,
|
|
1312
|
+
}}
|
|
1313
|
+
>
|
|
1314
|
+
{slides.map((_, index) => (
|
|
1315
|
+
<button
|
|
1316
|
+
key={index}
|
|
1317
|
+
onClick={() => goToCarouselItem(index)}
|
|
1318
|
+
style={{
|
|
1319
|
+
width: index === carouselIndex ? '12px' : '8px',
|
|
1320
|
+
height: index === carouselIndex ? '12px' : '8px',
|
|
1321
|
+
borderRadius: '50%',
|
|
1322
|
+
border: 'none',
|
|
1323
|
+
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1324
|
+
cursor: 'pointer',
|
|
1325
|
+
transition: 'all 0.3s ease',
|
|
1326
|
+
}}
|
|
1327
|
+
/>
|
|
1328
|
+
))}
|
|
1329
|
+
</div>
|
|
1330
|
+
</>
|
|
1331
|
+
)}
|
|
1332
|
+
</div>
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// Fallback for 1x1 or other cases
|
|
1337
|
+
const maxImages = getMaxImages();
|
|
1338
|
+
const displayImages = images.slice(0, maxImages);
|
|
1339
|
+
|
|
1340
|
+
const groupImageContentStyle = {
|
|
1341
|
+
display: 'grid',
|
|
1342
|
+
gridTemplateColumns: getGridColumns(),
|
|
1343
|
+
gridTemplateRows: getGridRows(),
|
|
1344
|
+
gap: '3px',
|
|
1345
|
+
height: '100%',
|
|
1346
|
+
width: '100%',
|
|
1347
|
+
overflow: 'hidden'
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
return (
|
|
1351
|
+
<div style={groupImageContentStyle}>
|
|
1352
|
+
{displayImages.map((image, index) => (
|
|
1353
|
+
<div key={index} className="media-box" style={{ width: '100%', height: '100%', minHeight: 0, minWidth: 0 }}>
|
|
1354
|
+
<img
|
|
1355
|
+
src={getImageUrl(
|
|
1356
|
+
getImageItemUrl(image, tab.tabContentGroupImage.type)
|
|
1357
|
+
)}
|
|
1358
|
+
alt={
|
|
1359
|
+
getImageItemAlt(image, tab.tabContentGroupImage.type)
|
|
1360
|
+
}
|
|
1361
|
+
className="media-content"
|
|
1362
|
+
style={{ objectFit: objectFit as any, width: '100%', height: '100%' }}
|
|
1363
|
+
/>
|
|
1364
|
+
</div>
|
|
1365
|
+
))}
|
|
1366
|
+
</div>
|
|
1367
|
+
);
|
|
1368
|
+
|
|
1369
|
+
}
|
|
1370
|
+
break;
|
|
1371
|
+
|
|
1372
|
+
case 'GROUPVIDEO':
|
|
1373
|
+
if (tab.tabContentGroupVideo) {
|
|
1374
|
+
// Prioritize showItems, fallback to dynamic/static arrays
|
|
1375
|
+
const videos = tab.tabContentGroupVideo.showItems && tab.tabContentGroupVideo.showItems.length > 0
|
|
1376
|
+
? tab.tabContentGroupVideo.showItems
|
|
1377
|
+
: (tab.tabContentGroupVideo.type === 'DYNAMIC'
|
|
1378
|
+
? tab.tabContentGroupVideo.dynamicVideos
|
|
1379
|
+
: (tab.tabContentGroupVideo.staticVideos || []));
|
|
1380
|
+
|
|
1381
|
+
if (!videos || videos.length === 0) {
|
|
1382
|
+
return <div>No videos available</div>;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
// 1x1 layout: use scrollbar if scroll type is set, otherwise carousel
|
|
1386
|
+
if (layout === '1x1' && scrollType) {
|
|
1387
|
+
// Use scrollable container with scrollbar - each item takes full width/height
|
|
1388
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1389
|
+
const isDynamic = tab.tabContentGroupVideo.type === 'DYNAMIC';
|
|
1390
|
+
|
|
1391
|
+
return (
|
|
1392
|
+
<div
|
|
1393
|
+
style={{
|
|
1394
|
+
width: '100%',
|
|
1395
|
+
height: '100%',
|
|
1396
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1397
|
+
display: 'flex',
|
|
1398
|
+
flexDirection: scrollDirection as any,
|
|
1399
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1400
|
+
gap: 0,
|
|
1401
|
+
padding: 0,
|
|
1402
|
+
}}
|
|
1403
|
+
className="scroll-container"
|
|
1404
|
+
>
|
|
1405
|
+
{videos.map((video, index) => (
|
|
1406
|
+
<div
|
|
1407
|
+
key={index}
|
|
1408
|
+
className="media-box"
|
|
1409
|
+
style={{
|
|
1410
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1411
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1412
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1413
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1414
|
+
flexShrink: 0,
|
|
1415
|
+
scrollSnapAlign: 'start',
|
|
1416
|
+
}}
|
|
1417
|
+
>
|
|
1418
|
+
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1419
|
+
width: '100%',
|
|
1420
|
+
height: '100%',
|
|
1421
|
+
objectFit: objectFit as any
|
|
1422
|
+
})}
|
|
1423
|
+
</div>
|
|
1424
|
+
))}
|
|
1425
|
+
</div>
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// 1x1 layout: carousel display (fallback when scroll is not set)
|
|
1430
|
+
if (layout === '1x1') {
|
|
1431
|
+
const currentVideo = videos[carouselIndex] || videos[0];
|
|
1432
|
+
const isDynamic = tab.tabContentGroupVideo.type === 'DYNAMIC';
|
|
1433
|
+
|
|
1434
|
+
const videoElement = currentVideo ? (
|
|
1435
|
+
<div className="media-box" style={{ width: '100%', height: '100%' }}>
|
|
1436
|
+
{renderVideoPlayer(currentVideo, isDynamic, 'media-content', {
|
|
1437
|
+
width: '100%',
|
|
1438
|
+
height: '100%',
|
|
1439
|
+
objectFit: objectFit as any
|
|
1440
|
+
})}
|
|
1441
|
+
</div>
|
|
1442
|
+
) : null;
|
|
1443
|
+
|
|
1444
|
+
return (
|
|
1445
|
+
<div
|
|
1446
|
+
style={{
|
|
1447
|
+
position: 'relative',
|
|
1448
|
+
width: '100%',
|
|
1449
|
+
height: '100%',
|
|
1450
|
+
overflow: 'hidden',
|
|
1451
|
+
display: 'flex',
|
|
1452
|
+
alignItems: 'stretch',
|
|
1453
|
+
justifyContent: 'center',
|
|
1454
|
+
}}
|
|
1455
|
+
>
|
|
1456
|
+
{currentVideo && (
|
|
1457
|
+
<div style={{ width: '100%', height: '100%', display: 'flex' }}>
|
|
1458
|
+
{videoElement}
|
|
1459
|
+
</div>
|
|
1460
|
+
)}
|
|
1461
|
+
|
|
1462
|
+
{/* Carousel Navigation */}
|
|
1463
|
+
{videos.length > 1 && (
|
|
1464
|
+
<>
|
|
1465
|
+
{/* Prev Button */}
|
|
1466
|
+
<button
|
|
1467
|
+
onClick={prevCarouselItem}
|
|
1468
|
+
disabled={carouselIndex === 0}
|
|
1469
|
+
style={{
|
|
1470
|
+
position: 'absolute',
|
|
1471
|
+
left: '10px',
|
|
1472
|
+
top: '50%',
|
|
1473
|
+
transform: 'translateY(-50%)',
|
|
1474
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1475
|
+
color: 'white',
|
|
1476
|
+
border: 'none',
|
|
1477
|
+
borderRadius: '50%',
|
|
1478
|
+
width: '40px',
|
|
1479
|
+
height: '40px',
|
|
1480
|
+
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1481
|
+
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1482
|
+
display: 'flex',
|
|
1483
|
+
alignItems: 'center',
|
|
1484
|
+
justifyContent: 'center',
|
|
1485
|
+
fontSize: '18px',
|
|
1486
|
+
zIndex: 10,
|
|
1487
|
+
}}
|
|
1488
|
+
>
|
|
1489
|
+
‹
|
|
1490
|
+
</button>
|
|
1491
|
+
|
|
1492
|
+
{/* Next Button */}
|
|
1493
|
+
<button
|
|
1494
|
+
onClick={nextCarouselItem}
|
|
1495
|
+
disabled={carouselIndex >= videos.length - 1}
|
|
1496
|
+
style={{
|
|
1497
|
+
position: 'absolute',
|
|
1498
|
+
right: '10px',
|
|
1499
|
+
top: '50%',
|
|
1500
|
+
transform: 'translateY(-50%)',
|
|
1501
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1502
|
+
color: 'white',
|
|
1503
|
+
border: 'none',
|
|
1504
|
+
borderRadius: '50%',
|
|
1505
|
+
width: '40px',
|
|
1506
|
+
height: '40px',
|
|
1507
|
+
cursor: carouselIndex >= videos.length - 1 ? 'not-allowed' : 'pointer',
|
|
1508
|
+
opacity: carouselIndex >= videos.length - 1 ? 0.5 : 1,
|
|
1509
|
+
display: 'flex',
|
|
1510
|
+
alignItems: 'center',
|
|
1511
|
+
justifyContent: 'center',
|
|
1512
|
+
fontSize: '18px',
|
|
1513
|
+
zIndex: 10,
|
|
1514
|
+
}}
|
|
1515
|
+
>
|
|
1516
|
+
›
|
|
1517
|
+
</button>
|
|
1518
|
+
|
|
1519
|
+
{/* Dots Indicator */}
|
|
1520
|
+
<div
|
|
1521
|
+
style={{
|
|
1522
|
+
position: 'absolute',
|
|
1523
|
+
bottom: '10px',
|
|
1524
|
+
left: '50%',
|
|
1525
|
+
transform: 'translateX(-50%)',
|
|
1526
|
+
display: 'flex',
|
|
1527
|
+
gap: '8px',
|
|
1528
|
+
zIndex: 10,
|
|
1529
|
+
}}
|
|
1530
|
+
>
|
|
1531
|
+
{videos.map((_, index) => (
|
|
1532
|
+
<button
|
|
1533
|
+
key={index}
|
|
1534
|
+
onClick={() => goToCarouselItem(index)}
|
|
1535
|
+
style={{
|
|
1536
|
+
width: index === carouselIndex ? '12px' : '8px',
|
|
1537
|
+
height: index === carouselIndex ? '12px' : '8px',
|
|
1538
|
+
borderRadius: '50%',
|
|
1539
|
+
border: 'none',
|
|
1540
|
+
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1541
|
+
cursor: 'pointer',
|
|
1542
|
+
transition: 'all 0.3s ease',
|
|
1543
|
+
}}
|
|
1544
|
+
/>
|
|
1545
|
+
))}
|
|
1618
1546
|
</div>
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
);
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// For 1x1 layout with scroll, show one item at a time (carousel-like)
|
|
1627
|
-
if (layout === '1x1' && scrollType) {
|
|
1628
|
-
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1629
|
-
return (
|
|
1630
|
-
<div
|
|
1631
|
-
style={{
|
|
1632
|
-
width: '100%',
|
|
1633
|
-
height: '100%',
|
|
1634
|
-
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1635
|
-
display: 'flex',
|
|
1636
|
-
flexDirection: scrollDirection as any,
|
|
1637
|
-
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1638
|
-
gap: 0,
|
|
1639
|
-
padding: 0,
|
|
1640
|
-
}}
|
|
1641
|
-
className="scroll-container"
|
|
1642
|
-
>
|
|
1643
|
-
{videos.map((video, index) => (
|
|
1644
|
-
<div
|
|
1645
|
-
key={index}
|
|
1646
|
-
className="media-box"
|
|
1647
|
-
style={{
|
|
1648
|
-
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1649
|
-
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1650
|
-
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1651
|
-
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1652
|
-
flexShrink: 0,
|
|
1653
|
-
scrollSnapAlign: 'start',
|
|
1654
|
-
}}
|
|
1655
|
-
>
|
|
1656
|
-
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1657
|
-
width: '100%',
|
|
1658
|
-
height: '100%',
|
|
1659
|
-
objectFit: objectFit as any
|
|
1660
|
-
})}
|
|
1661
|
-
</div>
|
|
1662
|
-
))}
|
|
1663
|
-
</div>
|
|
1664
|
-
);
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
// Grid layout without scroll - show one grid per slide with carousel navigation
|
|
1668
|
-
if (layout !== '1x1') {
|
|
1669
|
-
// Group items into slides based on layout
|
|
1670
|
-
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1671
|
-
const slides: any[][] = [];
|
|
1672
|
-
for (let i = 0; i < videos.length; i += itemsPerSlide) {
|
|
1673
|
-
slides.push(videos.slice(i, i + itemsPerSlide));
|
|
1547
|
+
</>
|
|
1548
|
+
)}
|
|
1549
|
+
</div>
|
|
1550
|
+
);
|
|
1674
1551
|
}
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
width: '100%',
|
|
1685
|
-
overflow: 'hidden',
|
|
1686
|
-
alignContent: 'stretch',
|
|
1687
|
-
boxSizing: 'border-box',
|
|
1552
|
+
|
|
1553
|
+
// Other layouts: grid display with limited videos
|
|
1554
|
+
const getMaxVideos = () => {
|
|
1555
|
+
switch (layout) {
|
|
1556
|
+
case '1x2': return 2;
|
|
1557
|
+
case '2x1': return 2;
|
|
1558
|
+
case '2x2': return 4;
|
|
1559
|
+
default: return videos.length;
|
|
1560
|
+
}
|
|
1688
1561
|
};
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1562
|
+
|
|
1563
|
+
const isDynamic = tab.tabContentGroupVideo.type === 'DYNAMIC';
|
|
1564
|
+
|
|
1565
|
+
// For grid layouts (1x2, 2x1, 2x2), show one grid per slide
|
|
1566
|
+
// For 1x1 layout with scroll, show one item at a time
|
|
1567
|
+
if (layout !== '1x1' && scrollType) {
|
|
1568
|
+
// Group items into slides based on layout
|
|
1569
|
+
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1570
|
+
const slides: any[][] = [];
|
|
1571
|
+
for (let i = 0; i < videos.length; i += itemsPerSlide) {
|
|
1572
|
+
slides.push(videos.slice(i, i + itemsPerSlide));
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1576
|
+
|
|
1577
|
+
return (
|
|
1578
|
+
<div
|
|
1579
|
+
style={{
|
|
1580
|
+
width: '100%',
|
|
1581
|
+
height: '100%',
|
|
1582
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1583
|
+
display: 'flex',
|
|
1584
|
+
flexDirection: scrollDirection as any,
|
|
1585
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1586
|
+
gap: 0,
|
|
1587
|
+
padding: 0,
|
|
1588
|
+
}}
|
|
1589
|
+
className="scroll-container"
|
|
1590
|
+
>
|
|
1591
|
+
{slides.map((slideVideos, slideIndex) => (
|
|
1592
|
+
<div
|
|
1593
|
+
key={slideIndex}
|
|
1594
|
+
style={{
|
|
1595
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1596
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1597
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1598
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1599
|
+
flexShrink: 0,
|
|
1600
|
+
scrollSnapAlign: 'start',
|
|
1601
|
+
display: 'grid',
|
|
1602
|
+
gridTemplateColumns: getGridColumns(),
|
|
1603
|
+
gridTemplateRows: getGridRows(),
|
|
1604
|
+
gap: '3px',
|
|
1702
1605
|
overflow: 'hidden',
|
|
1703
|
-
|
|
1704
|
-
alignItems: 'center',
|
|
1705
|
-
justifyContent: 'center',
|
|
1606
|
+
alignContent: 'stretch',
|
|
1706
1607
|
boxSizing: 'border-box',
|
|
1707
1608
|
}}
|
|
1708
1609
|
>
|
|
1709
|
-
{
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1610
|
+
{slideVideos.map((video, index) => (
|
|
1611
|
+
<div
|
|
1612
|
+
key={index}
|
|
1613
|
+
className="media-box"
|
|
1614
|
+
style={{
|
|
1615
|
+
width: '100%',
|
|
1616
|
+
height: '100%',
|
|
1617
|
+
minHeight: 0,
|
|
1618
|
+
overflow: 'hidden',
|
|
1619
|
+
display: 'flex',
|
|
1620
|
+
alignItems: 'center',
|
|
1621
|
+
justifyContent: 'center',
|
|
1622
|
+
boxSizing: 'border-box',
|
|
1623
|
+
}}
|
|
1624
|
+
>
|
|
1625
|
+
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1626
|
+
width: '100%',
|
|
1627
|
+
height: '100%',
|
|
1628
|
+
objectFit: objectFit as any
|
|
1629
|
+
})}
|
|
1630
|
+
</div>
|
|
1631
|
+
))}
|
|
1714
1632
|
</div>
|
|
1715
1633
|
))}
|
|
1716
1634
|
</div>
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
alignItems: 'center',
|
|
1739
|
-
justifyContent: 'center',
|
|
1740
|
-
fontSize: '18px',
|
|
1741
|
-
zIndex: 10,
|
|
1742
|
-
}}
|
|
1743
|
-
>
|
|
1744
|
-
‹
|
|
1745
|
-
</button>
|
|
1746
|
-
<button
|
|
1747
|
-
onClick={nextCarouselItem}
|
|
1748
|
-
disabled={carouselIndex >= slides.length - 1}
|
|
1749
|
-
style={{
|
|
1750
|
-
position: 'absolute',
|
|
1751
|
-
right: '10px',
|
|
1752
|
-
top: '50%',
|
|
1753
|
-
transform: 'translateY(-50%)',
|
|
1754
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1755
|
-
color: 'white',
|
|
1756
|
-
border: 'none',
|
|
1757
|
-
borderRadius: '50%',
|
|
1758
|
-
width: '40px',
|
|
1759
|
-
height: '40px',
|
|
1760
|
-
cursor: carouselIndex >= slides.length - 1 ? 'not-allowed' : 'pointer',
|
|
1761
|
-
opacity: carouselIndex >= slides.length - 1 ? 0.5 : 1,
|
|
1762
|
-
display: 'flex',
|
|
1763
|
-
alignItems: 'center',
|
|
1764
|
-
justifyContent: 'center',
|
|
1765
|
-
fontSize: '18px',
|
|
1766
|
-
zIndex: 10,
|
|
1767
|
-
}}
|
|
1768
|
-
>
|
|
1769
|
-
›
|
|
1770
|
-
</button>
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
// For 1x1 layout with scroll, show one item at a time (carousel-like)
|
|
1639
|
+
if (layout === '1x1' && scrollType) {
|
|
1640
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1641
|
+
return (
|
|
1642
|
+
<div
|
|
1643
|
+
style={{
|
|
1644
|
+
width: '100%',
|
|
1645
|
+
height: '100%',
|
|
1646
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1647
|
+
display: 'flex',
|
|
1648
|
+
flexDirection: scrollDirection as any,
|
|
1649
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1650
|
+
gap: 0,
|
|
1651
|
+
padding: 0,
|
|
1652
|
+
}}
|
|
1653
|
+
className="scroll-container"
|
|
1654
|
+
>
|
|
1655
|
+
{videos.map((video, index) => (
|
|
1771
1656
|
<div
|
|
1657
|
+
key={index}
|
|
1658
|
+
className="media-box"
|
|
1772
1659
|
style={{
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
zIndex: 10,
|
|
1660
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1661
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1662
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1663
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1664
|
+
flexShrink: 0,
|
|
1665
|
+
scrollSnapAlign: 'start',
|
|
1780
1666
|
}}
|
|
1781
1667
|
>
|
|
1782
|
-
{
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
width: index === carouselIndex ? '12px' : '8px',
|
|
1788
|
-
height: index === carouselIndex ? '12px' : '8px',
|
|
1789
|
-
borderRadius: '50%',
|
|
1790
|
-
border: 'none',
|
|
1791
|
-
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1792
|
-
cursor: 'pointer',
|
|
1793
|
-
transition: 'all 0.3s ease',
|
|
1794
|
-
}}
|
|
1795
|
-
/>
|
|
1796
|
-
))}
|
|
1668
|
+
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1669
|
+
width: '100%',
|
|
1670
|
+
height: '100%',
|
|
1671
|
+
objectFit: objectFit as any
|
|
1672
|
+
})}
|
|
1797
1673
|
</div>
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
);
|
|
1802
|
-
}
|
|
1803
|
-
|
|
1804
|
-
// Fallback for 1x1 or other cases
|
|
1805
|
-
const maxVideos = getMaxVideos();
|
|
1806
|
-
const displayVideos = videos.slice(0, maxVideos);
|
|
1807
|
-
|
|
1808
|
-
const groupVideoContentStyle = {
|
|
1809
|
-
display: 'grid',
|
|
1810
|
-
gridTemplateColumns: getGridColumns(),
|
|
1811
|
-
gridTemplateRows: getGridRows(),
|
|
1812
|
-
gap: '3px',
|
|
1813
|
-
height: '100%',
|
|
1814
|
-
width: '100%',
|
|
1815
|
-
overflow: 'hidden'
|
|
1816
|
-
};
|
|
1817
|
-
|
|
1818
|
-
return (
|
|
1819
|
-
<div style={groupVideoContentStyle}>
|
|
1820
|
-
{displayVideos.map((video, index) => (
|
|
1821
|
-
<div
|
|
1822
|
-
key={index}
|
|
1823
|
-
className="media-box"
|
|
1824
|
-
style={{
|
|
1825
|
-
width: '100%',
|
|
1826
|
-
height: '100%',
|
|
1827
|
-
minHeight: 0,
|
|
1828
|
-
minWidth: 0,
|
|
1829
|
-
display: 'flex',
|
|
1830
|
-
alignItems: 'stretch'
|
|
1831
|
-
}}
|
|
1832
|
-
>
|
|
1833
|
-
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1834
|
-
width: '100%',
|
|
1835
|
-
height: '100%',
|
|
1836
|
-
objectFit: objectFit as any
|
|
1837
|
-
})}
|
|
1838
|
-
</div>
|
|
1839
|
-
))}
|
|
1840
|
-
</div>
|
|
1841
|
-
);
|
|
1842
|
-
|
|
1674
|
+
))}
|
|
1675
|
+
</div>
|
|
1676
|
+
);
|
|
1843
1677
|
}
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1873
|
-
gap: 0,
|
|
1874
|
-
padding: 0,
|
|
1875
|
-
}}
|
|
1876
|
-
className="scroll-container"
|
|
1877
|
-
>
|
|
1878
|
-
{products.map((product: any, index: number) => (
|
|
1678
|
+
|
|
1679
|
+
// Grid layout without scroll - show one grid per slide with carousel navigation
|
|
1680
|
+
if (layout !== '1x1') {
|
|
1681
|
+
// Group items into slides based on layout
|
|
1682
|
+
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
1683
|
+
const slides: any[][] = [];
|
|
1684
|
+
for (let i = 0; i < videos.length; i += itemsPerSlide) {
|
|
1685
|
+
slides.push(videos.slice(i, i + itemsPerSlide));
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
const currentSlide = slides[carouselIndex] || slides[0] || [];
|
|
1689
|
+
|
|
1690
|
+
const groupVideoContentStyle: React.CSSProperties = {
|
|
1691
|
+
display: 'grid',
|
|
1692
|
+
gridTemplateColumns: getGridColumns(),
|
|
1693
|
+
gridTemplateRows: getGridRows(),
|
|
1694
|
+
gap: '3px',
|
|
1695
|
+
height: '100%',
|
|
1696
|
+
width: '100%',
|
|
1697
|
+
overflow: 'hidden',
|
|
1698
|
+
alignContent: 'stretch',
|
|
1699
|
+
boxSizing: 'border-box',
|
|
1700
|
+
};
|
|
1701
|
+
|
|
1702
|
+
return (
|
|
1703
|
+
<div style={{ position: 'relative', width: '100%', height: '100%', overflow: 'hidden' }}>
|
|
1704
|
+
<div style={groupVideoContentStyle}>
|
|
1705
|
+
{currentSlide.map((video, index) => (
|
|
1879
1706
|
<div
|
|
1880
1707
|
key={index}
|
|
1708
|
+
className="media-box"
|
|
1881
1709
|
style={{
|
|
1882
|
-
width:
|
|
1883
|
-
height:
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1710
|
+
width: '100%',
|
|
1711
|
+
height: '100%',
|
|
1712
|
+
minHeight: 0,
|
|
1713
|
+
minWidth: 0,
|
|
1714
|
+
overflow: 'hidden',
|
|
1715
|
+
display: 'flex',
|
|
1716
|
+
alignItems: 'center',
|
|
1717
|
+
justifyContent: 'center',
|
|
1718
|
+
boxSizing: 'border-box',
|
|
1888
1719
|
}}
|
|
1889
1720
|
>
|
|
1890
|
-
|
|
1721
|
+
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1722
|
+
width: '100%',
|
|
1723
|
+
height: '100%',
|
|
1724
|
+
objectFit: objectFit as any
|
|
1725
|
+
})}
|
|
1891
1726
|
</div>
|
|
1892
1727
|
))}
|
|
1893
1728
|
</div>
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1729
|
+
|
|
1730
|
+
{/* Carousel Navigation for grid slides */}
|
|
1731
|
+
{slides.length > 1 && (
|
|
1732
|
+
<>
|
|
1733
|
+
<button
|
|
1734
|
+
onClick={prevCarouselItem}
|
|
1735
|
+
disabled={carouselIndex === 0}
|
|
1736
|
+
style={{
|
|
1737
|
+
position: 'absolute',
|
|
1738
|
+
left: '10px',
|
|
1739
|
+
top: '50%',
|
|
1740
|
+
transform: 'translateY(-50%)',
|
|
1741
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1742
|
+
color: 'white',
|
|
1743
|
+
border: 'none',
|
|
1744
|
+
borderRadius: '50%',
|
|
1745
|
+
width: '40px',
|
|
1746
|
+
height: '40px',
|
|
1747
|
+
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1748
|
+
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1749
|
+
display: 'flex',
|
|
1750
|
+
alignItems: 'center',
|
|
1751
|
+
justifyContent: 'center',
|
|
1752
|
+
fontSize: '18px',
|
|
1753
|
+
zIndex: 10,
|
|
1754
|
+
}}
|
|
1755
|
+
>
|
|
1756
|
+
‹
|
|
1757
|
+
</button>
|
|
1758
|
+
<button
|
|
1759
|
+
onClick={nextCarouselItem}
|
|
1760
|
+
disabled={carouselIndex >= slides.length - 1}
|
|
1761
|
+
style={{
|
|
1762
|
+
position: 'absolute',
|
|
1763
|
+
right: '10px',
|
|
1764
|
+
top: '50%',
|
|
1765
|
+
transform: 'translateY(-50%)',
|
|
1766
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1767
|
+
color: 'white',
|
|
1768
|
+
border: 'none',
|
|
1769
|
+
borderRadius: '50%',
|
|
1770
|
+
width: '40px',
|
|
1771
|
+
height: '40px',
|
|
1772
|
+
cursor: carouselIndex >= slides.length - 1 ? 'not-allowed' : 'pointer',
|
|
1773
|
+
opacity: carouselIndex >= slides.length - 1 ? 0.5 : 1,
|
|
1774
|
+
display: 'flex',
|
|
1775
|
+
alignItems: 'center',
|
|
1776
|
+
justifyContent: 'center',
|
|
1777
|
+
fontSize: '18px',
|
|
1778
|
+
zIndex: 10,
|
|
1779
|
+
}}
|
|
1780
|
+
>
|
|
1781
|
+
›
|
|
1782
|
+
</button>
|
|
1783
|
+
<div
|
|
1784
|
+
style={{
|
|
1785
|
+
position: 'absolute',
|
|
1786
|
+
bottom: '10px',
|
|
1787
|
+
left: '50%',
|
|
1788
|
+
transform: 'translateX(-50%)',
|
|
1789
|
+
display: 'flex',
|
|
1790
|
+
gap: '8px',
|
|
1791
|
+
zIndex: 10,
|
|
1792
|
+
}}
|
|
1793
|
+
>
|
|
1794
|
+
{slides.map((_, index) => (
|
|
1795
|
+
<button
|
|
1796
|
+
key={index}
|
|
1797
|
+
onClick={() => goToCarouselItem(index)}
|
|
1798
|
+
style={{
|
|
1799
|
+
width: index === carouselIndex ? '12px' : '8px',
|
|
1800
|
+
height: index === carouselIndex ? '12px' : '8px',
|
|
1801
|
+
borderRadius: '50%',
|
|
1802
|
+
border: 'none',
|
|
1803
|
+
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
1804
|
+
cursor: 'pointer',
|
|
1805
|
+
transition: 'all 0.3s ease',
|
|
1806
|
+
}}
|
|
1807
|
+
/>
|
|
1808
|
+
))}
|
|
1809
|
+
</div>
|
|
1810
|
+
</>
|
|
1811
|
+
)}
|
|
1812
|
+
</div>
|
|
1813
|
+
);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// Fallback for 1x1 or other cases
|
|
1817
|
+
const maxVideos = getMaxVideos();
|
|
1818
|
+
const displayVideos = videos.slice(0, maxVideos);
|
|
1819
|
+
|
|
1820
|
+
const groupVideoContentStyle = {
|
|
1821
|
+
display: 'grid',
|
|
1822
|
+
gridTemplateColumns: getGridColumns(),
|
|
1823
|
+
gridTemplateRows: getGridRows(),
|
|
1824
|
+
gap: '3px',
|
|
1825
|
+
height: '100%',
|
|
1826
|
+
width: '100%',
|
|
1827
|
+
overflow: 'hidden'
|
|
1828
|
+
};
|
|
1829
|
+
|
|
1830
|
+
return (
|
|
1831
|
+
<div style={groupVideoContentStyle}>
|
|
1832
|
+
{displayVideos.map((video, index) => (
|
|
1833
|
+
<div
|
|
1834
|
+
key={index}
|
|
1835
|
+
className="media-box"
|
|
1836
|
+
style={{
|
|
1837
|
+
width: '100%',
|
|
1838
|
+
height: '100%',
|
|
1839
|
+
minHeight: 0,
|
|
1840
|
+
minWidth: 0,
|
|
1841
|
+
display: 'flex',
|
|
1842
|
+
alignItems: 'stretch'
|
|
1843
|
+
}}
|
|
1844
|
+
>
|
|
1845
|
+
{renderVideoPlayer(video, isDynamic, 'media-content', {
|
|
1846
|
+
width: '100%',
|
|
1847
|
+
height: '100%',
|
|
1848
|
+
objectFit: objectFit as any
|
|
1849
|
+
})}
|
|
1850
|
+
</div>
|
|
1851
|
+
))}
|
|
1852
|
+
</div>
|
|
1853
|
+
);
|
|
1854
|
+
|
|
1855
|
+
}
|
|
1856
|
+
break;
|
|
1857
|
+
|
|
1858
|
+
case 'GROUPPRODUCT':
|
|
1859
|
+
if (tab.tabContentGroupProduct) {
|
|
1860
|
+
// Prioritize showItems, fallback to dynamic/static arrays
|
|
1861
|
+
const products = tab.tabContentGroupProduct.showItems && tab.tabContentGroupProduct.showItems.length > 0
|
|
1862
|
+
? tab.tabContentGroupProduct.showItems
|
|
1863
|
+
: (tab.tabContentGroupProduct.type === 'DYNAMIC'
|
|
1864
|
+
? tab.tabContentGroupProduct.dynamic?.list
|
|
1865
|
+
: tab.tabContentGroupProduct.staticProducts);
|
|
1866
|
+
|
|
1867
|
+
if (!products || products.length === 0) {
|
|
1868
|
+
return <div>No products available</div>;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
// 1x1 layout: use scrollbar if scroll type is set, otherwise carousel
|
|
1872
|
+
if (layout === '1x1' && scrollType) {
|
|
1873
|
+
// Use scrollable container with scrollbar - each item takes full width/height
|
|
1874
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
1875
|
+
|
|
1876
|
+
return (
|
|
1877
|
+
<div
|
|
1878
|
+
style={{
|
|
1879
|
+
width: '100%',
|
|
1880
|
+
height: '100%',
|
|
1881
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
1882
|
+
display: 'flex',
|
|
1883
|
+
flexDirection: scrollDirection as any,
|
|
1884
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
1885
|
+
gap: 0,
|
|
1886
|
+
padding: 0,
|
|
1887
|
+
}}
|
|
1888
|
+
className="scroll-container"
|
|
1889
|
+
>
|
|
1890
|
+
{products.map((product: any, index: number) => (
|
|
1891
|
+
<div
|
|
1892
|
+
key={index}
|
|
1893
|
+
style={{
|
|
1894
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1895
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
1896
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
1897
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
1898
|
+
flexShrink: 0,
|
|
1899
|
+
scrollSnapAlign: 'start',
|
|
1900
|
+
}}
|
|
1901
|
+
>
|
|
1902
|
+
<ProductCard product={product} layout={layout} />
|
|
1903
|
+
</div>
|
|
1904
|
+
))}
|
|
1905
|
+
</div>
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
// 1x1 layout: Carousel view (fallback when scroll is not set)
|
|
1910
|
+
if (layout === '1x1') {
|
|
1911
|
+
const currentProduct = products[carouselIndex] || products[0];
|
|
1912
|
+
|
|
1913
|
+
return (
|
|
1914
|
+
<div
|
|
1903
1915
|
style={{
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1916
|
+
position: 'relative',
|
|
1917
|
+
width: '100%',
|
|
1918
|
+
height: '100%', // Full height of tab content
|
|
1919
|
+
overflow: 'hidden',
|
|
1920
|
+
display: 'flex',
|
|
1921
|
+
alignItems: 'stretch',
|
|
1922
|
+
justifyContent: 'center',
|
|
1911
1923
|
}}
|
|
1912
|
-
|
|
1924
|
+
>
|
|
1913
1925
|
{currentProduct && (
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1926
|
+
<div style={{ width: '100%', height: '100%', display: 'flex' }}>
|
|
1927
|
+
<ProductCard product={currentProduct} layout={layout} />
|
|
1928
|
+
</div>
|
|
1917
1929
|
)}
|
|
1918
|
-
|
|
1930
|
+
|
|
1919
1931
|
{/* Carousel Navigation */}
|
|
1920
1932
|
{products.length > 1 && (
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
<button
|
|
1924
|
-
onClick={prevCarouselItem}
|
|
1925
|
-
disabled={carouselIndex === 0}
|
|
1926
|
-
style={{
|
|
1927
|
-
position: 'absolute',
|
|
1928
|
-
left: '10px',
|
|
1929
|
-
top: '50%',
|
|
1930
|
-
transform: 'translateY(-50%)',
|
|
1931
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1932
|
-
color: 'white',
|
|
1933
|
-
border: 'none',
|
|
1934
|
-
borderRadius: '50%',
|
|
1935
|
-
width: '40px',
|
|
1936
|
-
height: '40px',
|
|
1937
|
-
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1938
|
-
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1939
|
-
display: 'flex',
|
|
1940
|
-
alignItems: 'center',
|
|
1941
|
-
justifyContent: 'center',
|
|
1942
|
-
fontSize: '18px',
|
|
1943
|
-
zIndex: 10,
|
|
1944
|
-
}}
|
|
1945
|
-
>
|
|
1946
|
-
‹
|
|
1947
|
-
</button>
|
|
1948
|
-
|
|
1949
|
-
{/* Next Button */}
|
|
1950
|
-
<button
|
|
1951
|
-
onClick={nextCarouselItem}
|
|
1952
|
-
disabled={carouselIndex >= products.length - 1}
|
|
1953
|
-
style={{
|
|
1954
|
-
position: 'absolute',
|
|
1955
|
-
right: '10px',
|
|
1956
|
-
top: '50%',
|
|
1957
|
-
transform: 'translateY(-50%)',
|
|
1958
|
-
background: 'rgba(0,0,0,0.5)',
|
|
1959
|
-
color: 'white',
|
|
1960
|
-
border: 'none',
|
|
1961
|
-
borderRadius: '50%',
|
|
1962
|
-
width: '40px',
|
|
1963
|
-
height: '40px',
|
|
1964
|
-
cursor:
|
|
1965
|
-
carouselIndex >= products.length - 1
|
|
1966
|
-
? 'not-allowed'
|
|
1967
|
-
: 'pointer',
|
|
1968
|
-
opacity: carouselIndex >= products.length - 1 ? 0.5 : 1,
|
|
1969
|
-
display: 'flex',
|
|
1970
|
-
alignItems: 'center',
|
|
1971
|
-
justifyContent: 'center',
|
|
1972
|
-
fontSize: '18px',
|
|
1973
|
-
zIndex: 10,
|
|
1974
|
-
}}
|
|
1975
|
-
>
|
|
1976
|
-
›
|
|
1977
|
-
</button>
|
|
1978
|
-
|
|
1979
|
-
{/* Dots */}
|
|
1980
|
-
<div
|
|
1981
|
-
style={{
|
|
1982
|
-
position: 'absolute',
|
|
1983
|
-
bottom: '10px',
|
|
1984
|
-
left: '50%',
|
|
1985
|
-
transform: 'translateX(-50%)',
|
|
1986
|
-
display: 'flex',
|
|
1987
|
-
gap: '8px',
|
|
1988
|
-
zIndex: 10,
|
|
1989
|
-
}}
|
|
1990
|
-
>
|
|
1991
|
-
{products.map((_: any, index: number) => (
|
|
1933
|
+
<>
|
|
1934
|
+
{/* Prev Button */}
|
|
1992
1935
|
<button
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
: '
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
className="scroll-container"
|
|
2050
|
-
>
|
|
2051
|
-
{slides.map((slideProducts, slideIndex) => (
|
|
1936
|
+
onClick={prevCarouselItem}
|
|
1937
|
+
disabled={carouselIndex === 0}
|
|
1938
|
+
style={{
|
|
1939
|
+
position: 'absolute',
|
|
1940
|
+
left: '10px',
|
|
1941
|
+
top: '50%',
|
|
1942
|
+
transform: 'translateY(-50%)',
|
|
1943
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1944
|
+
color: 'white',
|
|
1945
|
+
border: 'none',
|
|
1946
|
+
borderRadius: '50%',
|
|
1947
|
+
width: '40px',
|
|
1948
|
+
height: '40px',
|
|
1949
|
+
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
1950
|
+
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
1951
|
+
display: 'flex',
|
|
1952
|
+
alignItems: 'center',
|
|
1953
|
+
justifyContent: 'center',
|
|
1954
|
+
fontSize: '18px',
|
|
1955
|
+
zIndex: 10,
|
|
1956
|
+
}}
|
|
1957
|
+
>
|
|
1958
|
+
‹
|
|
1959
|
+
</button>
|
|
1960
|
+
|
|
1961
|
+
{/* Next Button */}
|
|
1962
|
+
<button
|
|
1963
|
+
onClick={nextCarouselItem}
|
|
1964
|
+
disabled={carouselIndex >= products.length - 1}
|
|
1965
|
+
style={{
|
|
1966
|
+
position: 'absolute',
|
|
1967
|
+
right: '10px',
|
|
1968
|
+
top: '50%',
|
|
1969
|
+
transform: 'translateY(-50%)',
|
|
1970
|
+
background: 'rgba(0,0,0,0.5)',
|
|
1971
|
+
color: 'white',
|
|
1972
|
+
border: 'none',
|
|
1973
|
+
borderRadius: '50%',
|
|
1974
|
+
width: '40px',
|
|
1975
|
+
height: '40px',
|
|
1976
|
+
cursor:
|
|
1977
|
+
carouselIndex >= products.length - 1
|
|
1978
|
+
? 'not-allowed'
|
|
1979
|
+
: 'pointer',
|
|
1980
|
+
opacity: carouselIndex >= products.length - 1 ? 0.5 : 1,
|
|
1981
|
+
display: 'flex',
|
|
1982
|
+
alignItems: 'center',
|
|
1983
|
+
justifyContent: 'center',
|
|
1984
|
+
fontSize: '18px',
|
|
1985
|
+
zIndex: 10,
|
|
1986
|
+
}}
|
|
1987
|
+
>
|
|
1988
|
+
›
|
|
1989
|
+
</button>
|
|
1990
|
+
|
|
1991
|
+
{/* Dots */}
|
|
2052
1992
|
<div
|
|
2053
|
-
key={slideIndex}
|
|
2054
1993
|
style={{
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
gridTemplateColumns: getGridColumns(),
|
|
2063
|
-
gridTemplateRows: getGridRows(),
|
|
2064
|
-
gap: '12px',
|
|
2065
|
-
padding: '12px',
|
|
2066
|
-
overflow: 'hidden',
|
|
2067
|
-
alignContent: 'stretch'
|
|
1994
|
+
position: 'absolute',
|
|
1995
|
+
bottom: '10px',
|
|
1996
|
+
left: '50%',
|
|
1997
|
+
transform: 'translateX(-50%)',
|
|
1998
|
+
display: 'flex',
|
|
1999
|
+
gap: '8px',
|
|
2000
|
+
zIndex: 10,
|
|
2068
2001
|
}}
|
|
2069
2002
|
>
|
|
2070
|
-
{
|
|
2071
|
-
<
|
|
2003
|
+
{products.map((_: any, index: number) => (
|
|
2004
|
+
<button
|
|
2072
2005
|
key={index}
|
|
2006
|
+
onClick={() => goToCarouselItem(index)}
|
|
2073
2007
|
style={{
|
|
2074
|
-
width: '
|
|
2075
|
-
height: '
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2008
|
+
width: index === carouselIndex ? '12px' : '8px',
|
|
2009
|
+
height: index === carouselIndex ? '12px' : '8px',
|
|
2010
|
+
borderRadius: '50%',
|
|
2011
|
+
border: 'none',
|
|
2012
|
+
background:
|
|
2013
|
+
index === carouselIndex
|
|
2014
|
+
? 'white'
|
|
2015
|
+
: 'rgba(255,255,255,0.5)',
|
|
2016
|
+
cursor: 'pointer',
|
|
2017
|
+
transition: 'all 0.3s ease',
|
|
2083
2018
|
}}
|
|
2084
|
-
|
|
2085
|
-
<ProductCard product={product} layout={layout} />
|
|
2086
|
-
</div>
|
|
2019
|
+
/>
|
|
2087
2020
|
))}
|
|
2088
2021
|
</div>
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2022
|
+
</>
|
|
2023
|
+
)}
|
|
2024
|
+
</div>
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// Other layouts: Grid view with limited products
|
|
2029
|
+
const getMaxProducts = () => {
|
|
2030
|
+
switch (layout) {
|
|
2031
|
+
case '1x2': return 2;
|
|
2032
|
+
case '2x1': return 2;
|
|
2033
|
+
case '2x2': return 4;
|
|
2034
|
+
default: return products.length;
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
|
|
2038
|
+
// For grid layouts (1x2, 2x1, 2x2), show one grid per slide
|
|
2039
|
+
if (layout !== '1x1' && scrollType) {
|
|
2040
|
+
// Group items into slides based on layout
|
|
2041
|
+
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
2042
|
+
const slides: any[][] = [];
|
|
2043
|
+
for (let i = 0; i < products.length; i += itemsPerSlide) {
|
|
2044
|
+
slides.push(products.slice(i, i + itemsPerSlide));
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
const scrollDirection = scrollType === 'horizontal' ? 'row' : 'column';
|
|
2048
|
+
|
|
2049
|
+
return (
|
|
2050
|
+
<div
|
|
2051
|
+
style={{
|
|
2052
|
+
width: '100%',
|
|
2053
|
+
height: '100%',
|
|
2054
|
+
overflow: scrollType === 'horizontal' ? 'auto' : 'auto',
|
|
2055
|
+
display: 'flex',
|
|
2056
|
+
flexDirection: scrollDirection as any,
|
|
2057
|
+
scrollSnapType: scrollType === 'horizontal' ? 'x mandatory' : 'y mandatory',
|
|
2058
|
+
gap: 0,
|
|
2059
|
+
padding: 0,
|
|
2060
|
+
}}
|
|
2061
|
+
className="scroll-container"
|
|
2062
|
+
>
|
|
2063
|
+
{slides.map((slideProducts, slideIndex) => (
|
|
2064
|
+
<div
|
|
2065
|
+
key={slideIndex}
|
|
2066
|
+
style={{
|
|
2067
|
+
width: scrollType === 'horizontal' ? '100%' : '100%',
|
|
2068
|
+
height: scrollType === 'vertical' ? '100%' : '100%',
|
|
2069
|
+
minWidth: scrollType === 'horizontal' ? '100%' : '100%',
|
|
2070
|
+
minHeight: scrollType === 'vertical' ? '100%' : '100%',
|
|
2071
|
+
flexShrink: 0,
|
|
2072
|
+
scrollSnapAlign: 'start',
|
|
2073
|
+
display: 'grid',
|
|
2074
|
+
gridTemplateColumns: getGridColumns(),
|
|
2075
|
+
gridTemplateRows: getGridRows(),
|
|
2076
|
+
gap: '12px',
|
|
2077
|
+
padding: '12px',
|
|
2078
|
+
overflow: 'hidden',
|
|
2079
|
+
alignContent: 'stretch'
|
|
2080
|
+
}}
|
|
2081
|
+
>
|
|
2082
|
+
{slideProducts.map((product: any, index: number) => (
|
|
2122
2083
|
<div
|
|
2123
2084
|
key={index}
|
|
2124
2085
|
style={{
|
|
@@ -2137,98 +2098,23 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
2137
2098
|
</div>
|
|
2138
2099
|
))}
|
|
2139
2100
|
</div>
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
height: '40px',
|
|
2158
|
-
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
2159
|
-
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
2160
|
-
display: 'flex',
|
|
2161
|
-
alignItems: 'center',
|
|
2162
|
-
justifyContent: 'center',
|
|
2163
|
-
fontSize: '18px',
|
|
2164
|
-
zIndex: 10,
|
|
2165
|
-
}}
|
|
2166
|
-
>
|
|
2167
|
-
‹
|
|
2168
|
-
</button>
|
|
2169
|
-
<button
|
|
2170
|
-
onClick={nextCarouselItem}
|
|
2171
|
-
disabled={carouselIndex >= slides.length - 1}
|
|
2172
|
-
style={{
|
|
2173
|
-
position: 'absolute',
|
|
2174
|
-
right: '10px',
|
|
2175
|
-
top: '50%',
|
|
2176
|
-
transform: 'translateY(-50%)',
|
|
2177
|
-
background: 'rgba(0,0,0,0.5)',
|
|
2178
|
-
color: 'white',
|
|
2179
|
-
border: 'none',
|
|
2180
|
-
borderRadius: '50%',
|
|
2181
|
-
width: '40px',
|
|
2182
|
-
height: '40px',
|
|
2183
|
-
cursor: carouselIndex >= slides.length - 1 ? 'not-allowed' : 'pointer',
|
|
2184
|
-
opacity: carouselIndex >= slides.length - 1 ? 0.5 : 1,
|
|
2185
|
-
display: 'flex',
|
|
2186
|
-
alignItems: 'center',
|
|
2187
|
-
justifyContent: 'center',
|
|
2188
|
-
fontSize: '18px',
|
|
2189
|
-
zIndex: 10,
|
|
2190
|
-
}}
|
|
2191
|
-
>
|
|
2192
|
-
›
|
|
2193
|
-
</button>
|
|
2194
|
-
<div
|
|
2195
|
-
style={{
|
|
2196
|
-
position: 'absolute',
|
|
2197
|
-
bottom: '10px',
|
|
2198
|
-
left: '50%',
|
|
2199
|
-
transform: 'translateX(-50%)',
|
|
2200
|
-
display: 'flex',
|
|
2201
|
-
gap: '8px',
|
|
2202
|
-
zIndex: 10,
|
|
2203
|
-
}}
|
|
2204
|
-
>
|
|
2205
|
-
{slides.map((_, index) => (
|
|
2206
|
-
<button
|
|
2207
|
-
key={index}
|
|
2208
|
-
onClick={() => goToCarouselItem(index)}
|
|
2209
|
-
style={{
|
|
2210
|
-
width: index === carouselIndex ? '12px' : '8px',
|
|
2211
|
-
height: index === carouselIndex ? '12px' : '8px',
|
|
2212
|
-
borderRadius: '50%',
|
|
2213
|
-
border: 'none',
|
|
2214
|
-
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
2215
|
-
cursor: 'pointer',
|
|
2216
|
-
transition: 'all 0.3s ease',
|
|
2217
|
-
}}
|
|
2218
|
-
/>
|
|
2219
|
-
))}
|
|
2220
|
-
</div>
|
|
2221
|
-
</>
|
|
2222
|
-
)}
|
|
2223
|
-
</div>
|
|
2224
|
-
);
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
// Fallback for 1x1 or other cases
|
|
2228
|
-
const maxProducts = getMaxProducts();
|
|
2229
|
-
const displayProducts = products.slice(0, maxProducts);
|
|
2230
|
-
|
|
2231
|
-
const groupProductContentStyle = {
|
|
2101
|
+
))}
|
|
2102
|
+
</div>
|
|
2103
|
+
);
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// Grid layout without scroll - show one grid per slide with carousel navigation
|
|
2107
|
+
if (layout !== '1x1') {
|
|
2108
|
+
// Group items into slides based on layout
|
|
2109
|
+
const itemsPerSlide = layout === '2x2' ? 4 : 2; // 4 for 2x2, 2 for 1x2/2x1
|
|
2110
|
+
const slides: any[][] = [];
|
|
2111
|
+
for (let i = 0; i < products.length; i += itemsPerSlide) {
|
|
2112
|
+
slides.push(products.slice(i, i + itemsPerSlide));
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
const currentSlide = slides[carouselIndex] || slides[0] || [];
|
|
2116
|
+
|
|
2117
|
+
const groupProductContentStyle = {
|
|
2232
2118
|
display: 'grid',
|
|
2233
2119
|
gridTemplateColumns: getGridColumns(),
|
|
2234
2120
|
gridTemplateRows: getGridRows(),
|
|
@@ -2238,46 +2124,172 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
2238
2124
|
overflow: 'hidden',
|
|
2239
2125
|
padding: '12px',
|
|
2240
2126
|
alignItems: 'stretch',
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2127
|
+
alignContent: 'stretch'
|
|
2128
|
+
};
|
|
2129
|
+
|
|
2130
|
+
return (
|
|
2131
|
+
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
|
|
2132
|
+
<div style={groupProductContentStyle}>
|
|
2133
|
+
{currentSlide.map((product: any, index: number) => (
|
|
2134
|
+
<div
|
|
2135
|
+
key={index}
|
|
2136
|
+
style={{
|
|
2137
|
+
width: '100%',
|
|
2138
|
+
height: '100%',
|
|
2139
|
+
maxHeight: '100%',
|
|
2140
|
+
overflow: 'hidden',
|
|
2141
|
+
display: 'flex',
|
|
2142
|
+
alignItems: 'stretch',
|
|
2143
|
+
justifyContent: 'center',
|
|
2144
|
+
minHeight: 0,
|
|
2145
|
+
minWidth: 0
|
|
2146
|
+
}}
|
|
2147
|
+
>
|
|
2148
|
+
<ProductCard product={product} layout={layout} />
|
|
2149
|
+
</div>
|
|
2150
|
+
))}
|
|
2151
|
+
</div>
|
|
2152
|
+
|
|
2153
|
+
{/* Carousel Navigation for grid slides */}
|
|
2154
|
+
{slides.length > 1 && (
|
|
2155
|
+
<>
|
|
2156
|
+
<button
|
|
2157
|
+
onClick={prevCarouselItem}
|
|
2158
|
+
disabled={carouselIndex === 0}
|
|
2159
|
+
style={{
|
|
2160
|
+
position: 'absolute',
|
|
2161
|
+
left: '10px',
|
|
2162
|
+
top: '50%',
|
|
2163
|
+
transform: 'translateY(-50%)',
|
|
2164
|
+
background: 'rgba(0,0,0,0.5)',
|
|
2165
|
+
color: 'white',
|
|
2166
|
+
border: 'none',
|
|
2167
|
+
borderRadius: '50%',
|
|
2168
|
+
width: '40px',
|
|
2169
|
+
height: '40px',
|
|
2170
|
+
cursor: carouselIndex === 0 ? 'not-allowed' : 'pointer',
|
|
2171
|
+
opacity: carouselIndex === 0 ? 0.5 : 1,
|
|
2172
|
+
display: 'flex',
|
|
2173
|
+
alignItems: 'center',
|
|
2174
|
+
justifyContent: 'center',
|
|
2175
|
+
fontSize: '18px',
|
|
2176
|
+
zIndex: 10,
|
|
2177
|
+
}}
|
|
2178
|
+
>
|
|
2179
|
+
‹
|
|
2180
|
+
</button>
|
|
2181
|
+
<button
|
|
2182
|
+
onClick={nextCarouselItem}
|
|
2183
|
+
disabled={carouselIndex >= slides.length - 1}
|
|
2184
|
+
style={{
|
|
2185
|
+
position: 'absolute',
|
|
2186
|
+
right: '10px',
|
|
2187
|
+
top: '50%',
|
|
2188
|
+
transform: 'translateY(-50%)',
|
|
2189
|
+
background: 'rgba(0,0,0,0.5)',
|
|
2190
|
+
color: 'white',
|
|
2191
|
+
border: 'none',
|
|
2192
|
+
borderRadius: '50%',
|
|
2193
|
+
width: '40px',
|
|
2194
|
+
height: '40px',
|
|
2195
|
+
cursor: carouselIndex >= slides.length - 1 ? 'not-allowed' : 'pointer',
|
|
2196
|
+
opacity: carouselIndex >= slides.length - 1 ? 0.5 : 1,
|
|
2197
|
+
display: 'flex',
|
|
2198
|
+
alignItems: 'center',
|
|
2199
|
+
justifyContent: 'center',
|
|
2200
|
+
fontSize: '18px',
|
|
2201
|
+
zIndex: 10,
|
|
2202
|
+
}}
|
|
2203
|
+
>
|
|
2204
|
+
›
|
|
2205
|
+
</button>
|
|
2206
|
+
<div
|
|
2207
|
+
style={{
|
|
2208
|
+
position: 'absolute',
|
|
2209
|
+
bottom: '10px',
|
|
2210
|
+
left: '50%',
|
|
2211
|
+
transform: 'translateX(-50%)',
|
|
2212
|
+
display: 'flex',
|
|
2213
|
+
gap: '8px',
|
|
2214
|
+
zIndex: 10,
|
|
2215
|
+
}}
|
|
2216
|
+
>
|
|
2217
|
+
{slides.map((_, index) => (
|
|
2218
|
+
<button
|
|
2219
|
+
key={index}
|
|
2220
|
+
onClick={() => goToCarouselItem(index)}
|
|
2221
|
+
style={{
|
|
2222
|
+
width: index === carouselIndex ? '12px' : '8px',
|
|
2223
|
+
height: index === carouselIndex ? '12px' : '8px',
|
|
2224
|
+
borderRadius: '50%',
|
|
2225
|
+
border: 'none',
|
|
2226
|
+
background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
|
|
2227
|
+
cursor: 'pointer',
|
|
2228
|
+
transition: 'all 0.3s ease',
|
|
2229
|
+
}}
|
|
2230
|
+
/>
|
|
2231
|
+
))}
|
|
2232
|
+
</div>
|
|
2233
|
+
</>
|
|
2234
|
+
)}
|
|
2235
|
+
</div>
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
// Fallback for 1x1 or other cases
|
|
2240
|
+
const maxProducts = getMaxProducts();
|
|
2241
|
+
const displayProducts = products.slice(0, maxProducts);
|
|
2242
|
+
|
|
2243
|
+
const groupProductContentStyle = {
|
|
2244
|
+
display: 'grid',
|
|
2245
|
+
gridTemplateColumns: getGridColumns(),
|
|
2246
|
+
gridTemplateRows: getGridRows(),
|
|
2247
|
+
gap: '12px',
|
|
2248
|
+
height: '100%',
|
|
2249
|
+
width: '100%',
|
|
2250
|
+
overflow: 'hidden',
|
|
2251
|
+
padding: '12px',
|
|
2252
|
+
alignItems: 'stretch',
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
return (
|
|
2256
|
+
<div style={groupProductContentStyle}>
|
|
2257
|
+
{displayProducts.map((product: any, index: number) => (
|
|
2246
2258
|
<div
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2259
|
+
key={index}
|
|
2260
|
+
style={{
|
|
2261
|
+
width: '100%',
|
|
2262
|
+
height: '100%',
|
|
2263
|
+
display: 'flex',
|
|
2264
|
+
alignItems: 'stretch',
|
|
2265
|
+
justifyContent: 'center',
|
|
2266
|
+
minHeight: 0,
|
|
2267
|
+
minWidth: 0
|
|
2268
|
+
}}
|
|
2257
2269
|
>
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2270
|
+
<ProductCard product={product} layout={layout} />
|
|
2271
|
+
</div>
|
|
2272
|
+
))}
|
|
2273
|
+
</div>
|
|
2274
|
+
);
|
|
2275
|
+
}
|
|
2276
|
+
break;
|
|
2277
|
+
|
|
2278
|
+
default:
|
|
2279
|
+
return (
|
|
2280
|
+
<div style={{
|
|
2281
|
+
...contentStyle,
|
|
2282
|
+
alignItems: 'center',
|
|
2283
|
+
justifyContent: 'center',
|
|
2284
|
+
backgroundColor: '#f8f9fa',
|
|
2285
|
+
borderRadius: '8px'
|
|
2286
|
+
}}>
|
|
2287
|
+
<p style={{ color: '#6c757d', textAlign: 'center' }}>No content available</p>
|
|
2261
2288
|
</div>
|
|
2262
2289
|
);
|
|
2263
|
-
|
|
2264
|
-
break;
|
|
2265
|
-
|
|
2266
|
-
default:
|
|
2267
|
-
return (
|
|
2268
|
-
<div style={{
|
|
2269
|
-
...contentStyle,
|
|
2270
|
-
alignItems: 'center',
|
|
2271
|
-
justifyContent: 'center',
|
|
2272
|
-
backgroundColor: '#f8f9fa',
|
|
2273
|
-
borderRadius: '8px'
|
|
2274
|
-
}}>
|
|
2275
|
-
<p style={{ color: '#6c757d', textAlign: 'center' }}>No content available</p>
|
|
2276
|
-
</div>
|
|
2277
|
-
);
|
|
2278
|
-
}
|
|
2290
|
+
}
|
|
2279
2291
|
|
|
2280
|
-
|
|
2292
|
+
return null;
|
|
2281
2293
|
} catch (error: any) {
|
|
2282
2294
|
console.error('Error rendering tab content:', error);
|
|
2283
2295
|
return (
|
|
@@ -2313,107 +2325,107 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
|
|
|
2313
2325
|
}
|
|
2314
2326
|
|
|
2315
2327
|
return (
|
|
2316
|
-
<div style={{
|
|
2317
|
-
width: '100%',
|
|
2318
|
-
height: `${props.height}px`,
|
|
2319
|
-
backgroundColor: '#ffffff',
|
|
2320
|
-
overflow: 'hidden',
|
|
2321
|
-
boxShadow: '0 4px 20px rgba(0,0,0,0.08)',
|
|
2322
|
-
border: '1px solid #e5e7eb',
|
|
2323
|
-
display: 'flex',
|
|
2324
|
-
flexDirection: isVertical ? 'row' : 'column'
|
|
2325
|
-
}}>
|
|
2326
|
-
{/* Header Section */}
|
|
2327
|
-
<div style={{
|
|
2328
|
-
display: 'flex',
|
|
2329
|
-
flexDirection: isVertical ? 'column' : 'row',
|
|
2330
|
-
alignItems: isVertical ? 'stretch' : 'center',
|
|
2331
|
-
justifyContent: isVertical ? 'space-between' : 'space-between',
|
|
2332
|
-
padding: isVertical ? '20px 16px' : '20px 32px',
|
|
2333
|
-
backgroundColor: '#ffffff',
|
|
2334
|
-
borderBottom: isVertical ? 'none' : '1px solid #e5e7eb',
|
|
2335
|
-
borderRight: isVertical ? '1px solid #e5e7eb' : 'none',
|
|
2336
|
-
width: isVertical ? '200px' : '100%',
|
|
2337
|
-
minWidth: isVertical ? '180px' : 'auto',
|
|
2338
|
-
flexShrink: 0
|
|
2339
|
-
}}>
|
|
2340
|
-
{/* Title */}
|
|
2341
|
-
{props.showTitle && (
|
|
2342
|
-
<h1 style={{
|
|
2343
|
-
...getTitleStyle(),
|
|
2344
|
-
marginBottom: isVertical ? '16px' : '0',
|
|
2345
|
-
textAlign: isVertical ? 'left' : getTitleStyle().textAlign,
|
|
2346
|
-
writingMode: isVertical ? 'horizontal-tb' : 'initial',
|
|
2347
|
-
flexShrink: 0
|
|
2348
|
-
}}>
|
|
2349
|
-
{props?.title?.titleText}
|
|
2350
|
-
</h1>
|
|
2351
|
-
)}
|
|
2352
|
-
|
|
2353
|
-
{/* Tab Headers */}
|
|
2354
2328
|
<div style={{
|
|
2329
|
+
width: '100%',
|
|
2330
|
+
height: `${props.height}px`,
|
|
2331
|
+
backgroundColor: '#ffffff',
|
|
2332
|
+
overflow: 'hidden',
|
|
2333
|
+
boxShadow: '0 4px 20px rgba(0,0,0,0.08)',
|
|
2334
|
+
border: '1px solid #e5e7eb',
|
|
2355
2335
|
display: 'flex',
|
|
2356
|
-
flexDirection: isVertical ? '
|
|
2357
|
-
alignItems: isVertical ? 'stretch' : 'center',
|
|
2358
|
-
gap: isVertical ? '8px' : '0',
|
|
2359
|
-
width: isVertical ? '100%' : 'auto',
|
|
2360
|
-
marginLeft: isVertical ? '0' : 'auto'
|
|
2336
|
+
flexDirection: isVertical ? 'row' : 'column'
|
|
2361
2337
|
}}>
|
|
2362
|
-
{
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2338
|
+
{/* Header Section */}
|
|
2339
|
+
<div style={{
|
|
2340
|
+
display: 'flex',
|
|
2341
|
+
flexDirection: isVertical ? 'column' : 'row',
|
|
2342
|
+
alignItems: isVertical ? 'stretch' : 'center',
|
|
2343
|
+
justifyContent: isVertical ? 'space-between' : 'space-between',
|
|
2344
|
+
padding: isVertical ? '20px 16px' : '20px 32px',
|
|
2345
|
+
backgroundColor: '#ffffff',
|
|
2346
|
+
borderBottom: isVertical ? 'none' : '1px solid #e5e7eb',
|
|
2347
|
+
borderRight: isVertical ? '1px solid #e5e7eb' : 'none',
|
|
2348
|
+
width: isVertical ? '200px' : '100%',
|
|
2349
|
+
minWidth: isVertical ? '180px' : 'auto',
|
|
2350
|
+
flexShrink: 0
|
|
2351
|
+
}}>
|
|
2352
|
+
{/* Title */}
|
|
2353
|
+
{props.showTitle && (
|
|
2354
|
+
<h1 style={{
|
|
2355
|
+
...getTitleStyle(),
|
|
2356
|
+
marginBottom: isVertical ? '16px' : '0',
|
|
2357
|
+
textAlign: isVertical ? 'left' : getTitleStyle().textAlign,
|
|
2358
|
+
writingMode: isVertical ? 'horizontal-tb' : 'initial',
|
|
2359
|
+
flexShrink: 0
|
|
2360
|
+
}}>
|
|
2361
|
+
{props?.title?.titleText}
|
|
2362
|
+
</h1>
|
|
2363
|
+
)}
|
|
2364
|
+
|
|
2365
|
+
{/* Tab Headers */}
|
|
2366
|
+
<div style={{
|
|
2367
|
+
display: 'flex',
|
|
2368
|
+
flexDirection: isVertical ? 'column' : 'row',
|
|
2369
|
+
alignItems: isVertical ? 'stretch' : 'center',
|
|
2370
|
+
gap: isVertical ? '8px' : '0',
|
|
2371
|
+
width: isVertical ? '100%' : 'auto',
|
|
2372
|
+
marginLeft: isVertical ? '0' : 'auto'
|
|
2373
|
+
}}>
|
|
2374
|
+
{tabs.map((tab, index) => (
|
|
2375
|
+
<React.Fragment key={index}>
|
|
2376
|
+
<button
|
|
2377
|
+
style={{
|
|
2378
|
+
...getTabHeaderStyle(index),
|
|
2379
|
+
width: isVertical ? '100%' : 'auto',
|
|
2380
|
+
textAlign: isVertical ? 'left' : 'center',
|
|
2381
|
+
justifyContent: isVertical ? 'flex-start' : 'center',
|
|
2382
|
+
marginBottom: isVertical ? '0' : '0'
|
|
2383
|
+
}}
|
|
2384
|
+
onClick={() => handleTabChange(index)}
|
|
2385
|
+
onMouseEnter={() => setHoveredTab(index)}
|
|
2386
|
+
onMouseLeave={() => setHoveredTab(null)}
|
|
2387
|
+
>
|
|
2388
|
+
{tab.tabHeaderType === 'text' ? (
|
|
2389
|
+
tab.tabHeaderText
|
|
2390
|
+
) : tab.tabHeaderImage.url ? (
|
|
2391
|
+
<img
|
|
2392
|
+
src={getImageUrl(tab.tabHeaderImage.url)}
|
|
2393
|
+
alt={tab.tabHeaderImage.alt}
|
|
2394
|
+
style={{ height: '20px', width: 'auto' }}
|
|
2395
|
+
/>
|
|
2396
|
+
) : (
|
|
2397
|
+
tab.tabHeaderText
|
|
2398
|
+
)}
|
|
2399
|
+
</button>
|
|
2396
2400
|
|
|
2397
|
-
|
|
2401
|
+
{/* Add separator - only for horizontal orientation */}
|
|
2402
|
+
{!isVertical && index < tabs.length - 1 && (
|
|
2403
|
+
<span style={{ color: '#9ca3af', margin: '0 4px' }}>|</span>
|
|
2404
|
+
)}
|
|
2405
|
+
</React.Fragment>
|
|
2406
|
+
))}
|
|
2407
|
+
</div>
|
|
2398
2408
|
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
flex: 1,
|
|
2403
|
-
overflow: 'hidden',
|
|
2404
|
-
minHeight: 0, // Allows flex child to shrink below content size
|
|
2405
|
-
width: isVertical ? 'calc(100% - 200px)' : '100%'
|
|
2406
|
-
}}>
|
|
2407
|
-
{tabs.length > 0 && tabs[activeTab] && (
|
|
2409
|
+
</div>
|
|
2410
|
+
|
|
2411
|
+
{/* Tab Content */}
|
|
2408
2412
|
<div style={{
|
|
2409
|
-
|
|
2410
|
-
|
|
2413
|
+
position: 'relative',
|
|
2414
|
+
flex: 1,
|
|
2415
|
+
overflow: 'hidden',
|
|
2416
|
+
minHeight: 0, // Allows flex child to shrink below content size
|
|
2417
|
+
width: isVertical ? 'calc(100% - 200px)' : '100%'
|
|
2411
2418
|
}}>
|
|
2412
|
-
{
|
|
2419
|
+
{tabs.length > 0 && tabs[activeTab] && (
|
|
2420
|
+
<div style={{
|
|
2421
|
+
width: '100%',
|
|
2422
|
+
height: '100%'
|
|
2423
|
+
}}>
|
|
2424
|
+
{renderTabContent(tabs[activeTab])}
|
|
2425
|
+
</div>
|
|
2426
|
+
)}
|
|
2413
2427
|
</div>
|
|
2414
|
-
|
|
2415
|
-
</div>
|
|
2416
|
-
</div>
|
|
2428
|
+
</div>
|
|
2417
2429
|
);
|
|
2418
2430
|
} catch (error: any) {
|
|
2419
2431
|
console.error('Error rendering TabComponent:', error);
|