funuicss 3.7.15 → 3.8.0

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 (45) hide show
  1. package/css/fun.css +560 -203
  2. package/demo/theme.tsx +1311 -0
  3. package/index.d.ts +3 -0
  4. package/index.js +7 -1
  5. package/package.json +1 -1
  6. package/ui/button/Button.d.ts +2 -1
  7. package/ui/button/Button.js +3 -3
  8. package/ui/components/ImageScaler.d.ts +6 -0
  9. package/ui/components/ImageScaler.js +17 -0
  10. package/ui/div/Div.d.ts +3 -1
  11. package/ui/div/Div.js +2 -2
  12. package/ui/empty/Empty.d.ts +17 -0
  13. package/ui/empty/Empty.js +66 -0
  14. package/ui/feature/Feature.d.ts +130 -0
  15. package/ui/feature/Feature.js +380 -0
  16. package/ui/flex/Flex.d.ts +2 -1
  17. package/ui/flex/Flex.js +3 -3
  18. package/ui/footer/Footer.d.ts +1 -0
  19. package/ui/footer/Footer.js +6 -1
  20. package/ui/icons/Dynamic.d.ts +12 -0
  21. package/ui/icons/Dynamic.js +163 -0
  22. package/ui/modal/Modal.d.ts +1 -1
  23. package/ui/products/CartModal.d.ts +20 -0
  24. package/ui/products/CartModal.js +85 -0
  25. package/ui/products/ProductCard.d.ts +13 -0
  26. package/ui/products/ProductCard.js +56 -0
  27. package/ui/products/ProductDetail.d.ts +14 -0
  28. package/ui/products/ProductDetail.js +249 -0
  29. package/ui/products/ProductDetailModal.d.ts +17 -0
  30. package/ui/products/ProductDetailModal.js +99 -0
  31. package/ui/products/Products.d.ts +60 -0
  32. package/ui/products/Products.js +312 -0
  33. package/ui/products/Store.d.ts +99 -0
  34. package/ui/products/Store.js +515 -0
  35. package/ui/sidebar/SideBar.d.ts +3 -1
  36. package/ui/sidebar/SideBar.js +50 -11
  37. package/ui/specials/Circle.d.ts +2 -1
  38. package/ui/specials/Circle.js +2 -2
  39. package/ui/table/Table.d.ts +15 -1
  40. package/ui/table/Table.js +143 -15
  41. package/ui/theme/theme.d.ts +91 -0
  42. package/ui/theme/theme.js +468 -25
  43. package/ui/vista/Vista.js +8 -12
  44. package/utils/Buckets.d.ts +0 -0
  45. package/utils/Buckets.js +1 -0
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { CartItem } from './Store';
3
+ interface CartModalProps {
4
+ cart: CartItem[];
5
+ isOpen: boolean;
6
+ setIsOpen: (open: boolean) => void;
7
+ currency?: string;
8
+ updateQuantity: (cartItemId: string, quantity: number) => void;
9
+ removeFromCart: (cartItemId: string) => void;
10
+ clearCart: () => void;
11
+ handleCheckout: () => void;
12
+ cartBadgeColor?: string;
13
+ checkoutText?: string;
14
+ checkoutIcon?: React.ReactNode;
15
+ small?: boolean;
16
+ big?: boolean;
17
+ persistCart?: boolean;
18
+ }
19
+ declare const CartModal: React.FC<CartModalProps>;
20
+ export default CartModal;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ // components/products/CartModal.tsx
3
+ 'use client';
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ var react_1 = __importDefault(require("react"));
9
+ var pi_1 = require("react-icons/pi");
10
+ var Modal_1 = __importDefault(require("../modal/Modal"));
11
+ var RowFlex_1 = __importDefault(require("../specials/RowFlex"));
12
+ var Text_1 = __importDefault(require("../text/Text"));
13
+ var Input_1 = __importDefault(require("../input/Input"));
14
+ var Div_1 = __importDefault(require("../div/Div"));
15
+ var Button_1 = __importDefault(require("../button/Button"));
16
+ var Circle_1 = __importDefault(require("../specials/Circle"));
17
+ var Flex_1 = __importDefault(require("../flex/Flex"));
18
+ var generateCartItemId = function (product, options) {
19
+ var parts = [
20
+ product.id,
21
+ (options === null || options === void 0 ? void 0 : options.color) || '',
22
+ (options === null || options === void 0 ? void 0 : options.size) || ''
23
+ ].filter(Boolean);
24
+ return parts.join('_');
25
+ };
26
+ var CartModal = function (_a) {
27
+ var cart = _a.cart, isOpen = _a.isOpen, setIsOpen = _a.setIsOpen, _b = _a.currency, currency = _b === void 0 ? '$' : _b, updateQuantity = _a.updateQuantity, removeFromCart = _a.removeFromCart, clearCart = _a.clearCart, handleCheckout = _a.handleCheckout, _c = _a.cartBadgeColor, cartBadgeColor = _c === void 0 ? 'error' : _c, _d = _a.checkoutText, checkoutText = _d === void 0 ? 'Checkout' : _d, checkoutIcon = _a.checkoutIcon, _e = _a.small, small = _e === void 0 ? false : _e, _f = _a.big, big = _f === void 0 ? false : _f, _g = _a.persistCart, persistCart = _g === void 0 ? true : _g;
28
+ var totalItems = cart.reduce(function (sum, item) { return sum + item.quantity; }, 0);
29
+ var subtotal = cart.reduce(function (sum, item) { return sum + (item.product.price * item.quantity); }, 0);
30
+ var handleRemoveItem = function (item) {
31
+ var cartItemId = generateCartItemId(item.product, {
32
+ color: item.selectedColor,
33
+ size: item.selectedSize
34
+ });
35
+ removeFromCart(cartItemId);
36
+ };
37
+ var handleUpdateQuantity = function (item, newQuantity) {
38
+ var cartItemId = generateCartItemId(item.product, {
39
+ color: item.selectedColor,
40
+ size: item.selectedSize
41
+ });
42
+ updateQuantity(cartItemId, newQuantity);
43
+ };
44
+ return (react_1.default.createElement(Modal_1.default, { animation: "SlideLeft", position: "right", duration: 0.3, open: isOpen, setOpen: setIsOpen, funcss: "funui_products_cart_modal width-400 sm:width-500", title: react_1.default.createElement(Text_1.default, { text: "Your Cart", size: "h3" }), body: react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_body max-height-70vh overflow-y-auto" }, cart.length === 0 ? (react_1.default.createElement(Div_1.default, { funcss: "flex-center padding-40" },
45
+ react_1.default.createElement(Text_1.default, { text: "Your cart is empty", color: "text-light", size: "large" }))) : (react_1.default.createElement(react_1.default.Fragment, null,
46
+ cart.map(function (item, index) {
47
+ var _a;
48
+ var cartItemId = generateCartItemId(item.product, {
49
+ color: item.selectedColor,
50
+ size: item.selectedSize
51
+ });
52
+ return (react_1.default.createElement(RowFlex_1.default, { key: "".concat(cartItemId, "-").concat(index), funcss: "lighter p round-edge section", alignItems: "center", justify: 'space-between', gap: 1 },
53
+ react_1.default.createElement(Div_1.default, { funcss: " width-80 height-80" }, ((_a = item.product.images) === null || _a === void 0 ? void 0 : _a[0]) ? (react_1.default.createElement("img", { src: item.product.images[0], alt: item.product.name, loading: "lazy", className: "fit round-edge" })) : (react_1.default.createElement(Div_1.default, { funcss: "w-80 h-80 flex central" },
54
+ react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-light", size: "sm" })))),
55
+ react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_details flex-1 min-width-0" },
56
+ react_1.default.createElement(Text_1.default, { text: item.product.name, block: true }),
57
+ (item.selectedColor || item.selectedSize) && (react_1.default.createElement(Text_1.default, { text: "".concat(item.selectedColor ? "Color: ".concat(item.selectedColor) : '', " ").concat(item.selectedSize ? "Size: ".concat(item.selectedSize) : ''), size: 'sm' })),
58
+ react_1.default.createElement(Text_1.default, { text: "".concat(item.product.currency || currency).concat((item.product.price * item.quantity).toFixed(2)), block: true, size: 'lg' })),
59
+ react_1.default.createElement("div", { className: "col" },
60
+ react_1.default.createElement(Flex_1.default, { width: '100%', gap: 0.5, alignItems: 'center' },
61
+ react_1.default.createElement(Circle_1.default, { size: 2.5, bg: 'bg', body: react_1.default.createElement(pi_1.PiMinus, null), onClick: function () { return handleUpdateQuantity(item, item.quantity - 1); } }),
62
+ react_1.default.createElement("div", { className: "w-90" },
63
+ react_1.default.createElement(Input_1.default, { type: "number", value: item.quantity, onChange: function (e) {
64
+ var value = parseInt(e.target.value);
65
+ if (!isNaN(value)) {
66
+ handleUpdateQuantity(item, Math.max(1, value));
67
+ }
68
+ }, fullWidth: true, bordered: true })),
69
+ react_1.default.createElement(Circle_1.default, { bg: 'bg', size: 2.5, body: react_1.default.createElement(pi_1.PiPlus, null), onClick: function () { return handleUpdateQuantity(item, item.quantity + 1); } }))),
70
+ react_1.default.createElement(Circle_1.default, { size: 2.5, body: react_1.default.createElement(pi_1.PiTrash, null), onClick: function () { return handleRemoveItem(item); }, bg: 'error' })));
71
+ }),
72
+ react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_summary padding-20 space-y-3" },
73
+ react_1.default.createElement(RowFlex_1.default, { justify: "space-between" },
74
+ react_1.default.createElement(Text_1.default, { text: "Subtotal", color: "text-light" }),
75
+ react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(subtotal.toFixed(2)) })),
76
+ react_1.default.createElement(RowFlex_1.default, { justify: "space-between" },
77
+ react_1.default.createElement(Text_1.default, { text: "Items", color: "text-light" }),
78
+ react_1.default.createElement(Text_1.default, { text: totalItems.toString() })))))), footer: cart.length > 0 ? (react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_footer padding-20 border-top border-light" },
79
+ react_1.default.createElement(RowFlex_1.default, { justify: "space-between", alignItems: "center" },
80
+ react_1.default.createElement(Div_1.default, null,
81
+ react_1.default.createElement(Text_1.default, { text: "Total", color: "text-light", size: "sm", block: true }),
82
+ react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(subtotal.toFixed(2)), size: "h4" })),
83
+ react_1.default.createElement(Button_1.default, { text: checkoutText, bg: "primary", raised: true, onClick: handleCheckout, funcss: "padding-x-30", startIcon: checkoutIcon, small: small, big: big })))) : react_1.default.createElement(react_1.default.Fragment, null) }));
84
+ };
85
+ exports.default = CartModal;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { Product } from './Store';
3
+ interface ProductCardProps {
4
+ product: Product;
5
+ currency?: string;
6
+ onClick?: (product: Product) => void;
7
+ onAddToCart?: (product: Product) => void;
8
+ className?: string;
9
+ funcss?: string;
10
+ showBadges?: boolean;
11
+ }
12
+ declare const ProductCard: React.FC<ProductCardProps>;
13
+ export default ProductCard;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ var react_1 = __importDefault(require("react"));
8
+ var Div_1 = __importDefault(require("../div/Div"));
9
+ var Text_1 = __importDefault(require("../text/Text"));
10
+ var Flex_1 = __importDefault(require("../flex/Flex"));
11
+ var ProductCard = function (_a) {
12
+ var _b;
13
+ var product = _a.product, _c = _a.currency, currency = _c === void 0 ? '$' : _c, onClick = _a.onClick, onAddToCart = _a.onAddToCart, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.funcss, funcss = _e === void 0 ? '' : _e, _f = _a.showBadges, showBadges = _f === void 0 ? true : _f;
14
+ var hasDiscount = product.comparePrice && product.comparePrice > product.price;
15
+ var discountPercent = hasDiscount
16
+ ? Math.round(((product.comparePrice - product.price) / product.comparePrice) * 100)
17
+ : 0;
18
+ var stockAvailable = product.stock === undefined || product.stock > 0;
19
+ var handleClick = function () {
20
+ onClick === null || onClick === void 0 ? void 0 : onClick(product);
21
+ };
22
+ var handleAddToCart = function (e) {
23
+ e.stopPropagation();
24
+ onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product);
25
+ };
26
+ var getDisplayPrice = function () {
27
+ var price = product.price || 0;
28
+ var productCurrency = product.currency || currency;
29
+ return "".concat(productCurrency).concat(price.toFixed(2));
30
+ };
31
+ return (react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-card ".concat(className, " ").concat(funcss), onClick: handleClick, customStyle: { cursor: 'pointer' } },
32
+ react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container" },
33
+ ((_b = product.images) === null || _b === void 0 ? void 0 : _b[0]) ? (react_1.default.createElement("img", { src: product.images[0], alt: product.name, loading: "lazy", className: "funui_store_product-image" })) : (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
34
+ react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-muted", size: "sm" }))),
35
+ showBadges && (react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-badges" }, product.isSale && (react_1.default.createElement("span", { className: "funui_store_badge sale" }, "Sale"))))),
36
+ react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-info" },
37
+ react_1.default.createElement(Flex_1.default, { fit: true, justify: 'space-between', alignItems: 'center', gap: 1 },
38
+ product.category && (react_1.default.createElement("span", { className: "funui_store_product-category" }, product.category)),
39
+ product.isNew && (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'success', weight: 600 }, "New"))),
40
+ react_1.default.createElement(Flex_1.default, { gap: 0.5, direction: 'column', width: '100%' },
41
+ react_1.default.createElement(Text_1.default, { block: true, size: 'lg', truncate: 2 }, product.name),
42
+ react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1, justify: 'space-between' },
43
+ react_1.default.createElement(Flex_1.default, { gap: 0.5, alignItems: 'center' },
44
+ react_1.default.createElement("span", { className: "text-lg block" }, getDisplayPrice()),
45
+ hasDiscount && (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'info', weight: 600 },
46
+ discountPercent,
47
+ "% Off"))),
48
+ hasDiscount && (react_1.default.createElement(Text_1.default, { size: "sm", opacity: 4, textDecoration: 'line-through' },
49
+ product.currency || currency,
50
+ product.comparePrice.toFixed(2)))),
51
+ !stockAvailable ? (react_1.default.createElement("span", { className: "funui_store_stock-info out text-xs" }, "Out of Stock")) : product.stock !== undefined && product.stock > 0 && product.stock < 10 ? (react_1.default.createElement("span", { className: "funui_store_stock-info low text-xs" },
52
+ "Only ",
53
+ product.stock,
54
+ " left")) : stockAvailable && (react_1.default.createElement("span", { className: "funui_store_stock-info in text-xs" }, "In Stock"))))));
55
+ };
56
+ exports.default = ProductCard;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { Product } from './Store';
3
+ interface ProductDetailProps {
4
+ product: Product;
5
+ open: boolean;
6
+ setOpen: (open: boolean) => void;
7
+ currency?: string;
8
+ onAddToCart?: (product: Product, quantity: number, selectedOptions?: {
9
+ color?: string;
10
+ size?: string;
11
+ }) => void;
12
+ }
13
+ declare const ProductDetail: React.FC<ProductDetailProps>;
14
+ export default ProductDetail;
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ // components/products/ProductDetail.tsx
3
+ 'use client';
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
38
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
39
+ if (ar || !(i in from)) {
40
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
41
+ ar[i] = from[i];
42
+ }
43
+ }
44
+ return to.concat(ar || Array.prototype.slice.call(from));
45
+ };
46
+ var __importDefault = (this && this.__importDefault) || function (mod) {
47
+ return (mod && mod.__esModule) ? mod : { "default": mod };
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ var react_1 = __importStar(require("react"));
51
+ var pi_1 = require("react-icons/pi");
52
+ var tfi_1 = require("react-icons/tfi");
53
+ var si_1 = require("react-icons/si");
54
+ var Modal_1 = __importDefault(require("../modal/Modal"));
55
+ var Div_1 = __importDefault(require("../div/Div"));
56
+ var Text_1 = __importDefault(require("../text/Text"));
57
+ var Flex_1 = __importDefault(require("../flex/Flex"));
58
+ var Button_1 = __importDefault(require("../button/Button"));
59
+ var RowFlex_1 = __importDefault(require("../specials/RowFlex"));
60
+ var Input_1 = __importDefault(require("../input/Input"));
61
+ var Circle_1 = __importDefault(require("../specials/Circle"));
62
+ var Carousel_1 = __importDefault(require("../carousel/Carousel"));
63
+ var Select_1 = __importDefault(require("../select/Select"));
64
+ var io5_1 = require("react-icons/io5");
65
+ var ImageScaler_1 = __importDefault(require("../components/ImageScaler"));
66
+ var ProductDetail = function (_a) {
67
+ var product = _a.product, open = _a.open, setOpen = _a.setOpen, _b = _a.currency, currency = _b === void 0 ? '$' : _b, onAddToCart = _a.onAddToCart;
68
+ var _c = (0, react_1.useState)(0), selectedImageIndex = _c[0], setSelectedImageIndex = _c[1];
69
+ var _d = (0, react_1.useState)(''), selectedColor = _d[0], setSelectedColor = _d[1];
70
+ var _e = (0, react_1.useState)(''), selectedSize = _e[0], setSelectedSize = _e[1];
71
+ var _f = (0, react_1.useState)(1), quantity = _f[0], setQuantity = _f[1];
72
+ var _g = (0, react_1.useState)(false), showFullDescription = _g[0], setShowFullDescription = _g[1];
73
+ var hasDiscount = product.comparePrice && product.comparePrice > product.price;
74
+ var discountPercent = hasDiscount
75
+ ? Math.round(((product.comparePrice - product.price) / product.comparePrice) * 100)
76
+ : 0;
77
+ var getDisplayPrice = function () {
78
+ var price = product.price || 0;
79
+ var productCurrency = product.currency || currency;
80
+ return "".concat(productCurrency).concat(price.toFixed(2));
81
+ };
82
+ var handleAddToCart = function () {
83
+ onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product, quantity, {
84
+ color: selectedColor,
85
+ size: selectedSize,
86
+ });
87
+ setOpen(false);
88
+ };
89
+ var totalPrice = ((product.price || 0) * quantity).toFixed(2);
90
+ // Function to safely process description
91
+ var processDescription = function (description) {
92
+ if (!description)
93
+ return '';
94
+ // Remove h1, h2, h3 tags but keep their content
95
+ var processed = description
96
+ .replace(/<h[1-3][^>]*>/gi, '<p>')
97
+ .replace(/<\/h[1-3]>/gi, '</p>');
98
+ return processed;
99
+ };
100
+ // Function to truncate HTML while preserving tags
101
+ var truncateHTML = function (html, maxLength) {
102
+ if (html.length <= maxLength)
103
+ return html;
104
+ var truncated = '';
105
+ var length = 0;
106
+ var inTag = false;
107
+ var tagBuffer = '';
108
+ for (var i = 0; i < html.length && length < maxLength; i++) {
109
+ var char = html[i];
110
+ if (char === '<') {
111
+ inTag = true;
112
+ tagBuffer = char;
113
+ }
114
+ else if (char === '>') {
115
+ inTag = false;
116
+ tagBuffer += char;
117
+ truncated += tagBuffer;
118
+ tagBuffer = '';
119
+ }
120
+ else if (inTag) {
121
+ tagBuffer += char;
122
+ }
123
+ else {
124
+ truncated += char;
125
+ length++;
126
+ }
127
+ }
128
+ // Close any open tags
129
+ var tempDiv = document.createElement('div');
130
+ tempDiv.innerHTML = truncated + '...';
131
+ // Get the innerHTML to ensure tags are properly closed
132
+ return tempDiv.innerHTML;
133
+ };
134
+ // Process the description
135
+ var processedDescription = processDescription(product.description || '');
136
+ var maxDescriptionLength = 200;
137
+ var shouldTruncate = processedDescription.length > maxDescriptionLength;
138
+ var displayDescription = showFullDescription
139
+ ? processedDescription
140
+ : (shouldTruncate ? truncateHTML(processedDescription, maxDescriptionLength) : processedDescription);
141
+ // Check if description has HTML tags
142
+ var hasHTML = /<[a-z][\s\S]*>/i.test(processedDescription);
143
+ return (react_1.default.createElement(Modal_1.default, { animation: "SlideDown", open: open, setOpen: setOpen, maxWidth: '1000px', title: react_1.default.createElement(react_1.default.Fragment, null), body: react_1.default.createElement(Flex_1.default, { width: '100%', gap: 2 },
144
+ react_1.default.createElement("div", { className: "w-400" }, product.images && product.images.length > 0 && (react_1.default.createElement(Div_1.default, { funcss: "margin-bottom-20" },
145
+ react_1.default.createElement(Div_1.default, { funcss: "funui_products_main_image_container mb-3" },
146
+ react_1.default.createElement(ImageScaler_1.default, { src: product.images[selectedImageIndex], size: "100%" })),
147
+ product.images.length > 1 && (react_1.default.createElement(Carousel_1.default, { gap: 1 }, product.images.map(function (image, index) { return (react_1.default.createElement(Div_1.default, { key: index, funcss: "funui_products_thumbnail rounde-edge ".concat(selectedImageIndex === index ? 'funui_products_thumbnail-active' : ''), onClick: function () { return setSelectedImageIndex(index); } },
148
+ react_1.default.createElement(ImageScaler_1.default, { src: image, size: "100px" }))); })))))),
149
+ react_1.default.createElement("div", { className: "col" },
150
+ react_1.default.createElement(Flex_1.default, { direction: 'column', gap: 2, alignItems: 'flex-start', justify: 'flex-start' },
151
+ react_1.default.createElement("div", null,
152
+ react_1.default.createElement(Text_1.default, { text: product.name, size: "2xl", block: true }),
153
+ react_1.default.createElement(Flex_1.default, { justify: "space-between", alignItems: "center", width: '100%' },
154
+ react_1.default.createElement(Text_1.default, { text: getDisplayPrice(), size: "xl" }),
155
+ (hasDiscount || product.comparePrice) && (react_1.default.createElement(Text_1.default, { text: "".concat(product.currency || currency).concat(product.comparePrice.toFixed(2)), textDecoration: 'line-through' })))),
156
+ ((product.colors && product.colors.length > 0) || (product.sizes && product.sizes.length > 0)) &&
157
+ react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1 },
158
+ product.colors && product.colors.length > 0 && (react_1.default.createElement("div", { className: "col" },
159
+ react_1.default.createElement(Select_1.default, { fullWidth: true, options: __spreadArray([
160
+ { text: 'Select Color', value: '' }
161
+ ], product.colors.map(function (color) { return ({
162
+ text: color.name,
163
+ value: color.name,
164
+ prefix: react_1.default.createElement("div", { className: 'circle', style: { width: "20px", height: '20px', backgroundColor: color.code } })
165
+ }); }), true), value: selectedColor, onChange: function (e) { return setSelectedColor(e); }, bordered: true }))),
166
+ product.sizes && product.sizes.length > 0 && (react_1.default.createElement("div", { className: "col" },
167
+ react_1.default.createElement(Select_1.default, { fullWidth: true, options: __spreadArray([
168
+ { text: 'Select Size', value: '' }
169
+ ], product.sizes.map(function (size) { return ({ text: size, value: size }); }), true), value: selectedSize, onChange: function (e) { return setSelectedSize(e); }, bordered: true })))),
170
+ processedDescription && (react_1.default.createElement("div", null,
171
+ react_1.default.createElement(Text_1.default, { text: "Description", size: "lg", funcss: "margin-bottom-1" }),
172
+ react_1.default.createElement("div", { className: "article text-sm ".concat(hasHTML ? '' : 'whitespace-pre-wrap'), dangerouslySetInnerHTML: { __html: displayDescription } }),
173
+ shouldTruncate && (react_1.default.createElement(Button_1.default, { text: showFullDescription ? 'Show Less' : 'Read More', onClick: function () { return setShowFullDescription(!showFullDescription); }, small: true, bg: 'lighter', startIcon: showFullDescription ? react_1.default.createElement(pi_1.PiCaretUp, null) : react_1.default.createElement(pi_1.PiCaretDown, null) })))),
174
+ react_1.default.createElement("div", null,
175
+ react_1.default.createElement(Flex_1.default, { gap: 3, width: '100%' },
176
+ product.warranty && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
177
+ react_1.default.createElement("div", null,
178
+ react_1.default.createElement(pi_1.PiShieldCheck, { className: 'text-primary' })),
179
+ react_1.default.createElement("div", null,
180
+ react_1.default.createElement(Text_1.default, { text: "Warranty", size: "xs", opacity: 4, block: true }),
181
+ react_1.default.createElement(Text_1.default, { text: product.warranty, size: "sm", block: true, lineHeight: '1' })))),
182
+ product.manufacturer && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
183
+ react_1.default.createElement("div", null,
184
+ react_1.default.createElement(pi_1.PiUser, { className: 'text-primary' })),
185
+ react_1.default.createElement("div", null,
186
+ react_1.default.createElement(Text_1.default, { text: "Manufacturer", size: "xs", opacity: 4, block: true }),
187
+ react_1.default.createElement(Text_1.default, { text: product.manufacturer, size: "sm", block: true, lineHeight: '1' })))),
188
+ product.countryOfOrigin && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
189
+ react_1.default.createElement("div", null,
190
+ react_1.default.createElement(pi_1.PiGlobe, { className: 'text-primary' })),
191
+ react_1.default.createElement("div", null,
192
+ react_1.default.createElement(Text_1.default, { text: "Country of Origin", size: "xs", opacity: 4, block: true }),
193
+ react_1.default.createElement(Text_1.default, { text: product.countryOfOrigin, size: "sm", block: true, lineHeight: '1' })))),
194
+ product.isFeatured && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
195
+ react_1.default.createElement("div", null,
196
+ react_1.default.createElement(pi_1.PiUsers, { className: 'text-primary' })),
197
+ react_1.default.createElement("div", null,
198
+ react_1.default.createElement(Text_1.default, { text: "Featured", size: "xs", opacity: 4, block: true }),
199
+ react_1.default.createElement(Text_1.default, { text: "Yes", size: "sm", block: true, lineHeight: '1' })))),
200
+ product.rating && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
201
+ react_1.default.createElement("div", null,
202
+ react_1.default.createElement(tfi_1.TfiComments, { className: 'text-primary' })),
203
+ react_1.default.createElement("div", null,
204
+ react_1.default.createElement(Text_1.default, { text: "Rating", size: "xs", opacity: 4, block: true }),
205
+ react_1.default.createElement(Text_1.default, { text: product.rating, size: "sm", block: true, lineHeight: '1' })))),
206
+ product.brand && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
207
+ react_1.default.createElement("div", null,
208
+ react_1.default.createElement(si_1.SiBlackmagicdesign, { className: 'text-primary' })),
209
+ react_1.default.createElement("div", null,
210
+ react_1.default.createElement(Text_1.default, { text: "Brand", size: "xs", opacity: 4, block: true }),
211
+ react_1.default.createElement(Text_1.default, { text: product.brand, size: "sm", block: true, lineHeight: '1' })))),
212
+ product.category && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
213
+ react_1.default.createElement("div", null,
214
+ react_1.default.createElement(io5_1.IoLayersOutline, { className: 'text-primary' })),
215
+ react_1.default.createElement("div", null,
216
+ react_1.default.createElement(Text_1.default, { text: "Category", size: "xs", opacity: 4, block: true }),
217
+ react_1.default.createElement(Text_1.default, { text: product.category, size: "sm", block: true, lineHeight: '1' })))),
218
+ product.isNew && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
219
+ react_1.default.createElement("div", null,
220
+ react_1.default.createElement(pi_1.PiChecks, { className: 'text-primary' })),
221
+ react_1.default.createElement("div", null,
222
+ react_1.default.createElement(Text_1.default, { text: "New", size: "xs", opacity: 4, block: true }),
223
+ react_1.default.createElement(Text_1.default, { text: "Yes", size: "sm", block: true, lineHeight: '1' })))),
224
+ product.isSale && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
225
+ react_1.default.createElement("div", null,
226
+ react_1.default.createElement(pi_1.PiChecks, { className: 'text-primary' })),
227
+ react_1.default.createElement("div", null,
228
+ react_1.default.createElement(Text_1.default, { text: "On Sale", size: "xs", opacity: 4, block: true }),
229
+ react_1.default.createElement(Text_1.default, { text: "Yes", size: "sm", block: true, lineHeight: '1' })))),
230
+ product.weight && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
231
+ react_1.default.createElement("div", null,
232
+ react_1.default.createElement(pi_1.PiScales, { className: 'text-primary' })),
233
+ react_1.default.createElement("div", null,
234
+ react_1.default.createElement(Text_1.default, { text: "Weight", size: "xs", opacity: 4, block: true }),
235
+ react_1.default.createElement(Text_1.default, { text: product.weight + " " + product.weightUnit, size: "sm", block: true, lineHeight: '1' }))))))))), footer: react_1.default.createElement(RowFlex_1.default, { gap: 1, justify: 'flex-end', funcss: 'pt' },
236
+ react_1.default.createElement(RowFlex_1.default, { gap: 0.5, alignItems: "center" },
237
+ react_1.default.createElement(Circle_1.default, { body: react_1.default.createElement(pi_1.PiMinus, null), onClick: function () { return setQuantity(Math.max(1, quantity - 1)); }, funcss: quantity <= 1 ? "disabled" : "" }),
238
+ react_1.default.createElement("div", { className: "w-90" },
239
+ react_1.default.createElement(Input_1.default, { type: "number", value: quantity, onChange: function (e) {
240
+ var value = parseInt(e.target.value);
241
+ if (!isNaN(value)) {
242
+ setQuantity(Math.max(1, value));
243
+ }
244
+ }, funcss: "text-center", bordered: true })),
245
+ react_1.default.createElement(Circle_1.default, { onClick: function () { return setQuantity(quantity + 1); }, bg: 'lighter' },
246
+ react_1.default.createElement(pi_1.PiPlus, null))),
247
+ react_1.default.createElement(Button_1.default, { text: "Add to Cart - ".concat(currency).concat(totalPrice), bg: "primary", raised: true, onClick: handleAddToCart })) }));
248
+ };
249
+ exports.default = ProductDetail;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { Product } from './Products';
3
+ declare const ProductDetailModal: React.MemoExoticComponent<({ isOpen, setIsOpen, selectedProduct, selectedImageIndex, setSelectedImageIndex, selectedColor, setSelectedColor, quantity, setQuantity, handleAddFromModal, small, big }: {
4
+ isOpen: boolean;
5
+ setIsOpen: (open: boolean) => void;
6
+ selectedProduct: Product;
7
+ selectedImageIndex: number;
8
+ setSelectedImageIndex: (index: number) => void;
9
+ selectedColor: string;
10
+ setSelectedColor: (color: string) => void;
11
+ quantity: number;
12
+ setQuantity: (qty: number) => void;
13
+ handleAddFromModal: () => void;
14
+ small?: boolean;
15
+ big?: boolean;
16
+ }) => React.JSX.Element>;
17
+ export default ProductDetailModal;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ var react_1 = __importStar(require("react"));
40
+ var pi_1 = require("react-icons/pi");
41
+ var Modal_1 = __importDefault(require("../modal/Modal"));
42
+ var Close_1 = __importDefault(require("../modal/Close"));
43
+ var Button_1 = __importDefault(require("../button/Button"));
44
+ var RowFlex_1 = __importDefault(require("../specials/RowFlex"));
45
+ var Text_1 = __importDefault(require("../text/Text"));
46
+ var Input_1 = __importDefault(require("../input/Input"));
47
+ var Div_1 = __importDefault(require("../div/Div"));
48
+ var DETAIL_EMPTY_SVG = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%23f3f4f6"><rect width="100" height="100"/><text x="50" y="55" text-anchor="middle" fill="%239ca3af" font-size="12">No Image</text></svg>';
49
+ var THUMBNAIL_EMPTY_SVG = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%23f3f4f6"><rect width="100" height="100"/></svg>';
50
+ var ProductDetailModal = (0, react_1.memo)(function (_a) {
51
+ var isOpen = _a.isOpen, setIsOpen = _a.setIsOpen, selectedProduct = _a.selectedProduct, selectedImageIndex = _a.selectedImageIndex, setSelectedImageIndex = _a.setSelectedImageIndex, selectedColor = _a.selectedColor, setSelectedColor = _a.setSelectedColor, quantity = _a.quantity, setQuantity = _a.setQuantity, handleAddFromModal = _a.handleAddFromModal, small = _a.small, big = _a.big;
52
+ return (react_1.default.createElement(Modal_1.default, { animation: "ScaleUp", duration: 0.3, open: isOpen, setOpen: setIsOpen, funcss: "funui_products_detail_modal max-width-600", title: react_1.default.createElement(RowFlex_1.default, { justify: "space-between", alignItems: "center" },
53
+ react_1.default.createElement(Text_1.default, { text: selectedProduct.name, size: "h3", funcss: "text-bold", block: true }),
54
+ react_1.default.createElement(Close_1.default, { onClick: function () { return setIsOpen(false); } })), body: react_1.default.createElement(Div_1.default, { funcss: "funui_products_detail_body" },
55
+ selectedProduct.images && selectedProduct.images.length > 0 && (react_1.default.createElement(Div_1.default, { funcss: "margin-bottom-20" },
56
+ react_1.default.createElement(Div_1.default, { funcss: "margin-bottom-10" },
57
+ react_1.default.createElement("img", { src: selectedProduct.images[selectedImageIndex], alt: selectedProduct.name, style: { width: '100%', borderRadius: '0.5rem' }, loading: "lazy", onError: function (e) {
58
+ e.target.src = DETAIL_EMPTY_SVG;
59
+ } })),
60
+ selectedProduct.images.length > 1 && (react_1.default.createElement(RowFlex_1.default, { gap: 1, wrap: "wrap" }, selectedProduct.images.map(function (image, index) { return (react_1.default.createElement(Div_1.default, { key: index, funcss: "cursor-pointer ".concat(selectedImageIndex === index ? 'border-2 border-primary' : 'border border-light'), onClick: function () { return setSelectedImageIndex(index); }, customStyle: {
61
+ width: '80px',
62
+ height: '80px',
63
+ borderRadius: '0.5rem',
64
+ overflow: 'hidden',
65
+ cursor: 'pointer'
66
+ } },
67
+ react_1.default.createElement("img", { src: image, alt: "".concat(selectedProduct.name, " ").concat(index + 1), loading: "lazy", style: {
68
+ width: '100%',
69
+ height: '100%',
70
+ objectFit: 'cover'
71
+ }, onError: function (e) {
72
+ e.target.src = THUMBNAIL_EMPTY_SVG;
73
+ } }))); }))))),
74
+ react_1.default.createElement(Div_1.default, { funcss: "funui_products_detail_info space-y-3" },
75
+ react_1.default.createElement(RowFlex_1.default, { justify: "space-between", alignItems: "center" },
76
+ react_1.default.createElement(Text_1.default, { text: "$".concat(selectedProduct.price.toFixed(2)), size: "h3", funcss: "text-bold" }),
77
+ selectedProduct.comparePrice && selectedProduct.comparePrice > selectedProduct.price && (react_1.default.createElement(Text_1.default, { text: "$".concat(selectedProduct.comparePrice.toFixed(2)), funcss: "text-light line-through" }))),
78
+ selectedProduct.description && (react_1.default.createElement(Text_1.default, { text: selectedProduct.description, funcss: "text-light line-height-1.6" })),
79
+ selectedProduct.colors && selectedProduct.colors.length > 0 && (react_1.default.createElement(Div_1.default, { funcss: "funui_products_color_selection space-y-2" },
80
+ react_1.default.createElement(Text_1.default, { text: "Color", funcss: "text-bold" }),
81
+ react_1.default.createElement(RowFlex_1.default, { gap: 1, wrap: "wrap" }, selectedProduct.colors.map(function (color) { return (react_1.default.createElement(Button_1.default, { key: color.name, onClick: function () { return setSelectedColor(color.name); }, funcss: "padding-10 rounded ".concat(selectedColor === color.name
82
+ ? 'border-2 border-primary'
83
+ : 'border border-light'), style: { backgroundColor: color.code }, "aria-label": color.name }, selectedColor === color.name && (react_1.default.createElement(pi_1.PiCheck, { style: { color: 'white' } })))); })))),
84
+ react_1.default.createElement(Div_1.default, { funcss: "funui_products_quantity_selection space-y-2" },
85
+ react_1.default.createElement(Text_1.default, { text: "Quantity", funcss: "text-bold" }),
86
+ react_1.default.createElement(RowFlex_1.default, { gap: 2, alignItems: "center" },
87
+ react_1.default.createElement(Button_1.default, { startIcon: "-", onClick: function () { return setQuantity(Math.max(1, quantity - 1)); }, disabled: quantity <= 1, color: "text", small: small }),
88
+ react_1.default.createElement(Input_1.default, { type: "number", value: quantity, onChange: function (e) {
89
+ var value = parseInt(e.target.value);
90
+ if (!isNaN(value)) {
91
+ setQuantity(Math.max(1, value));
92
+ }
93
+ }, funcss: "width-100 text-center", bordered: true }),
94
+ react_1.default.createElement(Button_1.default, { startIcon: react_1.default.createElement(pi_1.PiPlus, null), onClick: function () { return setQuantity(quantity + 1); }, color: "text", small: small }))))), footer: react_1.default.createElement(RowFlex_1.default, { gap: 1, justify: "flex-end", funcss: "funui_products_detail_footer" },
95
+ react_1.default.createElement(Button_1.default, { text: "Cancel", color: "text", onClick: function () { return setIsOpen(false); }, small: small }),
96
+ react_1.default.createElement(Button_1.default, { text: "Add to Cart - $".concat(((selectedProduct.price || 0) * quantity).toFixed(2)), bg: "primary", raised: true, startIcon: react_1.default.createElement(pi_1.PiShoppingCart, null), onClick: handleAddFromModal, small: small, big: big })) }));
97
+ });
98
+ ProductDetailModal.displayName = 'ProductDetailModal';
99
+ exports.default = ProductDetailModal;
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ export type Product = {
3
+ id: string;
4
+ name: string;
5
+ price: number;
6
+ comparePrice?: number;
7
+ description?: string;
8
+ images?: string[];
9
+ category?: string;
10
+ brand?: string;
11
+ tags?: string[];
12
+ colors?: {
13
+ name: string;
14
+ code: string;
15
+ }[];
16
+ sku?: string;
17
+ stock?: number;
18
+ rating?: number;
19
+ isNew?: boolean;
20
+ isSale?: boolean;
21
+ discountPercentage?: number;
22
+ };
23
+ export type CartItem = {
24
+ product: Product;
25
+ quantity: number;
26
+ selectedColor?: string;
27
+ };
28
+ type ProductsPageProps = {
29
+ products: Product[] | string;
30
+ title?: string;
31
+ showHeader?: boolean;
32
+ showSearch?: boolean;
33
+ showFilters?: boolean;
34
+ showCart?: boolean;
35
+ cartIcon?: string | React.ReactNode;
36
+ cartBadgeColor?: string;
37
+ cartBadgeText?: string;
38
+ checkoutText?: string;
39
+ checkoutIcon?: string | React.ReactNode;
40
+ onAddToCart?: (item: CartItem) => void;
41
+ onRemoveFromCart?: (itemId: string) => void;
42
+ onUpdateQuantity?: (itemId: string, quantity: number) => void;
43
+ onCheckout?: (cartItems: CartItem[], totalAmount: number) => void;
44
+ onProductClick?: (product: Product) => void;
45
+ className?: string;
46
+ gridClassName?: string;
47
+ children?: React.ReactNode;
48
+ style?: React.CSSProperties;
49
+ id?: string;
50
+ funcss?: string;
51
+ bg?: string;
52
+ color?: string;
53
+ rounded?: boolean;
54
+ raised?: boolean;
55
+ fullWidth?: boolean;
56
+ small?: boolean;
57
+ big?: boolean;
58
+ };
59
+ declare const Products: React.FC<ProductsPageProps>;
60
+ export default Products;