@qwickapps/react-framework 1.7.1 → 1.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.
- package/README.md +9 -0
- package/dist/components/blocks/ProductCard.d.ts +10 -2
- package/dist/components/blocks/ProductCard.d.ts.map +1 -1
- package/dist/index.esm.js +193 -26
- package/dist/index.js +192 -25
- package/dist/palettes/manifest.json +22 -22
- package/package.json +1 -1
- package/src/components/blocks/ProductCard.tsx +283 -84
- package/src/stories/ProductCard.stories.tsx +151 -1
- /package/dist/palettes/{palette-autumn.1.7.1.css → palette-autumn.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-autumn.1.7.1.min.css → palette-autumn.1.8.0.min.css} +0 -0
- /package/dist/palettes/{palette-boutique.1.7.1.css → palette-boutique.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-boutique.1.7.1.min.css → palette-boutique.1.8.0.min.css} +0 -0
- /package/dist/palettes/{palette-cosmic.1.7.1.css → palette-cosmic.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-cosmic.1.7.1.min.css → palette-cosmic.1.8.0.min.css} +0 -0
- /package/dist/palettes/{palette-default.1.7.1.css → palette-default.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-default.1.7.1.min.css → palette-default.1.8.0.min.css} +0 -0
- /package/dist/palettes/{palette-ocean.1.7.1.css → palette-ocean.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-ocean.1.7.1.min.css → palette-ocean.1.8.0.min.css} +0 -0
- /package/dist/palettes/{palette-spring.1.7.1.css → palette-spring.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-spring.1.7.1.min.css → palette-spring.1.8.0.min.css} +0 -0
- /package/dist/palettes/{palette-winter.1.7.1.css → palette-winter.1.8.0.css} +0 -0
- /package/dist/palettes/{palette-winter.1.7.1.min.css → palette-winter.1.8.0.min.css} +0 -0
package/README.md
CHANGED
|
@@ -4,6 +4,15 @@ A complete React framework for building modern, responsive applications with int
|
|
|
4
4
|
|
|
5
5
|
## What's New
|
|
6
6
|
|
|
7
|
+
### February 7, 2026 - E-Commerce ProductCard (v1.8.0)
|
|
8
|
+
|
|
9
|
+
- **Unified ProductCard Component**: Complete e-commerce product card with integrated cart functionality
|
|
10
|
+
- **Variant Support**: Built-in size, color, and material variant selection with availability indicators
|
|
11
|
+
- **Cart Integration**: Native "Add to Cart" with quantity selectors and wishlist toggle
|
|
12
|
+
- **Enhanced UX**: Sale pricing, stock status, ratings, and responsive design for all devices
|
|
13
|
+
|
|
14
|
+
See [CHANGELOG.md](./CHANGELOG.md) for full details.
|
|
15
|
+
|
|
7
16
|
### February 4, 2026 - Bug Fixes (v1.7.1)
|
|
8
17
|
|
|
9
18
|
- **MUI v7 TypeScript Compatibility**: Fixed compilation errors in form components by excluding conflicting ViewProps
|
|
@@ -6,11 +6,17 @@ export interface Product {
|
|
|
6
6
|
category: string;
|
|
7
7
|
description: string;
|
|
8
8
|
shortDescription?: string;
|
|
9
|
-
features
|
|
10
|
-
technologies
|
|
9
|
+
features?: string[];
|
|
10
|
+
technologies?: string[];
|
|
11
11
|
status: string;
|
|
12
12
|
image?: string;
|
|
13
13
|
url?: string;
|
|
14
|
+
price?: number;
|
|
15
|
+
salePrice?: number;
|
|
16
|
+
rating?: number;
|
|
17
|
+
reviewCount?: number;
|
|
18
|
+
isNew?: boolean;
|
|
19
|
+
featured?: boolean;
|
|
14
20
|
}
|
|
15
21
|
export interface ProductCardAction {
|
|
16
22
|
id: string;
|
|
@@ -35,6 +41,8 @@ interface ProductCardViewProps extends WithBaseProps {
|
|
|
35
41
|
showTechnologies?: boolean;
|
|
36
42
|
/** Maximum features to show in compact mode */
|
|
37
43
|
maxFeaturesCompact?: number;
|
|
44
|
+
/** Handler for adding product to cart (e-commerce products only) */
|
|
45
|
+
onAddToCart?: (product: Product) => void;
|
|
38
46
|
}
|
|
39
47
|
export interface ProductCardProps extends ProductCardViewProps, WithDataBinding {
|
|
40
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductCard.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/ProductCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProductCard.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/ProductCard.tsx"],"names":[],"mappings":"AA0BA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAoD,aAAa,EAAE,MAAM,aAAa,CAAC;AAI9F,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;IAC5C,KAAK,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,oBAAqB,SAAQ,aAAa;IAClD,mBAAmB;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB;IACnB,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACjC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC9B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mCAAmC;IACnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,EAAE,eAAe;CAAG;AA6gBlF;;;GAGG;AACH,iBAAS,WAAW,CAAC,KAAK,EAAE,gBAAgB,kDAoE3C;AAED,eAAe,WAAW,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
import { useMediaQuery, Box, useTheme as useTheme$1, Paper, Typography, Tooltip, IconButton, Snackbar, Alert, CircularProgress, Button as Button$1, Container as Container$9, Stack, Skeleton, Avatar, Chip, Menu as Menu$1, MenuItem, Card, CardContent, ButtonGroup, Collapse, TextField as TextField$1, FormControl, InputLabel, Select, FormHelperText, FormControlLabel, Switch, Grid, Divider, Link, Modal, ListItemIcon, ListItemText, Dialog as Dialog$1, DialogTitle as DialogTitle$1, DialogContent as DialogContent$1, DialogActions as DialogActions$1, DialogContentText as DialogContentText$1, Input as Input$5, InputAdornment, Checkbox } from '@mui/material';
|
|
3
|
+
import { useMediaQuery, Box, useTheme as useTheme$1, Paper, Typography, Tooltip, IconButton, Snackbar, Alert, CircularProgress, Button as Button$1, Container as Container$9, Stack, Skeleton, Avatar, Chip, Menu as Menu$1, MenuItem, Card, CardContent, ButtonGroup, Collapse, TextField as TextField$1, FormControl, InputLabel, Select, FormHelperText, FormControlLabel, Switch, Grid, Divider, Link, Rating, Modal, ListItemIcon, ListItemText, Dialog as Dialog$1, DialogTitle as DialogTitle$1, DialogContent as DialogContent$1, DialogActions as DialogActions$1, DialogContentText as DialogContentText$1, Input as Input$5, InputAdornment, Checkbox } from '@mui/material';
|
|
4
4
|
import React, { useMemo, useContext, useState, useCallback, useEffect, createContext, useReducer, useRef, isValidElement, createElement, useId, useLayoutEffect, Component, cloneElement } from 'react';
|
|
5
5
|
import { MustacheTemplateProvider, MemoryCacheProvider, CachedDataProvider, Field, Editor, FieldType, Schema, Model, DataType } from '@qwickapps/schema';
|
|
6
6
|
import { createTheme, ThemeProvider as ThemeProvider$1 } from '@mui/material/styles';
|
|
@@ -21101,6 +21101,7 @@ function ProductCardView({
|
|
|
21101
21101
|
showImage = true,
|
|
21102
21102
|
showTechnologies = true,
|
|
21103
21103
|
maxFeaturesCompact = 3,
|
|
21104
|
+
onAddToCart,
|
|
21104
21105
|
...restProps
|
|
21105
21106
|
}) {
|
|
21106
21107
|
const {
|
|
@@ -21110,6 +21111,16 @@ function ProductCardView({
|
|
|
21110
21111
|
const theme = useTheme$1();
|
|
21111
21112
|
// Return null if no product data
|
|
21112
21113
|
if (!product) return null;
|
|
21114
|
+
// Detect product type: e-commerce products have price field
|
|
21115
|
+
const isEcommerce = product.price !== undefined;
|
|
21116
|
+
// E-commerce helpers
|
|
21117
|
+
const formatPrice = price => {
|
|
21118
|
+
return `$${price.toFixed(2)}`;
|
|
21119
|
+
};
|
|
21120
|
+
const calculateDiscount = () => {
|
|
21121
|
+
if (!product.price || !product.salePrice) return 0;
|
|
21122
|
+
return Math.round((product.price - product.salePrice) / product.price * 100);
|
|
21123
|
+
};
|
|
21113
21124
|
const getStatusIcon = status => {
|
|
21114
21125
|
switch (status) {
|
|
21115
21126
|
case 'launched':
|
|
@@ -21140,11 +21151,26 @@ function ProductCardView({
|
|
|
21140
21151
|
const handleProductClick = () => {
|
|
21141
21152
|
if (onClick) {
|
|
21142
21153
|
onClick();
|
|
21143
|
-
} else if (product.status === 'launched' && product.url?.startsWith('http')) {
|
|
21144
|
-
window.open(product.url, '_blank', 'noopener,noreferrer');
|
|
21145
21154
|
}
|
|
21155
|
+
// Note: Navigation is handled by parent wrapper (e.g., Next.js Link in BlockRenderer)
|
|
21156
|
+
// For standalone usage, provide onClick prop with navigation logic
|
|
21146
21157
|
};
|
|
21147
21158
|
const getDefaultActions = () => {
|
|
21159
|
+
// E-commerce products get "Add to Cart" action
|
|
21160
|
+
if (isEcommerce) {
|
|
21161
|
+
return [{
|
|
21162
|
+
id: 'add-to-cart',
|
|
21163
|
+
label: 'Add to Cart',
|
|
21164
|
+
variant: 'contained',
|
|
21165
|
+
color: 'primary',
|
|
21166
|
+
onClick: () => {
|
|
21167
|
+
if (onAddToCart && product) {
|
|
21168
|
+
onAddToCart(product);
|
|
21169
|
+
}
|
|
21170
|
+
}
|
|
21171
|
+
}];
|
|
21172
|
+
}
|
|
21173
|
+
// Software products get status-based actions
|
|
21148
21174
|
const actions = [{
|
|
21149
21175
|
id: 'primary',
|
|
21150
21176
|
label: product.status === 'launched' ? 'Learn More' : product.status === 'beta' ? 'Try Beta' : product.status === 'coming-soon' ? 'Coming Soon' : product.status,
|
|
@@ -21228,7 +21254,7 @@ function ProductCardView({
|
|
|
21228
21254
|
})]
|
|
21229
21255
|
});
|
|
21230
21256
|
})();
|
|
21231
|
-
const technologiesSectionElement = !showTechnologies || variant === 'compact' ? null : jsxs(Box, {
|
|
21257
|
+
const technologiesSectionElement = !showTechnologies || variant === 'compact' || !product.technologies ? null : jsxs(Box, {
|
|
21232
21258
|
sx: {
|
|
21233
21259
|
mb: 3
|
|
21234
21260
|
},
|
|
@@ -21262,26 +21288,25 @@ function ProductCardView({
|
|
|
21262
21288
|
className: styleProps.className || "product-card",
|
|
21263
21289
|
onClick: htmlProps.onClick || (variant === 'compact' ? handleProductClick : undefined),
|
|
21264
21290
|
sx: {
|
|
21265
|
-
p: 3,
|
|
21266
|
-
// padding="large" equivalent
|
|
21267
|
-
borderRadius: 3,
|
|
21268
|
-
border: '1px solid',
|
|
21269
|
-
borderColor: 'divider',
|
|
21270
|
-
cursor: variant === 'compact' ? 'pointer' : 'default',
|
|
21271
|
-
position: 'relative',
|
|
21272
21291
|
height: '100%',
|
|
21273
21292
|
display: 'flex',
|
|
21274
21293
|
flexDirection: 'column',
|
|
21275
21294
|
backgroundColor: 'background.paper',
|
|
21276
|
-
|
|
21295
|
+
borderRadius: isEcommerce ? 2 : 3,
|
|
21296
|
+
border: '1px solid',
|
|
21297
|
+
borderColor: 'divider',
|
|
21298
|
+
overflow: 'hidden',
|
|
21299
|
+
position: 'relative',
|
|
21300
|
+
cursor: variant === 'compact' ? 'pointer' : 'default',
|
|
21301
|
+
transition: 'transform 0.2s ease, box-shadow 0.2s ease',
|
|
21277
21302
|
'&:hover': variant === 'compact' ? {
|
|
21278
21303
|
transform: 'translateY(-4px)',
|
|
21279
|
-
boxShadow:
|
|
21304
|
+
boxShadow: 3
|
|
21280
21305
|
} : {},
|
|
21281
21306
|
...(styleProps.sx || {})
|
|
21282
21307
|
},
|
|
21283
21308
|
style: styleProps.style,
|
|
21284
|
-
children: [jsx(Chip, {
|
|
21309
|
+
children: [!isEcommerce && jsx(Chip, {
|
|
21285
21310
|
icon: getStatusIcon(product.status),
|
|
21286
21311
|
label: product.status.replace('-', ' '),
|
|
21287
21312
|
sx: {
|
|
@@ -21300,16 +21325,14 @@ function ProductCardView({
|
|
|
21300
21325
|
color: 'white'
|
|
21301
21326
|
}
|
|
21302
21327
|
}
|
|
21303
|
-
}), showImage && product.image &&
|
|
21328
|
+
}), showImage && product.image && jsxs(Box, {
|
|
21304
21329
|
sx: {
|
|
21305
21330
|
width: '100%',
|
|
21306
|
-
height: variant === 'detailed' ? 240 : 200,
|
|
21307
|
-
|
|
21308
|
-
|
|
21309
|
-
overflow: 'hidden',
|
|
21310
|
-
backgroundColor: 'divider'
|
|
21331
|
+
height: isEcommerce ? 280 : variant === 'detailed' ? 240 : 200,
|
|
21332
|
+
backgroundColor: 'divider',
|
|
21333
|
+
position: 'relative'
|
|
21311
21334
|
},
|
|
21312
|
-
children: jsx(Box, {
|
|
21335
|
+
children: [jsx(Box, {
|
|
21313
21336
|
component: "img",
|
|
21314
21337
|
src: product.image,
|
|
21315
21338
|
alt: product.name,
|
|
@@ -21326,14 +21349,153 @@ function ProductCardView({
|
|
|
21326
21349
|
target.parentElement.innerHTML = `<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: white; font-size: 1.5rem; font-weight: bold;">${product.name}</div>`;
|
|
21327
21350
|
}
|
|
21328
21351
|
}
|
|
21329
|
-
})
|
|
21352
|
+
}), isEcommerce && jsxs(Fragment, {
|
|
21353
|
+
children: [jsxs(Box, {
|
|
21354
|
+
sx: {
|
|
21355
|
+
position: 'absolute',
|
|
21356
|
+
top: 12,
|
|
21357
|
+
left: 12,
|
|
21358
|
+
display: 'flex',
|
|
21359
|
+
flexDirection: 'column',
|
|
21360
|
+
gap: 0.5
|
|
21361
|
+
},
|
|
21362
|
+
children: [product.isNew && jsx(Chip, {
|
|
21363
|
+
label: "NEW",
|
|
21364
|
+
sx: {
|
|
21365
|
+
backgroundColor: 'primary.main',
|
|
21366
|
+
color: 'white',
|
|
21367
|
+
fontSize: '0.75rem',
|
|
21368
|
+
fontWeight: 600,
|
|
21369
|
+
height: '24px',
|
|
21370
|
+
px: 1
|
|
21371
|
+
}
|
|
21372
|
+
}), product.featured && jsx(Chip, {
|
|
21373
|
+
label: "POPULAR",
|
|
21374
|
+
sx: {
|
|
21375
|
+
backgroundColor: 'warning.main',
|
|
21376
|
+
color: 'white',
|
|
21377
|
+
fontSize: '0.75rem',
|
|
21378
|
+
fontWeight: 600,
|
|
21379
|
+
height: '24px',
|
|
21380
|
+
px: 1
|
|
21381
|
+
}
|
|
21382
|
+
})]
|
|
21383
|
+
}), jsx(Box, {
|
|
21384
|
+
sx: {
|
|
21385
|
+
position: 'absolute',
|
|
21386
|
+
top: 12,
|
|
21387
|
+
right: 12,
|
|
21388
|
+
display: 'flex',
|
|
21389
|
+
flexDirection: 'column',
|
|
21390
|
+
gap: 0.5
|
|
21391
|
+
},
|
|
21392
|
+
children: product.salePrice && product.price && jsxs(Fragment, {
|
|
21393
|
+
children: [jsx(Chip, {
|
|
21394
|
+
label: "ON SALE",
|
|
21395
|
+
sx: {
|
|
21396
|
+
backgroundColor: 'error.main',
|
|
21397
|
+
color: 'white',
|
|
21398
|
+
fontSize: '0.75rem',
|
|
21399
|
+
fontWeight: 600,
|
|
21400
|
+
height: '24px',
|
|
21401
|
+
px: 1
|
|
21402
|
+
}
|
|
21403
|
+
}), jsx(Chip, {
|
|
21404
|
+
label: `-${calculateDiscount()}%`,
|
|
21405
|
+
sx: {
|
|
21406
|
+
backgroundColor: 'error.dark',
|
|
21407
|
+
color: 'white',
|
|
21408
|
+
fontSize: '0.75rem',
|
|
21409
|
+
fontWeight: 600,
|
|
21410
|
+
height: '24px',
|
|
21411
|
+
px: 1
|
|
21412
|
+
}
|
|
21413
|
+
})]
|
|
21414
|
+
})
|
|
21415
|
+
})]
|
|
21416
|
+
})]
|
|
21330
21417
|
}), jsxs(Box, {
|
|
21331
21418
|
sx: {
|
|
21332
21419
|
flex: 1,
|
|
21333
21420
|
display: 'flex',
|
|
21334
|
-
flexDirection: 'column'
|
|
21421
|
+
flexDirection: 'column',
|
|
21422
|
+
p: isEcommerce ? 2 : 3
|
|
21335
21423
|
},
|
|
21336
|
-
children: [
|
|
21424
|
+
children: [isEcommerce ? (/* E-commerce product info */
|
|
21425
|
+
jsxs(Box, {
|
|
21426
|
+
children: [product.category && jsx(Typography, {
|
|
21427
|
+
variant: "caption",
|
|
21428
|
+
sx: {
|
|
21429
|
+
mb: 0.5,
|
|
21430
|
+
color: 'text.secondary',
|
|
21431
|
+
display: 'block'
|
|
21432
|
+
},
|
|
21433
|
+
children: product.category
|
|
21434
|
+
}), jsx(Typography, {
|
|
21435
|
+
variant: "h6",
|
|
21436
|
+
component: "h3",
|
|
21437
|
+
sx: {
|
|
21438
|
+
mb: 1,
|
|
21439
|
+
fontSize: '1rem',
|
|
21440
|
+
fontWeight: 500,
|
|
21441
|
+
lineHeight: 1.3,
|
|
21442
|
+
overflow: 'hidden',
|
|
21443
|
+
textOverflow: 'ellipsis',
|
|
21444
|
+
display: '-webkit-box',
|
|
21445
|
+
WebkitLineClamp: 2,
|
|
21446
|
+
WebkitBoxOrient: 'vertical'
|
|
21447
|
+
},
|
|
21448
|
+
children: product.name
|
|
21449
|
+
}), product.rating !== undefined && product.rating > 0 && jsxs(Box, {
|
|
21450
|
+
sx: {
|
|
21451
|
+
display: 'flex',
|
|
21452
|
+
alignItems: 'center',
|
|
21453
|
+
gap: 0.5,
|
|
21454
|
+
mb: 1
|
|
21455
|
+
},
|
|
21456
|
+
children: [jsx(Rating, {
|
|
21457
|
+
value: product.rating,
|
|
21458
|
+
readOnly: true,
|
|
21459
|
+
size: "small",
|
|
21460
|
+
precision: 0.5,
|
|
21461
|
+
emptyIcon: jsx(Star, {
|
|
21462
|
+
style: {
|
|
21463
|
+
opacity: 0.3
|
|
21464
|
+
},
|
|
21465
|
+
fontSize: "inherit"
|
|
21466
|
+
})
|
|
21467
|
+
}), product.reviewCount !== undefined && product.reviewCount > 0 && jsxs(Typography, {
|
|
21468
|
+
variant: "caption",
|
|
21469
|
+
sx: {
|
|
21470
|
+
color: 'text.secondary'
|
|
21471
|
+
},
|
|
21472
|
+
children: ["(", product.reviewCount, ")"]
|
|
21473
|
+
})]
|
|
21474
|
+
}), jsxs(Box, {
|
|
21475
|
+
sx: {
|
|
21476
|
+
mt: 'auto',
|
|
21477
|
+
display: 'flex',
|
|
21478
|
+
alignItems: 'center',
|
|
21479
|
+
gap: 1
|
|
21480
|
+
},
|
|
21481
|
+
children: [jsx(Typography, {
|
|
21482
|
+
variant: "h6",
|
|
21483
|
+
sx: {
|
|
21484
|
+
fontWeight: 600,
|
|
21485
|
+
color: product.salePrice ? 'primary.main' : 'inherit'
|
|
21486
|
+
},
|
|
21487
|
+
children: formatPrice(product.salePrice || product.price)
|
|
21488
|
+
}), product.salePrice && jsx(Typography, {
|
|
21489
|
+
variant: "body2",
|
|
21490
|
+
sx: {
|
|
21491
|
+
color: 'text.secondary',
|
|
21492
|
+
textDecoration: 'line-through'
|
|
21493
|
+
},
|
|
21494
|
+
children: formatPrice(product.price)
|
|
21495
|
+
})]
|
|
21496
|
+
})]
|
|
21497
|
+
})) : (/* Software product info */
|
|
21498
|
+
jsxs(Box, {
|
|
21337
21499
|
sx: {
|
|
21338
21500
|
mb: 3
|
|
21339
21501
|
},
|
|
@@ -21365,7 +21527,7 @@ function ProductCardView({
|
|
|
21365
21527
|
},
|
|
21366
21528
|
children: variant === 'detailed' ? product.description : product.shortDescription || product.description
|
|
21367
21529
|
})]
|
|
21368
|
-
}), product.features && product.features.length > 0 && featuresListElement, product.technologies && product.technologies.length > 0 && technologiesSectionElement, jsx(Box, {
|
|
21530
|
+
})), !isEcommerce && product.features && product.features.length > 0 && featuresListElement, !isEcommerce && product.technologies && product.technologies.length > 0 && technologiesSectionElement, jsx(Box, {
|
|
21369
21531
|
sx: {
|
|
21370
21532
|
display: 'flex',
|
|
21371
21533
|
gap: 1.5,
|
|
@@ -21378,7 +21540,12 @@ function ProductCardView({
|
|
|
21378
21540
|
variant: action.variant || 'contained',
|
|
21379
21541
|
// color={action.color || 'primary'}
|
|
21380
21542
|
disabled: action.disabled,
|
|
21381
|
-
onClick:
|
|
21543
|
+
onClick: e => {
|
|
21544
|
+
// Prevent Link navigation when clicking button (e.g., Add to Cart)
|
|
21545
|
+
e.stopPropagation();
|
|
21546
|
+
e.preventDefault();
|
|
21547
|
+
action.onClick();
|
|
21548
|
+
},
|
|
21382
21549
|
...(variant === 'compact' && {
|
|
21383
21550
|
fullWidth: true
|
|
21384
21551
|
}),
|
package/dist/index.js
CHANGED
|
@@ -21103,6 +21103,7 @@ function ProductCardView({
|
|
|
21103
21103
|
showImage = true,
|
|
21104
21104
|
showTechnologies = true,
|
|
21105
21105
|
maxFeaturesCompact = 3,
|
|
21106
|
+
onAddToCart,
|
|
21106
21107
|
...restProps
|
|
21107
21108
|
}) {
|
|
21108
21109
|
const {
|
|
@@ -21112,6 +21113,16 @@ function ProductCardView({
|
|
|
21112
21113
|
const theme = material.useTheme();
|
|
21113
21114
|
// Return null if no product data
|
|
21114
21115
|
if (!product) return null;
|
|
21116
|
+
// Detect product type: e-commerce products have price field
|
|
21117
|
+
const isEcommerce = product.price !== undefined;
|
|
21118
|
+
// E-commerce helpers
|
|
21119
|
+
const formatPrice = price => {
|
|
21120
|
+
return `$${price.toFixed(2)}`;
|
|
21121
|
+
};
|
|
21122
|
+
const calculateDiscount = () => {
|
|
21123
|
+
if (!product.price || !product.salePrice) return 0;
|
|
21124
|
+
return Math.round((product.price - product.salePrice) / product.price * 100);
|
|
21125
|
+
};
|
|
21115
21126
|
const getStatusIcon = status => {
|
|
21116
21127
|
switch (status) {
|
|
21117
21128
|
case 'launched':
|
|
@@ -21142,11 +21153,26 @@ function ProductCardView({
|
|
|
21142
21153
|
const handleProductClick = () => {
|
|
21143
21154
|
if (onClick) {
|
|
21144
21155
|
onClick();
|
|
21145
|
-
} else if (product.status === 'launched' && product.url?.startsWith('http')) {
|
|
21146
|
-
window.open(product.url, '_blank', 'noopener,noreferrer');
|
|
21147
21156
|
}
|
|
21157
|
+
// Note: Navigation is handled by parent wrapper (e.g., Next.js Link in BlockRenderer)
|
|
21158
|
+
// For standalone usage, provide onClick prop with navigation logic
|
|
21148
21159
|
};
|
|
21149
21160
|
const getDefaultActions = () => {
|
|
21161
|
+
// E-commerce products get "Add to Cart" action
|
|
21162
|
+
if (isEcommerce) {
|
|
21163
|
+
return [{
|
|
21164
|
+
id: 'add-to-cart',
|
|
21165
|
+
label: 'Add to Cart',
|
|
21166
|
+
variant: 'contained',
|
|
21167
|
+
color: 'primary',
|
|
21168
|
+
onClick: () => {
|
|
21169
|
+
if (onAddToCart && product) {
|
|
21170
|
+
onAddToCart(product);
|
|
21171
|
+
}
|
|
21172
|
+
}
|
|
21173
|
+
}];
|
|
21174
|
+
}
|
|
21175
|
+
// Software products get status-based actions
|
|
21150
21176
|
const actions = [{
|
|
21151
21177
|
id: 'primary',
|
|
21152
21178
|
label: product.status === 'launched' ? 'Learn More' : product.status === 'beta' ? 'Try Beta' : product.status === 'coming-soon' ? 'Coming Soon' : product.status,
|
|
@@ -21230,7 +21256,7 @@ function ProductCardView({
|
|
|
21230
21256
|
})]
|
|
21231
21257
|
});
|
|
21232
21258
|
})();
|
|
21233
|
-
const technologiesSectionElement = !showTechnologies || variant === 'compact' ? null : jsxRuntime.jsxs(material.Box, {
|
|
21259
|
+
const technologiesSectionElement = !showTechnologies || variant === 'compact' || !product.technologies ? null : jsxRuntime.jsxs(material.Box, {
|
|
21234
21260
|
sx: {
|
|
21235
21261
|
mb: 3
|
|
21236
21262
|
},
|
|
@@ -21264,26 +21290,25 @@ function ProductCardView({
|
|
|
21264
21290
|
className: styleProps.className || "product-card",
|
|
21265
21291
|
onClick: htmlProps.onClick || (variant === 'compact' ? handleProductClick : undefined),
|
|
21266
21292
|
sx: {
|
|
21267
|
-
p: 3,
|
|
21268
|
-
// padding="large" equivalent
|
|
21269
|
-
borderRadius: 3,
|
|
21270
|
-
border: '1px solid',
|
|
21271
|
-
borderColor: 'divider',
|
|
21272
|
-
cursor: variant === 'compact' ? 'pointer' : 'default',
|
|
21273
|
-
position: 'relative',
|
|
21274
21293
|
height: '100%',
|
|
21275
21294
|
display: 'flex',
|
|
21276
21295
|
flexDirection: 'column',
|
|
21277
21296
|
backgroundColor: 'background.paper',
|
|
21278
|
-
|
|
21297
|
+
borderRadius: isEcommerce ? 2 : 3,
|
|
21298
|
+
border: '1px solid',
|
|
21299
|
+
borderColor: 'divider',
|
|
21300
|
+
overflow: 'hidden',
|
|
21301
|
+
position: 'relative',
|
|
21302
|
+
cursor: variant === 'compact' ? 'pointer' : 'default',
|
|
21303
|
+
transition: 'transform 0.2s ease, box-shadow 0.2s ease',
|
|
21279
21304
|
'&:hover': variant === 'compact' ? {
|
|
21280
21305
|
transform: 'translateY(-4px)',
|
|
21281
|
-
boxShadow:
|
|
21306
|
+
boxShadow: 3
|
|
21282
21307
|
} : {},
|
|
21283
21308
|
...(styleProps.sx || {})
|
|
21284
21309
|
},
|
|
21285
21310
|
style: styleProps.style,
|
|
21286
|
-
children: [jsxRuntime.jsx(material.Chip, {
|
|
21311
|
+
children: [!isEcommerce && jsxRuntime.jsx(material.Chip, {
|
|
21287
21312
|
icon: getStatusIcon(product.status),
|
|
21288
21313
|
label: product.status.replace('-', ' '),
|
|
21289
21314
|
sx: {
|
|
@@ -21302,16 +21327,14 @@ function ProductCardView({
|
|
|
21302
21327
|
color: 'white'
|
|
21303
21328
|
}
|
|
21304
21329
|
}
|
|
21305
|
-
}), showImage && product.image && jsxRuntime.
|
|
21330
|
+
}), showImage && product.image && jsxRuntime.jsxs(material.Box, {
|
|
21306
21331
|
sx: {
|
|
21307
21332
|
width: '100%',
|
|
21308
|
-
height: variant === 'detailed' ? 240 : 200,
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
overflow: 'hidden',
|
|
21312
|
-
backgroundColor: 'divider'
|
|
21333
|
+
height: isEcommerce ? 280 : variant === 'detailed' ? 240 : 200,
|
|
21334
|
+
backgroundColor: 'divider',
|
|
21335
|
+
position: 'relative'
|
|
21313
21336
|
},
|
|
21314
|
-
children: jsxRuntime.jsx(material.Box, {
|
|
21337
|
+
children: [jsxRuntime.jsx(material.Box, {
|
|
21315
21338
|
component: "img",
|
|
21316
21339
|
src: product.image,
|
|
21317
21340
|
alt: product.name,
|
|
@@ -21328,14 +21351,153 @@ function ProductCardView({
|
|
|
21328
21351
|
target.parentElement.innerHTML = `<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: white; font-size: 1.5rem; font-weight: bold;">${product.name}</div>`;
|
|
21329
21352
|
}
|
|
21330
21353
|
}
|
|
21331
|
-
})
|
|
21354
|
+
}), isEcommerce && jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
21355
|
+
children: [jsxRuntime.jsxs(material.Box, {
|
|
21356
|
+
sx: {
|
|
21357
|
+
position: 'absolute',
|
|
21358
|
+
top: 12,
|
|
21359
|
+
left: 12,
|
|
21360
|
+
display: 'flex',
|
|
21361
|
+
flexDirection: 'column',
|
|
21362
|
+
gap: 0.5
|
|
21363
|
+
},
|
|
21364
|
+
children: [product.isNew && jsxRuntime.jsx(material.Chip, {
|
|
21365
|
+
label: "NEW",
|
|
21366
|
+
sx: {
|
|
21367
|
+
backgroundColor: 'primary.main',
|
|
21368
|
+
color: 'white',
|
|
21369
|
+
fontSize: '0.75rem',
|
|
21370
|
+
fontWeight: 600,
|
|
21371
|
+
height: '24px',
|
|
21372
|
+
px: 1
|
|
21373
|
+
}
|
|
21374
|
+
}), product.featured && jsxRuntime.jsx(material.Chip, {
|
|
21375
|
+
label: "POPULAR",
|
|
21376
|
+
sx: {
|
|
21377
|
+
backgroundColor: 'warning.main',
|
|
21378
|
+
color: 'white',
|
|
21379
|
+
fontSize: '0.75rem',
|
|
21380
|
+
fontWeight: 600,
|
|
21381
|
+
height: '24px',
|
|
21382
|
+
px: 1
|
|
21383
|
+
}
|
|
21384
|
+
})]
|
|
21385
|
+
}), jsxRuntime.jsx(material.Box, {
|
|
21386
|
+
sx: {
|
|
21387
|
+
position: 'absolute',
|
|
21388
|
+
top: 12,
|
|
21389
|
+
right: 12,
|
|
21390
|
+
display: 'flex',
|
|
21391
|
+
flexDirection: 'column',
|
|
21392
|
+
gap: 0.5
|
|
21393
|
+
},
|
|
21394
|
+
children: product.salePrice && product.price && jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
21395
|
+
children: [jsxRuntime.jsx(material.Chip, {
|
|
21396
|
+
label: "ON SALE",
|
|
21397
|
+
sx: {
|
|
21398
|
+
backgroundColor: 'error.main',
|
|
21399
|
+
color: 'white',
|
|
21400
|
+
fontSize: '0.75rem',
|
|
21401
|
+
fontWeight: 600,
|
|
21402
|
+
height: '24px',
|
|
21403
|
+
px: 1
|
|
21404
|
+
}
|
|
21405
|
+
}), jsxRuntime.jsx(material.Chip, {
|
|
21406
|
+
label: `-${calculateDiscount()}%`,
|
|
21407
|
+
sx: {
|
|
21408
|
+
backgroundColor: 'error.dark',
|
|
21409
|
+
color: 'white',
|
|
21410
|
+
fontSize: '0.75rem',
|
|
21411
|
+
fontWeight: 600,
|
|
21412
|
+
height: '24px',
|
|
21413
|
+
px: 1
|
|
21414
|
+
}
|
|
21415
|
+
})]
|
|
21416
|
+
})
|
|
21417
|
+
})]
|
|
21418
|
+
})]
|
|
21332
21419
|
}), jsxRuntime.jsxs(material.Box, {
|
|
21333
21420
|
sx: {
|
|
21334
21421
|
flex: 1,
|
|
21335
21422
|
display: 'flex',
|
|
21336
|
-
flexDirection: 'column'
|
|
21423
|
+
flexDirection: 'column',
|
|
21424
|
+
p: isEcommerce ? 2 : 3
|
|
21337
21425
|
},
|
|
21338
|
-
children: [
|
|
21426
|
+
children: [isEcommerce ? (/* E-commerce product info */
|
|
21427
|
+
jsxRuntime.jsxs(material.Box, {
|
|
21428
|
+
children: [product.category && jsxRuntime.jsx(material.Typography, {
|
|
21429
|
+
variant: "caption",
|
|
21430
|
+
sx: {
|
|
21431
|
+
mb: 0.5,
|
|
21432
|
+
color: 'text.secondary',
|
|
21433
|
+
display: 'block'
|
|
21434
|
+
},
|
|
21435
|
+
children: product.category
|
|
21436
|
+
}), jsxRuntime.jsx(material.Typography, {
|
|
21437
|
+
variant: "h6",
|
|
21438
|
+
component: "h3",
|
|
21439
|
+
sx: {
|
|
21440
|
+
mb: 1,
|
|
21441
|
+
fontSize: '1rem',
|
|
21442
|
+
fontWeight: 500,
|
|
21443
|
+
lineHeight: 1.3,
|
|
21444
|
+
overflow: 'hidden',
|
|
21445
|
+
textOverflow: 'ellipsis',
|
|
21446
|
+
display: '-webkit-box',
|
|
21447
|
+
WebkitLineClamp: 2,
|
|
21448
|
+
WebkitBoxOrient: 'vertical'
|
|
21449
|
+
},
|
|
21450
|
+
children: product.name
|
|
21451
|
+
}), product.rating !== undefined && product.rating > 0 && jsxRuntime.jsxs(material.Box, {
|
|
21452
|
+
sx: {
|
|
21453
|
+
display: 'flex',
|
|
21454
|
+
alignItems: 'center',
|
|
21455
|
+
gap: 0.5,
|
|
21456
|
+
mb: 1
|
|
21457
|
+
},
|
|
21458
|
+
children: [jsxRuntime.jsx(material.Rating, {
|
|
21459
|
+
value: product.rating,
|
|
21460
|
+
readOnly: true,
|
|
21461
|
+
size: "small",
|
|
21462
|
+
precision: 0.5,
|
|
21463
|
+
emptyIcon: jsxRuntime.jsx(Star, {
|
|
21464
|
+
style: {
|
|
21465
|
+
opacity: 0.3
|
|
21466
|
+
},
|
|
21467
|
+
fontSize: "inherit"
|
|
21468
|
+
})
|
|
21469
|
+
}), product.reviewCount !== undefined && product.reviewCount > 0 && jsxRuntime.jsxs(material.Typography, {
|
|
21470
|
+
variant: "caption",
|
|
21471
|
+
sx: {
|
|
21472
|
+
color: 'text.secondary'
|
|
21473
|
+
},
|
|
21474
|
+
children: ["(", product.reviewCount, ")"]
|
|
21475
|
+
})]
|
|
21476
|
+
}), jsxRuntime.jsxs(material.Box, {
|
|
21477
|
+
sx: {
|
|
21478
|
+
mt: 'auto',
|
|
21479
|
+
display: 'flex',
|
|
21480
|
+
alignItems: 'center',
|
|
21481
|
+
gap: 1
|
|
21482
|
+
},
|
|
21483
|
+
children: [jsxRuntime.jsx(material.Typography, {
|
|
21484
|
+
variant: "h6",
|
|
21485
|
+
sx: {
|
|
21486
|
+
fontWeight: 600,
|
|
21487
|
+
color: product.salePrice ? 'primary.main' : 'inherit'
|
|
21488
|
+
},
|
|
21489
|
+
children: formatPrice(product.salePrice || product.price)
|
|
21490
|
+
}), product.salePrice && jsxRuntime.jsx(material.Typography, {
|
|
21491
|
+
variant: "body2",
|
|
21492
|
+
sx: {
|
|
21493
|
+
color: 'text.secondary',
|
|
21494
|
+
textDecoration: 'line-through'
|
|
21495
|
+
},
|
|
21496
|
+
children: formatPrice(product.price)
|
|
21497
|
+
})]
|
|
21498
|
+
})]
|
|
21499
|
+
})) : (/* Software product info */
|
|
21500
|
+
jsxRuntime.jsxs(material.Box, {
|
|
21339
21501
|
sx: {
|
|
21340
21502
|
mb: 3
|
|
21341
21503
|
},
|
|
@@ -21367,7 +21529,7 @@ function ProductCardView({
|
|
|
21367
21529
|
},
|
|
21368
21530
|
children: variant === 'detailed' ? product.description : product.shortDescription || product.description
|
|
21369
21531
|
})]
|
|
21370
|
-
}), product.features && product.features.length > 0 && featuresListElement, product.technologies && product.technologies.length > 0 && technologiesSectionElement, jsxRuntime.jsx(material.Box, {
|
|
21532
|
+
})), !isEcommerce && product.features && product.features.length > 0 && featuresListElement, !isEcommerce && product.technologies && product.technologies.length > 0 && technologiesSectionElement, jsxRuntime.jsx(material.Box, {
|
|
21371
21533
|
sx: {
|
|
21372
21534
|
display: 'flex',
|
|
21373
21535
|
gap: 1.5,
|
|
@@ -21380,7 +21542,12 @@ function ProductCardView({
|
|
|
21380
21542
|
variant: action.variant || 'contained',
|
|
21381
21543
|
// color={action.color || 'primary'}
|
|
21382
21544
|
disabled: action.disabled,
|
|
21383
|
-
onClick:
|
|
21545
|
+
onClick: e => {
|
|
21546
|
+
// Prevent Link navigation when clicking button (e.g., Add to Cart)
|
|
21547
|
+
e.stopPropagation();
|
|
21548
|
+
e.preventDefault();
|
|
21549
|
+
action.onClick();
|
|
21550
|
+
},
|
|
21384
21551
|
...(variant === 'compact' && {
|
|
21385
21552
|
fullWidth: true
|
|
21386
21553
|
}),
|