@deneb-ui/ui 2.0.95 → 2.0.96
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 +119 -0
- package/dist/DenebComponentStyles.js +7 -0
- package/dist/EditableCustomerReviews.d.ts +2 -1
- package/dist/EditableCustomerReviews.js +2 -2
- package/dist/EditableFAQAccordion.d.ts +3 -2
- package/dist/EditableFAQAccordion.js +2 -1
- package/dist/EditableGoogleFeedback.js +1 -1
- package/dist/EditableHero.js +2 -2
- package/dist/EditableProductCard.d.ts +15 -71
- package/dist/EditableProductCard.js +176 -27
- package/dist/EditableProductDetail.d.ts +11 -6
- package/dist/EditableProductDetail.js +24 -9
- package/dist/EditableProductGrid.d.ts +4 -1
- package/dist/EditableProductGrid.js +3 -3
- package/dist/EditableProductShowcase.js +1 -1
- package/dist/EditableSection.d.ts +32 -7
- package/dist/EditableSection.js +20 -7
- package/dist/EditableTestimonialSection.js +1 -1
- package/dist/EditableText.d.ts +5 -1
- package/dist/EditableText.js +2 -2
- package/dist/SiteDataProvider.js +16 -5
- package/dist/TrustBadges.js +1 -1
- package/dist/cart/useCart.d.ts +3 -0
- package/dist/cart/useCart.js +20 -9
- package/dist/examples/CompleteStorefrontExample.d.ts +11 -0
- package/dist/examples/CompleteStorefrontExample.js +97 -0
- package/dist/examples/ProductPricingExample.d.ts +9 -0
- package/dist/examples/ProductPricingExample.js +99 -0
- package/dist/examples/SectionLayoutExample.d.ts +7 -0
- package/dist/examples/SectionLayoutExample.js +17 -0
- package/dist/examples/index.d.ts +3 -0
- package/dist/examples/index.js +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/utils/productOptions.d.ts +57 -40
- package/dist/utils/productOptions.js +249 -62
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -600,6 +600,125 @@ The engine automatically:
|
|
|
600
600
|
|
|
601
601
|
---
|
|
602
602
|
|
|
603
|
+
### Modular Section Architecture (`<section>` & `<Section>`)
|
|
604
|
+
|
|
605
|
+
DENEB UI introduces a modular `<section>` architecture designed specifically for visual website builders, enabling 1-click section deletion, full layout centering, and background styling.
|
|
606
|
+
|
|
607
|
+
#### Key Features
|
|
608
|
+
* **100% Contract Compliant**: Automatically sets `data-design-section`, `data-section-id`, and `id`.
|
|
609
|
+
* **1-Click Delete / Hide**: Supports `hidden={true}` or visual editor hide toggle (`display: none`).
|
|
610
|
+
* **Instant Centering**: One-prop horizontal and text centering with `center={true}` or `align="center"`.
|
|
611
|
+
* **Responsive Container**: `container={true}` wraps children in a responsive, max-width contained inner wrapper (`1280px`).
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
import { Section, EditableSection, Heading, Paragraph, Button } from "@deneb-ui/ui";
|
|
615
|
+
|
|
616
|
+
export function PromoSection() {
|
|
617
|
+
return (
|
|
618
|
+
// Clean shorthand alias
|
|
619
|
+
<Section
|
|
620
|
+
name="special-promo"
|
|
621
|
+
center={true}
|
|
622
|
+
container={true}
|
|
623
|
+
bg="#f8fafc"
|
|
624
|
+
padding="xl"
|
|
625
|
+
>
|
|
626
|
+
<Heading level={2} id="promo.title" defaultValue="Limited Time Offer" />
|
|
627
|
+
<Paragraph id="promo.subtitle" defaultValue="Get 20% off all handcrafted items." />
|
|
628
|
+
<Button id="promo.cta" defaultValue="Shop the Sale" />
|
|
629
|
+
</Section>
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
### Dual Product Pricing & Apparel Variants
|
|
637
|
+
|
|
638
|
+
DENEB UI commerce components natively support both **Single Fixed Prices** and **Dynamic Price Ranges**, as well as apparel clothing options (color swatches with image swapping and size chips).
|
|
639
|
+
|
|
640
|
+
#### 1. Single Fixed Price
|
|
641
|
+
```tsx
|
|
642
|
+
import { ProductCard } from "@deneb-ui/ui";
|
|
643
|
+
|
|
644
|
+
<ProductCard
|
|
645
|
+
item={{
|
|
646
|
+
id: "prod-1",
|
|
647
|
+
name: "Classic Silk Shirt",
|
|
648
|
+
price: 3500,
|
|
649
|
+
compareAtPrice: 4500,
|
|
650
|
+
currency: "LKR",
|
|
651
|
+
imageUrl: "/images/shirt.jpg"
|
|
652
|
+
}}
|
|
653
|
+
itemPath="products[0]"
|
|
654
|
+
/>
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
#### 2. Dynamic Price Range & Apparel Color Swatches
|
|
658
|
+
```tsx
|
|
659
|
+
import { ProductCard } from "@deneb-ui/ui";
|
|
660
|
+
|
|
661
|
+
<ProductCard
|
|
662
|
+
item={{
|
|
663
|
+
id: "prod-2",
|
|
664
|
+
name: "Linen Summer Tunic",
|
|
665
|
+
minPrice: 2500,
|
|
666
|
+
maxPrice: 4500,
|
|
667
|
+
priceRange: "LKR 2,500 – LKR 4,500",
|
|
668
|
+
isPriceRange: true,
|
|
669
|
+
currency: "LKR",
|
|
670
|
+
imageUrl: "/images/tunic-navy.jpg",
|
|
671
|
+
colors: [
|
|
672
|
+
{ name: "Navy Blue", hex: "#1e3a8a", imageUrl: "/images/tunic-navy.jpg" },
|
|
673
|
+
{ name: "Olive Green", hex: "#3f6212", imageUrl: "/images/tunic-olive.jpg" },
|
|
674
|
+
{ name: "Cream White", hex: "#f8fafc", imageUrl: "/images/tunic-white.jpg" }
|
|
675
|
+
],
|
|
676
|
+
sizes: ["S", "M", "L", "XL"],
|
|
677
|
+
variants: [
|
|
678
|
+
{ color: "Navy Blue", size: "S", price: 2500 },
|
|
679
|
+
{ color: "Navy Blue", size: "XL", price: 3200 },
|
|
680
|
+
{ color: "Olive Green", size: "L", price: 4500 }
|
|
681
|
+
]
|
|
682
|
+
}}
|
|
683
|
+
itemPath="products[1]"
|
|
684
|
+
whatsappPhone="+94771234567"
|
|
685
|
+
/>
|
|
686
|
+
```
|
|
687
|
+
* **Interactive Color Swatches**: Clicking a color automatically swaps the card's active product photo to that color's image.
|
|
688
|
+
* **Variant Price Resolution**: Displays the range (`LKR 2,500 – LKR 4,500`) initially, then resolves to the exact variant price when a size/color is selected.
|
|
689
|
+
* **Smart WhatsApp & Cart**: Automatically compiles `[Color: Navy Blue, Size: XL]` into the customer's WhatsApp order message and cart drawer line items.
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## Reference Examples
|
|
694
|
+
|
|
695
|
+
DENEB UI includes full, ready-to-run reference examples demonstrating modular layouts, dual pricing, and complete storefront architecture:
|
|
696
|
+
|
|
697
|
+
```tsx
|
|
698
|
+
import {
|
|
699
|
+
SectionLayoutExample,
|
|
700
|
+
ProductPricingExample,
|
|
701
|
+
CompleteStorefrontExample
|
|
702
|
+
} from "@deneb-ui/ui";
|
|
703
|
+
|
|
704
|
+
// 1. Modular section centering & hiding controls
|
|
705
|
+
export function SectionDemo() {
|
|
706
|
+
return <SectionLayoutExample />;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// 2. Single price, price ranges, and apparel swatches with photo switching
|
|
710
|
+
export function CommerceDemo() {
|
|
711
|
+
return <ProductPricingExample />;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// 3. Full production-ready Next.js storefront page
|
|
715
|
+
export function FullStorefrontDemo() {
|
|
716
|
+
return <CompleteStorefrontExample />;
|
|
717
|
+
}
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
603
722
|
## Related Packages
|
|
604
723
|
|
|
605
724
|
| Package | Purpose |
|
|
@@ -78,6 +78,13 @@ function DenebComponentStyles() {
|
|
|
78
78
|
max-width: var(--deneb-section-max-w, inherit);
|
|
79
79
|
background-color: var(--deneb-section-bg, inherit);
|
|
80
80
|
background-image: var(--deneb-section-bg-image, none);
|
|
81
|
+
text-align: var(--deneb-section-align, inherit);
|
|
82
|
+
display: var(--deneb-section-display, block);
|
|
83
|
+
order: var(--deneb-section-order, 0);
|
|
84
|
+
}
|
|
85
|
+
body > main, main, [data-preview-page-key] {
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
81
88
|
}
|
|
82
89
|
`;
|
|
83
90
|
return (0, jsx_runtime_1.jsx)("style", { "data-deneb-component-styles": true, children: css });
|
|
@@ -15,6 +15,7 @@ export interface EditableCustomerReviewsProps extends React.HTMLAttributes<HTMLE
|
|
|
15
15
|
* Field path prefix for live Fivora Visual Editing synchronization (e.g. "home").
|
|
16
16
|
*/
|
|
17
17
|
sectionPath?: string;
|
|
18
|
+
listPath?: string;
|
|
18
19
|
/**
|
|
19
20
|
* Title of the reviews section.
|
|
20
21
|
*/
|
|
@@ -44,5 +45,5 @@ export interface EditableCustomerReviewsProps extends React.HTMLAttributes<HTMLE
|
|
|
44
45
|
*
|
|
45
46
|
* Created by Chamika Gayashan & Induranga Kawishwara
|
|
46
47
|
*/
|
|
47
|
-
export declare function EditableCustomerReviews({ sectionPath, title, subtitle, averageRating, totalReviews, reviews, className, style, ...props }: EditableCustomerReviewsProps): React.JSX.Element;
|
|
48
|
+
export declare function EditableCustomerReviews({ sectionPath, listPath, title, subtitle, averageRating, totalReviews, reviews, className, style, ...props }: EditableCustomerReviewsProps): React.JSX.Element;
|
|
48
49
|
export declare const CustomerReviews: typeof EditableCustomerReviews;
|
|
@@ -44,7 +44,7 @@ const DEFAULT_REVIEWS = [
|
|
|
44
44
|
*
|
|
45
45
|
* Created by Chamika Gayashan & Induranga Kawishwara
|
|
46
46
|
*/
|
|
47
|
-
function EditableCustomerReviews({ sectionPath = 'home', title, subtitle, averageRating, totalReviews, reviews, className = '', style, ...props }) {
|
|
47
|
+
function EditableCustomerReviews({ sectionPath = 'home', listPath = 'reviews', title, subtitle, averageRating, totalReviews, reviews, className = '', style, ...props }) {
|
|
48
48
|
const [selectedStarFilter, setSelectedStarFilter] = (0, react_1.useState)(null);
|
|
49
49
|
const liveReviews = (0, SiteDataProvider_1.useReviews)();
|
|
50
50
|
const siteData = (0, SiteDataProvider_1.useSiteData)();
|
|
@@ -85,7 +85,7 @@ function EditableCustomerReviews({ sectionPath = 'home', title, subtitle, averag
|
|
|
85
85
|
return normalizedReviews;
|
|
86
86
|
return normalizedReviews.filter((r) => r.rating === selectedStarFilter);
|
|
87
87
|
}, [normalizedReviews, selectedStarFilter]);
|
|
88
|
-
return ((0, jsx_runtime_1.jsxs)("section", { "data-preview-page-key": sectionPath, className: `editable-customer-reviews 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: "text-center max-w-2xl mx-auto mb-12", children: [subtitle && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsSubtitle`, className: "text-xs font-black tracking-widest uppercase text-emerald-600 dark:text-lime-400 block mb-2", children: resolvedSubtitle })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `${sectionPath}.reviewsTitle`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-slate-900 dark:text-white leading-tight", children: resolvedTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex text-amber-500 dark:text-amber-400 text-lg", children: '★★★★★' }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-900 dark:text-white font-extrabold text-lg", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsAverage`, children: resolvedAverageRating }), " / 5.0"] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-500 dark:text-slate-400 text-sm", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsCount`, children: resolvedTotalReviews }), " reviews)"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center gap-2 mb-8", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedStarFilter(null), className: `px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all ${selectedStarFilter === null
|
|
88
|
+
return ((0, jsx_runtime_1.jsxs)("section", { id: props.id || "customer-reviews", "data-design-section": "customer-reviews", "data-section-id": "customer-reviews", "data-preview-page-key": sectionPath, className: `editable-customer-reviews 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: "text-center max-w-2xl mx-auto mb-12", children: [subtitle && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsSubtitle`, className: "text-xs font-black tracking-widest uppercase text-emerald-600 dark:text-lime-400 block mb-2", children: resolvedSubtitle })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `${sectionPath}.reviewsTitle`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-slate-900 dark:text-white leading-tight", children: resolvedTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex text-amber-500 dark:text-amber-400 text-lg", children: '★★★★★' }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-900 dark:text-white font-extrabold text-lg", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsAverage`, children: resolvedAverageRating }), " / 5.0"] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-500 dark:text-slate-400 text-sm", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsCount`, children: resolvedTotalReviews }), " reviews)"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center gap-2 mb-8", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedStarFilter(null), className: `px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all ${selectedStarFilter === null
|
|
89
89
|
? 'bg-slate-900 text-white dark:bg-lime-400 dark:text-slate-950 font-extrabold shadow-sm'
|
|
90
90
|
: 'bg-slate-100 text-slate-600 hover:text-slate-900 border border-slate-200 dark:bg-slate-900/60 dark:text-slate-400 dark:hover:text-white dark:border-slate-800'}`, children: "All Reviews" }), [5, 4, 3].map((stars) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: () => setSelectedStarFilter(stars), className: `px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-1 ${selectedStarFilter === stars
|
|
91
91
|
? 'bg-slate-900 text-white dark:bg-lime-400 dark:text-slate-950 font-extrabold shadow-sm'
|
|
@@ -13,7 +13,8 @@ export interface EditableFAQItemProps extends React.HTMLAttributes<HTMLElement>
|
|
|
13
13
|
export declare function EditableFAQItem({ itemPath, item, defaultOpen, className, style, ...props }: EditableFAQItemProps): React.JSX.Element;
|
|
14
14
|
export interface EditableFAQAccordionProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
15
15
|
listPath?: string;
|
|
16
|
-
items
|
|
16
|
+
items?: FAQItem[];
|
|
17
|
+
faqs?: FAQItem[];
|
|
17
18
|
defaultOpenIndex?: number;
|
|
18
19
|
}
|
|
19
|
-
export declare function EditableFAQAccordion({ listPath, items, defaultOpenIndex, className, style, ...props }: EditableFAQAccordionProps): React.JSX.Element;
|
|
20
|
+
export declare function EditableFAQAccordion({ listPath, items: itemsProp, faqs, defaultOpenIndex, className, style, ...props }: EditableFAQAccordionProps): React.JSX.Element;
|
|
@@ -53,7 +53,8 @@ function EditableFAQItem({ itemPath, item, defaultOpen = true, className = '', s
|
|
|
53
53
|
lineHeight: 1.6,
|
|
54
54
|
} }) })] }));
|
|
55
55
|
}
|
|
56
|
-
function EditableFAQAccordion({ listPath = 'home.faq', items
|
|
56
|
+
function EditableFAQAccordion({ listPath = 'home.faq', items: itemsProp, faqs, defaultOpenIndex = 0, className = '', style, ...props }) {
|
|
57
|
+
const items = faqs || itemsProp || [];
|
|
57
58
|
return ((0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": listPath, style: {
|
|
58
59
|
maxWidth: '800px',
|
|
59
60
|
margin: '0 auto',
|
|
@@ -153,7 +153,7 @@ function EditableGoogleFeedback({ heading, subheading, badgeTitle = 'Google Revi
|
|
|
153
153
|
const effectiveSubheading = subheading ?? siteData?.content?.[basePath]?.subheading ?? 'Real stories and verified 5-star reviews from our official Google Business profile.';
|
|
154
154
|
const hasCustomPy = /(^|\s)(p|py|pt)-/.test(className);
|
|
155
155
|
const defaultPadding = hasCustomPy ? '' : 'py-6 sm:py-8';
|
|
156
|
-
return ((0, jsx_runtime_1.jsx)("section", { "data-preview-page-key": basePath, className: `editable-google-feedback w-full ${defaultPadding} ${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-6 sm:mb-8", 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-100 border border-slate-200 dark:bg-slate-900/80 dark: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-slate-800 dark:text-slate-200", children: badgeTitle }), (0, jsx_runtime_1.jsx)("span", { className: "w-1 h-1 rounded-full bg-slate-400 dark:bg-slate-600" }), (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-600 dark:text-amber-400", children: effectiveBadgeRating }), (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-500 dark:text-slate-400 font-medium hidden sm:inline", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, children: effectiveBadgeCount }), ")"] })] }), (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-slate-900 dark:text-white tracking-tight", children: effectiveHeading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `feedback.subheading`, className: "text-xs sm:text-base text-slate-600 dark:text-slate-400 leading-relaxed", children: effectiveSubheading })] }), (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-amber-500 dark: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-500 dark: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, badgeTitle: badgeTitle, cardClassName: cardClassName }, item.id || String(index)))) })] }) }));
|
|
156
|
+
return ((0, jsx_runtime_1.jsx)("section", { id: props.id || "google-feedback", "data-design-section": "google-feedback", "data-section-id": "google-feedback", "data-preview-page-key": basePath, className: `editable-google-feedback w-full ${defaultPadding} ${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-6 sm:mb-8", 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-100 border border-slate-200 dark:bg-slate-900/80 dark: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-slate-800 dark:text-slate-200", children: badgeTitle }), (0, jsx_runtime_1.jsx)("span", { className: "w-1 h-1 rounded-full bg-slate-400 dark:bg-slate-600" }), (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-600 dark:text-amber-400", children: effectiveBadgeRating }), (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-500 dark:text-slate-400 font-medium hidden sm:inline", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, children: effectiveBadgeCount }), ")"] })] }), (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-slate-900 dark:text-white tracking-tight", children: effectiveHeading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `feedback.subheading`, className: "text-xs sm:text-base text-slate-600 dark:text-slate-400 leading-relaxed", children: effectiveSubheading })] }), (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-amber-500 dark: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-500 dark: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, badgeTitle: badgeTitle, cardClassName: cardClassName }, item.id || String(index)))) })] }) }));
|
|
157
157
|
}
|
|
158
158
|
// Canonical alias
|
|
159
159
|
exports.GoogleFeedback = EditableGoogleFeedback;
|
package/dist/EditableHero.js
CHANGED
|
@@ -33,7 +33,7 @@ function EditableHeroCentered({ pageKey = 'home', badgePath = 'home.heroEyebrow'
|
|
|
33
33
|
window.location.href = `${cleanBase}${cleanPath}` || '/';
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
-
return ((0, jsx_runtime_1.jsx)("section", { "data-design-section": "hero", style: {
|
|
36
|
+
return ((0, jsx_runtime_1.jsx)("section", { id: props.id || "hero", "data-design-section": "hero", "data-section-id": "hero", style: {
|
|
37
37
|
padding: '5rem 1.5rem',
|
|
38
38
|
textAlign: 'center',
|
|
39
39
|
position: 'relative',
|
|
@@ -112,7 +112,7 @@ function EditableHeroSplit({ pageKey = 'home', badgePath = 'home.heroEyebrow', t
|
|
|
112
112
|
window.location.href = `${cleanBase}${cleanPath}` || '/';
|
|
113
113
|
}
|
|
114
114
|
};
|
|
115
|
-
return ((0, jsx_runtime_1.jsxs)("section", { "data-design-section": "hero", style: {
|
|
115
|
+
return ((0, jsx_runtime_1.jsxs)("section", { id: props.id || "hero", "data-design-section": "hero", "data-section-id": "hero", style: {
|
|
116
116
|
padding: '5rem 1.5rem',
|
|
117
117
|
display: 'grid',
|
|
118
118
|
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { MeasurementUnit } from './utils/productOptions';
|
|
2
|
+
import { MeasurementUnit, ProductVariant } from './utils/productOptions';
|
|
3
3
|
export interface ProductItem {
|
|
4
4
|
id?: string | number;
|
|
5
5
|
name?: string;
|
|
@@ -46,101 +46,45 @@ export interface ProductItem {
|
|
|
46
46
|
colors?: Array<string | {
|
|
47
47
|
name: string;
|
|
48
48
|
hex?: string;
|
|
49
|
+
image?: string;
|
|
49
50
|
}> | string;
|
|
50
51
|
colorsText?: string;
|
|
51
52
|
colorsLabel?: string;
|
|
53
|
+
variants?: ProductVariant[];
|
|
54
|
+
variantPrices?: Record<string, number | string>;
|
|
55
|
+
minPrice?: string | number;
|
|
56
|
+
maxPrice?: string | number;
|
|
57
|
+
priceMin?: string | number;
|
|
58
|
+
priceMax?: string | number;
|
|
59
|
+
priceRange?: [number | string, number | string] | string;
|
|
52
60
|
[key: string]: unknown;
|
|
53
61
|
}
|
|
54
62
|
export type ProductCardVariant = 'modern-glass' | 'classic' | 'minimal' | 'horizontal';
|
|
55
63
|
export interface EditableProductCardProps extends React.HTMLAttributes<HTMLElement> {
|
|
56
|
-
/**
|
|
57
|
-
* The item path for the product, e.g. "products[0]" or "featuredProducts[1]".
|
|
58
|
-
*/
|
|
59
64
|
itemPath: string;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
*/
|
|
63
|
-
product: ProductItem;
|
|
64
|
-
/**
|
|
65
|
-
* Design variant: 'modern-glass' | 'classic' | 'minimal' | 'horizontal'
|
|
66
|
-
*/
|
|
65
|
+
product?: ProductItem;
|
|
66
|
+
item?: ProductItem;
|
|
67
67
|
cardVariant?: ProductCardVariant;
|
|
68
|
-
/**
|
|
69
|
-
* Fallback image URL if product image is empty.
|
|
70
|
-
*/
|
|
71
68
|
imageFallback?: string;
|
|
72
|
-
/**
|
|
73
|
-
* HTML wrapper tag (default: 'article').
|
|
74
|
-
*/
|
|
75
69
|
as?: React.ElementType;
|
|
76
|
-
/**
|
|
77
|
-
* Currency code or symbol (default: 'LKR').
|
|
78
|
-
*/
|
|
79
70
|
currency?: string;
|
|
80
|
-
/**
|
|
81
|
-
* Whether to display the brand tag (default: true).
|
|
82
|
-
*/
|
|
83
71
|
showBrand?: boolean;
|
|
84
|
-
/**
|
|
85
|
-
* Whether to display the price field (default: true).
|
|
86
|
-
*/
|
|
87
72
|
showPrice?: boolean;
|
|
88
|
-
/**
|
|
89
|
-
* Whether to display the description field (default: true).
|
|
90
|
-
*/
|
|
91
73
|
showDescription?: boolean;
|
|
92
|
-
/**
|
|
93
|
-
* Whether to display category pill (default: true if present).
|
|
94
|
-
*/
|
|
95
74
|
showCategory?: boolean;
|
|
96
|
-
/**
|
|
97
|
-
* Default WhatsApp account number for inquiries (e.g. '94771234567').
|
|
98
|
-
*/
|
|
99
75
|
whatsappNumber?: string;
|
|
100
|
-
|
|
101
|
-
* Store name for WhatsApp message templates.
|
|
102
|
-
*/
|
|
76
|
+
whatsappPhone?: string;
|
|
103
77
|
storeName?: string;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
*/
|
|
78
|
+
showOptions?: boolean;
|
|
79
|
+
allowInteractiveSwatches?: boolean;
|
|
107
80
|
showWhatsAppButton?: boolean;
|
|
108
|
-
/**
|
|
109
|
-
* Whether to display the Add to Cart button (default: true).
|
|
110
|
-
*/
|
|
111
81
|
showAddToCartButton?: boolean;
|
|
112
|
-
/**
|
|
113
|
-
* Default label for the WhatsApp button (default: 'Inquire on WhatsApp').
|
|
114
|
-
*/
|
|
115
82
|
whatsappActionLabel?: string;
|
|
116
|
-
/**
|
|
117
|
-
* Default label for the Add to Cart button (default: 'Add to Cart').
|
|
118
|
-
*/
|
|
119
83
|
addToCartLabel?: string;
|
|
120
|
-
/**
|
|
121
|
-
* Optional custom action slot (overrides dual action buttons).
|
|
122
|
-
*/
|
|
123
84
|
actionSlot?: React.ReactNode;
|
|
124
|
-
/**
|
|
125
|
-
* Legacy action label fallback.
|
|
126
|
-
*/
|
|
127
85
|
actionLabel?: string;
|
|
128
|
-
/**
|
|
129
|
-
* Legacy action label path fallback.
|
|
130
|
-
*/
|
|
131
86
|
actionLabelPath?: string;
|
|
132
|
-
/**
|
|
133
|
-
* Optional callback when Add to Cart is clicked.
|
|
134
|
-
*/
|
|
135
87
|
onAddToCart?: (product: ProductItem) => void;
|
|
136
|
-
/**
|
|
137
|
-
* Optional callback when WhatsApp button is clicked.
|
|
138
|
-
*/
|
|
139
88
|
onWhatsAppClick?: (product: ProductItem, url: string) => void;
|
|
140
89
|
}
|
|
141
|
-
|
|
142
|
-
* EditableProductCard is an elite, auto-balancing commerce card featuring
|
|
143
|
-
* Sri Lankan Rupee (LKR) pricing, dual WhatsApp + Add to Cart actions,
|
|
144
|
-
* brand attribution, and strict Fivora visual editing synchronization.
|
|
145
|
-
*/
|
|
146
|
-
export declare function EditableProductCard({ itemPath, product, cardVariant, imageFallback, as: Component, currency, showBrand, showPrice, showDescription, showCategory, whatsappNumber, storeName, showWhatsAppButton, showAddToCartButton, whatsappActionLabel, addToCartLabel, actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
|
|
90
|
+
export declare function EditableProductCard({ itemPath, product: productProp, item: itemProp, cardVariant, imageFallback, as: Component, currency, showBrand, showPrice, showDescription, showCategory, whatsappNumber: whatsappNumberProp, whatsappPhone: whatsappPhoneProp, showOptions, allowInteractiveSwatches, storeName, showWhatsAppButton, showAddToCartButton, whatsappActionLabel, addToCartLabel, actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
|