@deneb-ui/ui 2.0.62 → 2.0.64

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 CHANGED
@@ -217,6 +217,12 @@ reactive `SiteDataProvider` catalog, retries `api.catalogUrl`, and renders safe
217
217
  loading, network-error, and not-found states. `usePlatformProductDetail()` is
218
218
  also exported for developers who need complete control of the page markup.
219
219
 
220
+ If the template already has a native `/products/[id]` design, the stable page
221
+ must reuse that renderer through `renderProduct` (or render the same component
222
+ from `usePlatformProductDetail`). The validator rejects a generic stable page
223
+ next to a different native detail layout because newly-created products would
224
+ otherwise look different from products present at build time.
225
+
220
226
  ---
221
227
 
222
228
  ## Data Fetching & Backend Integration Hooks
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EditableGoogleFeedback = EditableGoogleFeedback;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /* eslint-disable @next/next/no-img-element */
5
6
  const react_1 = require("react");
6
7
  const DEFAULT_GOOGLE_ICON = 'https://upload.wikimedia.org/wikipedia/commons/c/c1/Google_%22G%22_logo.svg';
7
8
  const DEFAULT_FEEDBACKS = [
@@ -55,12 +56,12 @@ function GoogleStarSvg({ filled = true, size = 18 }) {
55
56
  return ((0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 24 24", style: {
56
57
  width: `${size}px`,
57
58
  height: `${size}px`,
58
- fill: filled ? '#fa7014' : '#dadce0',
59
- color: filled ? '#fa7014' : '#dadce0',
59
+ fill: filled ? '#fbbf24' : '#334155',
60
+ color: filled ? '#fbbf24' : '#334155',
60
61
  flexShrink: 0,
61
62
  }, "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" }) }));
62
63
  }
63
- function FeedbackCard({ item, index, basePath, maxStars, badgeIcon, badgeTitle, cardClassName, }) {
64
+ function FeedbackCard({ item, index, maxStars, badgeIcon, cardClassName, }) {
64
65
  const currentItem = item || {};
65
66
  const rawRating = currentItem.rating != null && currentItem.rating !== '' ? currentItem.rating : 5;
66
67
  const initialRating = Math.min(Math.max(Math.round(Number(rawRating) || 5), 1), maxStars);
@@ -100,23 +101,9 @@ function FeedbackCard({ item, index, basePath, maxStars, badgeIcon, badgeTitle,
100
101
  'https://images.unsplash.com/photo-1534528741775-53994a69daeb?q=80&w=300&auto=format&fit=crop');
101
102
  const reviewerComment = String(currentItem.comment || '');
102
103
  const reviewerDate = String(currentItem.date || 'Recent review');
103
- return ((0, jsx_runtime_1.jsx)("div", { "data-preview-item-path": `feedback.feedbacks[${index}]`, className: `p-6 sm:p-7 rounded-3xl bg-[#ffffff] border border-[#3d2114]/12 shadow-sm hover:shadow-md transition-all duration-300 flex flex-col justify-between space-y-4 ${cardClassName || ''}`.trim(), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("img", { src: reviewerAvatar, alt: reviewerName, "data-preview-field-path": `feedback.feedbacks[${index}].avatar`, className: "w-11 h-11 rounded-full object-cover border border-[#3d2114]/15 shadow-sm" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.feedbacks[${index}].name`, className: "block text-sm font-black text-[#2b170e]", children: reviewerName }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.feedbacks[${index}].date`, className: "block text-xs text-[#8c7a6e]", children: reviewerDate })] })] }), (() => {
104
- const itemCustomIcon = currentItem?.badgeIcon || currentItem?.platformIcon;
105
- const finalCardIcon = typeof itemCustomIcon === 'string' && itemCustomIcon.trim() ? itemCustomIcon : (badgeIcon || DEFAULT_GOOGLE_ICON);
106
- const cardIconFieldPath = typeof itemCustomIcon === 'string' && itemCustomIcon.trim()
107
- ? `${basePath}.feedbacks[${index}].badgeIcon`
108
- : `${basePath}.badgeIcon`;
109
- return ((0, jsx_runtime_1.jsx)("img", { src: finalCardIcon, alt: badgeTitle || 'Review Platform', "data-preview-field-path": cardIconFieldPath, className: "w-5 h-5 object-contain opacity-90 shrink-0 cursor-pointer", style: {
110
- width: '20px',
111
- height: '20px',
112
- minWidth: '20px',
113
- minHeight: '20px',
114
- maxWidth: '20px',
115
- maxHeight: '20px',
116
- }, title: "Click to upload/change review platform icon (Google, Twitter, Trustpilot, etc.)" }));
117
- })()] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-2 pt-1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-2 p-1 -ml-1 rounded-lg cursor-pointer transition-all hover:bg-[#fa7014]/10 group", onClick: handleFocusRating, title: `Rating: ${currentRating} of ${maxStars} (Click to edit)`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", "data-fivora-stars-row": "true", children: Array.from({ length: maxStars }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: sIdx < currentRating, size: 18 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { ref: ratingRef, "data-preview-field-path": `feedback.feedbacks[${index}].rating`, "data-fivora-rating-text": "true", className: "text-xs font-black text-[#fa7014] bg-[#fa7014]/10 px-1.5 py-0.5 rounded-md border border-[#fa7014]/20 group-hover:bg-[#fa7014]/20 transition-colors tabular-nums", title: "Star count (1-5)", children: currentRating })] }), (0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-1 text-[11px] font-bold text-[#1a73e8] bg-[#e8f0fe] px-2.5 py-1 rounded-full border border-[#1a73e8]/20", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-3 h-3 fill-current", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) }), (0, jsx_runtime_1.jsx)("span", { children: "Verified" })] })] }), (0, jsx_runtime_1.jsxs)("p", { "data-preview-field-path": `feedback.feedbacks[${index}].comment`, className: "text-sm sm:text-base text-[#3d2114] leading-relaxed italic font-normal pt-1", children: ["\u201C", reviewerComment, "\u201D"] })] }) }));
104
+ return ((0, jsx_runtime_1.jsx)("div", { "data-preview-item-path": `feedback.feedbacks[${index}]`, className: `p-6 sm:p-7 rounded-2xl bg-gradient-to-b from-slate-900/60 to-slate-950/80 border border-slate-800/80 hover:border-slate-700 shadow-md transition-all duration-300 flex flex-col justify-between space-y-4 ${cardClassName || ''}`.trim(), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("img", { src: reviewerAvatar, alt: reviewerName, "data-preview-field-path": `feedback.feedbacks[${index}].avatar`, className: "w-11 h-11 rounded-full object-cover border border-slate-700 shadow-sm" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.feedbacks[${index}].name`, className: "block text-sm font-black text-white", children: reviewerName }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.feedbacks[${index}].date`, className: "block text-xs text-slate-400", children: reviewerDate })] })] }), (0, jsx_runtime_1.jsx)("img", { src: badgeIcon || DEFAULT_GOOGLE_ICON, alt: "Google", "data-preview-static": "true", className: "w-5 h-5 object-contain opacity-90" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-2 pt-1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-2 p-1 -ml-1 rounded-lg cursor-pointer transition-all hover:bg-amber-400/10 group", onClick: handleFocusRating, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", "data-fivora-stars-row": "true", children: Array.from({ length: maxStars }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: sIdx < currentRating, size: 18 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { ref: ratingRef, "data-preview-field-path": `feedback.feedbacks[${index}].rating`, "data-fivora-rating-text": "true", className: "text-xs font-black text-amber-400 bg-amber-400/10 px-1.5 py-0.5 rounded-md border border-amber-400/20 group-hover:bg-amber-400/20 transition-colors tabular-nums", title: "Star count (1-5)", children: currentRating })] }), (0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-1 text-[11px] font-bold text-emerald-400 bg-emerald-500/10 px-2.5 py-0.5 rounded-full border border-emerald-500/20", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-3 h-3 fill-current", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) }), (0, jsx_runtime_1.jsx)("span", { "data-preview-static": "true", children: "Verified" })] })] }), (0, jsx_runtime_1.jsxs)("p", { "data-preview-field-path": `feedback.feedbacks[${index}].comment`, className: "text-sm sm:text-base text-slate-300 leading-relaxed italic font-normal pt-1", children: ["\u201C", reviewerComment, "\u201D"] })] }) }));
118
105
  }
119
- function EditableGoogleFeedback({ basePath = 'feedback', badgeIcon = DEFAULT_GOOGLE_ICON, badgeTitle = 'Google Reviews', badgeRating = '4.9', badgeReviewsCount = '340+ Verified Reviews', heading = 'PRAISED BY COFFEE LOVERS', subheading = 'Real experiences from patrons who visit our roastery parlor and brew our micro-lots.', feedbacks = DEFAULT_FEEDBACKS, maxStars = 5, className = '', cardClassName = '', style, ...props }) {
106
+ function EditableGoogleFeedback({ basePath = 'feedback', badgeIcon = DEFAULT_GOOGLE_ICON, badgeTitle = 'Google Reviews', badgeRating = '4.9', badgeReviewsCount = '340+ Verified Reviews', heading = 'Loved by Customers Worldwide', subheading = 'Real experiences and verified reviews from Google Business ratings.', feedbacks = DEFAULT_FEEDBACKS, maxStars = 5, className = '', cardClassName = '', style, ...props }) {
120
107
  const items = (0, react_1.useMemo)(() => {
121
108
  const list = Array.isArray(feedbacks) ? feedbacks : [];
122
109
  if (list.length === 0) {
@@ -135,5 +122,5 @@ function EditableGoogleFeedback({ basePath = 'feedback', badgeIcon = DEFAULT_GOO
135
122
  };
136
123
  });
137
124
  }, [feedbacks]);
138
- return ((0, jsx_runtime_1.jsx)("section", { "data-design-section": "google-feedback", className: `editable-google-feedback w-full ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-10", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row md:items-end justify-between gap-6 mb-10 sm:mb-14", children: [(0, jsx_runtime_1.jsxs)("div", { className: "max-w-2xl space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-2.5 px-3.5 py-1.5 rounded-full bg-[#ede0d4]/80 border border-[#3d2114]/15 shadow-sm", children: [(0, jsx_runtime_1.jsx)("img", { src: badgeIcon || DEFAULT_GOOGLE_ICON, alt: "Google", "data-preview-field-path": `feedback.badgeIcon`, className: "w-4 h-4 object-contain" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeTitle`, className: "text-xs uppercase tracking-widest font-black text-[#3d2114]", children: badgeTitle }), (0, jsx_runtime_1.jsx)("span", { className: "w-1 h-1 rounded-full bg-[#84431b]" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1.5", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "text-xs font-black text-[#84431b]", children: badgeRating }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 14 }, sIdx))) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-[11px] text-[#786154] font-medium hidden sm:inline", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, children: badgeReviewsCount }), ")"] })] }), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `feedback.heading`, className: "font-heading text-2xl xs:text-3xl sm:text-4xl lg:text-5xl font-black text-[#2b170e] tracking-tight", children: heading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `feedback.subheading`, className: "text-xs sm:text-base text-[#5c493f] leading-relaxed", children: subheading })] }), (0, jsx_runtime_1.jsx)("div", { className: "hidden md:flex flex-col items-end text-right", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "font-heading text-4xl font-black text-[#84431b]", children: badgeRating }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 16 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, className: "text-xs text-[#786154] font-bold", children: badgeReviewsCount })] })] }) })] }), (0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": `feedback.feedbacks`, className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6", children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(FeedbackCard, { item: item, index: index, basePath: basePath, maxStars: maxStars, badgeIcon: badgeIcon, badgeTitle: badgeTitle, cardClassName: cardClassName }, item.id || `feedback-${index}`))) })] }) }));
125
+ return ((0, jsx_runtime_1.jsx)("section", { "data-design-section": "google-feedback", className: `editable-google-feedback w-full ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "w-full mx-auto px-4 sm:px-6 lg:px-10", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row md:items-end justify-between gap-6 mb-10 sm:mb-14", children: [(0, jsx_runtime_1.jsxs)("div", { className: "max-w-2xl space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-2.5 px-3.5 py-1.5 rounded-full bg-slate-900/80 border border-slate-800 shadow-sm", children: [(0, jsx_runtime_1.jsx)("img", { src: badgeIcon || DEFAULT_GOOGLE_ICON, alt: "Google", "data-preview-field-path": `feedback.badgeIcon`, className: "w-4 h-4 object-contain" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeTitle`, className: "text-xs uppercase tracking-widest font-black text-white", children: badgeTitle }), (0, jsx_runtime_1.jsx)("span", { className: "w-1 h-1 rounded-full bg-slate-700" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1.5", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "text-xs font-black text-amber-400", children: badgeRating }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 14 }, sIdx))) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-[11px] text-slate-400 font-medium sm:inline", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, children: badgeReviewsCount }), ")"] })] }), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `feedback.heading`, className: "font-heading text-2xl xs:text-3xl sm:text-4xl lg:text-5xl font-black text-white tracking-tight", children: heading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `feedback.subheading`, className: "text-xs sm:text-base text-slate-400 leading-relaxed", children: subheading })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col items-end text-right md:flex", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "font-heading text-4xl font-black text-amber-400", children: badgeRating }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 16 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, className: "text-xs text-slate-400 font-bold", children: badgeReviewsCount })] })] }) })] }), (0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": `feedback.feedbacks`, className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6", children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(FeedbackCard, { item: item, index: index, maxStars: maxStars, badgeIcon: badgeIcon, cardClassName: cardClassName }, item.id || String(index)))) })] }) }));
139
126
  }
@@ -6,7 +6,6 @@ export interface ProductItem {
6
6
  title?: string;
7
7
  brand?: string;
8
8
  price?: string | number;
9
- compareAtPrice?: string | number;
10
9
  originalPrice?: string | number;
11
10
  currency?: string;
12
11
  description?: string;
@@ -19,7 +18,6 @@ export interface ProductItem {
19
18
  reviewsCount?: number | string;
20
19
  isNew?: boolean;
21
20
  isBestSeller?: boolean;
22
- isAvailable?: boolean;
23
21
  whatsappNumber?: string;
24
22
  whatsappButtonText?: string;
25
23
  addToCartButtonText?: string;
@@ -26,13 +26,12 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
26
26
  const rawPrice = product?.price;
27
27
  const priceNum = typeof rawPrice === 'number' ? rawPrice : parseFloat(String(rawPrice || '').replace(/[^0-9.]/g, '')) || 0;
28
28
  const formattedPrice = hasPrice ? (typeof rawPrice === 'string' && rawPrice.includes('LKR') ? rawPrice : (0, useCart_1.formatCurrency)(priceNum, currency)) : '';
29
- const comparePrice = product?.originalPrice ?? product?.compareAtPrice;
30
- const originalPrice = comparePrice !== undefined && comparePrice !== null ? String(comparePrice) : '';
29
+ const originalPrice = product?.originalPrice !== undefined ? String(product.originalPrice) : '';
31
30
  const description = String(product?.description || '');
32
31
  const category = String(product?.category || '');
33
32
  const badge = String(product?.badge || '');
34
- const imageUrl = String(product?.imageUrl || product?.image || '');
35
- const isAvailable = product?.isAvailable !== false;
33
+ const fallbackImage = imageFallback || 'https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=800&q=80';
34
+ const imageUrl = String(product?.imageUrl || product?.image || fallbackImage);
36
35
  // Resolved phone number for WhatsApp
37
36
  const resolvedPhone = String(product?.whatsappNumber || whatsappNumber || '94770000000');
38
37
  const resolvedWhatsAppText = String(product?.whatsappButtonText || whatsappActionLabel);
@@ -40,8 +39,6 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
40
39
  const isHorizontal = cardVariant === 'horizontal';
41
40
  const handleWhatsAppClick = (e) => {
42
41
  e.stopPropagation();
43
- if (!isAvailable)
44
- return;
45
42
  const url = (0, useCart_1.getProductWhatsAppUrl)({ ...product, name, brand, price: formattedPrice }, resolvedPhone, { storeName, currency });
46
43
  if (onWhatsAppClick) {
47
44
  onWhatsAppClick(product, url);
@@ -52,8 +49,6 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
52
49
  };
53
50
  const handleAddToCartClick = (e) => {
54
51
  e.stopPropagation();
55
- if (!isAvailable)
56
- return;
57
52
  const itemToAdd = {
58
53
  id: String(product?.id || name.toLowerCase().replace(/\s+/g, '-')),
59
54
  name,
@@ -72,12 +67,12 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
72
67
  };
73
68
  const variantStyles = {
74
69
  'modern-glass': {
75
- backgroundColor: 'rgba(255, 255, 255, 0.85)',
70
+ backgroundColor: 'var(--product-card-bg, #0F1424)',
76
71
  backdropFilter: 'blur(16px)',
77
72
  WebkitBackdropFilter: 'blur(16px)',
78
- border: '1px solid rgba(226, 232, 240, 0.8)',
73
+ border: '1px solid var(--product-card-border, #1E2638)',
79
74
  borderRadius: '16px',
80
- boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.01)',
75
+ boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.4)',
81
76
  overflow: 'hidden',
82
77
  transition: 'transform 0.25s ease, box-shadow 0.25s ease',
83
78
  display: 'flex',
@@ -118,18 +113,7 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
118
113
  overflow: 'hidden',
119
114
  width: isHorizontal ? '40%' : '100%',
120
115
  flexShrink: 0,
121
- }, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.imageUrl`, "data-preview-field-path": `${itemPath}.imageUrl`, src: imageUrl, fallbackSrc: imageFallback, alt: name, aspectRatio: isHorizontal ? 'square' : '4/3', fit: "cover", hoverZoom: true, style: { width: '100%', height: '100%', display: 'block' } }), badge && ((0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', top: '10px', left: '10px', zIndex: 10 }, children: (0, jsx_runtime_1.jsx)(EditableText_2.EditableBadge, { id: `${itemPath}.badge`, "data-preview-field-path": `${itemPath}.badge`, defaultValue: badge, badgeVariant: "primary" }) })), !isAvailable && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${itemPath}.isAvailable`, style: {
122
- position: 'absolute',
123
- right: '10px',
124
- top: '10px',
125
- zIndex: 10,
126
- borderRadius: '999px',
127
- backgroundColor: '#be123c',
128
- color: '#ffffff',
129
- fontSize: '0.75rem',
130
- fontWeight: 700,
131
- padding: '4px 10px',
132
- }, children: "Out of Stock" }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
116
+ }, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.imageUrl`, "data-preview-field-path": `${itemPath}.imageUrl`, src: imageUrl, fallbackSrc: imageFallback, alt: name, aspectRatio: isHorizontal ? 'square' : '4/3', fit: "cover", hoverZoom: true, style: { width: '100%', height: '100%', display: 'block' } }), badge && ((0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', top: '10px', left: '10px', zIndex: 10 }, children: (0, jsx_runtime_1.jsx)(EditableText_2.EditableBadge, { id: `${itemPath}.badge`, "data-preview-field-path": `${itemPath}.badge`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
133
117
  padding: '1.25rem',
134
118
  display: 'flex',
135
119
  flexDirection: 'column',
@@ -139,27 +123,27 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
139
123
  fontSize: '0.75rem',
140
124
  textTransform: 'uppercase',
141
125
  letterSpacing: '0.05em',
142
- color: 'var(--brand-accent, #14b8a6)',
143
- fontWeight: 600,
126
+ color: 'var(--brand-accent, #a3e635)',
127
+ fontWeight: 700,
144
128
  display: 'inline-block',
145
129
  } })) : null, showBrand && brand ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.brand`, "data-preview-field-path": `${itemPath}.brand`, defaultValue: brand, style: {
146
130
  fontSize: '0.75rem',
147
131
  fontWeight: 700,
148
132
  letterSpacing: '0.08em',
149
133
  textTransform: 'uppercase',
150
- color: 'var(--muted-text, #64748b)',
151
- backgroundColor: 'rgba(241, 245, 249, 0.9)',
134
+ color: '#94a3b8',
135
+ backgroundColor: 'rgba(30, 41, 59, 0.8)',
152
136
  padding: '2px 8px',
153
137
  borderRadius: '6px',
154
138
  } })) : null] }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.name`, "data-preview-field-path": `${itemPath}.name`, defaultValue: name, style: {
155
139
  fontSize: '1.125rem',
156
140
  fontWeight: 700,
157
141
  lineHeight: 1.35,
158
- color: 'var(--heading-color, #0f172a)',
142
+ color: 'var(--heading-color, #ffffff)',
159
143
  marginBottom: '0.375rem',
160
144
  } }), showDescription && description ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, "data-preview-field-path": `${itemPath}.description`, defaultValue: description, style: {
161
145
  fontSize: '0.875rem',
162
- color: 'var(--muted-text, #64748b)',
146
+ color: 'var(--muted-text, #94a3b8)',
163
147
  lineHeight: 1.5,
164
148
  marginBottom: '0.75rem',
165
149
  display: '-webkit-box',
@@ -169,14 +153,14 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
169
153
  } })) : null] }), (0, jsx_runtime_1.jsxs)("div", { style: {
170
154
  marginTop: '0.75rem',
171
155
  paddingTop: '0.75rem',
172
- borderTop: cardVariant === 'minimal' ? 'none' : '1px solid rgba(226, 232, 240, 0.7)',
156
+ borderTop: cardVariant === 'minimal' ? 'none' : '1px solid rgba(51, 65, 85, 0.6)',
173
157
  display: 'flex',
174
158
  flexDirection: 'column',
175
159
  gap: '0.75rem',
176
160
  }, children: [hasPrice ? ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.5rem', flexWrap: 'wrap' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, "data-preview-field-path": `${itemPath}.price`, defaultValue: formattedPrice, style: {
177
161
  fontSize: '1.3rem',
178
162
  fontWeight: 800,
179
- color: 'var(--brand-color, #2563eb)',
163
+ color: 'var(--brand-color, #ffffff)',
180
164
  letterSpacing: '-0.02em',
181
165
  } }), originalPrice ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.originalPrice`, "data-preview-field-path": `${itemPath}.originalPrice`, defaultValue: originalPrice, style: {
182
166
  fontSize: '0.875rem',
@@ -186,16 +170,7 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
186
170
  fontSize: '0.8rem',
187
171
  fontWeight: 500,
188
172
  color: 'var(--muted-text, #64748b)',
189
- } })) : null] })) : null, !isAvailable ? ((0, jsx_runtime_1.jsx)("div", { "data-preview-field-path": `${itemPath}.isAvailable`, role: "status", style: {
190
- width: '100%',
191
- borderRadius: '10px',
192
- backgroundColor: '#e2e8f0',
193
- color: '#475569',
194
- padding: '0.65rem 0.75rem',
195
- textAlign: 'center',
196
- fontSize: '0.8125rem',
197
- fontWeight: 700,
198
- }, children: "Out of Stock" })) : actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsxs)("div", { style: {
173
+ } })) : null] })) : null, actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsxs)("div", { style: {
199
174
  display: 'grid',
200
175
  gridTemplateColumns: showWhatsAppButton && showAddToCartButton ? '1fr 1fr' : '1fr',
201
176
  gap: '0.5rem',
@@ -45,11 +45,11 @@ function EditableProductGrid({ sectionPath = 'home', listPath = 'products', titl
45
45
  const dClass = d === 3 ? 'lg:grid-cols-3' : d === 2 ? 'lg:grid-cols-2' : 'lg:grid-cols-4';
46
46
  return `${mClass} ${tClass} ${dClass}`;
47
47
  }, [columns]);
48
- return ((0, jsx_runtime_1.jsxs)("section", { "data-preview-page-key": sectionPath, className: `editable-product-grid max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 ${className}`.trim(), style: style, ...props, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row md:items-end justify-between mb-10 gap-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [subtitle && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.gridSubtitle`, className: "text-xs font-black tracking-widest uppercase text-lime-400 block mb-2", children: subtitle })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `${sectionPath}.gridTitle`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-white leading-tight", children: title })] }), resolvedCategories.length > 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap items-center gap-2", children: resolvedCategories.map((cat) => {
48
+ return ((0, jsx_runtime_1.jsxs)("section", { "data-preview-page-key": sectionPath, className: `editable-product-grid w-full mx-auto px-4 sm:px-6 lg:px-8 py-16 ${className}`.trim(), style: style, ...props, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row md:items-end justify-between mb-10 gap-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [subtitle && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.gridSubtitle`, className: "text-xs font-black tracking-widest uppercase text-lime-400 block mb-2", children: subtitle })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `${sectionPath}.gridTitle`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-white leading-tight", children: title })] }), resolvedCategories.length > 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap items-center gap-2", children: resolvedCategories.map((cat) => {
49
49
  const isActive = activeCategory.toLowerCase() === cat.toLowerCase();
50
50
  return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveCategory(cat), className: `px-4 py-2 rounded-xl text-xs font-bold transition-all duration-200 ${isActive
51
- ? 'bg-white text-slate-950 shadow-md scale-102 font-extrabold'
52
- : 'bg-slate-900/60 text-slate-400 hover:text-white border border-slate-800/80 hover:bg-slate-850'}`, children: cat }, cat));
51
+ ? 'bg-lime-400 text-slate-950 shadow-md scale-102 font-extrabold'
52
+ : 'bg-slate-900/60 text-slate-400 hover:text-white border border-slate-800/80 hover:bg-slate-800'}`, children: cat }, cat));
53
53
  }) }))] }), filteredProducts.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { ...(listPath ? { 'data-preview-list-path': listPath } : {}), className: `deneb-product-grid grid ${gridColClasses} gap-6 sm:gap-8`, children: filteredProducts.map((product, idx) => {
54
54
  const itemPath = listPath
55
55
  ? `${listPath}[${idx}]`
@@ -15,3 +15,4 @@ export interface EditableTestimonialSectionProps extends React.HTMLAttributes<HT
15
15
  cardClassName?: string;
16
16
  }
17
17
  export declare function EditableTestimonialSection({ basePath, badge, heading, subheading, testimonials, maxStars, className, cardClassName, style, ...props }: EditableTestimonialSectionProps): React.JSX.Element;
18
+ export type { TestimonialItem };
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EditableTestimonialSection = EditableTestimonialSection;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /* eslint-disable @next/next/no-img-element */
5
6
  const react_1 = require("react");
6
7
  const DEFAULT_TESTIMONIALS = [
7
8
  {
@@ -36,12 +37,12 @@ function StarSvg({ filled = true, size = 16 }) {
36
37
  return ((0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 24 24", style: {
37
38
  width: `${size}px`,
38
39
  height: `${size}px`,
39
- fill: filled ? '#fa7014' : '#dadce0',
40
- color: filled ? '#fa7014' : '#dadce0',
40
+ fill: filled ? '#fbbf24' : '#334155',
41
+ color: filled ? '#fbbf24' : '#334155',
41
42
  flexShrink: 0,
42
43
  }, "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" }) }));
43
44
  }
44
- function TestimonialCard({ item, index, basePath, maxStars, cardClassName, }) {
45
+ function TestimonialCard({ item, index, maxStars, cardClassName, }) {
45
46
  const currentItem = item || {};
46
47
  const rawRating = currentItem.rating != null && currentItem.rating !== '' ? currentItem.rating : 5;
47
48
  const initialRating = Math.min(Math.max(Math.round(Number(rawRating) || 5), 1), maxStars);
@@ -80,9 +81,9 @@ function TestimonialCard({ item, index, basePath, maxStars, cardClassName, }) {
80
81
  const authorAvatar = String(currentItem.avatar ||
81
82
  'https://images.unsplash.com/photo-1583394838336-acd977736f90?q=80&w=300&auto=format&fit=crop');
82
83
  const tagText = String(currentItem.tag || '');
83
- return ((0, jsx_runtime_1.jsxs)("div", { "data-preview-item-path": `testimonials.testimonials[${index}]`, className: `relative p-5 sm:p-7 lg:p-8 rounded-3xl bg-[#ffffff] border border-[#3d2114]/12 shadow-md hover:shadow-xl transition-all duration-300 flex flex-col justify-between space-y-5 min-w-0 ${cardClassName || ''}`.trim(), children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4 min-w-0", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [Boolean(currentItem.tag) && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `testimonials.testimonials[${index}].tag`, className: "px-2.5 py-1 rounded-full bg-[#f5ebe1] text-[#84431b] text-[10px] sm:text-[11px] uppercase tracking-wider font-extrabold border border-[#3d2114]/10 shrink-0", children: tagText })), (0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-1.5 p-1 -mr-1 rounded-lg cursor-pointer transition-all hover:bg-[#fa7014]/10 group ml-auto shrink-0", onClick: handleFocusRating, title: `Rating: ${currentRating} of ${maxStars} (Click to edit)`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", "data-fivora-stars-row": "true", children: Array.from({ length: maxStars }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(StarSvg, { filled: sIdx < currentRating, size: 14 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { ref: ratingRef, "data-preview-field-path": `testimonials.testimonials[${index}].rating`, "data-fivora-rating-text": "true", className: "text-xs font-black text-[#fa7014] bg-[#fa7014]/10 px-1.5 py-0.5 rounded-md border border-[#fa7014]/20 group-hover:bg-[#fa7014]/20 transition-colors tabular-nums", title: "Star count (1-5)", children: currentRating })] })] }), (0, jsx_runtime_1.jsxs)("blockquote", { "data-preview-field-path": `testimonials.testimonials[${index}].quote`, className: "font-serif-italic text-sm sm:text-base text-[#2b170e] leading-relaxed break-words", children: ["\u201C", quoteText, "\u201D"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "pt-4 border-t border-[#3d2114]/10 flex items-center gap-3 min-w-0", children: [(0, jsx_runtime_1.jsx)("img", { src: authorAvatar, alt: authorName, "data-preview-field-path": `testimonials.testimonials[${index}].avatar`, className: "w-10 h-10 sm:w-12 sm:h-12 rounded-full object-cover border border-[#3d2114]/15 shadow-sm shrink-0" }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("h4", { "data-preview-field-path": `testimonials.testimonials[${index}].author`, className: "font-heading font-black text-sm sm:text-base text-[#2b170e] truncate", children: authorName }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `testimonials.testimonials[${index}].role`, className: "text-xs text-[#786154] font-medium leading-snug line-clamp-2", children: authorRole })] })] })] }));
84
+ return ((0, jsx_runtime_1.jsxs)("div", { "data-preview-item-path": `testimonials.testimonials[${index}]`, className: `relative p-5 sm:p-7 lg:p-8 rounded-2xl bg-gradient-to-b from-slate-900/60 to-slate-950/80 border border-slate-800/80 hover:border-slate-700 shadow-md transition-all duration-300 flex flex-col justify-between space-y-5 min-w-0 ${cardClassName || ''}`.trim(), children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4 min-w-0", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [Boolean(currentItem.tag) && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `testimonials.testimonials[${index}].tag`, className: "px-2.5 py-1 rounded-full bg-slate-800/80 text-lime-400 text-[10px] sm:text-[11px] uppercase tracking-wider font-extrabold border border-lime-400/20 shrink-0", children: tagText })), (0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-1.5 p-1 -mr-1 rounded-lg cursor-pointer transition-all hover:bg-amber-400/10 group ml-auto shrink-0", onClick: handleFocusRating, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", "data-fivora-stars-row": "true", children: Array.from({ length: maxStars }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(StarSvg, { filled: sIdx < currentRating, size: 14 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { ref: ratingRef, "data-preview-field-path": `testimonials.testimonials[${index}].rating`, "data-fivora-rating-text": "true", className: "text-xs font-black text-amber-400 bg-amber-400/10 px-1.5 py-0.5 rounded-md border border-amber-400/20 group-hover:bg-amber-400/20 transition-colors tabular-nums", children: currentRating })] })] }), (0, jsx_runtime_1.jsxs)("blockquote", { "data-preview-field-path": `testimonials.testimonials[${index}].quote`, className: "font-serif-italic text-sm sm:text-base text-slate-300 leading-relaxed break-words", children: ["\u201C", quoteText, "\u201D"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "pt-4 border-t border-slate-800/60 flex items-center gap-3 min-w-0", children: [(0, jsx_runtime_1.jsx)("img", { src: authorAvatar, alt: authorName, "data-preview-field-path": `testimonials.testimonials[${index}].avatar`, className: "w-10 h-10 sm:w-12 sm:h-12 rounded-full object-cover border border-slate-700 shadow-sm shrink-0" }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("h4", { "data-preview-field-path": `testimonials.testimonials[${index}].author`, className: "font-heading font-black text-sm sm:text-base text-white truncate", children: authorName }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `testimonials.testimonials[${index}].role`, className: "text-xs text-slate-400 font-medium leading-snug line-clamp-2", children: authorRole })] })] })] }));
84
85
  }
85
- function EditableTestimonialSection({ basePath = 'testimonials', badge = 'WORDS OF ACCLAIM', heading = 'WHAT THE CRITICS ARE SAYING', subheading = 'Reflections from international cuppers, culinary masters, and dedicated regulars.', testimonials = DEFAULT_TESTIMONIALS, maxStars = 5, className = '', cardClassName = '', style, ...props }) {
86
+ function EditableTestimonialSection({ basePath = 'testimonials', badge = 'CRITIC ACCLAIM', heading = 'What Connoisseurs Say', subheading = 'Unfiltered sensory impressions and reviews from sommeliers, culinary critics, and world sensory judges.', testimonials = DEFAULT_TESTIMONIALS, maxStars = 5, className = '', cardClassName = '', style, ...props }) {
86
87
  const items = (0, react_1.useMemo)(() => {
87
88
  const list = Array.isArray(testimonials) ? testimonials : [];
88
89
  if (list.length === 0) {
@@ -101,5 +102,5 @@ function EditableTestimonialSection({ basePath = 'testimonials', badge = 'WORDS
101
102
  };
102
103
  });
103
104
  }, [testimonials]);
104
- return ((0, jsx_runtime_1.jsx)("section", { "data-design-section": "testimonials", className: `editable-testimonial-section w-full py-12 sm:py-20 px-3 sm:px-6 lg:px-8 ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "w-full mx-auto", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-center max-w-3xl mx-auto space-y-3 mb-10 sm:mb-14 px-2", children: [badge && ((0, jsx_runtime_1.jsx)("div", { className: "inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-[#ede0d4] text-[#3d2114] text-xs uppercase tracking-widest font-black border border-[#3d2114]/15", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `testimonials.badge`, children: badge }) })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `testimonials.heading`, className: "font-heading text-2xl xs:text-3xl sm:text-4xl lg:text-5xl font-black text-[#2b170e] tracking-tight", children: heading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `testimonials.subheading`, className: "text-xs sm:text-base text-[#5c493f] leading-relaxed max-w-2xl mx-auto", children: subheading })] }), (0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": `testimonials.testimonials`, className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5 sm:gap-7 [grid-template-columns:repeat(auto-fit,minmax(min(100%,290px),1fr))] w-full", children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(TestimonialCard, { item: item, index: index, basePath: basePath, maxStars: maxStars, cardClassName: cardClassName }, item.id || `testimonial-${index}`))) })] }) }));
105
+ return ((0, jsx_runtime_1.jsx)("section", { "data-design-section": "testimonials", className: `editable-testimonial-section w-full py-12 sm:py-20 px-3 sm:px-6 lg:px-8 ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "w-full mx-auto", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-center max-w-3xl mx-auto space-y-3 mb-10 sm:mb-14 px-2", children: [badge && ((0, jsx_runtime_1.jsx)("div", { className: "inline-flex items-center gap-2 px-3.5 py-1 rounded-full bg-lime-400/10 text-lime-400 text-xs uppercase tracking-widest font-black border border-lime-400/20", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `testimonials.badge`, children: badge }) })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `testimonials.heading`, className: "font-heading text-2xl xs:text-3xl sm:text-4xl lg:text-5xl font-black text-white tracking-tight", children: heading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `testimonials.subheading`, className: "text-xs sm:text-base text-slate-400 leading-relaxed max-w-2xl mx-auto", children: subheading })] }), (0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": `testimonials.testimonials`, className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5 sm:gap-7 [grid-template-columns:repeat(auto-fit,minmax(min(100%,290px),1fr))] w-full", children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(TestimonialCard, { item: item, index: index, maxStars: maxStars, cardClassName: cardClassName }, item.id || String(index)))) })] }) }));
105
106
  }
@@ -61,27 +61,53 @@ function findProduct(products, productId) {
61
61
  };
62
62
  }
63
63
  function normalizeProductForDetail(product, siteData) {
64
- const image = (typeof product.featuredImage === 'string' && product.featuredImage) ||
65
- (typeof product.imageUrl === 'string' && product.imageUrl) ||
66
- (typeof product.image === 'string' && product.image) ||
64
+ const customData = (0, SiteDataProvider_1.isRecord)(product.customData) ? product.customData : {};
65
+ // Public catalog rows keep template-specific variants in customData. Flatten
66
+ // them for custom renderers while preserving explicit top-level fields.
67
+ const mergedProduct = {
68
+ ...customData,
69
+ ...product,
70
+ };
71
+ const name = (typeof mergedProduct.name === 'string' && mergedProduct.name) ||
72
+ (typeof mergedProduct.title === 'string' && mergedProduct.title) ||
73
+ undefined;
74
+ const image = (typeof mergedProduct.featuredImage === 'string' && mergedProduct.featuredImage) ||
75
+ (typeof mergedProduct.imageUrl === 'string' && mergedProduct.imageUrl) ||
76
+ (typeof mergedProduct.image === 'string' && mergedProduct.image) ||
67
77
  undefined;
68
- const images = Array.isArray(product.gallery)
69
- ? product.gallery
70
- : Array.isArray(product.images)
71
- ? product.images
72
- : undefined;
78
+ const images = Array.isArray(mergedProduct.gallery)
79
+ ? mergedProduct.gallery
80
+ : Array.isArray(mergedProduct.images)
81
+ ? mergedProduct.images
82
+ : Array.isArray(mergedProduct.additionalImages)
83
+ ? mergedProduct.additionalImages.filter((value) => typeof value === 'string' && Boolean(value.trim()))
84
+ : undefined;
85
+ const compareAtPrice = mergedProduct.compareAtPrice ?? mergedProduct.originalPrice;
73
86
  const shop = (0, SiteDataProvider_1.isRecord)(siteData.shop) ? siteData.shop : {};
74
87
  const merchant = (0, SiteDataProvider_1.isRecord)(siteData.merchant) ? siteData.merchant : {};
75
- const whatsappNumber = (typeof product.whatsappNumber === 'string' && product.whatsappNumber) ||
88
+ const whatsappNumber = (typeof mergedProduct.whatsappNumber === 'string' && mergedProduct.whatsappNumber) ||
76
89
  (typeof shop.whatsapp === 'string' && shop.whatsapp) ||
77
90
  (typeof shop.whatsappNumber === 'string' && shop.whatsappNumber) ||
78
91
  (typeof merchant.whatsapp === 'string' && merchant.whatsapp) ||
79
92
  undefined;
80
93
  return {
81
- ...product,
82
- ...(image && !product.featuredImage ? { featuredImage: image } : {}),
83
- ...(images && !product.gallery ? { gallery: images } : {}),
84
- ...(whatsappNumber && !product.whatsappNumber ? { whatsappNumber } : {}),
94
+ ...mergedProduct,
95
+ ...(name
96
+ ? {
97
+ name,
98
+ title: typeof mergedProduct.title === 'string' && mergedProduct.title
99
+ ? mergedProduct.title
100
+ : name,
101
+ }
102
+ : {}),
103
+ ...(image
104
+ ? { featuredImage: image, imageUrl: image, image }
105
+ : {}),
106
+ ...(images ? { gallery: images, images } : {}),
107
+ ...(compareAtPrice !== undefined
108
+ ? { compareAtPrice, originalPrice: compareAtPrice }
109
+ : {}),
110
+ ...(whatsappNumber ? { whatsappNumber } : {}),
85
111
  };
86
112
  }
87
113
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deneb-ui/ui",
3
- "version": "2.0.62",
3
+ "version": "2.0.64",
4
4
  "description": "Visual-first React component library for editable commerce storefronts. Built for Next.js and Fivora.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -50,7 +50,7 @@
50
50
  ],
51
51
  "license": "MIT",
52
52
  "dependencies": {
53
- "@deneb-ui/core": "^2.0.62"
53
+ "@deneb-ui/core": "^2.0.64"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "react": "^18.0.0 || ^19.0.0",