funuicss 3.8.12 → 3.8.14
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/css/fun.css +0 -152
- package/package.json +1 -1
- package/ui/feature/Feature.d.ts +40 -70
- package/ui/feature/Feature.js +913 -175
- package/ui/text/Text.d.ts +3 -0
- package/ui/text/Text.js +15 -2
- package/ui/vista/Vista.d.ts +19 -5
- package/ui/vista/Vista.js +210 -55
- package/utils/componentUtils.d.ts +2 -2
- package/utils/componentUtils.js +361 -310
package/ui/feature/Feature.js
CHANGED
|
@@ -54,7 +54,9 @@ var componentUtils_1 = require("../../utils/componentUtils");
|
|
|
54
54
|
var Text_1 = __importDefault(require("../text/Text"));
|
|
55
55
|
var Button_1 = __importDefault(require("../button/Button"));
|
|
56
56
|
var getDynamicIcon_1 = require("../../utils/getDynamicIcon");
|
|
57
|
-
var Carousel_1 = __importDefault(require("../carousel/Carousel"));
|
|
57
|
+
var Carousel_1 = __importDefault(require("../carousel/Carousel"));
|
|
58
|
+
var theme_1 = require("../theme/theme");
|
|
59
|
+
var pi_1 = require("react-icons/pi");
|
|
58
60
|
var useDynamicIcon = function (iconString) {
|
|
59
61
|
var _a = (0, react_1.useState)(null), iconNode = _a[0], setIconNode = _a[1];
|
|
60
62
|
var _b = (0, react_1.useState)(false), hasValidIcon = _b[0], setHasValidIcon = _b[1];
|
|
@@ -77,52 +79,98 @@ var useDynamicIcon = function (iconString) {
|
|
|
77
79
|
}, [iconString]);
|
|
78
80
|
return { iconNode: iconNode, hasValidIcon: hasValidIcon };
|
|
79
81
|
};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
// Dynamic Icon Component with proper typing
|
|
83
|
+
var DynamicIcon = function (_a) {
|
|
84
|
+
var icon = _a.icon, color = _a.color, _b = _a.size, size = _b === void 0 ? 24 : _b;
|
|
82
85
|
var isStringIcon = icon && typeof icon === 'string';
|
|
83
|
-
var
|
|
84
|
-
var
|
|
85
|
-
var getIconColorStyle = function (color) {
|
|
86
|
+
var _c = useDynamicIcon(isStringIcon ? icon : undefined), iconNode = _c.iconNode, hasValidIcon = _c.hasValidIcon;
|
|
87
|
+
var getIconColorStyle = function () {
|
|
86
88
|
if (!color)
|
|
87
89
|
return {};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
var colorNames = ['primary', 'secondary', 'accent', 'success', 'warning', 'error', 'info', 'dark', 'light'];
|
|
92
|
-
if (colorNames.includes(color)) {
|
|
93
|
-
var cssValue = (0, getCssVariable_1.getCssVariableValue)(color);
|
|
94
|
-
if (cssValue) {
|
|
95
|
-
return { color: cssValue };
|
|
96
|
-
}
|
|
90
|
+
var cssValue = (0, getCssVariable_1.getCssVariableValue)(color);
|
|
91
|
+
if (cssValue && cssValue !== color) {
|
|
92
|
+
return { color: cssValue };
|
|
97
93
|
}
|
|
98
94
|
return { color: color };
|
|
99
95
|
};
|
|
100
|
-
var iconColorStyle = getIconColorStyle(iconColor);
|
|
101
|
-
var checklistColorStyle = getIconColorStyle(checklistColor);
|
|
102
|
-
var renderIconWithProps = function (iconElement, className, style, size) {
|
|
103
|
-
if (!react_1.default.isValidElement(iconElement))
|
|
104
|
-
return iconElement;
|
|
105
|
-
var props = {
|
|
106
|
-
className: className,
|
|
107
|
-
style: __assign(__assign({}, style), iconElement.props.style),
|
|
108
|
-
};
|
|
109
|
-
if (size !== undefined) {
|
|
110
|
-
props.size = size;
|
|
111
|
-
}
|
|
112
|
-
return react_1.default.cloneElement(iconElement, props);
|
|
113
|
-
};
|
|
114
96
|
if (icon && typeof icon !== 'string' && react_1.default.isValidElement(icon)) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
97
|
+
// Handle React element icons
|
|
98
|
+
var iconElement = icon;
|
|
99
|
+
return react_1.default.cloneElement(iconElement, {
|
|
100
|
+
size: size,
|
|
101
|
+
style: __assign(__assign({}, getIconColorStyle()), iconElement.props.style),
|
|
102
|
+
});
|
|
119
103
|
}
|
|
120
|
-
if (
|
|
121
|
-
|
|
104
|
+
if (isStringIcon && hasValidIcon && iconNode && react_1.default.isValidElement(iconNode)) {
|
|
105
|
+
// Handle dynamically loaded icons
|
|
106
|
+
var dynamicIconElement = iconNode;
|
|
107
|
+
var newProps = {
|
|
108
|
+
size: size,
|
|
109
|
+
style: getIconColorStyle(),
|
|
110
|
+
};
|
|
111
|
+
// Preserve existing props
|
|
112
|
+
if (dynamicIconElement.props.className) {
|
|
113
|
+
newProps.className = dynamicIconElement.props.className;
|
|
114
|
+
}
|
|
115
|
+
return react_1.default.cloneElement(dynamicIconElement, newProps);
|
|
122
116
|
}
|
|
123
117
|
return null;
|
|
124
118
|
};
|
|
125
|
-
//
|
|
119
|
+
// Star Rating Component with dynamic icon
|
|
120
|
+
var StarRating = function (_a) {
|
|
121
|
+
var rating = _a.rating, _b = _a.icon, icon = _b === void 0 ? 'PiStar' : _b, _c = _a.color, color = _c === void 0 ? 'warning' : _c, _d = _a.size, size = _d === void 0 ? 16 : _d;
|
|
122
|
+
var _e = (0, react_1.useState)(null), ratingIconNode = _e[0], setRatingIconNode = _e[1];
|
|
123
|
+
var iconNode = useDynamicIcon(icon).iconNode;
|
|
124
|
+
(0, react_1.useEffect)(function () {
|
|
125
|
+
if (iconNode) {
|
|
126
|
+
setRatingIconNode(iconNode);
|
|
127
|
+
}
|
|
128
|
+
}, [iconNode]);
|
|
129
|
+
var renderIcon = function (type, index) {
|
|
130
|
+
var colorValue = (0, getCssVariable_1.getCssVariableValue)(color) || color;
|
|
131
|
+
var emptyColor = 'var(--muted)';
|
|
132
|
+
// If we have a dynamic icon and it's not empty
|
|
133
|
+
if (ratingIconNode && react_1.default.isValidElement(ratingIconNode) && type !== 'empty') {
|
|
134
|
+
var iconElement = ratingIconNode;
|
|
135
|
+
// Create a new props object
|
|
136
|
+
var newProps = {
|
|
137
|
+
key: index,
|
|
138
|
+
style: __assign({ color: colorValue }, iconElement.props.style)
|
|
139
|
+
};
|
|
140
|
+
// Add size prop if it exists
|
|
141
|
+
if (size !== undefined) {
|
|
142
|
+
newProps.size = size;
|
|
143
|
+
}
|
|
144
|
+
return react_1.default.cloneElement(iconElement, newProps);
|
|
145
|
+
}
|
|
146
|
+
// For empty stars or fallback, use PiStar icons
|
|
147
|
+
if (type === 'full') {
|
|
148
|
+
return react_1.default.createElement(pi_1.PiStarFill, { key: index, size: size, style: { color: colorValue } });
|
|
149
|
+
}
|
|
150
|
+
else if (type === 'half') {
|
|
151
|
+
return react_1.default.createElement(pi_1.PiStarHalf, { key: index, size: size, style: { color: colorValue } });
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
return react_1.default.createElement(pi_1.PiStar, { key: index, size: size, style: { color: emptyColor } });
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var stars = [];
|
|
158
|
+
var fullStars = Math.floor(rating);
|
|
159
|
+
var hasHalfStar = rating % 1 >= 0.5;
|
|
160
|
+
for (var i = 1; i <= 5; i++) {
|
|
161
|
+
if (i <= fullStars) {
|
|
162
|
+
stars.push(renderIcon('full', i));
|
|
163
|
+
}
|
|
164
|
+
else if (hasHalfStar && i === fullStars + 1) {
|
|
165
|
+
stars.push(renderIcon('half', i));
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
stars.push(renderIcon('empty', i));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return (react_1.default.createElement("div", { className: "star-rating", style: { display: 'flex', gap: '2px', alignItems: 'center' } }, stars));
|
|
172
|
+
};
|
|
173
|
+
// Helper function to convert shorthand flex values
|
|
126
174
|
var convertFlexValue = function (value) {
|
|
127
175
|
if (!value)
|
|
128
176
|
return undefined;
|
|
@@ -132,188 +180,878 @@ var convertFlexValue = function (value) {
|
|
|
132
180
|
'center': 'center',
|
|
133
181
|
'between': 'space-between',
|
|
134
182
|
'around': 'space-around',
|
|
135
|
-
'stretch': 'stretch',
|
|
136
183
|
};
|
|
137
184
|
return flexMap[value] || value;
|
|
138
185
|
};
|
|
186
|
+
// Format date
|
|
187
|
+
var formatDate = function (dateString) {
|
|
188
|
+
if (!dateString)
|
|
189
|
+
return '';
|
|
190
|
+
try {
|
|
191
|
+
var date = new Date(dateString);
|
|
192
|
+
if (isNaN(date.getTime()))
|
|
193
|
+
return '';
|
|
194
|
+
return date.toLocaleDateString('en-US', {
|
|
195
|
+
month: 'short',
|
|
196
|
+
day: 'numeric',
|
|
197
|
+
year: 'numeric'
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch (_a) {
|
|
201
|
+
return dateString;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
// Truncate HTML content safely
|
|
205
|
+
var truncateHtml = function (html, maxLength) {
|
|
206
|
+
if (!html)
|
|
207
|
+
return { truncated: '', isTruncated: false };
|
|
208
|
+
// Strip HTML tags for length calculation
|
|
209
|
+
var text = html.replace(/<[^>]*>/g, '');
|
|
210
|
+
if (text.length <= maxLength) {
|
|
211
|
+
return { truncated: html, isTruncated: false };
|
|
212
|
+
}
|
|
213
|
+
// Truncate text
|
|
214
|
+
var truncatedText = text.substring(0, maxLength) + '...';
|
|
215
|
+
return { truncated: truncatedText, isTruncated: true };
|
|
216
|
+
};
|
|
139
217
|
var Feature = function (localProps) {
|
|
140
218
|
var mergeWithLocal = (0, componentUtils_1.useComponentConfiguration)('Feature', localProps.variant).mergeWithLocal;
|
|
141
219
|
var mergedProps = mergeWithLocal(localProps).props;
|
|
142
220
|
var final = mergedProps;
|
|
143
|
-
var _a = (0, react_1.useState)([]),
|
|
144
|
-
|
|
221
|
+
var _a = (0, react_1.useState)([]), itemsArray = _a[0], setItemsArray = _a[1];
|
|
222
|
+
var _b = (0, react_1.useState)(new Set()), expandedItems = _b[0], setExpandedItems = _b[1];
|
|
223
|
+
// Use bucket data if bucket is provided
|
|
224
|
+
var _c = (0, theme_1.usePaginatedRecords)(final.bucket || '', final.bucketPage || 1, final.bucketSize || 50), bucketRecords = _c.records, bucketLoading = _c.loading;
|
|
225
|
+
// Parse items from props or bucket
|
|
145
226
|
(0, react_1.useEffect)(function () {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
227
|
+
var parseItems = function () {
|
|
228
|
+
if (final.bucket && bucketRecords) {
|
|
229
|
+
// Map bucket records to content format
|
|
230
|
+
var mappedItems = bucketRecords.map(function (record) {
|
|
231
|
+
var _a, _b;
|
|
232
|
+
var values = record.values || record;
|
|
233
|
+
if (final.isTestimonial) {
|
|
234
|
+
return {
|
|
235
|
+
customerName: values.customerName || values.name || values.customer,
|
|
236
|
+
company: values.company || values.organization,
|
|
237
|
+
avatar: ((_a = values === null || values === void 0 ? void 0 : values.avatar) === null || _a === void 0 ? void 0 : _a.url) || values.imageUrl || values.photo,
|
|
238
|
+
content: values.content || values.testimonial || values.description,
|
|
239
|
+
rating: values.rating || values.stars || 5,
|
|
240
|
+
role: values.role || values.position,
|
|
241
|
+
project: values.project || values.service,
|
|
242
|
+
date: values.date || values.createdAt,
|
|
243
|
+
featured: values.featured || values.highlighted || false,
|
|
244
|
+
title: values.customerName || values.name,
|
|
245
|
+
description: values.content || values.testimonial,
|
|
246
|
+
imageUrl: values.avatar || values.imageUrl,
|
|
247
|
+
icon: final.quoteIcon || 'PiQuotes',
|
|
248
|
+
iconColor: final.quoteColor || 'primary'
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
return __assign({ title: values.title || values.name, description: values.description || values.content, icon: values.icon, iconColor: values.iconColor, imageUrl: values.imageUrl || ((_b = values.avatar) === null || _b === void 0 ? void 0 : _b.url) }, values);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
setItemsArray(mappedItems);
|
|
150
256
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
257
|
+
else if (typeof final.items === 'string') {
|
|
258
|
+
try {
|
|
259
|
+
var parsed = JSON.parse(final.items);
|
|
260
|
+
setItemsArray(Array.isArray(parsed) ? parsed : [parsed]);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
console.error('Error parsing items JSON:', error);
|
|
264
|
+
setItemsArray([]);
|
|
265
|
+
}
|
|
154
266
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
marginTop: '1rem',
|
|
177
|
-
display: 'inline-block',
|
|
178
|
-
textDecoration: 'none',
|
|
179
|
-
color: 'var(--primary)',
|
|
180
|
-
fontWeight: 500,
|
|
181
|
-
fontSize: '0.875rem',
|
|
182
|
-
} }, item.ctaText));
|
|
267
|
+
else if (Array.isArray(final.items)) {
|
|
268
|
+
setItemsArray(final.items);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
setItemsArray([]);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
parseItems();
|
|
275
|
+
}, [final.items, final.isTestimonial, final.bucket, bucketRecords, final.quoteIcon, final.quoteColor]);
|
|
276
|
+
// Toggle expanded state for an item
|
|
277
|
+
var toggleExpand = function (index) {
|
|
278
|
+
setExpandedItems(function (prev) {
|
|
279
|
+
var newSet = new Set(prev);
|
|
280
|
+
if (newSet.has(index)) {
|
|
281
|
+
newSet.delete(index);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
newSet.add(index);
|
|
285
|
+
}
|
|
286
|
+
return newSet;
|
|
287
|
+
});
|
|
183
288
|
};
|
|
184
|
-
var
|
|
185
|
-
var
|
|
186
|
-
|
|
187
|
-
|
|
289
|
+
var renderItem = function (item, index) {
|
|
290
|
+
var isExpanded = expandedItems.has(index);
|
|
291
|
+
var contentLimit = final.contentLimit || 150;
|
|
292
|
+
// Get content to display
|
|
293
|
+
var displayContent = item.description || item.content || '';
|
|
294
|
+
var isTruncated = false;
|
|
295
|
+
if (typeof displayContent === 'string' && displayContent.length > contentLimit && !isExpanded) {
|
|
296
|
+
var _a = truncateHtml(displayContent, contentLimit), truncated = _a.truncated, truncatedFlag = _a.isTruncated;
|
|
297
|
+
displayContent = truncated;
|
|
298
|
+
isTruncated = truncatedFlag;
|
|
188
299
|
}
|
|
189
|
-
|
|
190
|
-
var
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
react_1.default.createElement(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
300
|
+
// Item content
|
|
301
|
+
var itemContent = (react_1.default.createElement(react_1.default.Fragment, null,
|
|
302
|
+
final.isTestimonial && final.showQuote && (react_1.default.createElement("div", { className: "feature__quote-icon", style: { marginBottom: '1rem' } }, react_1.default.isValidElement(final.quoteIcon) ? final.quoteIcon : (react_1.default.createElement(DynamicIcon, { icon: final.quoteIcon || 'PiQuotes', color: final.quoteColor, size: final.iconSize })))),
|
|
303
|
+
(item.icon || item.imageUrl) && !final.isTestimonial && (react_1.default.createElement("div", { className: "feature__icon-container", style: { marginBottom: '1rem' } }, item.imageUrl ? (react_1.default.createElement("img", { src: item.imageUrl, alt: item.imageAlt || '', className: "feature__image", style: {
|
|
304
|
+
width: "".concat(final.iconSize || 24, "px"),
|
|
305
|
+
height: "".concat(final.iconSize || 24, "px"),
|
|
306
|
+
objectFit: 'cover',
|
|
307
|
+
borderRadius: '50%',
|
|
308
|
+
} })) : (react_1.default.createElement(DynamicIcon, { icon: item.icon, color: item.iconColor || final.iconColor, size: final.iconSize })))),
|
|
309
|
+
item.title && (react_1.default.createElement(Text_1.default, { block: true, size: final.itemTitleSize || 'lg', weight: 600, color: "default", style: { marginBottom: '0.75rem' } }, item.title)),
|
|
310
|
+
(item.description || item.content) && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
311
|
+
react_1.default.createElement(Text_1.default, { block: true, size: final.itemDescriptionSize || 'base', weight: 400, color: "muted", dangerouslySetInnerHTML: true, text: displayContent }),
|
|
312
|
+
isTruncated && final.showExpand && (react_1.default.createElement("button", { onClick: function () { return toggleExpand(index); }, className: "feature__expand-btn", style: {
|
|
313
|
+
background: 'none',
|
|
314
|
+
border: 'none',
|
|
315
|
+
color: 'var(--primary)',
|
|
316
|
+
cursor: 'pointer',
|
|
317
|
+
fontSize: '0.875rem',
|
|
318
|
+
marginTop: '0.5rem',
|
|
319
|
+
padding: 0,
|
|
320
|
+
textDecoration: 'underline'
|
|
321
|
+
} }, isExpanded ? (final.collapseText || 'Show less') : (final.expandText || 'Read more'))))),
|
|
322
|
+
final.isTestimonial && (react_1.default.createElement("div", { className: "feature__testimonial-info", style: { marginTop: '1rem' } },
|
|
323
|
+
final.showStars && item.rating && (react_1.default.createElement("div", { style: { marginBottom: '0.5rem' } },
|
|
324
|
+
react_1.default.createElement(StarRating, { rating: item.rating, icon: final.ratingIcon, color: final.starColor, size: 16 }))),
|
|
325
|
+
react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '0.75rem' } },
|
|
326
|
+
item.avatar && (react_1.default.createElement("img", { src: item.avatar, alt: item.customerName || 'Customer', style: {
|
|
327
|
+
width: '40px',
|
|
328
|
+
height: '40px',
|
|
329
|
+
borderRadius: '50%',
|
|
330
|
+
objectFit: 'cover'
|
|
331
|
+
} })),
|
|
332
|
+
react_1.default.createElement("div", null,
|
|
333
|
+
item.customerName && (react_1.default.createElement(Text_1.default, { block: true, size: "sm", weight: 600, style: { marginBottom: '0.25rem' } }, item.customerName)),
|
|
334
|
+
react_1.default.createElement("div", { style: { fontSize: '0.75rem', color: 'var(--text-muted)' } },
|
|
335
|
+
item.role && final.showRole && react_1.default.createElement("span", null, item.role),
|
|
336
|
+
item.company && final.showCompany && (react_1.default.createElement("span", null,
|
|
337
|
+
item.role ? ' at ' : '',
|
|
338
|
+
item.company)),
|
|
339
|
+
item.date && final.showDate && react_1.default.createElement("span", null,
|
|
340
|
+
" \u2022 ",
|
|
341
|
+
formatDate(item.date))))))),
|
|
342
|
+
!final.isTestimonial && final.showCTA && final.ctaText && (react_1.default.createElement("div", { style: { marginTop: '1rem' } },
|
|
343
|
+
react_1.default.createElement(Button_1.default, { url: final.ctaUrl, color: "primary", text: final.ctaText, funcss: 'p-0' })))));
|
|
344
|
+
// Apply card styling if enabled
|
|
218
345
|
if (final.card) {
|
|
219
|
-
var
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
item.className || '',
|
|
224
|
-
final.cardClassName || '',
|
|
225
|
-
].filter(Boolean).join(' ');
|
|
226
|
-
var cardStyles = __assign({ padding: getSpacingValue(cardPadding, '1.5rem'), borderRadius: cardRounded, boxShadow: cardShadow !== 'none' ? (0, getCssVariable_1.getCssVariableValue)("shadow-".concat(cardShadow)) || undefined : undefined, border: cardBorder ? "1px solid ".concat((0, getCssVariable_1.getCssVariableValue)(cardBorderColor) || cardBorderColor) : 'none', height: '100%', maxWidth: final.itemMaxWidth || '100%' }, item.style);
|
|
227
|
-
return (react_1.default.createElement("div", { key: index, className: cardClasses, style: cardStyles }, featureContent));
|
|
346
|
+
var shadowValue = final.cardShadow !== 'none' ?
|
|
347
|
+
(0, getCssVariable_1.getCssVariableValue)("shadow-".concat(final.cardShadow)) || undefined :
|
|
348
|
+
undefined;
|
|
349
|
+
return (react_1.default.createElement("div", { key: index, className: "feature__card ".concat(final.cardClassName || ''), style: __assign({ padding: final.cardPadding || '1.5rem', borderRadius: final.cardRounded || '0.5rem', boxShadow: shadowValue, border: '1px solid var(--borderRgb)', height: '100%', maxWidth: final.itemMaxWidth || '100%' }, item.style) }, itemContent));
|
|
228
350
|
}
|
|
229
351
|
// Regular item without card
|
|
230
|
-
return (react_1.default.createElement("div", { key: index, className: "
|
|
352
|
+
return (react_1.default.createElement("div", { key: index, className: "feature__item", style: __assign({ maxWidth: final.itemMaxWidth || '100%' }, item.style) }, itemContent));
|
|
231
353
|
};
|
|
232
|
-
var
|
|
233
|
-
if (
|
|
354
|
+
var renderFlexItems = function () {
|
|
355
|
+
if (itemsArray.length === 0)
|
|
234
356
|
return null;
|
|
235
357
|
var gapValue = final.gap !== undefined ? "".concat(final.gap * 0.25, "rem") : '2rem';
|
|
236
|
-
var flexGap = gapValue;
|
|
237
358
|
if (final.layout === 'centered') {
|
|
238
359
|
var maxWidth = final.maxWidth || '48rem';
|
|
239
|
-
return (react_1.default.createElement("div", { className: "
|
|
360
|
+
return (react_1.default.createElement("div", { className: "feature__centered-container", style: {
|
|
240
361
|
maxWidth: maxWidth,
|
|
241
362
|
margin: '0 auto',
|
|
242
|
-
} },
|
|
363
|
+
} }, itemsArray.map(function (item, index) { return renderItem(item, index); })));
|
|
243
364
|
}
|
|
244
|
-
// Use Flex layout
|
|
245
|
-
return (react_1.default.createElement("div", { className: "
|
|
365
|
+
// Use Flex layout
|
|
366
|
+
return (react_1.default.createElement("div", { className: "feature__flex-container", style: {
|
|
246
367
|
display: 'flex',
|
|
247
368
|
flexWrap: final.wrap !== false ? 'wrap' : 'nowrap',
|
|
248
|
-
gap:
|
|
369
|
+
gap: gapValue,
|
|
249
370
|
alignItems: convertFlexValue(final.align) || 'stretch',
|
|
250
371
|
justifyContent: convertFlexValue(final.justify) || 'flex-start',
|
|
251
372
|
maxWidth: final.maxWidth || '100%',
|
|
252
373
|
margin: '0 auto',
|
|
253
|
-
} },
|
|
374
|
+
} }, itemsArray.map(function (item, index) { return (react_1.default.createElement("div", { key: index, className: "feature__flex-item", style: { flex: '1 1 300px' } }, renderItem(item, index))); })));
|
|
254
375
|
};
|
|
255
|
-
var
|
|
256
|
-
if (
|
|
376
|
+
var renderCarouselItems = function () {
|
|
377
|
+
if (itemsArray.length === 0)
|
|
257
378
|
return null;
|
|
258
379
|
// Prepare carousel items
|
|
259
|
-
var carouselItems =
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return (react_1.default.createElement("div", { className: "feature-section__carousel-container ".concat(final.carouselContainerClassName || ''), style: final.carouselContainerStyle },
|
|
263
|
-
react_1.default.createElement(Carousel_1.default, { scrollNumber: final.scrollNumber, gap: final.gap || 1, funcss: final.carouselFuncss, showDashes: final.showDashes, allowVerticalOverflow: final.allowVerticalOverflow, itemPadding: final.itemPadding || '0.5rem', controlerSize: final.controlerSize, controlerIconSize: final.controlerIconSize, infiniteScroll: final.infiniteScroll, infiniteScrollSpeed: final.infiniteScrollSpeed, infiniteScrollDirection: final.infiniteScrollDirection }, carouselItems)));
|
|
380
|
+
var carouselItems = itemsArray.map(function (item, index) { return renderItem(item, index); });
|
|
381
|
+
return (react_1.default.createElement("div", { className: "feature__carousel-container" },
|
|
382
|
+
react_1.default.createElement(Carousel_1.default, { scrollNumber: final.scrollNumber || 320, gap: final.gap || 1, funcss: final.carouselFuncss, showDashes: final.showDashes !== false }, carouselItems)));
|
|
264
383
|
};
|
|
265
|
-
var
|
|
266
|
-
if (
|
|
384
|
+
var renderContent = function () {
|
|
385
|
+
if (itemsArray.length === 0)
|
|
267
386
|
return null;
|
|
268
387
|
// Use carousel if isCarousel is true
|
|
269
388
|
if (final.isCarousel) {
|
|
270
|
-
return
|
|
389
|
+
return renderCarouselItems();
|
|
271
390
|
}
|
|
272
391
|
// Otherwise use flex layout
|
|
273
|
-
return
|
|
274
|
-
};
|
|
275
|
-
var getLayoutClasses = function () {
|
|
276
|
-
var classes = ['feature-section'];
|
|
277
|
-
if (final.layout) {
|
|
278
|
-
classes.push("feature-section--".concat(final.layout));
|
|
279
|
-
}
|
|
280
|
-
if (final.isCarousel) {
|
|
281
|
-
classes.push('feature-section--carousel');
|
|
282
|
-
}
|
|
283
|
-
if (final.className) {
|
|
284
|
-
classes.push(final.className);
|
|
285
|
-
}
|
|
286
|
-
if (final.sectionClass) {
|
|
287
|
-
classes.push(final.sectionClass);
|
|
288
|
-
}
|
|
289
|
-
if (final.funcss) {
|
|
290
|
-
classes.push(final.funcss);
|
|
291
|
-
}
|
|
292
|
-
return classes.filter(Boolean).join(' ');
|
|
293
|
-
};
|
|
294
|
-
var getContainerStyles = function () {
|
|
295
|
-
var padding = getSpacingValue(final.padding, '3rem 0');
|
|
296
|
-
return __assign({ padding: padding }, final.style);
|
|
392
|
+
return renderFlexItems();
|
|
297
393
|
};
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
394
|
+
return (react_1.default.createElement("section", { id: final.id, className: "feature-section ".concat(final.className || '', " ").concat(final.funcss || ''), style: {
|
|
395
|
+
padding: final.padding || '3rem 0',
|
|
396
|
+
} },
|
|
397
|
+
react_1.default.createElement("div", { className: "feature__container ".concat(final.containerClassName || ''), style: {
|
|
398
|
+
maxWidth: final.maxWidth || '1280px',
|
|
399
|
+
margin: '0 auto',
|
|
400
|
+
padding: '0 1rem',
|
|
401
|
+
} },
|
|
402
|
+
(final.title || final.subtitle || final.description) && (react_1.default.createElement("div", { className: "feature__header", style: {
|
|
403
|
+
marginBottom: '3rem',
|
|
404
|
+
maxWidth: final.layout === 'centered' ? '48rem' : '100%',
|
|
405
|
+
marginLeft: 'auto',
|
|
406
|
+
marginRight: 'auto',
|
|
407
|
+
textAlign: final.titleAlign || 'center',
|
|
408
|
+
} },
|
|
409
|
+
final.subtitle && (react_1.default.createElement(Text_1.default, { block: true, size: final.subtitleSize || 'sm', weight: 600, color: final.subtitleColor || 'primary', style: {
|
|
307
410
|
textTransform: 'uppercase',
|
|
308
411
|
letterSpacing: '0.05em',
|
|
309
412
|
marginBottom: '0.5rem',
|
|
310
413
|
} }, final.subtitle)),
|
|
311
|
-
final.title && (react_1.default.createElement(Text_1.default, { block: true, size: final.titleSize || 'xl', weight:
|
|
312
|
-
final.description && (react_1.default.createElement(Text_1.default, { block: true, size: final.descriptionSize || '
|
|
313
|
-
react_1.default.createElement("div", { className: "
|
|
314
|
-
|
|
414
|
+
final.title && (react_1.default.createElement(Text_1.default, { block: true, size: final.titleSize || 'xl', weight: 700, color: final.titleColor || 'default', style: { marginBottom: '1rem' } }, final.title)),
|
|
415
|
+
final.description && (react_1.default.createElement(Text_1.default, { block: true, size: final.descriptionSize || 'base', weight: 400, color: final.descriptionColor || 'muted' }, final.description)))),
|
|
416
|
+
react_1.default.createElement("div", { className: "feature__content" },
|
|
417
|
+
renderContent(),
|
|
315
418
|
final.children),
|
|
316
|
-
final.ctaText && (react_1.default.createElement("div", { className: "
|
|
317
|
-
|
|
419
|
+
final.ctaText && (react_1.default.createElement("div", { className: "feature__cta-container", style: {
|
|
420
|
+
marginTop: '2.5rem',
|
|
421
|
+
textAlign: final.ctaAlign || 'center',
|
|
422
|
+
} },
|
|
423
|
+
react_1.default.createElement(Button_1.default, { url: final.ctaUrl, bg: final.ctaBg || 'primary', text: final.ctaText }))))));
|
|
318
424
|
};
|
|
319
425
|
exports.default = Feature;
|
|
426
|
+
// 'use client';
|
|
427
|
+
// import React, { useState, useEffect } from 'react';
|
|
428
|
+
// import { getCssVariableValue } from '../../utils/getCssVariable';
|
|
429
|
+
// import { useComponentConfiguration } from '../../utils/componentUtils';
|
|
430
|
+
// import Text from '../text/Text';
|
|
431
|
+
// import Button from '../button/Button';
|
|
432
|
+
// import { getDynamicIcon } from '../../utils/getDynamicIcon';
|
|
433
|
+
// import Carousel from '../carousel/Carousel'; // Import the Carousel component
|
|
434
|
+
// type FeatureItem = {
|
|
435
|
+
// icon?: string | React.ReactNode;
|
|
436
|
+
// iconColor?: string;
|
|
437
|
+
// iconSize?: number;
|
|
438
|
+
// iconClassName?: string;
|
|
439
|
+
// title?: React.ReactNode;
|
|
440
|
+
// titleSize?: string;
|
|
441
|
+
// titleWeight?: number;
|
|
442
|
+
// titleColor?: string;
|
|
443
|
+
// titleClassName?: string;
|
|
444
|
+
// description?: React.ReactNode;
|
|
445
|
+
// descriptionSize?: string;
|
|
446
|
+
// descriptionWeight?: number;
|
|
447
|
+
// descriptionColor?: string;
|
|
448
|
+
// descriptionClassName?: string;
|
|
449
|
+
// imageUrl?: string;
|
|
450
|
+
// imageAlt?: string;
|
|
451
|
+
// imageClassName?: string;
|
|
452
|
+
// imageStyle?: React.CSSProperties;
|
|
453
|
+
// content?: React.ReactNode;
|
|
454
|
+
// className?: string;
|
|
455
|
+
// style?: React.CSSProperties;
|
|
456
|
+
// ctaText?: string;
|
|
457
|
+
// ctaUrl?: string;
|
|
458
|
+
// ctaOnClick?: () => void;
|
|
459
|
+
// ctaClassName?: string;
|
|
460
|
+
// customRender?: () => React.ReactNode;
|
|
461
|
+
// };
|
|
462
|
+
// // Carousel-specific props
|
|
463
|
+
// interface CarouselOptions {
|
|
464
|
+
// isCarousel?: boolean;
|
|
465
|
+
// // Carousel props
|
|
466
|
+
// scrollNumber?: number;
|
|
467
|
+
// gap?: number;
|
|
468
|
+
// carouselFuncss?: string;
|
|
469
|
+
// showDashes?: boolean;
|
|
470
|
+
// allowVerticalOverflow?: boolean;
|
|
471
|
+
// itemPadding?: string;
|
|
472
|
+
// controlerSize?: number;
|
|
473
|
+
// controlerIconSize?: number;
|
|
474
|
+
// infiniteScroll?: boolean;
|
|
475
|
+
// infiniteScrollSpeed?: number;
|
|
476
|
+
// infiniteScrollDirection?: 'left' | 'right' | 'alternate';
|
|
477
|
+
// // Carousel container styling
|
|
478
|
+
// carouselContainerClassName?: string;
|
|
479
|
+
// carouselContainerStyle?: React.CSSProperties;
|
|
480
|
+
// }
|
|
481
|
+
// type FeatureProps = {
|
|
482
|
+
// variant?: string;
|
|
483
|
+
// layout?: 'checklist' | 'centered' | 'grid';
|
|
484
|
+
// title?: React.ReactNode;
|
|
485
|
+
// titleSize?: string;
|
|
486
|
+
// titleWeight?: number;
|
|
487
|
+
// titleColor?: string;
|
|
488
|
+
// titleClassName?: string;
|
|
489
|
+
// titleAlign?: 'left' | 'center' | 'right';
|
|
490
|
+
// subtitle?: React.ReactNode;
|
|
491
|
+
// subtitleSize?: string;
|
|
492
|
+
// subtitleWeight?: number;
|
|
493
|
+
// subtitleColor?: string;
|
|
494
|
+
// subtitleClassName?: string;
|
|
495
|
+
// description?: React.ReactNode;
|
|
496
|
+
// descriptionSize?: string;
|
|
497
|
+
// descriptionWeight?: number;
|
|
498
|
+
// descriptionColor?: string;
|
|
499
|
+
// descriptionClassName?: string;
|
|
500
|
+
// features?: FeatureItem[] | string;
|
|
501
|
+
// gap?: number;
|
|
502
|
+
// itemMaxWidth?: string;
|
|
503
|
+
// align?: 'start' | 'center' | 'end' | 'stretch';
|
|
504
|
+
// justify?: 'start' | 'center' | 'end' | 'between' | 'around';
|
|
505
|
+
// wrap?: boolean;
|
|
506
|
+
// card?: boolean;
|
|
507
|
+
// cardPadding?: string;
|
|
508
|
+
// cardRounded?: string;
|
|
509
|
+
// cardShadow?: 'sm' | 'md' | 'lg' | 'xl' | 'none';
|
|
510
|
+
// cardBorder?: boolean;
|
|
511
|
+
// cardBorderColor?: string;
|
|
512
|
+
// cardHoverEffect?: 'lift' | 'glow' | 'scale' | 'none';
|
|
513
|
+
// cardClassName?: string;
|
|
514
|
+
// padding?: string;
|
|
515
|
+
// className?: string;
|
|
516
|
+
// style?: React.CSSProperties;
|
|
517
|
+
// containerClassName?: string;
|
|
518
|
+
// containerStyle?: React.CSSProperties;
|
|
519
|
+
// iconColor?: string;
|
|
520
|
+
// iconSize?: number;
|
|
521
|
+
// iconClassName?: string;
|
|
522
|
+
// itemTitleSize?: string;
|
|
523
|
+
// itemTitleWeight?: number;
|
|
524
|
+
// itemTitleColor?: string;
|
|
525
|
+
// itemDescriptionSize?: string;
|
|
526
|
+
// itemDescriptionWeight?: number;
|
|
527
|
+
// itemDescriptionColor?: string;
|
|
528
|
+
// checkmarkIcon?: string;
|
|
529
|
+
// checkmarkColor?: string;
|
|
530
|
+
// checkmarkSize?: number;
|
|
531
|
+
// checkmarkClassName?: string;
|
|
532
|
+
// ctaText?: string;
|
|
533
|
+
// ctaUrl?: string;
|
|
534
|
+
// ctaOnClick?: () => void;
|
|
535
|
+
// ctaClassName?: string;
|
|
536
|
+
// ctaAlign?: 'left' | 'center' | 'right';
|
|
537
|
+
// ctaStringPrefix?: string;
|
|
538
|
+
// ctaStringSuffix?: string;
|
|
539
|
+
// ctaStartIcon?: React.ReactNode;
|
|
540
|
+
// ctaEndIcon?: React.ReactNode;
|
|
541
|
+
// ctaIconSize?: number;
|
|
542
|
+
// ctaIsLoading?: boolean;
|
|
543
|
+
// ctaStatus?: 'success' | 'warning' | 'info' | 'error';
|
|
544
|
+
// ctaBg?: string;
|
|
545
|
+
// children?: React.ReactNode;
|
|
546
|
+
// id?: string;
|
|
547
|
+
// funcss?: string;
|
|
548
|
+
// sectionClass?: string;
|
|
549
|
+
// maxWidth?: string;
|
|
550
|
+
// } & CarouselOptions; // Merge CarouselOptions into FeatureProps
|
|
551
|
+
// const useDynamicIcon = (iconString?: string) => {
|
|
552
|
+
// const [iconNode, setIconNode] = useState<React.ReactNode>(null);
|
|
553
|
+
// const [hasValidIcon, setHasValidIcon] = useState(false);
|
|
554
|
+
// useEffect(() => {
|
|
555
|
+
// if (!iconString || typeof iconString !== 'string' || iconString.trim() === '') {
|
|
556
|
+
// setIconNode(null);
|
|
557
|
+
// setHasValidIcon(false);
|
|
558
|
+
// return;
|
|
559
|
+
// }
|
|
560
|
+
// getDynamicIcon(iconString).then((node) => {
|
|
561
|
+
// if (node) {
|
|
562
|
+
// setIconNode(node);
|
|
563
|
+
// setHasValidIcon(true);
|
|
564
|
+
// } else {
|
|
565
|
+
// setIconNode(null);
|
|
566
|
+
// setHasValidIcon(false);
|
|
567
|
+
// }
|
|
568
|
+
// });
|
|
569
|
+
// }, [iconString]);
|
|
570
|
+
// return { iconNode, hasValidIcon };
|
|
571
|
+
// };
|
|
572
|
+
// const FeatureIcon: React.FC<{
|
|
573
|
+
// icon?: string | React.ReactNode;
|
|
574
|
+
// iconColor?: string;
|
|
575
|
+
// iconSize?: number;
|
|
576
|
+
// iconClassName?: string;
|
|
577
|
+
// layout?: string;
|
|
578
|
+
// checklistIcon?: string;
|
|
579
|
+
// checklistColor?: string;
|
|
580
|
+
// checklistSize?: number;
|
|
581
|
+
// checklistClassName?: string;
|
|
582
|
+
// }> = ({
|
|
583
|
+
// icon,
|
|
584
|
+
// iconColor,
|
|
585
|
+
// iconSize = 24,
|
|
586
|
+
// iconClassName = '',
|
|
587
|
+
// layout,
|
|
588
|
+
// checklistIcon = 'PiCheck',
|
|
589
|
+
// checklistColor = 'success',
|
|
590
|
+
// checklistSize = 20,
|
|
591
|
+
// checklistClassName = ''
|
|
592
|
+
// }) => {
|
|
593
|
+
// const isStringIcon = icon && typeof icon === 'string';
|
|
594
|
+
// const { iconNode: dynamicIconNode, hasValidIcon: hasValidDynamicIcon } = useDynamicIcon(
|
|
595
|
+
// isStringIcon ? icon as string : undefined
|
|
596
|
+
// );
|
|
597
|
+
// const { iconNode: checkmarkIconNode, hasValidIcon: hasValidCheckmarkIcon } = useDynamicIcon(
|
|
598
|
+
// layout === 'checklist' ? checklistIcon : undefined
|
|
599
|
+
// );
|
|
600
|
+
// const getIconColorStyle = (color?: string): React.CSSProperties => {
|
|
601
|
+
// if (!color) return {};
|
|
602
|
+
// if (color.startsWith('text-') || color.startsWith('bg-') || color.startsWith('border-')) {
|
|
603
|
+
// return {};
|
|
604
|
+
// }
|
|
605
|
+
// const colorNames = ['primary', 'secondary', 'accent', 'success', 'warning', 'error', 'info', 'dark', 'light'];
|
|
606
|
+
// if (colorNames.includes(color)) {
|
|
607
|
+
// const cssValue = getCssVariableValue(color);
|
|
608
|
+
// if (cssValue) {
|
|
609
|
+
// return { color: cssValue };
|
|
610
|
+
// }
|
|
611
|
+
// }
|
|
612
|
+
// return { color };
|
|
613
|
+
// };
|
|
614
|
+
// const iconColorStyle = getIconColorStyle(iconColor);
|
|
615
|
+
// const checklistColorStyle = getIconColorStyle(checklistColor);
|
|
616
|
+
// const renderIconWithProps = (iconElement: React.ReactNode, className: string, style: React.CSSProperties, size?: number) => {
|
|
617
|
+
// if (!React.isValidElement(iconElement)) return iconElement;
|
|
618
|
+
// const props: any = {
|
|
619
|
+
// className,
|
|
620
|
+
// style: { ...style, ...(iconElement.props as any).style },
|
|
621
|
+
// };
|
|
622
|
+
// if (size !== undefined) {
|
|
623
|
+
// props.size = size;
|
|
624
|
+
// }
|
|
625
|
+
// return React.cloneElement(iconElement, props);
|
|
626
|
+
// };
|
|
627
|
+
// if (icon && typeof icon !== 'string' && React.isValidElement(icon)) {
|
|
628
|
+
// return renderIconWithProps(
|
|
629
|
+
// icon,
|
|
630
|
+
// `feature-section__icon ${iconClassName}`,
|
|
631
|
+
// iconColorStyle,
|
|
632
|
+
// iconSize
|
|
633
|
+
// );
|
|
634
|
+
// }
|
|
635
|
+
// if (isStringIcon && hasValidDynamicIcon && dynamicIconNode) {
|
|
636
|
+
// return renderIconWithProps(
|
|
637
|
+
// dynamicIconNode,
|
|
638
|
+
// `feature-section__icon ${iconClassName}`,
|
|
639
|
+
// iconColorStyle,
|
|
640
|
+
// iconSize
|
|
641
|
+
// );
|
|
642
|
+
// }
|
|
643
|
+
// if (layout === 'checklist' && hasValidCheckmarkIcon && checkmarkIconNode) {
|
|
644
|
+
// return renderIconWithProps(
|
|
645
|
+
// checkmarkIconNode,
|
|
646
|
+
// `feature-section__checkmark ${checklistClassName}`,
|
|
647
|
+
// checklistColorStyle,
|
|
648
|
+
// checklistSize
|
|
649
|
+
// );
|
|
650
|
+
// }
|
|
651
|
+
// return null;
|
|
652
|
+
// };
|
|
653
|
+
// // Helper function to convert shorthand flex values to proper CSS values
|
|
654
|
+
// const convertFlexValue = (value?: string): string | undefined => {
|
|
655
|
+
// if (!value) return undefined;
|
|
656
|
+
// const flexMap: Record<string, string> = {
|
|
657
|
+
// 'start': 'flex-start',
|
|
658
|
+
// 'end': 'flex-end',
|
|
659
|
+
// 'center': 'center',
|
|
660
|
+
// 'between': 'space-between',
|
|
661
|
+
// 'around': 'space-around',
|
|
662
|
+
// 'stretch': 'stretch',
|
|
663
|
+
// };
|
|
664
|
+
// return flexMap[value] || value;
|
|
665
|
+
// };
|
|
666
|
+
// const Feature: React.FC<FeatureProps> = (localProps) => {
|
|
667
|
+
// const { mergeWithLocal } = useComponentConfiguration('Feature', localProps.variant);
|
|
668
|
+
// const { props: mergedProps } = mergeWithLocal(localProps);
|
|
669
|
+
// const final = mergedProps;
|
|
670
|
+
// const [featuresArray, setFeaturesArray] = useState<FeatureItem[]>([]);
|
|
671
|
+
// // Parse features
|
|
672
|
+
// useEffect(() => {
|
|
673
|
+
// if (typeof final.features === 'string') {
|
|
674
|
+
// try {
|
|
675
|
+
// const parsed = JSON.parse(final.features);
|
|
676
|
+
// setFeaturesArray(Array.isArray(parsed) ? parsed : [parsed]);
|
|
677
|
+
// } catch (error) {
|
|
678
|
+
// console.error('Error parsing features JSON:', error);
|
|
679
|
+
// setFeaturesArray([]);
|
|
680
|
+
// }
|
|
681
|
+
// } else if (Array.isArray(final.features)) {
|
|
682
|
+
// setFeaturesArray(final.features);
|
|
683
|
+
// } else {
|
|
684
|
+
// setFeaturesArray([]);
|
|
685
|
+
// }
|
|
686
|
+
// }, [final.features]);
|
|
687
|
+
// const getSpacingValue = (value?: string, defaultValue: string = '0'): string => {
|
|
688
|
+
// if (!value) return defaultValue;
|
|
689
|
+
// if (/^\d+$/.test(value)) {
|
|
690
|
+
// return `${parseInt(value) * 0.25}rem`;
|
|
691
|
+
// }
|
|
692
|
+
// return value;
|
|
693
|
+
// };
|
|
694
|
+
// const renderItemCTA = (item: FeatureItem) => {
|
|
695
|
+
// if (!item.ctaText) return null;
|
|
696
|
+
// return (
|
|
697
|
+
// <a
|
|
698
|
+
// href={item.ctaUrl}
|
|
699
|
+
// onClick={item.ctaOnClick}
|
|
700
|
+
// className={`feature-section__item-cta ${item.ctaClassName || ''}`}
|
|
701
|
+
// style={{
|
|
702
|
+
// marginTop: '1rem',
|
|
703
|
+
// display: 'inline-block',
|
|
704
|
+
// textDecoration: 'none',
|
|
705
|
+
// color: 'var(--primary)',
|
|
706
|
+
// fontWeight: 500,
|
|
707
|
+
// fontSize: '0.875rem',
|
|
708
|
+
// }}
|
|
709
|
+
// >
|
|
710
|
+
// {item.ctaText}
|
|
711
|
+
// </a>
|
|
712
|
+
// );
|
|
713
|
+
// };
|
|
714
|
+
// const renderFeatureItem = (item: FeatureItem, index: number) => {
|
|
715
|
+
// if (item.customRender) {
|
|
716
|
+
// return item.customRender();
|
|
717
|
+
// }
|
|
718
|
+
// const iconColor = item.iconColor || final.iconColor;
|
|
719
|
+
// const iconSize = item.iconSize || final.iconSize || 24;
|
|
720
|
+
// const iconClassName = item.iconClassName || final.iconClassName || '';
|
|
721
|
+
// const checkmarkIcon = final.checkmarkIcon || 'PiCheck';
|
|
722
|
+
// const checkmarkColor = final.checkmarkColor || 'success';
|
|
723
|
+
// const checkmarkSize = final.checkmarkSize || 20;
|
|
724
|
+
// const checkmarkClassName = final.checkmarkClassName || '';
|
|
725
|
+
// const cardPadding = final.cardPadding || '1.5rem';
|
|
726
|
+
// const cardRounded = final.cardRounded || '0.5rem';
|
|
727
|
+
// const cardShadow = final.cardShadow || 'md';
|
|
728
|
+
// const cardBorder = final.cardBorder ?? true;
|
|
729
|
+
// const cardBorderColor = final.cardBorderColor || 'var(--borderRgb)';
|
|
730
|
+
// const cardHoverEffect = final.cardHoverEffect || 'none';
|
|
731
|
+
// const titleSize = item.titleSize || final.itemTitleSize || '1.125rem';
|
|
732
|
+
// const titleWeight = item.titleWeight || final.itemTitleWeight || 600;
|
|
733
|
+
// const titleColor = item.titleColor || final.itemTitleColor || 'var(--text-color)';
|
|
734
|
+
// const titleClassName = item.titleClassName || '';
|
|
735
|
+
// const descriptionSize = item.descriptionSize || final.itemDescriptionSize || '0.875rem';
|
|
736
|
+
// const descriptionWeight = item.descriptionWeight || final.itemDescriptionWeight || 400;
|
|
737
|
+
// const descriptionColor = item.descriptionColor || final.itemDescriptionColor || 'var(--text-muted)';
|
|
738
|
+
// const descriptionClassName = item.descriptionClassName || '';
|
|
739
|
+
// const featureContent = (
|
|
740
|
+
// <div className={`feature-section__item ${item.className || ''}`} style={item.style}>
|
|
741
|
+
// {(item.icon || item.imageUrl || final.layout === 'checklist') && (
|
|
742
|
+
// <div
|
|
743
|
+
// className="feature-section__icon-container"
|
|
744
|
+
// style={{ marginBottom: '1rem' }}
|
|
745
|
+
// >
|
|
746
|
+
// {item.imageUrl ? (
|
|
747
|
+
// <img
|
|
748
|
+
// src={item.imageUrl}
|
|
749
|
+
// alt={item.imageAlt || ''}
|
|
750
|
+
// className={`feature-section__image ${item.imageClassName || ''}`}
|
|
751
|
+
// style={{
|
|
752
|
+
// width: `${iconSize}px`,
|
|
753
|
+
// height: `${iconSize}px`,
|
|
754
|
+
// objectFit: 'cover',
|
|
755
|
+
// borderRadius: '50%',
|
|
756
|
+
// ...item.imageStyle,
|
|
757
|
+
// }}
|
|
758
|
+
// />
|
|
759
|
+
// ) : (
|
|
760
|
+
// <div className="feature-section__icon-wrapper">
|
|
761
|
+
// <FeatureIcon
|
|
762
|
+
// icon={item.icon}
|
|
763
|
+
// iconColor={iconColor}
|
|
764
|
+
// iconSize={iconSize}
|
|
765
|
+
// iconClassName={iconClassName}
|
|
766
|
+
// layout={final.layout}
|
|
767
|
+
// checklistIcon={checkmarkIcon}
|
|
768
|
+
// checklistColor={checkmarkColor}
|
|
769
|
+
// checklistSize={checkmarkSize}
|
|
770
|
+
// checklistClassName={checkmarkClassName}
|
|
771
|
+
// />
|
|
772
|
+
// </div>
|
|
773
|
+
// )}
|
|
774
|
+
// </div>
|
|
775
|
+
// )}
|
|
776
|
+
// {item.title && (
|
|
777
|
+
// <Text
|
|
778
|
+
// block
|
|
779
|
+
// size={titleSize}
|
|
780
|
+
// weight={titleWeight}
|
|
781
|
+
// color={titleColor}
|
|
782
|
+
// funcss={`feature-section__title ${titleClassName}`}
|
|
783
|
+
// style={{ marginBottom: '0.75rem' }}
|
|
784
|
+
// >
|
|
785
|
+
// {item.title}
|
|
786
|
+
// </Text>
|
|
787
|
+
// )}
|
|
788
|
+
// {item.description && (
|
|
789
|
+
// <Text
|
|
790
|
+
// block
|
|
791
|
+
// size={descriptionSize}
|
|
792
|
+
// weight={descriptionWeight}
|
|
793
|
+
// color={descriptionColor}
|
|
794
|
+
// funcss={`feature-section__description ${descriptionClassName}`}
|
|
795
|
+
// >
|
|
796
|
+
// {item.description}
|
|
797
|
+
// </Text>
|
|
798
|
+
// )}
|
|
799
|
+
// {item.content && (
|
|
800
|
+
// <div
|
|
801
|
+
// className="feature-section__additional-content"
|
|
802
|
+
// style={{ marginTop: '1rem' }}
|
|
803
|
+
// >
|
|
804
|
+
// {item.content}
|
|
805
|
+
// </div>
|
|
806
|
+
// )}
|
|
807
|
+
// {renderItemCTA(item)}
|
|
808
|
+
// </div>
|
|
809
|
+
// );
|
|
810
|
+
// // Apply card styling if card prop is true
|
|
811
|
+
// if (final.card) {
|
|
812
|
+
// const cardClasses = [
|
|
813
|
+
// 'feature-section__card',
|
|
814
|
+
// 'card',
|
|
815
|
+
// cardHoverEffect !== 'none' ? `card--hover-${cardHoverEffect}` : '',
|
|
816
|
+
// item.className || '',
|
|
817
|
+
// final.cardClassName || '',
|
|
818
|
+
// ].filter(Boolean).join(' ');
|
|
819
|
+
// const cardStyles: React.CSSProperties = {
|
|
820
|
+
// padding: getSpacingValue(cardPadding, '1.5rem'),
|
|
821
|
+
// borderRadius: cardRounded,
|
|
822
|
+
// boxShadow: cardShadow !== 'none' ? getCssVariableValue(`shadow-${cardShadow}`) || undefined : undefined,
|
|
823
|
+
// border: cardBorder ? `1px solid ${getCssVariableValue(cardBorderColor) || cardBorderColor}` : 'none',
|
|
824
|
+
// height: '100%',
|
|
825
|
+
// maxWidth: final.itemMaxWidth || '100%',
|
|
826
|
+
// ...item.style,
|
|
827
|
+
// };
|
|
828
|
+
// return (
|
|
829
|
+
// <div key={index} className={cardClasses} style={cardStyles}>
|
|
830
|
+
// {featureContent}
|
|
831
|
+
// </div>
|
|
832
|
+
// );
|
|
833
|
+
// }
|
|
834
|
+
// // Regular item without card
|
|
835
|
+
// return (
|
|
836
|
+
// <div
|
|
837
|
+
// key={index}
|
|
838
|
+
// className={`feature-section__item-wrapper ${item.className || ''}`}
|
|
839
|
+
// style={{
|
|
840
|
+
// maxWidth: final.itemMaxWidth || '100%',
|
|
841
|
+
// ...item.style
|
|
842
|
+
// }}
|
|
843
|
+
// >
|
|
844
|
+
// {featureContent}
|
|
845
|
+
// </div>
|
|
846
|
+
// );
|
|
847
|
+
// };
|
|
848
|
+
// const renderFlexFeatures = () => {
|
|
849
|
+
// if (featuresArray.length === 0) return null;
|
|
850
|
+
// const gapValue = final.gap !== undefined ? `${final.gap * 0.25}rem` : '2rem';
|
|
851
|
+
// const flexGap = gapValue;
|
|
852
|
+
// if (final.layout === 'centered') {
|
|
853
|
+
// const maxWidth = final.maxWidth || '48rem';
|
|
854
|
+
// return (
|
|
855
|
+
// <div
|
|
856
|
+
// className="feature-section__centered-container"
|
|
857
|
+
// style={{
|
|
858
|
+
// maxWidth,
|
|
859
|
+
// margin: '0 auto',
|
|
860
|
+
// }}
|
|
861
|
+
// >
|
|
862
|
+
// {featuresArray.map((item, index) => renderFeatureItem(item, index))}
|
|
863
|
+
// </div>
|
|
864
|
+
// );
|
|
865
|
+
// }
|
|
866
|
+
// // Use Flex layout with proper flexbox values
|
|
867
|
+
// return (
|
|
868
|
+
// <div
|
|
869
|
+
// className="feature-section__flex-container"
|
|
870
|
+
// style={{
|
|
871
|
+
// display: 'flex',
|
|
872
|
+
// flexWrap: final.wrap !== false ? 'wrap' : 'nowrap',
|
|
873
|
+
// gap: flexGap,
|
|
874
|
+
// alignItems: convertFlexValue(final.align) || 'stretch',
|
|
875
|
+
// justifyContent: convertFlexValue(final.justify) || 'flex-start',
|
|
876
|
+
// maxWidth: final.maxWidth || '100%',
|
|
877
|
+
// margin: '0 auto',
|
|
878
|
+
// }}
|
|
879
|
+
// >
|
|
880
|
+
// {featuresArray.map((item, index) => (
|
|
881
|
+
// <div key={index} className="feature-section__flex-item">
|
|
882
|
+
// {renderFeatureItem(item, index)}
|
|
883
|
+
// </div>
|
|
884
|
+
// ))}
|
|
885
|
+
// </div>
|
|
886
|
+
// );
|
|
887
|
+
// };
|
|
888
|
+
// const renderCarouselFeatures = () => {
|
|
889
|
+
// if (featuresArray.length === 0) return null;
|
|
890
|
+
// // Prepare carousel items
|
|
891
|
+
// const carouselItems = featuresArray.map((item, index) =>
|
|
892
|
+
// renderFeatureItem(item, index)
|
|
893
|
+
// );
|
|
894
|
+
// return (
|
|
895
|
+
// <div
|
|
896
|
+
// className={`feature-section__carousel-container ${final.carouselContainerClassName || ''}`}
|
|
897
|
+
// style={final.carouselContainerStyle}
|
|
898
|
+
// >
|
|
899
|
+
// <Carousel
|
|
900
|
+
// scrollNumber={final.scrollNumber}
|
|
901
|
+
// gap={final.gap || 1} // Default gap for carousel
|
|
902
|
+
// funcss={final.carouselFuncss}
|
|
903
|
+
// showDashes={final.showDashes}
|
|
904
|
+
// allowVerticalOverflow={final.allowVerticalOverflow}
|
|
905
|
+
// itemPadding={final.itemPadding || '0.5rem'}
|
|
906
|
+
// controlerSize={final.controlerSize}
|
|
907
|
+
// controlerIconSize={final.controlerIconSize}
|
|
908
|
+
// infiniteScroll={final.infiniteScroll}
|
|
909
|
+
// infiniteScrollSpeed={final.infiniteScrollSpeed}
|
|
910
|
+
// infiniteScrollDirection={final.infiniteScrollDirection}
|
|
911
|
+
// >
|
|
912
|
+
// {carouselItems}
|
|
913
|
+
// </Carousel>
|
|
914
|
+
// </div>
|
|
915
|
+
// );
|
|
916
|
+
// };
|
|
917
|
+
// const renderFeaturesContent = () => {
|
|
918
|
+
// if (featuresArray.length === 0) return null;
|
|
919
|
+
// // Use carousel if isCarousel is true
|
|
920
|
+
// if (final.isCarousel) {
|
|
921
|
+
// return renderCarouselFeatures();
|
|
922
|
+
// }
|
|
923
|
+
// // Otherwise use flex layout
|
|
924
|
+
// return renderFlexFeatures();
|
|
925
|
+
// };
|
|
926
|
+
// const getLayoutClasses = () => {
|
|
927
|
+
// const classes = ['feature-section'];
|
|
928
|
+
// if (final.layout) {
|
|
929
|
+
// classes.push(`feature-section--${final.layout}`);
|
|
930
|
+
// }
|
|
931
|
+
// if (final.isCarousel) {
|
|
932
|
+
// classes.push('feature-section--carousel');
|
|
933
|
+
// }
|
|
934
|
+
// if (final.className) {
|
|
935
|
+
// classes.push(final.className);
|
|
936
|
+
// }
|
|
937
|
+
// if (final.sectionClass) {
|
|
938
|
+
// classes.push(final.sectionClass);
|
|
939
|
+
// }
|
|
940
|
+
// if (final.funcss) {
|
|
941
|
+
// classes.push(final.funcss);
|
|
942
|
+
// }
|
|
943
|
+
// return classes.filter(Boolean).join(' ');
|
|
944
|
+
// };
|
|
945
|
+
// const getContainerStyles = (): React.CSSProperties => {
|
|
946
|
+
// const padding = getSpacingValue(final.padding, '3rem 0');
|
|
947
|
+
// return {
|
|
948
|
+
// padding: padding,
|
|
949
|
+
// ...final.style,
|
|
950
|
+
// };
|
|
951
|
+
// };
|
|
952
|
+
// const getTextAlign = (align?: 'left' | 'center' | 'right'): React.CSSProperties => {
|
|
953
|
+
// return {
|
|
954
|
+
// textAlign: align || 'center',
|
|
955
|
+
// };
|
|
956
|
+
// };
|
|
957
|
+
// return (
|
|
958
|
+
// <section
|
|
959
|
+
// id={final.id}
|
|
960
|
+
// className={getLayoutClasses()}
|
|
961
|
+
// style={getContainerStyles()}
|
|
962
|
+
// >
|
|
963
|
+
// <div
|
|
964
|
+
// className={`feature-section__container ${final.containerClassName || ''}`}
|
|
965
|
+
// style={{
|
|
966
|
+
// maxWidth: final.maxWidth || '1280px',
|
|
967
|
+
// margin: '0 auto',
|
|
968
|
+
// padding: '0 1rem',
|
|
969
|
+
// ...final.containerStyle,
|
|
970
|
+
// }}
|
|
971
|
+
// >
|
|
972
|
+
// {(final.title || final.subtitle || final.description) && (
|
|
973
|
+
// <div
|
|
974
|
+
// className="feature-section__header"
|
|
975
|
+
// style={{
|
|
976
|
+
// marginBottom: '3rem',
|
|
977
|
+
// maxWidth: final.layout === 'centered' ? '48rem' : '100%',
|
|
978
|
+
// marginLeft: 'auto',
|
|
979
|
+
// marginRight: 'auto',
|
|
980
|
+
// ...getTextAlign(final.titleAlign),
|
|
981
|
+
// }}
|
|
982
|
+
// >
|
|
983
|
+
// {final.subtitle && (
|
|
984
|
+
// <Text
|
|
985
|
+
// block
|
|
986
|
+
// size={final.subtitleSize || 'sm'}
|
|
987
|
+
// weight={final.subtitleWeight || 600}
|
|
988
|
+
// color={final.subtitleColor || 'var(--primary)'}
|
|
989
|
+
// funcss={`feature-section__subtitle ${final.subtitleClassName || ''}`}
|
|
990
|
+
// style={{
|
|
991
|
+
// textTransform: 'uppercase',
|
|
992
|
+
// letterSpacing: '0.05em',
|
|
993
|
+
// marginBottom: '0.5rem',
|
|
994
|
+
// }}
|
|
995
|
+
// >
|
|
996
|
+
// {final.subtitle}
|
|
997
|
+
// </Text>
|
|
998
|
+
// )}
|
|
999
|
+
// {final.title && (
|
|
1000
|
+
// <Text
|
|
1001
|
+
// block
|
|
1002
|
+
// size={final.titleSize || 'xl'}
|
|
1003
|
+
// weight={final.titleWeight || 700}
|
|
1004
|
+
// color={final.titleColor || 'var(--text-color)'}
|
|
1005
|
+
// funcss={`feature-section__main-title ${final.titleClassName || ''}`}
|
|
1006
|
+
// style={{ marginBottom: '1rem' }}
|
|
1007
|
+
// >
|
|
1008
|
+
// {final.title}
|
|
1009
|
+
// </Text>
|
|
1010
|
+
// )}
|
|
1011
|
+
// {final.description && (
|
|
1012
|
+
// <Text
|
|
1013
|
+
// block
|
|
1014
|
+
// size={final.descriptionSize || 'sm'}
|
|
1015
|
+
// weight={final.descriptionWeight || 400}
|
|
1016
|
+
// color={final.descriptionColor || 'var(--text-muted)'}
|
|
1017
|
+
// funcss={`feature-section__section-description ${final.descriptionClassName || ''}`}
|
|
1018
|
+
// >
|
|
1019
|
+
// {final.description}
|
|
1020
|
+
// </Text>
|
|
1021
|
+
// )}
|
|
1022
|
+
// </div>
|
|
1023
|
+
// )}
|
|
1024
|
+
// <div className="feature-section__content">
|
|
1025
|
+
// {renderFeaturesContent()}
|
|
1026
|
+
// {final.children}
|
|
1027
|
+
// </div>
|
|
1028
|
+
// {final.ctaText && (
|
|
1029
|
+
// <div
|
|
1030
|
+
// className="feature-section__cta-container"
|
|
1031
|
+
// style={{
|
|
1032
|
+
// marginTop: '2.5rem',
|
|
1033
|
+
// ...getTextAlign(final.ctaAlign),
|
|
1034
|
+
// }}
|
|
1035
|
+
// >
|
|
1036
|
+
// <Button
|
|
1037
|
+
// onClick={final.ctaOnClick || (() => final.ctaUrl && (window.location.href = final.ctaUrl))}
|
|
1038
|
+
// funcss={`feature-section__cta ${final.ctaClassName || ''}`}
|
|
1039
|
+
// stringPrefix={final.ctaStringPrefix}
|
|
1040
|
+
// stringSuffix={final.ctaStringSuffix}
|
|
1041
|
+
// startIcon={final.ctaStartIcon}
|
|
1042
|
+
// endIcon={final.ctaEndIcon}
|
|
1043
|
+
// iconSize={final.ctaIconSize}
|
|
1044
|
+
// bg={final.ctaBg || 'primary'}
|
|
1045
|
+
// isLoading={final.ctaIsLoading}
|
|
1046
|
+
// status={final.ctaStatus}
|
|
1047
|
+
// url={final.ctaUrl}
|
|
1048
|
+
// >
|
|
1049
|
+
// {final.ctaText}
|
|
1050
|
+
// </Button>
|
|
1051
|
+
// </div>
|
|
1052
|
+
// )}
|
|
1053
|
+
// </div>
|
|
1054
|
+
// </section>
|
|
1055
|
+
// );
|
|
1056
|
+
// };
|
|
1057
|
+
// export default Feature;
|