@deneb-ui/ui 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +182 -0
  2. package/dist/EditableBox.d.ts +56 -0
  3. package/dist/EditableBox.js +113 -0
  4. package/dist/EditableCard.d.ts +48 -0
  5. package/dist/EditableCard.js +85 -0
  6. package/dist/EditableContactForm.d.ts +11 -0
  7. package/dist/EditableContactForm.js +146 -0
  8. package/dist/EditableDialog.d.ts +25 -0
  9. package/dist/EditableDialog.js +145 -0
  10. package/dist/EditableFAQAccordion.d.ts +19 -0
  11. package/dist/EditableFAQAccordion.js +62 -0
  12. package/dist/EditableFooter.d.ts +31 -0
  13. package/dist/EditableFooter.js +330 -0
  14. package/dist/EditableGrid.d.ts +40 -0
  15. package/dist/EditableGrid.js +39 -0
  16. package/dist/EditableHero.d.ts +27 -0
  17. package/dist/EditableHero.js +154 -0
  18. package/dist/EditableImage.d.ts +13 -0
  19. package/dist/EditableImage.js +38 -0
  20. package/dist/EditableList.d.ts +33 -0
  21. package/dist/EditableList.js +19 -0
  22. package/dist/EditableNavbar.d.ts +28 -0
  23. package/dist/EditableNavbar.js +178 -0
  24. package/dist/EditablePricingCard.d.ts +31 -0
  25. package/dist/EditablePricingCard.js +93 -0
  26. package/dist/EditableProductCard.d.ts +60 -0
  27. package/dist/EditableProductCard.js +116 -0
  28. package/dist/EditableSection.d.ts +35 -0
  29. package/dist/EditableSection.js +34 -0
  30. package/dist/EditableServiceCard.d.ts +38 -0
  31. package/dist/EditableServiceCard.js +28 -0
  32. package/dist/EditableTestimonialCard.d.ts +17 -0
  33. package/dist/EditableTestimonialCard.js +46 -0
  34. package/dist/EditableText.d.ts +117 -0
  35. package/dist/EditableText.js +319 -0
  36. package/dist/SiteDataProvider.d.ts +61 -0
  37. package/dist/SiteDataProvider.js +316 -0
  38. package/dist/ThemeStyles.d.ts +46 -0
  39. package/dist/ThemeStyles.js +181 -0
  40. package/dist/business/BusinessHours.d.ts +20 -0
  41. package/dist/business/BusinessHours.js +109 -0
  42. package/dist/business/index.d.ts +1 -0
  43. package/dist/business/index.js +17 -0
  44. package/dist/contact/ContactActions.d.ts +24 -0
  45. package/dist/contact/ContactActions.js +30 -0
  46. package/dist/contact/ContactButton.d.ts +15 -0
  47. package/dist/contact/ContactButton.js +94 -0
  48. package/dist/contact/EmailButton.d.ts +6 -0
  49. package/dist/contact/EmailButton.js +12 -0
  50. package/dist/contact/PhoneButton.d.ts +6 -0
  51. package/dist/contact/PhoneButton.js +12 -0
  52. package/dist/contact/WhatsAppButton.d.ts +6 -0
  53. package/dist/contact/WhatsAppButton.js +13 -0
  54. package/dist/contact/index.d.ts +5 -0
  55. package/dist/contact/index.js +21 -0
  56. package/dist/core/DenebAction.d.ts +19 -0
  57. package/dist/core/DenebAction.js +107 -0
  58. package/dist/core/index.d.ts +1 -0
  59. package/dist/core/index.js +17 -0
  60. package/dist/index.d.ts +61 -0
  61. package/dist/index.js +106 -0
  62. package/dist/location/Address.d.ts +14 -0
  63. package/dist/location/Address.js +26 -0
  64. package/dist/location/LocationCard.d.ts +20 -0
  65. package/dist/location/LocationCard.js +41 -0
  66. package/dist/location/LocationLink.d.ts +18 -0
  67. package/dist/location/LocationLink.js +23 -0
  68. package/dist/location/MapEmbed.d.ts +18 -0
  69. package/dist/location/MapEmbed.js +30 -0
  70. package/dist/location/MapLink.d.ts +13 -0
  71. package/dist/location/MapLink.js +63 -0
  72. package/dist/location/index.d.ts +5 -0
  73. package/dist/location/index.js +21 -0
  74. package/dist/social/SocialButton.d.ts +11 -0
  75. package/dist/social/SocialButton.js +112 -0
  76. package/dist/social/SocialLinks.d.ts +14 -0
  77. package/dist/social/SocialLinks.js +42 -0
  78. package/dist/social/index.d.ts +2 -0
  79. package/dist/social/index.js +18 -0
  80. package/dist/utils/index.d.ts +1 -0
  81. package/dist/utils/index.js +17 -0
  82. package/dist/utils/urls.d.ts +32 -0
  83. package/dist/utils/urls.js +91 -0
  84. package/package.json +41 -0
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ export type ImageAspectRatio = 'square' | '1/1' | 'video' | '16/9' | 'portrait' | '3/4' | '4/3' | '2/3' | '21/9' | (string & {});
3
+ export type ImageRadius = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | (string & {});
4
+ export interface EditableImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
5
+ id?: string;
6
+ 'data-preview-field-path'?: string;
7
+ fallbackSrc?: string;
8
+ aspectRatio?: ImageAspectRatio;
9
+ radius?: ImageRadius;
10
+ fit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
11
+ hoverZoom?: boolean;
12
+ }
13
+ export declare function EditableImage({ id, 'data-preview-field-path': previewFieldPath, src, fallbackSrc, alt, aspectRatio, radius, fit, hoverZoom, style, className, ...props }: EditableImageProps): React.JSX.Element;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EditableImage = EditableImage;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ASPECT_MAP = {
6
+ square: '1 / 1',
7
+ '1/1': '1 / 1',
8
+ video: '16 / 9',
9
+ '16/9': '16 / 9',
10
+ portrait: '3 / 4',
11
+ '3/4': '3 / 4',
12
+ '4/3': '4 / 3',
13
+ '2/3': '2 / 3',
14
+ '21/9': '21 / 9',
15
+ };
16
+ const RADIUS_MAP = {
17
+ none: '0px',
18
+ sm: '4px',
19
+ md: '8px',
20
+ lg: '12px',
21
+ xl: '16px',
22
+ '2xl': '24px',
23
+ full: '9999px',
24
+ };
25
+ const DEFAULT_FALLBACK_SVG = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="400" viewBox="0 0 600 400" fill="none"><rect width="600" height="400" fill="%23f1f5f9"/><path d="M250 180a30 30 0 100-60 30 30 0 000 60zM170 300l80-90 60 70 70-100 90 120H170z" fill="%23cbd5e1"/></svg>';
26
+ function EditableImage({ id, 'data-preview-field-path': previewFieldPath, src, fallbackSrc = DEFAULT_FALLBACK_SVG, alt = '', aspectRatio, radius, fit = 'cover', hoverZoom = false, style, className = '', ...props }) {
27
+ const path = previewFieldPath || id;
28
+ const resolvedAspect = aspectRatio ? (ASPECT_MAP[aspectRatio] || aspectRatio) : undefined;
29
+ const resolvedRadius = radius ? (RADIUS_MAP[radius] || radius) : undefined;
30
+ const combinedStyle = {
31
+ ...(resolvedAspect ? { aspectRatio: resolvedAspect } : {}),
32
+ ...(resolvedRadius ? { borderRadius: resolvedRadius } : {}),
33
+ ...(fit ? { objectFit: fit } : {}),
34
+ ...(hoverZoom ? { transition: 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)' } : {}),
35
+ ...style,
36
+ };
37
+ return ((0, jsx_runtime_1.jsx)("img", { "data-preview-field-path": path, src: src || fallbackSrc, alt: alt, style: combinedStyle, className: `editable-image ${hoverZoom ? 'hover:scale-105' : ''} ${className}`.trim(), ...props }));
38
+ }
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ export interface EditableListProps<T = any> extends Omit<React.HTMLAttributes<HTMLElement>, 'children'> {
3
+ /**
4
+ * The collection path in siteData, e.g. "products", "services", or "home.features".
5
+ */
6
+ path?: string;
7
+ /**
8
+ * Explicit fivora visual editing attribute for strict static analysis.
9
+ */
10
+ 'data-preview-list-path'?: string;
11
+ /**
12
+ * The list of items to iterate over.
13
+ */
14
+ items?: T[];
15
+ /**
16
+ * The outer container HTML element or component (default: 'div').
17
+ */
18
+ as?: React.ElementType;
19
+ /**
20
+ * The wrapper element for each item (default: 'div').
21
+ * If false, items are not wrapped automatically.
22
+ */
23
+ itemAs?: React.ElementType | false;
24
+ /**
25
+ * Class name applied to each individual item container.
26
+ */
27
+ itemClassName?: string;
28
+ /**
29
+ * Render function called for each item in the list.
30
+ */
31
+ children: (item: T, index: number, itemPath: string) => React.ReactNode;
32
+ }
33
+ export declare function EditableList<T = any>({ path, 'data-preview-list-path': previewListPath, items, as: Container, itemAs: ItemContainer, itemClassName, children, ...props }: EditableListProps<T>): React.JSX.Element;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EditableList = EditableList;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = __importDefault(require("react"));
9
+ function EditableList({ path, 'data-preview-list-path': previewListPath, items = [], as: Container = 'div', itemAs: ItemContainer = 'div', itemClassName, children, ...props }) {
10
+ const listPath = previewListPath || path || '';
11
+ const list = Array.isArray(items) ? items : [];
12
+ return ((0, jsx_runtime_1.jsx)(Container, { "data-preview-list-path": listPath, ...props, children: list.map((item, index) => {
13
+ const itemPath = `${listPath}[${index}]`;
14
+ if (ItemContainer === false) {
15
+ return ((0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: children(item, index, itemPath) }, index));
16
+ }
17
+ return ((0, jsx_runtime_1.jsx)(ItemContainer, { "data-preview-item-path": itemPath, className: itemClassName, children: children(item, index, itemPath) }, index));
18
+ }) }));
19
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ export interface NavLinkItem {
3
+ id: string;
4
+ label: string;
5
+ route: string;
6
+ }
7
+ export interface EditableNavbarProps extends React.HTMLAttributes<HTMLElement> {
8
+ defaultLinks?: NavLinkItem[];
9
+ sticky?: boolean;
10
+ activeRoute?: string;
11
+ basePath?: string;
12
+ }
13
+ /**
14
+ * Next-Level DENEB UI Navbar / Header
15
+ *
16
+ * Features:
17
+ * - High-end Shadcn glassmorphism design (backdrop-blur-md)
18
+ * - Automatic real-time state synchronization with Footer (Logo, Title, Nav labels)
19
+ * - Strict visual editing compliance (`common.logoUrl`, `common.websiteTitle`, `common.navLabels.*`, `common.headerCtaLabel`)
20
+ * - Selected-page filtering (`data-target-page`)
21
+ * - Responsive mobile toggle and drawer menu
22
+ * - Tailwind CSS classes + resilient inline CSS fallbacks
23
+ *
24
+ * Created by Chamika Gayashan (CEE G)
25
+ */
26
+ export declare function EditableNavbar({ defaultLinks, sticky, activeRoute, basePath, className, style, ...props }: EditableNavbarProps): React.JSX.Element;
27
+ export declare const Navbar: typeof EditableNavbar;
28
+ export declare const Header: typeof EditableNavbar;
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Header = exports.Navbar = void 0;
5
+ exports.EditableNavbar = EditableNavbar;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const SiteDataProvider_1 = require("./SiteDataProvider");
9
+ const DEFAULT_PAGES = [
10
+ { id: 'home', label: 'Home', route: '/' },
11
+ { id: 'about_us', label: 'About', route: '/about_us' },
12
+ { id: 'services', label: 'Services', route: '/services' },
13
+ { id: 'contact', label: 'Contact', route: '/contact' },
14
+ ];
15
+ /**
16
+ * Next-Level DENEB UI Navbar / Header
17
+ *
18
+ * Features:
19
+ * - High-end Shadcn glassmorphism design (backdrop-blur-md)
20
+ * - Automatic real-time state synchronization with Footer (Logo, Title, Nav labels)
21
+ * - Strict visual editing compliance (`common.logoUrl`, `common.websiteTitle`, `common.navLabels.*`, `common.headerCtaLabel`)
22
+ * - Selected-page filtering (`data-target-page`)
23
+ * - Responsive mobile toggle and drawer menu
24
+ * - Tailwind CSS classes + resilient inline CSS fallbacks
25
+ *
26
+ * Created by Chamika Gayashan (CEE G)
27
+ */
28
+ function EditableNavbar({ defaultLinks = DEFAULT_PAGES, sticky = true, activeRoute, basePath = '', className = '', style, ...props }) {
29
+ const siteData = (0, SiteDataProvider_1.useSiteData)();
30
+ const [mobileMenuOpen, setMobileMenuOpen] = (0, react_1.useState)(false);
31
+ const content = (siteData?.content || {});
32
+ const common = (content?.common || {});
33
+ const siteName = String(common?.websiteTitle || common?.siteName || 'Storefront');
34
+ const logoUrl = String(common?.logoUrl || '');
35
+ const headerCtaLabel = String(common?.headerCtaLabel || 'Get in Touch');
36
+ const navLabels = (common?.navLabels || {});
37
+ const requiredPages = Array.isArray(siteData?.requirements?.requiredPages)
38
+ ? siteData.requirements.requiredPages
39
+ : siteData?.template?.structure?.pages || ['home', 'contact'];
40
+ const activeLinks = defaultLinks.filter((item) => item.id === 'home' || requiredPages.includes(item.id));
41
+ const hasContact = requiredPages.includes('contact');
42
+ const basePathEnv = typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_SITE_BASE_PATH
43
+ ? process.env.NEXT_PUBLIC_SITE_BASE_PATH
44
+ : '';
45
+ const effectiveBasePath = basePath || basePathEnv;
46
+ const navigate = (path) => {
47
+ if (typeof window !== 'undefined') {
48
+ const cleanBase = effectiveBasePath.replace(/\/$/, '');
49
+ const cleanPath = path.startsWith('/') ? path : `/${path}`;
50
+ window.location.href = `${cleanBase}${cleanPath}` || '/';
51
+ }
52
+ };
53
+ const withBase = (path) => {
54
+ if (!path || /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(path))
55
+ return path;
56
+ const cleanBase = effectiveBasePath.replace(/\/$/, '');
57
+ const cleanPath = path.startsWith('/') ? path : `/${path}`;
58
+ return `${cleanBase}${cleanPath}` || '/';
59
+ };
60
+ return ((0, jsx_runtime_1.jsxs)("header", { style: {
61
+ position: sticky ? 'sticky' : 'relative',
62
+ top: 0,
63
+ zIndex: 50,
64
+ width: '100%',
65
+ backgroundColor: 'rgba(255, 255, 255, 0.82)',
66
+ backdropFilter: 'blur(16px)',
67
+ WebkitBackdropFilter: 'blur(16px)',
68
+ borderBottom: '1px solid rgba(226, 232, 240, 0.8)',
69
+ transition: 'all 0.2s ease',
70
+ ...style,
71
+ }, className: `deneb-navbar sticky top-0 z-50 w-full border-b border-slate-200/80 bg-white/80 backdrop-blur-md dark:border-slate-800/80 dark:bg-slate-950/80 ${className}`.trim(), ...props, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
72
+ maxWidth: '1280px',
73
+ margin: '0 auto',
74
+ padding: '0.875rem 1.5rem',
75
+ display: 'flex',
76
+ alignItems: 'center',
77
+ justifyContent: 'space-between',
78
+ gap: '1.5rem',
79
+ }, className: "deneb-navbar-inner max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3.5 flex items-center justify-between gap-6", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: () => navigate('/'), style: {
80
+ display: 'flex',
81
+ alignItems: 'center',
82
+ gap: '0.75rem',
83
+ background: 'transparent',
84
+ border: 0,
85
+ padding: 0,
86
+ cursor: 'pointer',
87
+ textAlign: 'left',
88
+ }, className: "deneb-brand-btn flex items-center gap-3 group cursor-pointer border-0 bg-transparent p-0", children: [(0, jsx_runtime_1.jsx)("img", { src: withBase(logoUrl || '/placeholder.svg'), alt: siteName, "data-preview-field-path": "common.logoUrl", style: {
89
+ height: '36px',
90
+ width: 'auto',
91
+ maxWidth: '140px',
92
+ objectFit: 'contain',
93
+ borderRadius: '8px',
94
+ transition: 'transform 0.2s ease',
95
+ }, className: "deneb-logo h-9 w-auto max-w-[140px] object-contain rounded-lg group-hover:scale-105 transition-transform" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "common.websiteTitle", style: {
96
+ fontSize: '1.25rem',
97
+ fontWeight: 700,
98
+ letterSpacing: '-0.025em',
99
+ color: 'var(--color-text, #0f172a)',
100
+ }, className: "deneb-site-title text-xl font-bold tracking-tight text-slate-900 dark:text-white", children: siteName })] }), (0, jsx_runtime_1.jsx)("nav", { style: {
101
+ display: 'flex',
102
+ alignItems: 'center',
103
+ gap: '0.375rem',
104
+ }, className: "deneb-desktop-nav flex items-center gap-1.5", children: activeLinks.map((link) => {
105
+ const label = navLabels[link.id] || link.label;
106
+ const isActive = activeRoute === link.route;
107
+ return ((0, jsx_runtime_1.jsx)("span", { "data-target-page": link.id, children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => navigate(link.route), style: {
108
+ display: 'inline-flex',
109
+ alignItems: 'center',
110
+ padding: '0.45rem 0.875rem',
111
+ borderRadius: '9999px',
112
+ fontSize: '0.9rem',
113
+ fontWeight: isActive ? 600 : 500,
114
+ color: isActive ? 'var(--color-primary, #0f172a)' : 'var(--color-text-muted, #475569)',
115
+ backgroundColor: isActive ? 'var(--color-secondary, #f1f5f9)' : 'transparent',
116
+ border: 0,
117
+ cursor: 'pointer',
118
+ transition: 'all 0.15s ease',
119
+ }, className: `deneb-nav-item px-3.5 py-1.5 rounded-full text-sm font-medium transition-all border-0 cursor-pointer ${isActive
120
+ ? 'bg-slate-100 text-slate-900 font-semibold dark:bg-slate-800 dark:text-white'
121
+ : 'bg-transparent text-slate-600 hover:text-slate-900 hover:bg-slate-100/70 dark:text-slate-400 dark:hover:text-white dark:hover:bg-slate-800/70'}`, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `common.navLabels.${link.id}`, children: label }) }) }, link.id));
122
+ }) }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', gap: '0.75rem' }, className: "flex items-center gap-3", children: [hasContact ? ((0, jsx_runtime_1.jsx)("span", { "data-target-page": "contact", children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => navigate('/contact'), style: {
123
+ display: 'inline-flex',
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
126
+ backgroundColor: 'var(--color-primary, #0f172a)',
127
+ color: '#ffffff',
128
+ padding: '0.5rem 1.25rem',
129
+ borderRadius: '9999px',
130
+ fontSize: '0.875rem',
131
+ fontWeight: 600,
132
+ border: 0,
133
+ cursor: 'pointer',
134
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
135
+ transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
136
+ }, className: "deneb-header-cta inline-flex items-center justify-center px-4 py-2 rounded-full text-sm font-semibold bg-slate-900 text-white shadow-sm hover:bg-slate-800 hover:shadow-md transition-all border-0 cursor-pointer dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel }) }) })) : ((0, jsx_runtime_1.jsx)("span", { "data-target-page": "contact", className: "deneb-header-cta unavailable", "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel })), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "mobile-menu-toggle", onClick: () => setMobileMenuOpen(!mobileMenuOpen), "aria-label": "Toggle Navigation Menu", style: {
137
+ display: 'flex',
138
+ alignItems: 'center',
139
+ justifyContent: 'center',
140
+ width: '40px',
141
+ height: '40px',
142
+ borderRadius: '8px',
143
+ border: '1px solid var(--color-border, #e2e8f0)',
144
+ backgroundColor: 'transparent',
145
+ color: 'var(--color-text, #0f172a)',
146
+ cursor: 'pointer',
147
+ }, className: "deneb-mobile-toggle md:hidden flex items-center justify-center w-10 h-10 rounded-lg border border-slate-200 text-slate-700 hover:bg-slate-100 dark:border-slate-800 dark:text-slate-300 dark:hover:bg-slate-800 transition-colors", children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: mobileMenuOpen ? ((0, jsx_runtime_1.jsx)("path", { d: "M18 6L6 18M6 6l12 12" })) : ((0, jsx_runtime_1.jsx)("path", { d: "M4 6h16M4 12h16M4 18h16" })) }) })] })] }), mobileMenuOpen && ((0, jsx_runtime_1.jsx)("div", { style: {
148
+ borderTop: '1px solid var(--color-border, #e2e8f0)',
149
+ backgroundColor: 'rgba(255, 255, 255, 0.98)',
150
+ padding: '1.25rem 1.5rem',
151
+ display: 'flex',
152
+ flexDirection: 'column',
153
+ gap: '0.625rem',
154
+ }, className: "deneb-mobile-drawer md:hidden border-t border-slate-200 bg-white/95 backdrop-blur-lg px-4 py-5 flex flex-col gap-2.5 dark:border-slate-800 dark:bg-slate-950/95", children: activeLinks.map((link) => {
155
+ const label = navLabels[link.id] || link.label;
156
+ const isActive = activeRoute === link.route;
157
+ return ((0, jsx_runtime_1.jsx)("span", { "data-target-page": link.id, children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
158
+ setMobileMenuOpen(false);
159
+ navigate(link.route);
160
+ }, style: {
161
+ display: 'block',
162
+ width: '100%',
163
+ textAlign: 'left',
164
+ padding: '0.625rem 0.875rem',
165
+ borderRadius: '8px',
166
+ fontSize: '0.95rem',
167
+ fontWeight: isActive ? 600 : 500,
168
+ color: isActive ? 'var(--color-primary, #0f172a)' : 'var(--color-text, #0f172a)',
169
+ backgroundColor: isActive ? 'var(--color-secondary, #f1f5f9)' : 'transparent',
170
+ border: 0,
171
+ cursor: 'pointer',
172
+ }, className: `block w-full text-left px-3.5 py-2.5 rounded-lg text-base font-medium transition-colors border-0 cursor-pointer ${isActive
173
+ ? 'bg-slate-100 text-slate-900 font-semibold dark:bg-slate-800 dark:text-white'
174
+ : 'bg-transparent text-slate-700 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800'}`, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-static": "mobile-nav-item", children: label }) }) }, link.id));
175
+ }) }))] }));
176
+ }
177
+ exports.Navbar = EditableNavbar;
178
+ exports.Header = EditableNavbar;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ export interface PricingFeature {
3
+ text: string;
4
+ included?: boolean;
5
+ }
6
+ export interface PricingItem {
7
+ id?: string | number;
8
+ name?: string;
9
+ title?: string;
10
+ badge?: string;
11
+ price?: string | number;
12
+ interval?: string;
13
+ description?: string;
14
+ ctaText?: string;
15
+ ctaTarget?: string;
16
+ isPopular?: boolean;
17
+ features?: (string | PricingFeature)[];
18
+ [key: string]: unknown;
19
+ }
20
+ export interface EditablePricingCardProps extends React.HTMLAttributes<HTMLElement> {
21
+ itemPath: string;
22
+ item: PricingItem;
23
+ as?: React.ElementType;
24
+ isPopular?: boolean;
25
+ actionSlot?: React.ReactNode;
26
+ }
27
+ /**
28
+ * EditablePricingCard is a high-converting tier card designed for SaaS, digital products,
29
+ * and service packages with strict Fivora visual editing sync.
30
+ */
31
+ export declare function EditablePricingCard({ itemPath, item, as: Component, isPopular, actionSlot, className, style, ...props }: EditablePricingCardProps): React.JSX.Element;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EditablePricingCard = EditablePricingCard;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const EditableText_1 = require("./EditableText");
6
+ const EditableText_2 = require("./EditableText");
7
+ /**
8
+ * EditablePricingCard is a high-converting tier card designed for SaaS, digital products,
9
+ * and service packages with strict Fivora visual editing sync.
10
+ */
11
+ function EditablePricingCard({ itemPath, item, as: Component = 'div', isPopular = false, actionSlot, className = '', style, ...props }) {
12
+ const name = String(item?.name || item?.title || 'Standard Plan');
13
+ const badge = String(item?.badge || (item?.isPopular || isPopular ? 'Popular' : ''));
14
+ const price = String(item?.price || '$49');
15
+ const interval = String(item?.interval || '/month');
16
+ const description = String(item?.description || '');
17
+ const ctaText = String(item?.ctaText || 'Get Started');
18
+ const ctaTarget = String(item?.ctaTarget || 'contact');
19
+ const features = Array.isArray(item?.features) ? item.features : [];
20
+ const popular = item?.isPopular || isPopular;
21
+ const cardStyle = {
22
+ position: 'relative',
23
+ backgroundColor: popular ? '#ffffff' : 'rgba(255, 255, 255, 0.85)',
24
+ border: popular ? '2px solid var(--brand-color, #2563eb)' : '1px solid #e2e8f0',
25
+ borderRadius: '20px',
26
+ padding: '2.5rem 2rem',
27
+ boxShadow: popular
28
+ ? '0 20px 35px -10px rgba(37, 99, 235, 0.15), 0 1px 3px rgba(0,0,0,0.05)'
29
+ : '0 4px 6px -1px rgba(0, 0, 0, 0.05)',
30
+ display: 'flex',
31
+ flexDirection: 'column',
32
+ justifyContent: 'space-between',
33
+ transition: 'transform 0.25s ease, box-shadow 0.25s ease',
34
+ ...style,
35
+ };
36
+ return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, style: cardStyle, className: `editable-pricing-card ${popular ? 'is-popular' : ''} ${className}`.trim(), ...props, children: [(0, jsx_runtime_1.jsxs)("div", { children: [badge && ((0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', top: '-14px', right: '24px' }, children: (0, jsx_runtime_1.jsx)(EditableText_2.EditableBadge, { id: `${itemPath}.badge`, defaultValue: badge, badgeVariant: popular ? 'primary' : 'secondary' }) })), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.name`, defaultValue: name, style: {
37
+ fontSize: '1.25rem',
38
+ fontWeight: 700,
39
+ color: 'var(--heading-color, #0f172a)',
40
+ marginBottom: '0.5rem',
41
+ } }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, defaultValue: description, style: {
42
+ fontSize: '0.875rem',
43
+ color: 'var(--muted-text, #64748b)',
44
+ marginBottom: '1.5rem',
45
+ lineHeight: 1.5,
46
+ } }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.25rem', marginBottom: '1.5rem' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, defaultValue: price, style: {
47
+ fontSize: '2.75rem',
48
+ fontWeight: 800,
49
+ letterSpacing: '-0.03em',
50
+ color: 'var(--heading-color, #0f172a)',
51
+ } }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.interval`, defaultValue: interval, style: {
52
+ fontSize: '0.875rem',
53
+ color: 'var(--muted-text, #64748b)',
54
+ fontWeight: 500,
55
+ } })] }), (features.length > 0 || Array.isArray(item?.features)) && ((0, jsx_runtime_1.jsx)("ul", { "data-preview-list-path": `${itemPath}.features`, style: {
56
+ listStyle: 'none',
57
+ padding: 0,
58
+ margin: '0 0 2rem 0',
59
+ display: 'flex',
60
+ flexDirection: 'column',
61
+ gap: '0.75rem',
62
+ }, children: features.map((feat, idx) => {
63
+ const text = typeof feat === 'string' ? feat : feat?.text || '';
64
+ const included = typeof feat === 'string' ? true : feat?.included !== false;
65
+ return ((0, jsx_runtime_1.jsxs)("li", { "data-preview-item-path": `${itemPath}.features[${idx}]`, style: {
66
+ display: 'flex',
67
+ alignItems: 'center',
68
+ gap: '0.75rem',
69
+ fontSize: '0.925rem',
70
+ color: included ? 'var(--page-text, #0f172a)' : 'var(--muted-text, #94a3b8)',
71
+ textDecoration: included ? 'none' : 'line-through',
72
+ }, children: [(0, jsx_runtime_1.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 20 20", fill: "none", "data-preview-static": "pricing-check-icon", style: { flexShrink: 0 }, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "10", cy: "10", r: "9", fill: included ? 'var(--brand-color, #2563eb)' : '#e2e8f0', fillOpacity: included ? 0.15 : 1 }), (0, jsx_runtime_1.jsx)("path", { d: "M6 10l3 3 5-6", stroke: included ? 'var(--brand-color, #2563eb)' : '#94a3b8', strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { id: `${itemPath}.features[${idx}]`, defaultValue: text })] }, idx));
73
+ }) }))] }), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: 'auto', paddingTop: '1rem' }, children: actionSlot ? (actionSlot) : ((0, jsx_runtime_1.jsx)("span", { "data-target-page": ctaTarget, children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
74
+ if (typeof window !== 'undefined') {
75
+ const basePath = (process.env.NEXT_PUBLIC_SITE_BASE_PATH ?? '').replace(/\/$/, '');
76
+ window.location.href = `${basePath}/${ctaTarget}`;
77
+ }
78
+ }, style: {
79
+ display: 'block',
80
+ textAlign: 'center',
81
+ width: '100%',
82
+ padding: '0.875rem 1.5rem',
83
+ borderRadius: '10px',
84
+ fontWeight: 600,
85
+ fontSize: '0.95rem',
86
+ backgroundColor: popular ? 'var(--brand-color, #2563eb)' : 'var(--brand-secondary, #0f172a)',
87
+ color: '#ffffff',
88
+ border: 0,
89
+ cursor: 'pointer',
90
+ boxShadow: popular ? '0 4px 14px rgba(37, 99, 235, 0.35)' : 'none',
91
+ transition: 'opacity 0.2s ease',
92
+ }, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${itemPath}.ctaText`, children: ctaText }) }) })) })] }));
93
+ }
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ export interface ProductItem {
3
+ id?: string | number;
4
+ name?: string;
5
+ title?: string;
6
+ price?: string | number;
7
+ originalPrice?: string | number;
8
+ description?: string;
9
+ category?: string;
10
+ imageUrl?: string;
11
+ image?: string;
12
+ badge?: string;
13
+ rating?: number | string;
14
+ [key: string]: unknown;
15
+ }
16
+ export type ProductCardVariant = 'modern-glass' | 'classic' | 'minimal' | 'horizontal';
17
+ export interface EditableProductCardProps extends React.HTMLAttributes<HTMLElement> {
18
+ /**
19
+ * The item path for the product, e.g. "products[0]" or "featuredProducts[1]".
20
+ */
21
+ itemPath: string;
22
+ /**
23
+ * The product data object.
24
+ */
25
+ product: ProductItem;
26
+ /**
27
+ * Design variant: 'modern-glass' | 'classic' | 'minimal' | 'horizontal'
28
+ */
29
+ cardVariant?: ProductCardVariant;
30
+ /**
31
+ * Fallback image URL if product image is empty.
32
+ */
33
+ imageFallback?: string;
34
+ /**
35
+ * HTML wrapper tag (default: 'article').
36
+ */
37
+ as?: React.ElementType;
38
+ /**
39
+ * Whether to display the price field (default: true).
40
+ */
41
+ showPrice?: boolean;
42
+ /**
43
+ * Whether to display the description field (default: true).
44
+ */
45
+ showDescription?: boolean;
46
+ /**
47
+ * Whether to display category pill (default: true if present).
48
+ */
49
+ showCategory?: boolean;
50
+ /**
51
+ * Optional custom action slot (e.g. Add to Cart button).
52
+ */
53
+ actionSlot?: React.ReactNode;
54
+ }
55
+ /**
56
+ * EditableProductCard is an elite, auto-balancing commerce card supporting
57
+ * four visual variants (modern-glass, classic, minimal, horizontal) and
58
+ * strict Fivora visual editing synchronization.
59
+ */
60
+ export declare function EditableProductCard({ itemPath, product, cardVariant, imageFallback, as: Component, showPrice, showDescription, showCategory, actionSlot, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EditableProductCard = EditableProductCard;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const EditableText_1 = require("./EditableText");
6
+ const EditableImage_1 = require("./EditableImage");
7
+ const EditableText_2 = require("./EditableText");
8
+ /**
9
+ * EditableProductCard is an elite, auto-balancing commerce card supporting
10
+ * four visual variants (modern-glass, classic, minimal, horizontal) and
11
+ * strict Fivora visual editing synchronization.
12
+ */
13
+ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', showPrice = true, showDescription = true, showCategory = true, actionSlot, className = '', style, ...props }) {
14
+ const name = String(product?.name || product?.title || '');
15
+ const price = product?.price !== undefined ? String(product.price) : '';
16
+ const originalPrice = product?.originalPrice !== undefined ? String(product.originalPrice) : '';
17
+ const description = String(product?.description || '');
18
+ const category = String(product?.category || '');
19
+ const badge = String(product?.badge || '');
20
+ const imageUrl = String(product?.imageUrl || product?.image || '');
21
+ const isHorizontal = cardVariant === 'horizontal';
22
+ const variantStyles = {
23
+ 'modern-glass': {
24
+ backgroundColor: 'rgba(255, 255, 255, 0.85)',
25
+ backdropFilter: 'blur(16px)',
26
+ WebkitBackdropFilter: 'blur(16px)',
27
+ border: '1px solid rgba(226, 232, 240, 0.8)',
28
+ borderRadius: '16px',
29
+ boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.01)',
30
+ overflow: 'hidden',
31
+ transition: 'transform 0.25s ease, box-shadow 0.25s ease',
32
+ },
33
+ classic: {
34
+ backgroundColor: '#ffffff',
35
+ border: '1px solid #e2e8f0',
36
+ borderRadius: '12px',
37
+ boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.05)',
38
+ overflow: 'hidden',
39
+ transition: 'transform 0.2s ease',
40
+ },
41
+ minimal: {
42
+ backgroundColor: 'transparent',
43
+ border: 'none',
44
+ overflow: 'hidden',
45
+ },
46
+ horizontal: {
47
+ backgroundColor: '#ffffff',
48
+ border: '1px solid #e2e8f0',
49
+ borderRadius: '14px',
50
+ overflow: 'hidden',
51
+ display: 'flex',
52
+ flexDirection: 'row',
53
+ alignItems: 'center',
54
+ },
55
+ };
56
+ return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, style: {
57
+ ...variantStyles[cardVariant],
58
+ ...style,
59
+ }, className: `editable-product-card group ${className}`.trim(), ...props, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
60
+ position: 'relative',
61
+ overflow: 'hidden',
62
+ width: isHorizontal ? '38%' : '100%',
63
+ flexShrink: 0,
64
+ }, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${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`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
65
+ padding: '1.25rem',
66
+ display: 'flex',
67
+ flexDirection: 'column',
68
+ flex: 1,
69
+ justifyContent: 'space-between',
70
+ }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [showCategory && ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.category`, defaultValue: category, style: {
71
+ fontSize: '0.75rem',
72
+ textTransform: 'uppercase',
73
+ letterSpacing: '0.05em',
74
+ color: 'var(--brand-accent, #14b8a6)',
75
+ fontWeight: 600,
76
+ display: 'inline-block',
77
+ marginBottom: '0.375rem',
78
+ } })), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.name`, defaultValue: name, style: {
79
+ fontSize: '1.125rem',
80
+ fontWeight: 700,
81
+ lineHeight: 1.3,
82
+ color: 'var(--heading-color, #0f172a)',
83
+ marginBottom: '0.375rem',
84
+ } }), showDescription && ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, defaultValue: description, style: {
85
+ fontSize: '0.875rem',
86
+ color: 'var(--muted-text, #64748b)',
87
+ lineHeight: 1.5,
88
+ marginBottom: '0.75rem',
89
+ } }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
90
+ marginTop: '0.75rem',
91
+ paddingTop: '0.75rem',
92
+ borderTop: cardVariant === 'minimal' ? 'none' : '1px solid rgba(226, 232, 240, 0.6)',
93
+ display: 'flex',
94
+ alignItems: 'center',
95
+ justifyContent: 'space-between',
96
+ gap: '0.5rem',
97
+ }, children: [showPrice && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.375rem' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, defaultValue: price, style: {
98
+ fontSize: '1.25rem',
99
+ fontWeight: 700,
100
+ color: 'var(--brand-color, #2563eb)',
101
+ } }), originalPrice ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.originalPrice`, defaultValue: originalPrice, style: {
102
+ fontSize: '0.875rem',
103
+ textDecoration: 'line-through',
104
+ color: 'var(--muted-text, #94a3b8)',
105
+ } })) : null] })), actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "product-action-btn", style: {
106
+ backgroundColor: 'var(--brand-color, #2563eb)',
107
+ color: '#ffffff',
108
+ border: 'none',
109
+ padding: '0.5rem 1rem',
110
+ borderRadius: '8px',
111
+ fontSize: '0.875rem',
112
+ fontWeight: 600,
113
+ cursor: 'pointer',
114
+ transition: 'opacity 0.2s ease',
115
+ }, children: "Buy Now" }))] })] })] }));
116
+ }