@codesinger0/shared-components 1.1.21 → 1.1.22
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/components/IconGrid.jsx +144 -0
- package/dist/components/LargeItemCard.jsx +105 -65
- package/dist/components/VideoCard.jsx +1 -1
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -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-indigo-600" 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">
|
|
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;
|
|
@@ -4,6 +4,9 @@ import { motion } from 'framer-motion'
|
|
|
4
4
|
|
|
5
5
|
const LargeItemCard = ({
|
|
6
6
|
imageUrl,
|
|
7
|
+
videoUrl,
|
|
8
|
+
contentType = 'image',
|
|
9
|
+
mediaScale = 1,
|
|
7
10
|
title,
|
|
8
11
|
subtitle,
|
|
9
12
|
description,
|
|
@@ -12,7 +15,8 @@ const LargeItemCard = ({
|
|
|
12
15
|
reverse = false,
|
|
13
16
|
price,
|
|
14
17
|
discountPrice,
|
|
15
|
-
|
|
18
|
+
amountAvailable,
|
|
19
|
+
absolutePosition = true,
|
|
16
20
|
availableLabel = 'נותרו במלאי',
|
|
17
21
|
soldOutLabel = 'אזל במלאי',
|
|
18
22
|
icons = [],
|
|
@@ -26,14 +30,43 @@ const LargeItemCard = ({
|
|
|
26
30
|
price: priceClass = 'text-price',
|
|
27
31
|
} = classNames;
|
|
28
32
|
|
|
33
|
+
const MediaElement = ({ className, style }) => {
|
|
34
|
+
const scaleStyle = {
|
|
35
|
+
...style,
|
|
36
|
+
transform: `scale(${mediaScale})`,
|
|
37
|
+
transformOrigin: 'center'
|
|
38
|
+
};
|
|
39
|
+
if (contentType === 'video') {
|
|
40
|
+
return (
|
|
41
|
+
<video
|
|
42
|
+
autoPlay
|
|
43
|
+
muted
|
|
44
|
+
loop
|
|
45
|
+
playsInline
|
|
46
|
+
className={`rounded-lg shadow-2xl border border-primary max-w-full ${className}`}
|
|
47
|
+
style={{ ...scaleStyle, objectFit: 'contain' }}
|
|
48
|
+
>
|
|
49
|
+
<source src={videoUrl} type="video/mp4" />
|
|
50
|
+
</video>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
<img
|
|
55
|
+
src={imageUrl}
|
|
56
|
+
alt={title}
|
|
57
|
+
className={className}
|
|
58
|
+
style={scaleStyle}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
29
63
|
return (
|
|
30
64
|
<section className="relative w-full overflow-visible py-16 px-4">
|
|
31
65
|
{/* Background Section with Text Content */}
|
|
32
66
|
<div className="glass-card relative" style={{ minHeight: '48vh', overflow: 'visible' }}>
|
|
33
67
|
|
|
34
|
-
<div className="max-w-7xl mx-auto px-6
|
|
68
|
+
<div className="max-w-7xl mx-auto px-6 py-16">
|
|
35
69
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
|
36
|
-
|
|
37
70
|
{/* Text Content */}
|
|
38
71
|
<div
|
|
39
72
|
className={`text-center lg:text-right space-y-6 ${reverse ? 'lg:order-2' : 'lg:order-1'}`}
|
|
@@ -85,13 +118,15 @@ const LargeItemCard = ({
|
|
|
85
118
|
{soldOutLabel}
|
|
86
119
|
</div>
|
|
87
120
|
) : (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
buttonLabel && (
|
|
122
|
+
<RoundButton
|
|
123
|
+
variant="primary"
|
|
124
|
+
onClick={onButtonClick}
|
|
125
|
+
disabled={amountAvailable !== undefined && amountAvailable <= 0}
|
|
126
|
+
>
|
|
127
|
+
{buttonLabel}
|
|
128
|
+
</RoundButton>
|
|
129
|
+
)
|
|
95
130
|
)}
|
|
96
131
|
</div>
|
|
97
132
|
|
|
@@ -107,70 +142,75 @@ const LargeItemCard = ({
|
|
|
107
142
|
)}
|
|
108
143
|
</div>
|
|
109
144
|
|
|
110
|
-
{/*
|
|
111
|
-
|
|
112
|
-
{
|
|
113
|
-
|
|
145
|
+
{/* Desktop image/video positioning */}
|
|
146
|
+
{!absolutePosition && (
|
|
147
|
+
<div className={`hidden lg:block ${reverse ? 'lg:order-1' : 'lg:order-2'}`}>
|
|
148
|
+
<motion.div
|
|
149
|
+
key={'image'}
|
|
150
|
+
initial={{ opacity: 0, x: reverse ? -50 : 50 }}
|
|
151
|
+
whileInView={{ opacity: 1, x: 0 }}
|
|
152
|
+
viewport={{ once: true }}
|
|
153
|
+
transition={{ delay: 0.5 }}
|
|
154
|
+
className="h-full flex items-center justify-center"
|
|
155
|
+
>
|
|
156
|
+
<MediaElement
|
|
157
|
+
className="rounded-lg shadow-2xl border border-primary max-w-full"
|
|
158
|
+
style={{
|
|
159
|
+
maxHeight: '450px',
|
|
160
|
+
width: 'auto',
|
|
161
|
+
height: 'auto'
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
</motion.div>
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
114
167
|
</div>
|
|
115
|
-
|
|
116
168
|
</div>
|
|
117
169
|
|
|
118
170
|
{/* full-width mobile image */}
|
|
119
171
|
<div className="block lg:hidden mt-8 w-full">
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
whileInView={{ opacity: 1, y: 0 }}
|
|
124
|
-
viewport={{ once: true }}
|
|
125
|
-
transition={{ delay: 1 * 0.5 }}
|
|
126
|
-
className="h-full"
|
|
127
|
-
>
|
|
128
|
-
<img
|
|
129
|
-
src={imageUrl}
|
|
130
|
-
alt={title}
|
|
131
|
-
className="w-full h-auto rounded-none shadow-2xls"
|
|
132
|
-
/>
|
|
133
|
-
</motion.div>
|
|
172
|
+
<MediaElement
|
|
173
|
+
className="w-full h-auto rounded-none shadow-2xls"
|
|
174
|
+
/>
|
|
134
175
|
</div>
|
|
135
176
|
</div>
|
|
136
177
|
|
|
137
|
-
{/* Floating Image Container (desktop only,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
</motion.div>
|
|
178
|
+
{/* Floating Image Container (desktop only, absolute positioned) */}
|
|
179
|
+
{absolutePosition && (
|
|
180
|
+
<div
|
|
181
|
+
className="hidden lg:block absolute"
|
|
182
|
+
style={{
|
|
183
|
+
zIndex: 10,
|
|
184
|
+
width: '30vw',
|
|
185
|
+
maxWidth: '40vw',
|
|
186
|
+
top: '2rem',
|
|
187
|
+
left: reverse ? '4rem' : 'auto',
|
|
188
|
+
right: reverse ? 'auto' : '4rem',
|
|
189
|
+
transform: 'none'
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
<div className="relative">
|
|
193
|
+
<motion.div
|
|
194
|
+
key={'image'}
|
|
195
|
+
initial={{ opacity: 0, x: reverse ? -50 : 50 }}
|
|
196
|
+
whileInView={{ opacity: 1, x: 0 }}
|
|
197
|
+
viewport={{ once: true }}
|
|
198
|
+
transition={{ delay: 0.5 }}
|
|
199
|
+
className="h-full"
|
|
200
|
+
>
|
|
201
|
+
<MediaElement
|
|
202
|
+
className="rounded-lg shadow-2xl border border-primary"
|
|
203
|
+
style={{
|
|
204
|
+
maxHeight: '450px',
|
|
205
|
+
maxWidth: '100%',
|
|
206
|
+
width: 'auto',
|
|
207
|
+
height: 'auto'
|
|
208
|
+
}}
|
|
209
|
+
/>
|
|
210
|
+
</motion.div>
|
|
211
|
+
</div>
|
|
172
212
|
</div>
|
|
173
|
-
|
|
213
|
+
)}
|
|
174
214
|
</section>
|
|
175
215
|
);
|
|
176
216
|
};
|
|
@@ -30,7 +30,7 @@ export default function VideoCard({ videoUrl, title, description, index }) {
|
|
|
30
30
|
onMouseLeave={() => setShowControls(false)}
|
|
31
31
|
>
|
|
32
32
|
{/* Video Container */}
|
|
33
|
-
<div className="
|
|
33
|
+
<div className="relative w-full aspect-video overflow-hidden">
|
|
34
34
|
<video
|
|
35
35
|
ref={videoRef}
|
|
36
36
|
autoPlay
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export { default as AdvantagesList } from './components/AdvantagesList'
|
|
|
13
13
|
export { default as ShoppingCartModal } from './components/cart/ShoppingCartModal'
|
|
14
14
|
export { default as FloatingCartButton } from './components/cart/FloatingCartButton'
|
|
15
15
|
export { default as VideoCard } from './components/VideoCard'
|
|
16
|
+
export { default as IconGrid } from './components/IconGrid'
|
|
16
17
|
export { default as Menu } from './components/Menu'
|
|
17
18
|
export { default as ProductsDisplay } from './components/products/ProductsDisplay'
|
|
18
19
|
export { default as ProductsSidebar } from './components/products/ProductsSidebar'
|