@enadhq/enad-react-sdk 1.2.0 → 1.3.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/dist/client/storefront/blocks/card-video.mjs +1 -1
- package/dist/client/storefront/blocks/card-video.mjs.map +1 -1
- package/dist/client/storefront/blocks/gallery-with-link-blocks.d.ts.map +1 -1
- package/dist/client/storefront/blocks/gallery-with-link-blocks.mjs +13 -5
- package/dist/client/storefront/blocks/gallery-with-link-blocks.mjs.map +1 -1
- package/dist/client/storefront/blocks/gallery.d.ts +10 -1
- package/dist/client/storefront/blocks/gallery.d.ts.map +1 -1
- package/dist/client/storefront/blocks/gallery.mjs +51 -27
- package/dist/client/storefront/blocks/gallery.mjs.map +1 -1
- package/dist/client/storefront/blocks/hero.d.ts +12 -1
- package/dist/client/storefront/blocks/hero.d.ts.map +1 -1
- package/dist/client/storefront/blocks/hero.mjs +143 -145
- package/dist/client/storefront/blocks/hero.mjs.map +1 -1
- package/dist/client/storefront/blocks/link-block-small.d.ts.map +1 -1
- package/dist/client/storefront/blocks/link-block-small.mjs +1 -1
- package/dist/client/storefront/blocks/link-block-small.mjs.map +1 -1
- package/dist/client/storefront/blocks/link-block.d.ts.map +1 -1
- package/dist/client/storefront/blocks/link-block.mjs +4 -4
- package/dist/client/storefront/blocks/link-block.mjs.map +1 -1
- package/dist/client/storefront/blocks/product-card-parts.d.ts +1 -1
- package/dist/client/storefront/blocks/product-card-parts.d.ts.map +1 -1
- package/dist/client/storefront/blocks/product-card-parts.mjs +2 -2
- package/dist/client/storefront/blocks/product-card-parts.mjs.map +1 -1
- package/dist/client/storefront/blocks/product-card.d.ts +10 -1
- package/dist/client/storefront/blocks/product-card.d.ts.map +1 -1
- package/dist/client/storefront/blocks/product-card.mjs +122 -116
- package/dist/client/storefront/blocks/product-card.mjs.map +1 -1
- package/dist/client/storefront/blocks/product-image.mjs +2 -2
- package/dist/client/storefront/blocks/product-image.mjs.map +1 -1
- package/dist/client/storefront/blocks/text-content-with-image.d.ts +14 -1
- package/dist/client/storefront/blocks/text-content-with-image.d.ts.map +1 -1
- package/dist/client/storefront/blocks/text-content-with-image.mjs +141 -164
- package/dist/client/storefront/blocks/text-content-with-image.mjs.map +1 -1
- package/dist/client/storefront/carousel/swipeable-carousel.d.ts +5 -1
- package/dist/client/storefront/carousel/swipeable-carousel.d.ts.map +1 -1
- package/dist/client/storefront/carousel/swipeable-carousel.mjs +2 -1
- package/dist/client/storefront/carousel/swipeable-carousel.mjs.map +1 -1
- package/dist/client/storefront/components/product-recommendations.d.ts.map +1 -1
- package/dist/client/storefront/components/product-recommendations.mjs +29 -37
- package/dist/client/storefront/components/product-recommendations.mjs.map +1 -1
- package/dist/client/storefront/filters/filter-chip.d.ts +5 -2
- package/dist/client/storefront/filters/filter-chip.d.ts.map +1 -1
- package/dist/client/storefront/filters/filter-chip.mjs +5 -3
- package/dist/client/storefront/filters/filter-chip.mjs.map +1 -1
- package/dist/client/storefront/filters/filter-panel.mjs +1 -1
- package/dist/client/storefront/index.d.ts +12 -1
- package/dist/client/storefront/index.mjs +12 -1
- package/dist/client/storefront/layout/header.d.ts.map +1 -1
- package/dist/client/storefront/layout/header.mjs +1 -1
- package/dist/client/storefront/layout/header.mjs.map +1 -1
- package/dist/client/storefront/layout/mobile-menu-drawer.mjs +1 -1
- package/dist/client/storefront/primitives/block-heading.d.ts +40 -0
- package/dist/client/storefront/primitives/block-heading.d.ts.map +1 -0
- package/dist/client/storefront/primitives/block-heading.mjs +43 -0
- package/dist/client/storefront/primitives/block-heading.mjs.map +1 -0
- package/dist/client/storefront/primitives/cta-group.d.ts +25 -0
- package/dist/client/storefront/primitives/cta-group.d.ts.map +1 -0
- package/dist/client/storefront/primitives/cta-group.mjs +27 -0
- package/dist/client/storefront/primitives/cta-group.mjs.map +1 -0
- package/dist/client/storefront/primitives/image-with-hover.d.ts +18 -0
- package/dist/client/storefront/primitives/image-with-hover.d.ts.map +1 -0
- package/dist/client/storefront/primitives/image-with-hover.mjs +16 -0
- package/dist/client/storefront/primitives/image-with-hover.mjs.map +1 -0
- package/dist/client/storefront/primitives/index.d.ts +4 -1
- package/dist/client/storefront/primitives/index.mjs +4 -1
- package/dist/client/theme/apply.d.ts +1 -1
- package/dist/client/theme/apply.d.ts.map +1 -1
- package/dist/client/theme/apply.mjs +0 -12
- package/dist/client/theme/apply.mjs.map +1 -1
- package/dist/client/theme/cli.mjs +0 -16
- package/dist/client/theme/cli.mjs.map +1 -1
- package/dist/client/theme/codec.d.ts.map +1 -1
- package/dist/client/theme/codec.mjs +0 -2
- package/dist/client/theme/codec.mjs.map +1 -1
- package/dist/client/theme/defaults.d.ts +0 -2
- package/dist/client/theme/defaults.mjs +0 -2
- package/dist/client/theme/defaults.mjs.map +1 -1
- package/dist/client/ui/carousel.d.ts +9 -1
- package/dist/client/ui/carousel.d.ts.map +1 -1
- package/dist/client/ui/carousel.mjs +18 -2
- package/dist/client/ui/carousel.mjs.map +1 -1
- package/dist/client/ui-resolver/index.d.ts +2 -2
- package/dist/client/ui-resolver/index.mjs +2 -2
- package/dist/styles.css +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-card-parts.mjs","names":[],"sources":["../../../../src/client/storefront/blocks/product-card-parts.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../ui/utils\";\n\n/* ─── ProductCard compound sub-components ─── */\n\n/**\n * Root container for a composable product card.\n * Provides
|
|
1
|
+
{"version":3,"file":"product-card-parts.mjs","names":[],"sources":["../../../../src/client/storefront/blocks/product-card-parts.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../ui/utils\";\n\n/* ─── ProductCard compound sub-components ─── */\n\n/**\n * Root container for a composable product card.\n * Provides grouping and overflow handling for composed layouts.\n */\nfunction ProductCardRoot({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"product-card\"\n className={cn(\"group overflow-hidden rounded-[var(--enad-card-radius)]\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Container for the product image area.\n * Use as a wrapper for ProductCardImage, ProductCardTag, and ProductCardFavoriteButton.\n */\nfunction ProductCardImageArea({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"product-card-image-area\"\n className={cn(\"relative bg-muted\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Product image with lazy loading.\n */\nfunction ProductCardImage({\n className,\n alt = \"\",\n loading = \"lazy\",\n ...props\n}: React.ComponentProps<\"img\">) {\n return (\n <img\n data-slot=\"product-card-image\"\n alt={alt}\n loading={loading}\n className={cn(\"size-full object-cover\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Badge overlay for product status (Sale, New, etc.).\n * Positioned absolutely within ProductCardImageArea by default.\n */\nfunction ProductCardTag({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"product-card-tag\"\n className={cn(\n \"absolute start-3 top-3 rounded-[var(--enad-card-radius)] bg-background/90 px-2 py-0.5 text-xs font-medium text-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Favorite/wishlist toggle button.\n * Stops event propagation by default (safe inside links).\n */\nfunction ProductCardFavoriteButton({\n className,\n onClick,\n ...props\n}: React.ComponentProps<\"button\">) {\n return (\n <button\n type=\"button\"\n data-slot=\"product-card-favorite\"\n className={cn(\n \"rounded-full bg-background/80 p-1.5 text-foreground transition-colors hover:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n className,\n )}\n aria-label=\"Add to favorites\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onClick?.(e);\n }}\n {...props}\n />\n );\n}\n\n/**\n * Container for product text content (title, subtitle, price).\n */\nfunction ProductCardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"product-card-content\"\n className={cn(\"flex min-w-0 flex-col gap-0.5 p-3\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Product name / title.\n */\nfunction ProductCardTitle({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"product-card-title\"\n className={cn(\"line-clamp-2 text-sm font-medium text-foreground\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Secondary text (category, brand, etc.).\n */\nfunction ProductCardSubtitle({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"product-card-subtitle\"\n className={cn(\"truncate text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Price display.\n */\nfunction ProductCardPrice({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"product-card-price\"\n className={cn(\"text-sm font-medium text-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport {\n ProductCardRoot,\n ProductCardImageArea,\n ProductCardImage,\n ProductCardTag,\n ProductCardFavoriteButton,\n ProductCardContent,\n ProductCardTitle,\n ProductCardSubtitle,\n ProductCardPrice,\n};\n"],"mappings":";;;;;;;;;AAWA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAsC;AAC7E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,2DAA2D,UAAU;EACnF,GAAI;EACJ,CAAA;;;;;;AAQN,SAAS,qBAAqB,EAAE,WAAW,GAAG,SAAsC;AAClF,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,qBAAqB,UAAU;EAC7C,GAAI;EACJ,CAAA;;;;;AAON,SAAS,iBAAiB,EACxB,WACA,MAAM,IACN,UAAU,QACV,GAAG,SAC2B;AAC9B,QACE,oBAAC,OAAD;EACE,aAAU;EACL;EACI;EACT,WAAW,GAAG,0BAA0B,UAAU;EAClD,GAAI;EACJ,CAAA;;;;;;AAQN,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;AAC7E,QACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,6HACA,UACD;EACD,GAAI;EACJ,CAAA;;;;;;AAQN,SAAS,0BAA0B,EACjC,WACA,SACA,GAAG,SAC8B;AACjC,QACE,oBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,WAAW,GACT,qKACA,UACD;EACD,cAAW;EACX,UAAU,MAAM;AACd,KAAE,gBAAgB;AAClB,KAAE,iBAAiB;AACnB,aAAU,EAAE;;EAEd,GAAI;EACJ,CAAA;;;;;AAON,SAAS,mBAAmB,EAAE,WAAW,GAAG,SAAsC;AAChF,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,qCAAqC,UAAU;EAC7D,GAAI;EACJ,CAAA;;;;;AAON,SAAS,iBAAiB,EAAE,WAAW,GAAG,SAAoC;AAC5E,QACE,oBAAC,KAAD;EACE,aAAU;EACV,WAAW,GAAG,oDAAoD,UAAU;EAC5E,GAAI;EACJ,CAAA;;;;;AAON,SAAS,oBAAoB,EAAE,WAAW,GAAG,SAAoC;AAC/E,QACE,oBAAC,KAAD;EACE,aAAU;EACV,WAAW,GAAG,0CAA0C,UAAU;EAClE,GAAI;EACJ,CAAA;;;;;AAON,SAAS,iBAAiB,EAAE,WAAW,GAAG,SAAuC;AAC/E,QACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GAAG,uCAAuC,UAAU;EAC/D,GAAI;EACJ,CAAA"}
|
|
@@ -2,7 +2,16 @@ import { ProductCardProps } from "../types.js";
|
|
|
2
2
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/storefront/blocks/product-card.d.ts
|
|
5
|
+
declare const productCardRecipe: (props?: ({
|
|
6
|
+
layout?: "gallery" | "list" | "minimal" | "horizontal" | "stripped" | undefined;
|
|
7
|
+
} & {
|
|
8
|
+
className?: Partial<Record<"root" | "content" | "imageWrapper", string>> | undefined;
|
|
9
|
+
}) | undefined) => {
|
|
10
|
+
root: string;
|
|
11
|
+
content: string;
|
|
12
|
+
imageWrapper: string;
|
|
13
|
+
};
|
|
5
14
|
declare function ProductCard(props: ProductCardProps): react_jsx_runtime0.JSX.Element;
|
|
6
15
|
//#endregion
|
|
7
|
-
export { ProductCard, type ProductCardProps };
|
|
16
|
+
export { ProductCard, type ProductCardProps, productCardRecipe };
|
|
8
17
|
//# sourceMappingURL=product-card.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-card.d.ts","names":[],"sources":["../../../../src/client/storefront/blocks/product-card.tsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"product-card.d.ts","names":[],"sources":["../../../../src/client/storefront/blocks/product-card.tsx"],"mappings":";;;;cAuBM,iBAAA,GAAiB,KAAA;;;cAmCrB,OAAA,CAAA,MAAA;AAAA;;;;;iBAgQO,WAAA,CAAY,KAAA,EAAO,gBAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useIcon } from "../../icons/icon-context.mjs";
|
|
3
3
|
import { cn } from "../../ui/utils.mjs";
|
|
4
|
+
import { defineSlotRecipe } from "../../ui-resolver/recipe.mjs";
|
|
4
5
|
import { useVariantDefault } from "../../ui-resolver/context.mjs";
|
|
5
6
|
import { SwipeableCarousel } from "../carousel/swipeable-carousel.mjs";
|
|
6
7
|
import { ProductCardContent, ProductCardFavoriteButton, ProductCardImage, ProductCardImageArea, ProductCardPrice, ProductCardRoot, ProductCardSubtitle, ProductCardTag, ProductCardTitle } from "./product-card-parts.mjs";
|
|
7
8
|
import "react";
|
|
8
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
//#region src/client/storefront/blocks/product-card.tsx
|
|
11
|
+
const productCardRecipe = defineSlotRecipe({
|
|
12
|
+
slots: [
|
|
13
|
+
"root",
|
|
14
|
+
"imageWrapper",
|
|
15
|
+
"content"
|
|
16
|
+
],
|
|
17
|
+
base: {
|
|
18
|
+
root: "",
|
|
19
|
+
imageWrapper: "relative",
|
|
20
|
+
content: ""
|
|
21
|
+
},
|
|
22
|
+
variants: { layout: {
|
|
23
|
+
gallery: {
|
|
24
|
+
root: "shadow-none",
|
|
25
|
+
content: "flex min-w-0 flex-col gap-[var(--enad-product-card-content-gap,0.125rem)] p-[var(--enad-product-card-content-py,0.75rem)]"
|
|
26
|
+
},
|
|
27
|
+
horizontal: {
|
|
28
|
+
root: "flex shadow-[var(--enad-card-shadow)]",
|
|
29
|
+
imageWrapper: "w-1/3 shrink-0",
|
|
30
|
+
content: "flex min-w-0 flex-1 flex-col justify-center gap-0 p-4 md:p-6"
|
|
31
|
+
},
|
|
32
|
+
minimal: {
|
|
33
|
+
root: "relative",
|
|
34
|
+
content: ""
|
|
35
|
+
},
|
|
36
|
+
list: {
|
|
37
|
+
root: "flex shadow-none",
|
|
38
|
+
imageWrapper: "w-32 shrink-0",
|
|
39
|
+
content: "flex min-w-0 flex-1 flex-col justify-center p-4"
|
|
40
|
+
},
|
|
41
|
+
stripped: {
|
|
42
|
+
root: "rounded-none shadow-none",
|
|
43
|
+
content: ""
|
|
44
|
+
}
|
|
45
|
+
} },
|
|
46
|
+
defaultVariants: { layout: "gallery" }
|
|
47
|
+
});
|
|
10
48
|
function OptionalLink({ href, radiusClass, children }) {
|
|
11
49
|
if (!href) return children;
|
|
12
50
|
return /* @__PURE__ */ jsx("a", {
|
|
@@ -29,40 +67,95 @@ function GalleryImageArea({ imageElements, fallback, showPaginationDots }) {
|
|
|
29
67
|
if (imageElements.length === 1) return imageElements[0];
|
|
30
68
|
return fallback;
|
|
31
69
|
}
|
|
32
|
-
function
|
|
70
|
+
function VerticalCard({ images = [], title, subtitle, price, tag, href, layout = "gallery", showFavorites = false, showPaginationDots = true, onFavoriteClick, className, HeartIcon }) {
|
|
71
|
+
const classes = productCardRecipe({ layout });
|
|
72
|
+
const isStripped = layout === "stripped";
|
|
73
|
+
const imageElements = images.map((img, i) => /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
74
|
+
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
75
|
+
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
76
|
+
src: img.src,
|
|
77
|
+
alt: img.alt ?? title ?? ""
|
|
78
|
+
})
|
|
79
|
+
}, i));
|
|
33
80
|
return /* @__PURE__ */ jsx(OptionalLink, {
|
|
34
81
|
href,
|
|
35
82
|
children: /* @__PURE__ */ jsxs(ProductCardRoot, {
|
|
36
|
-
className: cn(
|
|
83
|
+
className: cn(classes.root, className),
|
|
84
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
85
|
+
className: classes.imageWrapper,
|
|
86
|
+
children: isStripped ? /* @__PURE__ */ jsx("div", {
|
|
87
|
+
className: "overflow-hidden",
|
|
88
|
+
children: images[0] ? /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
89
|
+
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
90
|
+
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
91
|
+
src: images[0].src,
|
|
92
|
+
alt: images[0].alt ?? title ?? ""
|
|
93
|
+
})
|
|
94
|
+
}) : /* @__PURE__ */ jsx(FallbackImage, {})
|
|
95
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
96
|
+
/* @__PURE__ */ jsx(GalleryImageArea, {
|
|
97
|
+
imageElements,
|
|
98
|
+
fallback: /* @__PURE__ */ jsx(FallbackImage, {}),
|
|
99
|
+
showPaginationDots
|
|
100
|
+
}),
|
|
101
|
+
tag && /* @__PURE__ */ jsx(ProductCardTag, { children: tag }),
|
|
102
|
+
showFavorites && /* @__PURE__ */ jsx(ProductCardFavoriteButton, {
|
|
103
|
+
className: "absolute end-3 top-3",
|
|
104
|
+
onClick: () => onFavoriteClick?.(),
|
|
105
|
+
children: /* @__PURE__ */ jsx(HeartIcon, { className: "size-4" })
|
|
106
|
+
})
|
|
107
|
+
] })
|
|
108
|
+
}), isStripped ? /* @__PURE__ */ jsxs(Fragment, { children: [title && /* @__PURE__ */ jsx(ProductCardTitle, {
|
|
109
|
+
className: "mt-2",
|
|
110
|
+
children: title
|
|
111
|
+
}), price && /* @__PURE__ */ jsx(ProductCardPrice, {
|
|
112
|
+
className: "text-muted-foreground",
|
|
113
|
+
children: price
|
|
114
|
+
})] }) : /* @__PURE__ */ jsxs(ProductCardContent, {
|
|
115
|
+
className: classes.content,
|
|
116
|
+
children: [
|
|
117
|
+
title && /* @__PURE__ */ jsx(ProductCardTitle, { children: title }),
|
|
118
|
+
subtitle && /* @__PURE__ */ jsx(ProductCardSubtitle, { children: subtitle }),
|
|
119
|
+
price && /* @__PURE__ */ jsx(ProductCardPrice, { children: price })
|
|
120
|
+
]
|
|
121
|
+
})]
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function HorizontalCardLayout({ images = [], title, subtitle, price, tag, href, layout = "horizontal", showFavorites = false, onFavoriteClick, className, HeartIcon }) {
|
|
126
|
+
const classes = productCardRecipe({ layout });
|
|
127
|
+
return /* @__PURE__ */ jsx(OptionalLink, {
|
|
128
|
+
href,
|
|
129
|
+
children: /* @__PURE__ */ jsxs(ProductCardRoot, {
|
|
130
|
+
className: cn(classes.root, className),
|
|
37
131
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
38
|
-
className:
|
|
132
|
+
className: classes.imageWrapper,
|
|
39
133
|
children: [images[0] ? /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
40
134
|
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
41
135
|
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
42
136
|
src: images[0].src,
|
|
43
|
-
alt: images[0].alt ?? title ?? ""
|
|
44
|
-
className: "transition-transform duration-[var(--enad-image-hover-duration)] group-hover:scale-[var(--enad-image-hover-scale)]"
|
|
137
|
+
alt: images[0].alt ?? title ?? ""
|
|
45
138
|
})
|
|
46
|
-
}) : /* @__PURE__ */ jsx(FallbackImage, {}), tag && /* @__PURE__ */ jsx(ProductCardTag, {
|
|
139
|
+
}) : /* @__PURE__ */ jsx(FallbackImage, {}), tag && layout === "horizontal" && /* @__PURE__ */ jsx(ProductCardTag, {
|
|
47
140
|
className: "start-2 top-2",
|
|
48
141
|
children: tag
|
|
49
142
|
})]
|
|
50
143
|
}), /* @__PURE__ */ jsxs(ProductCardContent, {
|
|
51
|
-
className:
|
|
144
|
+
className: classes.content,
|
|
52
145
|
children: [
|
|
53
146
|
title && /* @__PURE__ */ jsx(ProductCardTitle, {
|
|
54
|
-
className: "text-base",
|
|
147
|
+
className: layout === "horizontal" ? "text-base" : void 0,
|
|
55
148
|
children: title
|
|
56
149
|
}),
|
|
57
150
|
subtitle && /* @__PURE__ */ jsx(ProductCardSubtitle, {
|
|
58
|
-
className: "mt-1",
|
|
151
|
+
className: layout === "horizontal" ? "mt-1" : "mt-0.5",
|
|
59
152
|
children: subtitle
|
|
60
153
|
}),
|
|
61
154
|
price && /* @__PURE__ */ jsx(ProductCardPrice, {
|
|
62
|
-
className: "mt-2 text-base",
|
|
155
|
+
className: layout === "horizontal" ? "mt-2 text-base" : "mt-1",
|
|
63
156
|
children: price
|
|
64
157
|
}),
|
|
65
|
-
showFavorites && /* @__PURE__ */ jsx(ProductCardFavoriteButton, {
|
|
158
|
+
showFavorites && layout === "horizontal" && /* @__PURE__ */ jsx(ProductCardFavoriteButton, {
|
|
66
159
|
className: "mt-3 self-start bg-muted hover:bg-accent",
|
|
67
160
|
onClick: () => onFavoriteClick?.(),
|
|
68
161
|
children: /* @__PURE__ */ jsx(HeartIcon, { className: "size-4" })
|
|
@@ -77,14 +170,13 @@ function MinimalCard({ images = [], title, price, tag, href, showFavorites = fal
|
|
|
77
170
|
href,
|
|
78
171
|
radiusClass: "rounded-[var(--enad-card-radius)]",
|
|
79
172
|
children: /* @__PURE__ */ jsxs(ProductCardRoot, {
|
|
80
|
-
className: cn("
|
|
173
|
+
className: cn(productCardRecipe({ layout: "minimal" }).root, className),
|
|
81
174
|
children: [
|
|
82
175
|
images[0] ? /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
83
176
|
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
84
177
|
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
85
178
|
src: images[0].src,
|
|
86
|
-
alt: images[0].alt ?? title ?? ""
|
|
87
|
-
className: "transition-transform duration-[var(--enad-image-hover-duration)] group-hover:scale-[var(--enad-image-hover-scale)]"
|
|
179
|
+
alt: images[0].alt ?? title ?? ""
|
|
88
180
|
})
|
|
89
181
|
}) : /* @__PURE__ */ jsx(FallbackImage, {}),
|
|
90
182
|
tag && /* @__PURE__ */ jsx(ProductCardTag, {
|
|
@@ -97,7 +189,7 @@ function MinimalCard({ images = [], title, price, tag, href, showFavorites = fal
|
|
|
97
189
|
children: /* @__PURE__ */ jsx(HeartIcon, { className: "size-4" })
|
|
98
190
|
}),
|
|
99
191
|
/* @__PURE__ */ jsxs("div", {
|
|
100
|
-
className: "absolute inset-x-0 bottom-0 min-w-0
|
|
192
|
+
className: "absolute inset-x-0 bottom-0 min-w-0 p-4",
|
|
101
193
|
style: { background: "linear-gradient(to top, color-mix(in oklch, var(--enad-overlay-color) calc(var(--enad-overlay-from-opacity) * 100%), transparent), transparent)" },
|
|
102
194
|
children: [title && /* @__PURE__ */ jsx(ProductCardTitle, {
|
|
103
195
|
className: "text-white",
|
|
@@ -111,101 +203,6 @@ function MinimalCard({ images = [], title, price, tag, href, showFavorites = fal
|
|
|
111
203
|
})
|
|
112
204
|
});
|
|
113
205
|
}
|
|
114
|
-
function ListCard({ images = [], title, subtitle, price, href, className }) {
|
|
115
|
-
return /* @__PURE__ */ jsx(OptionalLink, {
|
|
116
|
-
href,
|
|
117
|
-
children: /* @__PURE__ */ jsxs(ProductCardRoot, {
|
|
118
|
-
className: cn("flex shadow-none", className),
|
|
119
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
120
|
-
className: "w-32 shrink-0",
|
|
121
|
-
children: images[0] ? /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
122
|
-
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
123
|
-
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
124
|
-
src: images[0].src,
|
|
125
|
-
alt: images[0].alt ?? title ?? ""
|
|
126
|
-
})
|
|
127
|
-
}) : /* @__PURE__ */ jsx(FallbackImage, {})
|
|
128
|
-
}), /* @__PURE__ */ jsxs(ProductCardContent, {
|
|
129
|
-
className: "flex-1 justify-center p-4",
|
|
130
|
-
children: [
|
|
131
|
-
title && /* @__PURE__ */ jsx(ProductCardTitle, { children: title }),
|
|
132
|
-
subtitle && /* @__PURE__ */ jsx(ProductCardSubtitle, {
|
|
133
|
-
className: "mt-0.5",
|
|
134
|
-
children: subtitle
|
|
135
|
-
}),
|
|
136
|
-
price && /* @__PURE__ */ jsx(ProductCardPrice, {
|
|
137
|
-
className: "mt-1",
|
|
138
|
-
children: price
|
|
139
|
-
})
|
|
140
|
-
]
|
|
141
|
-
})]
|
|
142
|
-
})
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
function StrippedCard({ images = [], title, price, href, className }) {
|
|
146
|
-
return /* @__PURE__ */ jsx(OptionalLink, {
|
|
147
|
-
href,
|
|
148
|
-
children: /* @__PURE__ */ jsxs(ProductCardRoot, {
|
|
149
|
-
className: cn("rounded-none shadow-none", className),
|
|
150
|
-
children: [
|
|
151
|
-
/* @__PURE__ */ jsx("div", {
|
|
152
|
-
className: "relative overflow-hidden",
|
|
153
|
-
children: images[0] ? /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
154
|
-
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
155
|
-
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
156
|
-
src: images[0].src,
|
|
157
|
-
alt: images[0].alt ?? title ?? "",
|
|
158
|
-
className: "transition-transform duration-[var(--enad-image-hover-duration)] group-hover:scale-[var(--enad-image-hover-scale)]"
|
|
159
|
-
})
|
|
160
|
-
}) : /* @__PURE__ */ jsx(FallbackImage, {})
|
|
161
|
-
}),
|
|
162
|
-
title && /* @__PURE__ */ jsx(ProductCardTitle, {
|
|
163
|
-
className: "mt-2",
|
|
164
|
-
children: title
|
|
165
|
-
}),
|
|
166
|
-
price && /* @__PURE__ */ jsx(ProductCardPrice, {
|
|
167
|
-
className: "text-muted-foreground",
|
|
168
|
-
children: price
|
|
169
|
-
})
|
|
170
|
-
]
|
|
171
|
-
})
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
function GalleryCard({ images = [], title, subtitle, price, tag, href, showFavorites = false, showPaginationDots = true, onFavoriteClick, className, HeartIcon }) {
|
|
175
|
-
const imageElements = images.map((img, i) => /* @__PURE__ */ jsx(ProductCardImageArea, {
|
|
176
|
-
className: "aspect-[var(--enad-image-product-aspect)]",
|
|
177
|
-
children: /* @__PURE__ */ jsx(ProductCardImage, {
|
|
178
|
-
src: img.src,
|
|
179
|
-
alt: img.alt ?? title ?? ""
|
|
180
|
-
})
|
|
181
|
-
}, i));
|
|
182
|
-
return /* @__PURE__ */ jsx(OptionalLink, {
|
|
183
|
-
href,
|
|
184
|
-
children: /* @__PURE__ */ jsxs(ProductCardRoot, {
|
|
185
|
-
className: cn("shadow-none", className),
|
|
186
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
187
|
-
className: "relative",
|
|
188
|
-
children: [
|
|
189
|
-
/* @__PURE__ */ jsx(GalleryImageArea, {
|
|
190
|
-
imageElements,
|
|
191
|
-
fallback: /* @__PURE__ */ jsx(FallbackImage, {}),
|
|
192
|
-
showPaginationDots
|
|
193
|
-
}),
|
|
194
|
-
tag && /* @__PURE__ */ jsx(ProductCardTag, { children: tag }),
|
|
195
|
-
showFavorites && /* @__PURE__ */ jsx(ProductCardFavoriteButton, {
|
|
196
|
-
className: "absolute end-3 top-3",
|
|
197
|
-
onClick: () => onFavoriteClick?.(),
|
|
198
|
-
children: /* @__PURE__ */ jsx(HeartIcon, { className: "size-4" })
|
|
199
|
-
})
|
|
200
|
-
]
|
|
201
|
-
}), /* @__PURE__ */ jsxs(ProductCardContent, { children: [
|
|
202
|
-
title && /* @__PURE__ */ jsx(ProductCardTitle, { children: title }),
|
|
203
|
-
subtitle && /* @__PURE__ */ jsx(ProductCardSubtitle, { children: subtitle }),
|
|
204
|
-
price && /* @__PURE__ */ jsx(ProductCardPrice, { children: price })
|
|
205
|
-
] })]
|
|
206
|
-
})
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
206
|
function ProductCard(props) {
|
|
210
207
|
const cardDefault = useVariantDefault("productCard");
|
|
211
208
|
const HeartIcon = useIcon("heart");
|
|
@@ -215,14 +212,23 @@ function ProductCard(props) {
|
|
|
215
212
|
HeartIcon
|
|
216
213
|
};
|
|
217
214
|
switch (layout) {
|
|
218
|
-
case "horizontal":
|
|
215
|
+
case "horizontal":
|
|
216
|
+
case "list": return /* @__PURE__ */ jsx(HorizontalCardLayout, {
|
|
217
|
+
...layoutProps,
|
|
218
|
+
layout
|
|
219
|
+
});
|
|
219
220
|
case "minimal": return /* @__PURE__ */ jsx(MinimalCard, { ...layoutProps });
|
|
220
|
-
case "
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
case "stripped": return /* @__PURE__ */ jsx(VerticalCard, {
|
|
222
|
+
...layoutProps,
|
|
223
|
+
layout: "stripped"
|
|
224
|
+
});
|
|
225
|
+
default: return /* @__PURE__ */ jsx(VerticalCard, {
|
|
226
|
+
...layoutProps,
|
|
227
|
+
layout: "gallery"
|
|
228
|
+
});
|
|
223
229
|
}
|
|
224
230
|
}
|
|
225
231
|
//#endregion
|
|
226
|
-
export { ProductCard };
|
|
232
|
+
export { ProductCard, productCardRecipe };
|
|
227
233
|
|
|
228
234
|
//# sourceMappingURL=product-card.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-card.mjs","names":[],"sources":["../../../../src/client/storefront/blocks/product-card.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { cn } from \"../../ui/utils\";\nimport { useVariantDefault } from \"../../ui-resolver/context\";\nimport { SwipeableCarousel } from \"../carousel/swipeable-carousel\";\nimport type { ProductCardProps } from \"../types\";\nimport {\n ProductCardContent,\n ProductCardFavoriteButton,\n ProductCardImage,\n ProductCardImageArea,\n ProductCardPrice,\n ProductCardRoot,\n ProductCardSubtitle,\n ProductCardTag,\n ProductCardTitle,\n} from \"./product-card-parts\";\n\n/* ─── Shared helpers ─── */\n\ntype CardLayoutProps = ProductCardProps & {\n HeartIcon: React.ComponentType<{ className?: string }>;\n};\n\nfunction OptionalLink({\n href,\n radiusClass,\n children,\n}: {\n href?: string;\n radiusClass?: string;\n children: React.ReactNode;\n}) {\n if (!href) return children;\n return (\n <a\n href={href}\n className={cn(\n \"block focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n radiusClass,\n )}\n >\n {children}\n </a>\n );\n}\n\nfunction FallbackImage() {\n return (\n <ProductCardImageArea\n className=\"aspect-[var(--enad-image-product-aspect)]\"\n aria-hidden=\"true\"\n />\n );\n}\n\n/* ─── Gallery image element helper ─── */\n\nfunction GalleryImageArea({\n imageElements,\n fallback,\n showPaginationDots,\n}: {\n imageElements: React.ReactNode[];\n fallback: React.ReactNode;\n showPaginationDots: boolean;\n}) {\n if (imageElements.length > 1) {\n return <SwipeableCarousel items={imageElements} showDots={showPaginationDots} />;\n }\n if (imageElements.length === 1) {\n return imageElements[0];\n }\n return fallback;\n}\n\n/* ─── Horizontal layout ─── */\n\nfunction HorizontalCard({\n images = [],\n title,\n subtitle,\n price,\n tag,\n href,\n showFavorites = false,\n onFavoriteClick,\n className,\n HeartIcon,\n}: CardLayoutProps) {\n const content = (\n <ProductCardRoot\n className={cn(\n \"flex shadow-[var(--enad-card-shadow)] transition-shadow duration-[var(--enad-motion-duration)] hover:shadow-[var(--enad-card-hover-shadow)]\",\n className,\n )}\n >\n <div className=\"relative w-1/3 shrink-0\">\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage\n src={images[0].src}\n alt={images[0].alt ?? title ?? \"\"}\n className=\"transition-transform duration-[var(--enad-image-hover-duration)] group-hover:scale-[var(--enad-image-hover-scale)]\"\n />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n {tag && <ProductCardTag className=\"start-2 top-2\">{tag}</ProductCardTag>}\n </div>\n <ProductCardContent className=\"flex-1 justify-center gap-0 p-4 md:p-6\">\n {title && <ProductCardTitle className=\"text-base\">{title}</ProductCardTitle>}\n {subtitle && <ProductCardSubtitle className=\"mt-1\">{subtitle}</ProductCardSubtitle>}\n {price && <ProductCardPrice className=\"mt-2 text-base\">{price}</ProductCardPrice>}\n {showFavorites && (\n <ProductCardFavoriteButton\n className=\"mt-3 self-start bg-muted hover:bg-accent\"\n onClick={() => onFavoriteClick?.()}\n >\n <HeartIcon className=\"size-4\" />\n </ProductCardFavoriteButton>\n )}\n </ProductCardContent>\n </ProductCardRoot>\n );\n return <OptionalLink href={href}>{content}</OptionalLink>;\n}\n\n/* ─── Minimal layout ─── */\n\nfunction MinimalCard({\n images = [],\n title,\n price,\n tag,\n href,\n showFavorites = false,\n onFavoriteClick,\n className,\n HeartIcon,\n}: CardLayoutProps) {\n const content = (\n <ProductCardRoot className={cn(\"relative\", className)}>\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage\n src={images[0].src}\n alt={images[0].alt ?? title ?? \"\"}\n className=\"transition-transform duration-[var(--enad-image-hover-duration)] group-hover:scale-[var(--enad-image-hover-scale)]\"\n />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n\n {tag && <ProductCardTag className=\"z-10\">{tag}</ProductCardTag>}\n\n {showFavorites && (\n <ProductCardFavoriteButton\n className=\"absolute end-3 top-3 z-10\"\n onClick={() => onFavoriteClick?.()}\n >\n <HeartIcon className=\"size-4\" />\n </ProductCardFavoriteButton>\n )}\n\n {/* Hover overlay with product info */}\n <div\n className=\"absolute inset-x-0 bottom-0 min-w-0 translate-y-full p-4 transition-transform duration-[var(--enad-motion-duration)] group-hover:translate-y-0\"\n style={{\n background:\n \"linear-gradient(to top, color-mix(in oklch, var(--enad-overlay-color) calc(var(--enad-overlay-from-opacity) * 100%), transparent), transparent)\",\n }}\n >\n {title && <ProductCardTitle className=\"text-white\">{title}</ProductCardTitle>}\n {price && <ProductCardPrice className=\"mt-0.5 text-white/80\">{price}</ProductCardPrice>}\n </div>\n </ProductCardRoot>\n );\n return (\n <OptionalLink href={href} radiusClass=\"rounded-[var(--enad-card-radius)]\">\n {content}\n </OptionalLink>\n );\n}\n\n/* ─── List layout ─── */\n\nfunction ListCard({ images = [], title, subtitle, price, href, className }: CardLayoutProps) {\n const content = (\n <ProductCardRoot className={cn(\"flex shadow-none\", className)}>\n <div className=\"w-32 shrink-0\">\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage src={images[0].src} alt={images[0].alt ?? title ?? \"\"} />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n </div>\n <ProductCardContent className=\"flex-1 justify-center p-4\">\n {title && <ProductCardTitle>{title}</ProductCardTitle>}\n {subtitle && <ProductCardSubtitle className=\"mt-0.5\">{subtitle}</ProductCardSubtitle>}\n {price && <ProductCardPrice className=\"mt-1\">{price}</ProductCardPrice>}\n </ProductCardContent>\n </ProductCardRoot>\n );\n return <OptionalLink href={href}>{content}</OptionalLink>;\n}\n\n/* ─── Stripped layout ─── */\n\nfunction StrippedCard({ images = [], title, price, href, className }: CardLayoutProps) {\n const content = (\n <ProductCardRoot className={cn(\"rounded-none shadow-none\", className)}>\n <div className=\"relative overflow-hidden\">\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage\n src={images[0].src}\n alt={images[0].alt ?? title ?? \"\"}\n className=\"transition-transform duration-[var(--enad-image-hover-duration)] group-hover:scale-[var(--enad-image-hover-scale)]\"\n />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n </div>\n {title && <ProductCardTitle className=\"mt-2\">{title}</ProductCardTitle>}\n {price && <ProductCardPrice className=\"text-muted-foreground\">{price}</ProductCardPrice>}\n </ProductCardRoot>\n );\n return <OptionalLink href={href}>{content}</OptionalLink>;\n}\n\n/* ─── Gallery layout (default) ─── */\n\nfunction GalleryCard({\n images = [],\n title,\n subtitle,\n price,\n tag,\n href,\n showFavorites = false,\n showPaginationDots = true,\n onFavoriteClick,\n className,\n HeartIcon,\n}: CardLayoutProps) {\n const imageElements = images.map((img, i) => (\n <ProductCardImageArea key={i} className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage src={img.src} alt={img.alt ?? title ?? \"\"} />\n </ProductCardImageArea>\n ));\n\n const content = (\n <ProductCardRoot className={cn(\"shadow-none\", className)}>\n <div className=\"relative\">\n <GalleryImageArea\n imageElements={imageElements}\n fallback={<FallbackImage />}\n showPaginationDots={showPaginationDots}\n />\n\n {tag && <ProductCardTag>{tag}</ProductCardTag>}\n\n {showFavorites && (\n <ProductCardFavoriteButton\n className=\"absolute end-3 top-3\"\n onClick={() => onFavoriteClick?.()}\n >\n <HeartIcon className=\"size-4\" />\n </ProductCardFavoriteButton>\n )}\n </div>\n\n <ProductCardContent>\n {title && <ProductCardTitle>{title}</ProductCardTitle>}\n {subtitle && <ProductCardSubtitle>{subtitle}</ProductCardSubtitle>}\n {price && <ProductCardPrice>{price}</ProductCardPrice>}\n </ProductCardContent>\n </ProductCardRoot>\n );\n return <OptionalLink href={href}>{content}</OptionalLink>;\n}\n\n/* ─── Main component (dispatcher) ─── */\n\nfunction ProductCard(props: ProductCardProps) {\n const cardDefault = useVariantDefault(\"productCard\");\n const HeartIcon = useIcon(\"heart\");\n const layout = props.layout ?? cardDefault ?? \"gallery\";\n const layoutProps: CardLayoutProps = { ...props, HeartIcon };\n\n switch (layout) {\n case \"horizontal\":\n return <HorizontalCard {...layoutProps} />;\n case \"minimal\":\n return <MinimalCard {...layoutProps} />;\n case \"list\":\n return <ListCard {...layoutProps} />;\n case \"stripped\":\n return <StrippedCard {...layoutProps} />;\n default:\n return <GalleryCard {...layoutProps} />;\n }\n}\n\nexport { ProductCard, type ProductCardProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"product-card.mjs","names":[],"sources":["../../../../src/client/storefront/blocks/product-card.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { cn } from \"../../ui/utils\";\nimport { defineSlotRecipe } from \"../../ui-resolver/recipe\";\nimport { useVariantDefault } from \"../../ui-resolver/context\";\nimport { SwipeableCarousel } from \"../carousel/swipeable-carousel\";\nimport type { ProductCardProps } from \"../types\";\nimport {\n ProductCardContent,\n ProductCardFavoriteButton,\n ProductCardImage,\n ProductCardImageArea,\n ProductCardPrice,\n ProductCardRoot,\n ProductCardSubtitle,\n ProductCardTag,\n ProductCardTitle,\n} from \"./product-card-parts\";\n\n/* ─── Recipe ─── */\n\nconst productCardRecipe = defineSlotRecipe({\n slots: [\"root\", \"imageWrapper\", \"content\"] as const,\n base: {\n root: \"\",\n imageWrapper: \"relative\",\n content: \"\",\n },\n variants: {\n layout: {\n gallery: {\n root: \"shadow-none\",\n content:\n \"flex min-w-0 flex-col gap-[var(--enad-product-card-content-gap,0.125rem)] p-[var(--enad-product-card-content-py,0.75rem)]\",\n },\n horizontal: {\n root: \"flex shadow-[var(--enad-card-shadow)]\",\n imageWrapper: \"w-1/3 shrink-0\",\n content: \"flex min-w-0 flex-1 flex-col justify-center gap-0 p-4 md:p-6\",\n },\n minimal: {\n root: \"relative\",\n content: \"\",\n },\n list: {\n root: \"flex shadow-none\",\n imageWrapper: \"w-32 shrink-0\",\n content: \"flex min-w-0 flex-1 flex-col justify-center p-4\",\n },\n stripped: {\n root: \"rounded-none shadow-none\",\n content: \"\",\n },\n },\n },\n defaultVariants: { layout: \"gallery\" },\n});\n\n/* ─── Shared helpers ─── */\n\nfunction OptionalLink({\n href,\n radiusClass,\n children,\n}: {\n href?: string;\n radiusClass?: string;\n children: React.ReactNode;\n}) {\n if (!href) return children;\n return (\n <a\n href={href}\n className={cn(\n \"block focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n radiusClass,\n )}\n >\n {children}\n </a>\n );\n}\n\nfunction FallbackImage() {\n return (\n <ProductCardImageArea\n className=\"aspect-[var(--enad-image-product-aspect)]\"\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction GalleryImageArea({\n imageElements,\n fallback,\n showPaginationDots,\n}: {\n imageElements: React.ReactNode[];\n fallback: React.ReactNode;\n showPaginationDots: boolean;\n}) {\n if (imageElements.length > 1) {\n return <SwipeableCarousel items={imageElements} showDots={showPaginationDots} />;\n }\n if (imageElements.length === 1) {\n return imageElements[0];\n }\n return fallback;\n}\n\n/* ─── Internal layout prop type ─── */\n\ntype CardLayoutProps = ProductCardProps & {\n HeartIcon: React.ComponentType<{ className?: string }>;\n};\n\n/* ─── Vertical layout (gallery + stripped) ─── */\n\nfunction VerticalCard({\n images = [],\n title,\n subtitle,\n price,\n tag,\n href,\n layout = \"gallery\",\n showFavorites = false,\n showPaginationDots = true,\n onFavoriteClick,\n className,\n HeartIcon,\n}: CardLayoutProps) {\n const classes = productCardRecipe({ layout });\n const isStripped = layout === \"stripped\";\n\n const imageElements = images.map((img, i) => (\n <ProductCardImageArea key={i} className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage src={img.src} alt={img.alt ?? title ?? \"\"} />\n </ProductCardImageArea>\n ));\n\n const content = (\n <ProductCardRoot className={cn(classes.root, className)}>\n <div className={classes.imageWrapper}>\n {isStripped ? (\n <div className=\"overflow-hidden\">\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage src={images[0].src} alt={images[0].alt ?? title ?? \"\"} />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n </div>\n ) : (\n <>\n <GalleryImageArea\n imageElements={imageElements}\n fallback={<FallbackImage />}\n showPaginationDots={showPaginationDots}\n />\n {tag && <ProductCardTag>{tag}</ProductCardTag>}\n {showFavorites && (\n <ProductCardFavoriteButton\n className=\"absolute end-3 top-3\"\n onClick={() => onFavoriteClick?.()}\n >\n <HeartIcon className=\"size-4\" />\n </ProductCardFavoriteButton>\n )}\n </>\n )}\n </div>\n\n {isStripped ? (\n <>\n {title && <ProductCardTitle className=\"mt-2\">{title}</ProductCardTitle>}\n {price && <ProductCardPrice className=\"text-muted-foreground\">{price}</ProductCardPrice>}\n </>\n ) : (\n <ProductCardContent className={classes.content}>\n {title && <ProductCardTitle>{title}</ProductCardTitle>}\n {subtitle && <ProductCardSubtitle>{subtitle}</ProductCardSubtitle>}\n {price && <ProductCardPrice>{price}</ProductCardPrice>}\n </ProductCardContent>\n )}\n </ProductCardRoot>\n );\n\n return <OptionalLink href={href}>{content}</OptionalLink>;\n}\n\n/* ─── Horizontal layout (horizontal + list) ─── */\n\nfunction HorizontalCardLayout({\n images = [],\n title,\n subtitle,\n price,\n tag,\n href,\n layout = \"horizontal\",\n showFavorites = false,\n onFavoriteClick,\n className,\n HeartIcon,\n}: CardLayoutProps) {\n const classes = productCardRecipe({ layout });\n\n const content = (\n <ProductCardRoot className={cn(classes.root, className)}>\n <div className={classes.imageWrapper}>\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage src={images[0].src} alt={images[0].alt ?? title ?? \"\"} />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n {tag && layout === \"horizontal\" && (\n <ProductCardTag className=\"start-2 top-2\">{tag}</ProductCardTag>\n )}\n </div>\n <ProductCardContent className={classes.content}>\n {title && (\n <ProductCardTitle className={layout === \"horizontal\" ? \"text-base\" : undefined}>\n {title}\n </ProductCardTitle>\n )}\n {subtitle && (\n <ProductCardSubtitle className={layout === \"horizontal\" ? \"mt-1\" : \"mt-0.5\"}>\n {subtitle}\n </ProductCardSubtitle>\n )}\n {price && (\n <ProductCardPrice className={layout === \"horizontal\" ? \"mt-2 text-base\" : \"mt-1\"}>\n {price}\n </ProductCardPrice>\n )}\n {showFavorites && layout === \"horizontal\" && (\n <ProductCardFavoriteButton\n className=\"mt-3 self-start bg-muted hover:bg-accent\"\n onClick={() => onFavoriteClick?.()}\n >\n <HeartIcon className=\"size-4\" />\n </ProductCardFavoriteButton>\n )}\n </ProductCardContent>\n </ProductCardRoot>\n );\n\n return <OptionalLink href={href}>{content}</OptionalLink>;\n}\n\n/* ─── Minimal layout (hover overlay) ─── */\n\nfunction MinimalCard({\n images = [],\n title,\n price,\n tag,\n href,\n showFavorites = false,\n onFavoriteClick,\n className,\n HeartIcon,\n}: CardLayoutProps) {\n const classes = productCardRecipe({ layout: \"minimal\" });\n\n const content = (\n <ProductCardRoot className={cn(classes.root, className)}>\n {images[0] ? (\n <ProductCardImageArea className=\"aspect-[var(--enad-image-product-aspect)]\">\n <ProductCardImage src={images[0].src} alt={images[0].alt ?? title ?? \"\"} />\n </ProductCardImageArea>\n ) : (\n <FallbackImage />\n )}\n\n {tag && <ProductCardTag className=\"z-10\">{tag}</ProductCardTag>}\n\n {showFavorites && (\n <ProductCardFavoriteButton\n className=\"absolute end-3 top-3 z-10\"\n onClick={() => onFavoriteClick?.()}\n >\n <HeartIcon className=\"size-4\" />\n </ProductCardFavoriteButton>\n )}\n\n <div\n className=\"absolute inset-x-0 bottom-0 min-w-0 p-4\"\n style={{\n background:\n \"linear-gradient(to top, color-mix(in oklch, var(--enad-overlay-color) calc(var(--enad-overlay-from-opacity) * 100%), transparent), transparent)\",\n }}\n >\n {title && <ProductCardTitle className=\"text-white\">{title}</ProductCardTitle>}\n {price && <ProductCardPrice className=\"mt-0.5 text-white/80\">{price}</ProductCardPrice>}\n </div>\n </ProductCardRoot>\n );\n\n return (\n <OptionalLink href={href} radiusClass=\"rounded-[var(--enad-card-radius)]\">\n {content}\n </OptionalLink>\n );\n}\n\n/* ─── Main component (dispatcher) ─── */\n\nfunction ProductCard(props: ProductCardProps) {\n const cardDefault = useVariantDefault(\"productCard\");\n const HeartIcon = useIcon(\"heart\");\n const layout = props.layout ?? cardDefault ?? \"gallery\";\n const layoutProps: CardLayoutProps = { ...props, HeartIcon };\n\n switch (layout) {\n case \"horizontal\":\n case \"list\":\n return <HorizontalCardLayout {...layoutProps} layout={layout} />;\n case \"minimal\":\n return <MinimalCard {...layoutProps} />;\n case \"stripped\":\n return <VerticalCard {...layoutProps} layout=\"stripped\" />;\n default:\n return <VerticalCard {...layoutProps} layout=\"gallery\" />;\n }\n}\n\nexport { ProductCard, productCardRecipe, type ProductCardProps };\n"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ const aspectClasses = {
|
|
|
11
11
|
function getZoomLabel(zoomed) {
|
|
12
12
|
return zoomed ? "Zoom out" : "Zoom in";
|
|
13
13
|
}
|
|
14
|
-
function ProductImage({ images, aspectRatio = "4:5", showZoom = false, arrows =
|
|
14
|
+
function ProductImage({ images, aspectRatio = "4:5", showZoom = false, arrows = void 0, showDots = true, showThumbnails = false, className }) {
|
|
15
15
|
const [zoomed, setZoomed] = React$1.useState(false);
|
|
16
16
|
const [activeSlide, setActiveSlide] = React$1.useState(0);
|
|
17
17
|
const toggleZoom = () => {
|
|
@@ -35,7 +35,7 @@ function ProductImage({ images, aspectRatio = "4:5", showZoom = false, arrows =
|
|
|
35
35
|
children: /* @__PURE__ */ jsx("img", {
|
|
36
36
|
src: img.src,
|
|
37
37
|
alt: img.alt ?? "",
|
|
38
|
-
className: cn("size-full object-cover
|
|
38
|
+
className: cn("size-full object-cover", zoomed && "scale-150")
|
|
39
39
|
})
|
|
40
40
|
}, i));
|
|
41
41
|
if (images.length === 0) return /* @__PURE__ */ jsx("div", { className: cn("bg-muted", aspectClasses[aspectRatio], className) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-image.mjs","names":["React"],"sources":["../../../../src/client/storefront/blocks/product-image.tsx"],"sourcesContent":["\"use client\"
|
|
1
|
+
{"version":3,"file":"product-image.mjs","names":["React"],"sources":["../../../../src/client/storefront/blocks/product-image.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../ui/utils\";\nimport { SwipeableCarousel } from \"../carousel/swipeable-carousel\";\nimport type { ProductImageProps } from \"../types\";\n\nconst aspectClasses: Record<string, string> = {\n \"1:1\": \"aspect-square\",\n \"4:5\": \"aspect-[4/5]\",\n};\n\nfunction getZoomLabel(zoomed: boolean): string {\n return zoomed ? \"Zoom out\" : \"Zoom in\";\n}\n\nfunction ProductImage({\n images,\n aspectRatio = \"4:5\",\n showZoom = false,\n arrows = undefined,\n showDots = true,\n showThumbnails = false,\n className,\n}: ProductImageProps) {\n const [zoomed, setZoomed] = React.useState(false);\n const [activeSlide, setActiveSlide] = React.useState(0);\n\n const toggleZoom = () => {\n if (showZoom) setZoomed((z) => !z);\n };\n\n const handleZoomKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggleZoom();\n }\n };\n\n const imageElements = images.map((img, i) => (\n <div\n key={i}\n className={cn(\n \"relative overflow-hidden bg-muted\",\n aspectClasses[aspectRatio],\n showZoom && (zoomed ? \"cursor-zoom-out\" : \"cursor-zoom-in\"),\n )}\n {...(showZoom && {\n role: \"button\" as const,\n tabIndex: 0,\n \"aria-label\": getZoomLabel(zoomed),\n onClick: toggleZoom,\n onKeyDown: handleZoomKeyDown,\n })}\n >\n <img\n src={img.src}\n alt={img.alt ?? \"\"}\n className={cn(\"size-full object-cover\", zoomed && \"scale-150\")}\n />\n </div>\n ));\n\n if (images.length === 0) {\n return <div className={cn(\"bg-muted\", aspectClasses[aspectRatio], className)} />;\n }\n\n if (images.length === 1) {\n return <div className={className}>{imageElements[0]}</div>;\n }\n\n const carousel = (\n <SwipeableCarousel\n items={imageElements}\n arrows={arrows}\n showDots={showDots}\n activeSlide={activeSlide}\n onSlideChange={setActiveSlide}\n />\n );\n\n if (showThumbnails && images.length > 1) {\n return (\n <div className={cn(\"flex gap-3\", className)}>\n <div className=\"hidden md:flex flex-col gap-2 w-16 shrink-0\">\n {images.map((img, i) => (\n <button\n key={i}\n type=\"button\"\n aria-label={`View image ${i + 1}`}\n onClick={() => setActiveSlide(i)}\n className={cn(\n \"relative aspect-square overflow-hidden rounded-[var(--enad-card-radius)] border-2 transition\",\n i === activeSlide\n ? \"border-primary ring-1 ring-primary/30\"\n : \"border-transparent opacity-60 hover:opacity-100\",\n )}\n >\n <img src={img.src} alt={img.alt ?? \"\"} className=\"size-full object-cover\" />\n </button>\n ))}\n </div>\n <div className=\"min-w-0 flex-1\">{carousel}</div>\n </div>\n );\n }\n\n return <div className={className}>{carousel}</div>;\n}\n\nexport { ProductImage, type ProductImageProps };\n"],"mappings":";;;;;;AAOA,MAAM,gBAAwC;CAC5C,OAAO;CACP,OAAO;CACR;AAED,SAAS,aAAa,QAAyB;AAC7C,QAAO,SAAS,aAAa;;AAG/B,SAAS,aAAa,EACpB,QACA,cAAc,OACd,WAAW,OACX,SAAS,KAAA,GACT,WAAW,MACX,iBAAiB,OACjB,aACoB;CACpB,MAAM,CAAC,QAAQ,aAAaA,QAAM,SAAS,MAAM;CACjD,MAAM,CAAC,aAAa,kBAAkBA,QAAM,SAAS,EAAE;CAEvD,MAAM,mBAAmB;AACvB,MAAI,SAAU,YAAW,MAAM,CAAC,EAAE;;CAGpC,MAAM,qBAAqB,MAA2B;AACpD,MAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,KAAE,gBAAgB;AAClB,eAAY;;;CAIhB,MAAM,gBAAgB,OAAO,KAAK,KAAK,MACrC,oBAAC,OAAD;EAEE,WAAW,GACT,qCACA,cAAc,cACd,aAAa,SAAS,oBAAoB,kBAC3C;EACD,GAAK,YAAY;GACf,MAAM;GACN,UAAU;GACV,cAAc,aAAa,OAAO;GAClC,SAAS;GACT,WAAW;GACZ;YAED,oBAAC,OAAD;GACE,KAAK,IAAI;GACT,KAAK,IAAI,OAAO;GAChB,WAAW,GAAG,0BAA0B,UAAU,YAAY;GAC9D,CAAA;EACE,EAnBC,EAmBD,CACN;AAEF,KAAI,OAAO,WAAW,EACpB,QAAO,oBAAC,OAAD,EAAK,WAAW,GAAG,YAAY,cAAc,cAAc,UAAU,EAAI,CAAA;AAGlF,KAAI,OAAO,WAAW,EACpB,QAAO,oBAAC,OAAD;EAAgB;YAAY,cAAc;EAAS,CAAA;CAG5D,MAAM,WACJ,oBAAC,mBAAD;EACE,OAAO;EACC;EACE;EACG;EACb,eAAe;EACf,CAAA;AAGJ,KAAI,kBAAkB,OAAO,SAAS,EACpC,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,cAAc,UAAU;YAA3C,CACE,oBAAC,OAAD;GAAK,WAAU;aACZ,OAAO,KAAK,KAAK,MAChB,oBAAC,UAAD;IAEE,MAAK;IACL,cAAY,cAAc,IAAI;IAC9B,eAAe,eAAe,EAAE;IAChC,WAAW,GACT,gGACA,MAAM,cACF,0CACA,kDACL;cAED,oBAAC,OAAD;KAAK,KAAK,IAAI;KAAK,KAAK,IAAI,OAAO;KAAI,WAAU;KAA2B,CAAA;IACrE,EAZF,EAYE,CACT;GACE,CAAA,EACN,oBAAC,OAAD;GAAK,WAAU;aAAkB;GAAe,CAAA,CAC5C;;AAIV,QAAO,oBAAC,OAAD;EAAgB;YAAY;EAAe,CAAA"}
|
|
@@ -2,7 +2,20 @@ import { TextContentWithImageProps } from "../types.js";
|
|
|
2
2
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/storefront/blocks/text-content-with-image.d.ts
|
|
5
|
+
declare const textContentWithImageRecipe: (props?: ({
|
|
6
|
+
variant?: "side-by-side" | "stacked" | "overlap" | undefined;
|
|
7
|
+
fullWidth?: "true" | "false" | undefined;
|
|
8
|
+
imagePosition?: "first" | "last" | undefined;
|
|
9
|
+
} & {
|
|
10
|
+
className?: Partial<Record<"root" | "image" | "inner" | "imageArea" | "textArea", string>> | undefined;
|
|
11
|
+
}) | undefined) => {
|
|
12
|
+
root: string;
|
|
13
|
+
image: string;
|
|
14
|
+
inner: string;
|
|
15
|
+
imageArea: string;
|
|
16
|
+
textArea: string;
|
|
17
|
+
};
|
|
5
18
|
declare function TextContentWithImage(props: TextContentWithImageProps): react_jsx_runtime0.JSX.Element;
|
|
6
19
|
//#endregion
|
|
7
|
-
export { TextContentWithImage, type TextContentWithImageProps };
|
|
20
|
+
export { TextContentWithImage, type TextContentWithImageProps, textContentWithImageRecipe };
|
|
8
21
|
//# sourceMappingURL=text-content-with-image.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-content-with-image.d.ts","names":[],"sources":["../../../../src/client/storefront/blocks/text-content-with-image.tsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"text-content-with-image.d.ts","names":[],"sources":["../../../../src/client/storefront/blocks/text-content-with-image.tsx"],"mappings":";;;;cAWM,0BAAA,GAA0B,KAAA;;;;;cA6E9B,OAAA,CAAA,MAAA;AAAA;;;;;;;iBA6JO,oBAAA,CAAqB,KAAA,EAAO,yBAAA,GAAyB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|