@codesinger0/shared-components 1.1.84 → 1.1.85

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.
Files changed (50) hide show
  1. package/dist/components/LargeItemCard.jsx +35 -11
  2. package/dist/components 2/AccessibilityMenu.jsx +474 -0
  3. package/dist/components 2/AdvantagesList.jsx +89 -0
  4. package/dist/components 2/ArticlesList.jsx +269 -0
  5. package/dist/components 2/DualTextCard.jsx +73 -0
  6. package/dist/components 2/FloatingWhatsAppButton.jsx +180 -0
  7. package/dist/components 2/FullscreenCarousel.jsx +292 -0
  8. package/dist/components 2/Hero.jsx +198 -0
  9. package/dist/components 2/IconGrid.jsx +144 -0
  10. package/dist/components 2/IntroSection.jsx +74 -0
  11. package/dist/components 2/LargeItemCard.jsx +267 -0
  12. package/dist/components 2/MasonryItemCard.jsx +247 -0
  13. package/dist/components 2/Menu.d.ts +26 -0
  14. package/dist/components 2/Menu.jsx +268 -0
  15. package/dist/components 2/MyOrdersDisplay.jsx +311 -0
  16. package/dist/components 2/QAAccordion.jsx +212 -0
  17. package/dist/components 2/SmallItemCard.jsx +152 -0
  18. package/dist/components 2/SmallItemsGrid.jsx +313 -0
  19. package/dist/components 2/TextListCards.jsx +107 -0
  20. package/dist/components 2/ToastProvider.jsx +38 -0
  21. package/dist/components 2/UnderConstruction.jsx +76 -0
  22. package/dist/components 2/VideoCard.jsx +88 -0
  23. package/dist/components 2/cart/CartItem.jsx +101 -0
  24. package/dist/components 2/cart/FloatingCartButton.jsx +49 -0
  25. package/dist/components 2/cart/OrderForm.jsx +960 -0
  26. package/dist/components 2/cart/ShoppingCartModal.jsx +229 -0
  27. package/dist/components 2/clubMembership/ClubMembershipModal.jsx +289 -0
  28. package/dist/components 2/clubMembership/ClubPromoModal.jsx +108 -0
  29. package/dist/components 2/elements/CTAButton.jsx +17 -0
  30. package/dist/components 2/elements/FixedWidthHeroVideo.jsx +92 -0
  31. package/dist/components 2/elements/ImageLightbox.jsx +112 -0
  32. package/dist/components 2/elements/RoundButton.jsx +44 -0
  33. package/dist/components 2/elements/SmallButton.jsx +35 -0
  34. package/dist/components 2/elements/Toast.jsx +37 -0
  35. package/dist/components 2/elements/VideoLightbox.jsx +76 -0
  36. package/dist/components 2/modals/ItemDetailsModal.jsx +192 -0
  37. package/dist/components 2/products/CategoryList.jsx +24 -0
  38. package/dist/components 2/products/PriceRangeSlider.jsx +162 -0
  39. package/dist/components 2/products/ProductsDisplay.jsx +40 -0
  40. package/dist/components 2/products/ProductsSidebar.jsx +46 -0
  41. package/dist/components 2/products/SubcategorySection.jsx +37 -0
  42. package/dist/context 2/CartContext.jsx +165 -0
  43. package/dist/context 2/ItemModalContext.jsx +40 -0
  44. package/dist/hooks 2/useScrollLock.js +52 -0
  45. package/dist/index 2.js +45 -0
  46. package/dist/integrations 2/emailService.js +167 -0
  47. package/dist/styles 2/shared-components.css +29 -0
  48. package/dist/utils 2/ScrollManager.jsx +85 -0
  49. package/dist/utils 2/ScrollToTop.jsx +14 -0
  50. package/package.json +1 -1
@@ -0,0 +1,292 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import useEmblaCarousel from 'embla-carousel-react';
3
+ import Autoplay from 'embla-carousel-autoplay';
4
+
5
+ const FullscreenCarousel = ({
6
+ slides = [],
7
+ desktopHeight = '100vh',
8
+ mobileHeight = '100vh',
9
+ autoplay = true,
10
+ scrollInterval = 5000,
11
+ loop = true,
12
+ showDots = true,
13
+ showArrows = true,
14
+ className = '',
15
+ ...props
16
+ }) => {
17
+ const [prevBtnEnabled, setPrevBtnEnabled] = useState(false);
18
+ const [nextBtnEnabled, setNextBtnEnabled] = useState(false);
19
+ const [selectedIndex, setSelectedIndex] = useState(0);
20
+ const [scrollSnaps, setScrollSnaps] = useState([]);
21
+
22
+ // Embla carousel setup
23
+ const autoplayOptions = {
24
+ delay: scrollInterval,
25
+ stopOnInteraction: false,
26
+ stopOnMouseEnter: false,
27
+ rootNode: (emblaRoot) => emblaRoot.parentElement,
28
+ };
29
+
30
+ const plugins = autoplay ? [Autoplay(autoplayOptions)] : [];
31
+
32
+ const [emblaRef, emblaApi] = useEmblaCarousel(
33
+ {
34
+ loop: loop,
35
+ direction: 'rtl',
36
+ skipSnaps: false,
37
+ },
38
+ plugins
39
+ );
40
+
41
+ const scrollPrev = useCallback(() => emblaApi && emblaApi.scrollPrev(), [emblaApi]);
42
+ const scrollNext = useCallback(() => emblaApi && emblaApi.scrollNext(), [emblaApi]);
43
+ const scrollTo = useCallback((index) => emblaApi && emblaApi.scrollTo(index), [emblaApi]);
44
+
45
+ const onSelect = useCallback(() => {
46
+ if (!emblaApi) return;
47
+ setSelectedIndex(emblaApi.selectedScrollSnap());
48
+ setPrevBtnEnabled(emblaApi.canScrollPrev());
49
+ setNextBtnEnabled(emblaApi.canScrollNext());
50
+ }, [emblaApi]);
51
+
52
+ useEffect(() => {
53
+ if (!emblaApi) return;
54
+ onSelect();
55
+ setScrollSnaps(emblaApi.scrollSnapList());
56
+ emblaApi.on('select', onSelect);
57
+ emblaApi.on('reInit', onSelect);
58
+ }, [emblaApi, onSelect]);
59
+
60
+ if (!slides || slides.length === 0) {
61
+ return (
62
+ <div className="w-full flex items-center justify-center bg-gray-100" style={{ height: desktopHeight }}>
63
+ <p className="text-gray-500">No slides to display</p>
64
+ </div>
65
+ );
66
+ }
67
+
68
+ return (
69
+ <div className={`fullscreen-carousel-wrapper ${className}`} {...props}>
70
+ <div className="fullscreen-carousel" dir="rtl">
71
+ <div className="fullscreen-carousel__viewport" ref={emblaRef}>
72
+ <div className="fullscreen-carousel__container">
73
+ {slides.map((slide, index) => {
74
+ const isSingleSlide = !slide.leftContent && !slide.rightContent;
75
+
76
+ return (
77
+ <div key={index} className="fullscreen-carousel__slide">
78
+ {isSingleSlide ? (
79
+ /* Single Slide Mode */
80
+ <div
81
+ className="w-full h-full"
82
+ style={{ height: desktopHeight }}
83
+ >
84
+ {slide.content}
85
+ </div>
86
+ ) : (
87
+ <>
88
+ {/* Desktop Layout - Horizontal Split */}
89
+ <div
90
+ className="hidden md:grid md:grid-cols-2 w-full h-full"
91
+ style={{ height: desktopHeight }}
92
+ >
93
+ <div className="w-full h-full">
94
+ {slide.leftContent}
95
+ </div>
96
+ <div className="w-full h-full">
97
+ {slide.rightContent}
98
+ </div>
99
+ </div>
100
+
101
+ {/* Mobile Layout - Vertical Split */}
102
+ <div
103
+ className="md:hidden grid grid-rows-2 w-full h-full"
104
+ style={{ height: mobileHeight }}
105
+ >
106
+ <div className="w-full h-full">
107
+ {slide.leftContent}
108
+ </div>
109
+ <div className="w-full h-full">
110
+ {slide.rightContent}
111
+ </div>
112
+ </div>
113
+ </>
114
+ )}
115
+ </div>
116
+ );
117
+ })}
118
+ </div>
119
+ </div>
120
+
121
+ {/* Dots indicator */}
122
+ {showDots && slides.length > 1 && (
123
+ <div className="fullscreen-carousel__dots">
124
+ {scrollSnaps.map((_, index) => (
125
+ <button
126
+ key={index}
127
+ className={`fullscreen-carousel__dot ${index === selectedIndex ? 'fullscreen-carousel__dot--selected' : ''}`}
128
+ onClick={() => scrollTo(index)}
129
+ aria-label={`Go to slide ${index + 1}`}
130
+ />
131
+ ))}
132
+ </div>
133
+ )}
134
+
135
+ {/* Navigation buttons */}
136
+ {showArrows && slides.length > 1 && (
137
+ <>
138
+ <button
139
+ className="fullscreen-carousel__button fullscreen-carousel__button--prev"
140
+ onClick={scrollPrev}
141
+ disabled={!prevBtnEnabled}
142
+ aria-label="Previous slide"
143
+ >
144
+ <svg className="fullscreen-carousel__button__svg" viewBox="0 0 24 24">
145
+ <path d="M9 18l6-6-6-6" />
146
+ </svg>
147
+ </button>
148
+ <button
149
+ className="fullscreen-carousel__button fullscreen-carousel__button--next"
150
+ onClick={scrollNext}
151
+ disabled={!nextBtnEnabled}
152
+ aria-label="Next slide"
153
+ >
154
+ <svg className="fullscreen-carousel__button__svg" viewBox="0 0 24 24">
155
+ <path d="M15 18l-6-6 6-6" />
156
+ </svg>
157
+ </button>
158
+ </>
159
+ )}
160
+ </div>
161
+
162
+ {/* Styles */}
163
+ <style jsx>{`
164
+ .fullscreen-carousel-wrapper {
165
+ position: relative;
166
+ width: 100%;
167
+ overflow: hidden;
168
+ }
169
+
170
+ .fullscreen-carousel {
171
+ position: relative;
172
+ width: 100%;
173
+ }
174
+
175
+ .fullscreen-carousel__viewport {
176
+ overflow: hidden;
177
+ width: 100%;
178
+ }
179
+
180
+ .fullscreen-carousel__container {
181
+ display: flex;
182
+ width: 100%;
183
+ }
184
+
185
+ .fullscreen-carousel__slide {
186
+ flex: 0 0 100%;
187
+ min-width: 0;
188
+ position: relative;
189
+ }
190
+
191
+ .fullscreen-carousel__button {
192
+ display: none;
193
+ background-color: rgba(255, 255, 255, 0.9);
194
+ color: #333;
195
+ border: none;
196
+ width: 3rem;
197
+ height: 3rem;
198
+ border-radius: 50%;
199
+ cursor: pointer;
200
+ align-items: center;
201
+ justify-content: center;
202
+ transition: all 0.2s ease;
203
+ box-shadow: 0 2px 8px rgba(0,0,0,0.15);
204
+ position: absolute;
205
+ top: 50%;
206
+ transform: translateY(-50%);
207
+ z-index: 10;
208
+ }
209
+
210
+ @media (min-width: 768px) {
211
+ .fullscreen-carousel__button {
212
+ display: flex;
213
+ }
214
+ }
215
+
216
+ .fullscreen-carousel__button--prev {
217
+ right: 2rem;
218
+ }
219
+
220
+ .fullscreen-carousel__button--next {
221
+ left: 2rem;
222
+ }
223
+
224
+ .fullscreen-carousel__controls {
225
+ display: flex;
226
+ justify-content: center;
227
+ gap: 1rem;
228
+ position: absolute;
229
+ bottom: 4rem;
230
+ left: 50%;
231
+ transform: translateX(-50%);
232
+ z-index: 10;
233
+ }
234
+
235
+ .fullscreen-carousel__button:hover:not(:disabled) {
236
+ background-color: rgba(255, 255, 255, 1);
237
+ transform: scale(1.1);
238
+ box-shadow: 0 4px 12px rgba(0,0,0,0.2);
239
+ }
240
+
241
+ .fullscreen-carousel__button:disabled {
242
+ opacity: 0.3;
243
+ cursor: not-allowed;
244
+ }
245
+
246
+ .fullscreen-carousel__button__svg {
247
+ width: 1rem;
248
+ height: 1rem;
249
+ fill: none;
250
+ stroke: currentColor;
251
+ stroke-width: 2;
252
+ stroke-linecap: round;
253
+ stroke-linejoin: round;
254
+ }
255
+
256
+ .fullscreen-carousel__dots {
257
+ display: flex;
258
+ justify-content: center;
259
+ gap: 0.5rem;
260
+ position: absolute;
261
+ bottom: 2rem;
262
+ left: 50%;
263
+ transform: translateX(-50%);
264
+ z-index: 10;
265
+ }
266
+
267
+ .fullscreen-carousel__dot {
268
+ background-color: rgba(255, 255, 255, 0.5);
269
+ border: none;
270
+ width: 0.75rem;
271
+ height: 0.75rem;
272
+ border-radius: 50%;
273
+ cursor: pointer;
274
+ opacity: 0.5;
275
+ transition: all 0.2s ease;
276
+ }
277
+
278
+ .fullscreen-carousel__dot--selected {
279
+ opacity: 1;
280
+ background-color: rgba(255, 255, 255, 1);
281
+ transform: scale(1.2);
282
+ }
283
+
284
+ .fullscreen-carousel__dot:hover {
285
+ opacity: 0.8;
286
+ }
287
+ `}</style>
288
+ </div>
289
+ );
290
+ };
291
+
292
+ export default FullscreenCarousel;
@@ -0,0 +1,198 @@
1
+ import CTAButton from "./elements/CTAButton";
2
+ import FixedWidthHeroVideo from "./elements/FixedWidthHeroVideo";
3
+ import { ArrowDown } from 'lucide-react'
4
+ import { motion } from "framer-motion";
5
+
6
+ const Hero = ({
7
+ // Media props
8
+ mediaType = 'image', // 'video' or 'image'
9
+ videoId = '', // YouTube video ID
10
+ useYoutube = true, // Use YouTube or direct video
11
+ videoUrl = '', // Direct video URL (when useYoutube is false)
12
+ imageUrl = '', // Image URL for static background
13
+ mediaHeight = '70vh', // Height of the media section
14
+
15
+ // Overlay
16
+ opacity = 70,
17
+ overlayColor = 'white',
18
+
19
+ // Hero text props
20
+ title,
21
+ subtitle,
22
+ miniSubtitle,
23
+ additionalElements,
24
+ ctaText,
25
+ secondaryButtonLabel, // Optional secondary button label
26
+ onSecondaryClick, // Optional secondary button click handler
27
+ showArrow = true, // Show/hide animated arrow
28
+
29
+ // Introduction section props
30
+ showIntroSection,
31
+ introHeight = '40vh',
32
+ introTitle,
33
+ introContent,
34
+ introImage,
35
+ onCtaClick,
36
+
37
+ classNames = {}
38
+ }) => {
39
+ const {
40
+ title: titleClass = 'main-title',
41
+ subtitle: subtitleClass = 'main-subtitle',
42
+ miniSubtitle: miniSubtitleClass = 'main-content',
43
+ cta: ctaClass = '',
44
+ introTitle: introTitleClass = 'title',
45
+ introContent: introContentClass = 'subtitle'
46
+ } = classNames;
47
+
48
+ const hexToRgba = (hex, alpha) => {
49
+ const r = parseInt(hex.slice(1, 3), 16);
50
+ const g = parseInt(hex.slice(3, 5), 16);
51
+ const b = parseInt(hex.slice(5, 7), 16);
52
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
53
+ };
54
+
55
+ return (
56
+ <>
57
+ <section className="hero-section relative w-full overflow-hidden" style={{ height: mediaHeight }}>
58
+ {/* Media Background Container */}
59
+ <div className="absolute inset-0 w-full h-full" aria-hidden="true">
60
+ {mediaType === 'video' ? (
61
+ <FixedWidthHeroVideo
62
+ useYoutube={useYoutube}
63
+ youtubeVideoId={videoId}
64
+ videoUrl={videoUrl}
65
+ />
66
+ ) : (
67
+ <div
68
+ className="absolute inset-0 bg-cover bg-center bg-no-repeat"
69
+ style={{
70
+ backgroundImage: `url(${imageUrl})`,
71
+ backgroundColor: '#1a1a1a' // Fallback color
72
+ }}
73
+ />
74
+ )}
75
+ </div>
76
+
77
+ {/* Content Overlay */}
78
+ <div
79
+ className="relative z-10 flex items-center justify-center h-full"
80
+ style={{
81
+ background: overlayColor === 'white' ? `rgba(255, 255, 255, ${opacity / 100})` :
82
+ overlayColor === 'black' ? `rgba(0, 0, 0, ${opacity / 100})` :
83
+ overlayColor.startsWith('#') ? hexToRgba(overlayColor, opacity / 100) :
84
+ overlayColor.startsWith('rgb') ? overlayColor :
85
+ `rgba(255, 255, 255, ${opacity / 100})` // fallback to white
86
+ }}
87
+ >
88
+ <div className="text-center px-0">
89
+ <motion.div
90
+ initial={{ opacity: 0, y: 30 }}
91
+ animate={{ opacity: 1, y: 0 }}
92
+ transition={{ duration: 0.8 }}
93
+ className="mb-8"
94
+ >
95
+ <h1 className={titleClass + " mb-4"}>
96
+ {title}
97
+ </h1>
98
+ <p className={subtitleClass + " mb-4"}>
99
+ {subtitle}
100
+ </p>
101
+ <p className={miniSubtitleClass + " mb-12"}>
102
+ {miniSubtitle}
103
+ </p>
104
+ {additionalElements}
105
+ <div className="flex flex-wrap gap-4 justify-center items-center">
106
+ {secondaryButtonLabel && onSecondaryClick && (
107
+ <button
108
+ onClick={onSecondaryClick}
109
+ className="px-6 py-3 border-2 border-primary text-primary bg-main font-normal hover:bg-primary hover:text-primary-dark transition-all duration-300 shadow-lg"
110
+ >
111
+ {secondaryButtonLabel}
112
+ </button>
113
+ )}
114
+ <CTAButton onClick={onCtaClick} className="shadow-lg">
115
+ {ctaText}
116
+ </CTAButton>
117
+ </div>
118
+ </motion.div>
119
+ </div>
120
+
121
+ {showArrow && (
122
+ <motion.div
123
+ className="absolute"
124
+ style={{
125
+ bottom: '2rem',
126
+ left: '50%',
127
+ transform: 'translateX(-50%)',
128
+ zIndex: 100
129
+ }}
130
+ animate={{ y: [0, 10, 0] }}
131
+ transition={{ duration: 2, repeat: Infinity }}
132
+ >
133
+ <ArrowDown className="w-8 h-8 text-sky-600" />
134
+ </motion.div>
135
+ )}
136
+ </div>
137
+ </section>
138
+
139
+ {/* Introduction Section */}
140
+ {showIntroSection && (
141
+ <section className=" py-16 px-4" style={{ minHeight: introHeight }}>
142
+ <div className="max-w-6xl mx-auto" dir="rtl">
143
+ {introImage ? (
144
+ /* Layout with image */
145
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-12 items-center">
146
+ {/* Text Content */}
147
+ <div className="text-center lg:text-right order-2 lg:order-1">
148
+ <h2 className={introTitleClass + " mb-6"}>
149
+ {introTitle}
150
+ </h2>
151
+ <p className={introContentClass + " leading-relaxed"} style={{ whiteSpace: 'pre-line' }}>
152
+ {introContent}
153
+ </p>
154
+ </div>
155
+
156
+ {/* Image */}
157
+ <motion.div
158
+ key={'image'}
159
+ initial={{ opacity: 0, x: 50 }}
160
+ whileInView={{ opacity: 1, x: 0 }}
161
+ viewport={{ once: true }}
162
+ transition={{ delay: 1 * 0.5 }}
163
+ className="h-full"
164
+ >
165
+ <div className="order-1 lg:order-2 flex justify-center lg:justify-end">
166
+ <div className="w-full max-w-md lg:max-w-lg">
167
+ <img
168
+ src={introImage}
169
+ alt={introTitle || "Introduction image"}
170
+ className="w-full h-auto rounded-lg shadow-lg object-cover"
171
+ onError={(e) => {
172
+ e.target.style.display = 'none';
173
+ console.warn('Failed to load intro image:', introImage);
174
+ }}
175
+ />
176
+ </div>
177
+ </div>
178
+ </motion.div>
179
+ </div>
180
+ ) : (
181
+ /* Text only layout (original) */
182
+ <div className="text-center max-w-4xl mx-auto">
183
+ <h2 className="title mb-6">
184
+ {introTitle}
185
+ </h2>
186
+ <p className="subtitle leading-relaxed" style={{ whiteSpace: 'pre-line' }}>
187
+ {introContent}
188
+ </p>
189
+ </div>
190
+ )}
191
+ </div>
192
+ </section>
193
+ )}
194
+ </>
195
+ );
196
+ }
197
+
198
+ export default Hero
@@ -0,0 +1,144 @@
1
+ import React from 'react';
2
+ import { Users, Monitor, Smartphone, ThumbsUp, Paintbrush } from 'lucide-react';
3
+
4
+ const IconGrid = ({ items = [], className = '' }) => {
5
+ if (!items || items.length === 0) {
6
+ return null;
7
+ }
8
+
9
+ // Calculate rows distribution
10
+ const totalItems = items.length;
11
+ const isEven = totalItems % 2 === 0;
12
+ const itemsPerRow = Math.ceil(totalItems / 2);
13
+
14
+ // Split items into rows
15
+ const topRowCount = isEven ? itemsPerRow : itemsPerRow;
16
+ const topRow = items.slice(0, topRowCount);
17
+ const bottomRow = items.slice(topRowCount);
18
+
19
+ const GridItem = ({ icon: Icon, text }) => (
20
+ <div className="flex flex-col items-center justify-center p-6 bg-gradient-to-br from-purple-50 to-indigo-50 rounded-2xl hover:shadow-lg transition-shadow duration-300">
21
+ <div className="w-20 h-20 mb-4 flex items-center justify-center">
22
+ <Icon className="w-full h-full text-main" strokeWidth={1.5} />
23
+ </div>
24
+ <p className="text-center text-gray-800 font-medium text-lg" dir="rtl">
25
+ {text}
26
+ </p>
27
+ </div>
28
+ );
29
+
30
+ return (
31
+ <div className={`w-full max-w-6xl mx-auto px-4 ${className}`}>
32
+ {/* Mobile: Single column */}
33
+ <div className="md:hidden space-y-4">
34
+ {items.map((item, index) => (
35
+ <GridItem key={index} {...item} />
36
+ ))}
37
+ </div>
38
+
39
+ {/* Desktop: Smart grid */}
40
+ <div className="hidden md:block space-y-4 mt-20 mb-20">
41
+ {/* Top row */}
42
+ <div
43
+ className="grid gap-4 mb-4"
44
+ style={{
45
+ gridTemplateColumns: `repeat(${topRowCount}, 1fr)`,
46
+ justifyItems: 'center'
47
+ }}
48
+ >
49
+ {topRow.map((item, index) => (
50
+ <div key={index} className="w-full max-w-sm">
51
+ <GridItem {...item} />
52
+ </div>
53
+ ))}
54
+ </div>
55
+
56
+ {/* Bottom row - centered if fewer items */}
57
+ {bottomRow.length > 0 && (
58
+ <div
59
+ className="grid gap-4"
60
+ style={{
61
+ gridTemplateColumns: `repeat(${bottomRow.length}, 1fr)`,
62
+ justifyItems: 'center',
63
+ maxWidth: bottomRow.length < topRowCount ? `${(bottomRow.length / topRowCount) * 100}%` : '100%',
64
+ margin: '0 auto'
65
+ }}
66
+ >
67
+ {bottomRow.map((item, index) => (
68
+ <div key={index} className="w-full max-w-sm">
69
+ <GridItem {...item} />
70
+ </div>
71
+ ))}
72
+ </div>
73
+ )}
74
+ </div>
75
+ </div>
76
+ );
77
+ };
78
+
79
+ // Demo
80
+ const Demo = () => {
81
+ const demoItems = [
82
+ {
83
+ icon: Users,
84
+ text: 'מתאים לכל סוגי העסקים'
85
+ },
86
+ {
87
+ icon: Monitor,
88
+ text: 'חווית משתמש UX/UI'
89
+ },
90
+ {
91
+ icon: Smartphone,
92
+ text: 'התאמה מלאה לכל המסכים'
93
+ },
94
+ {
95
+ icon: ThumbsUp,
96
+ text: 'תמיכה מלאה'
97
+ },
98
+ {
99
+ icon: Paintbrush,
100
+ text: 'עיצוב יוצר נשימה'
101
+ }
102
+ ];
103
+
104
+ return (
105
+ <div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 py-16">
106
+ <div className="max-w-7xl mx-auto px-4">
107
+ <h1 className="text-4xl font-bold text-center text-gray-800 mb-4" dir="rtl">
108
+ IconGrid Component
109
+ </h1>
110
+ <p className="text-center text-gray-600 mb-12" dir="rtl">
111
+ רכיב גריד חכם המתאים את עצמו למספר הפריטים
112
+ </p>
113
+
114
+ <IconGrid items={demoItems} />
115
+
116
+ <div className="mt-16 bg-white rounded-xl p-8 shadow-lg">
117
+ <h2 className="text-2xl font-bold mb-4" dir="rtl">תכונות:</h2>
118
+ <ul className="space-y-2 text-gray-700" dir="rtl">
119
+ <li>✅ מספר זוגי של פריטים - חלוקה שווה בין שורות</li>
120
+ <li>✅ מספר אי-זוגי - שורה עליונה עם פריט אחד נוסף, ממורכזת</li>
121
+ <li>✅ במובייל - עמודה אנכית בודדת</li>
122
+ <li>✅ תמיכה מלאה ב-RTL</li>
123
+ <li>✅ עיצוב רספונסיבי עם אנימציות</li>
124
+ </ul>
125
+
126
+ <h3 className="text-xl font-bold mt-6 mb-3" dir="rtl">דוגמת שימוש:</h3>
127
+ <pre className="bg-gray-50 p-4 rounded-lg overflow-x-auto text-sm">
128
+ {`const items = [
129
+ { icon: Users, text: 'טקסט 1' },
130
+ { icon: Monitor, text: 'טקסט 2' },
131
+ { icon: Smartphone, text: 'טקסט 3' },
132
+ { icon: ThumbsUp, text: 'טקסט 4' },
133
+ { icon: Paintbrush, text: 'טקסט 5' }
134
+ ];
135
+
136
+ <IconGrid items={items} />`}
137
+ </pre>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ );
142
+ };
143
+
144
+ export default IconGrid;