@deneb-ui/ui 2.0.4 → 2.0.6

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.
@@ -85,8 +85,7 @@ function EditableAnnouncementBar({ fieldPath = 'site.announcement', defaultText
85
85
  borderRadius: '0.25rem',
86
86
  transition: 'color 0.15s ease',
87
87
  };
88
- const hasDynamicField = Boolean(fieldPath && siteData?.site?.announcement);
89
- return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-announcement-bar relative z-40 bg-slate-900 text-white text-xs md:text-sm font-medium px-4 py-2 flex items-center justify-center text-center ${className}`, style: containerStyle, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center flex-wrap gap-1.5 max-w-7xl mx-auto pr-6", children: [badge && ((0, jsx_runtime_1.jsx)("span", { className: "deneb-announcement-badge bg-white/20 text-white px-2 py-0.5 rounded-full text-[10px] font-bold tracking-wider uppercase inline-flex items-center", style: badgeStyle, ...(hasDynamicField ? { 'data-preview-field-path': `${fieldPath}.badge` } : { 'data-preview-static': 'announcement-badge' }), children: badge })), (0, jsx_runtime_1.jsx)("span", { className: "deneb-announcement-text", ...(hasDynamicField ? { 'data-preview-field-path': `${fieldPath}.text` } : { 'data-preview-static': 'announcement-text' }), children: text }), linkText && linkUrl && ((0, jsx_runtime_1.jsxs)("a", { href: linkUrl, className: "deneb-announcement-link underline font-semibold text-white hover:opacity-90 transition-opacity ml-1 inline-flex items-center gap-1", style: linkStyle, ...(hasDynamicField ? { 'data-preview-field-path': `${fieldPath}.linkText` } : { 'data-preview-static': 'announcement-link' }), children: [linkText, " \u2192"] }))] }), dismissible && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setIsDismissed(true), style: closeButtonStyle, "aria-label": "Dismiss announcement", className: "hover:text-white transition-colors", "data-preview-static": "announcement-dismiss", children: (0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }))] }));
88
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-announcement-bar relative z-40 bg-slate-900 text-white text-xs md:text-sm font-medium px-4 py-2 flex items-center justify-center text-center ${className}`, style: containerStyle, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center flex-wrap gap-1.5 max-w-7xl mx-auto pr-6", children: [badge && ((0, jsx_runtime_1.jsx)("span", { className: "deneb-announcement-badge bg-white/20 text-white px-2 py-0.5 rounded-full text-[10px] font-bold tracking-wider uppercase inline-flex items-center", style: badgeStyle, "data-preview-field-path": fieldPath ? `${fieldPath}.badge` : undefined, children: badge })), (0, jsx_runtime_1.jsx)("span", { className: "deneb-announcement-text", "data-preview-field-path": fieldPath ? `${fieldPath}.text` : undefined, children: text }), linkText && linkUrl && ((0, jsx_runtime_1.jsxs)("a", { href: linkUrl, className: "deneb-announcement-link underline font-semibold text-white hover:opacity-90 transition-opacity ml-1 inline-flex items-center gap-1", style: linkStyle, "data-preview-field-path": fieldPath ? `${fieldPath}.linkText` : undefined, children: [linkText, " \u2192"] }))] }), dismissible && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setIsDismissed(true), style: closeButtonStyle, "aria-label": "Dismiss announcement", className: "hover:text-white transition-colors", "data-preview-static": "announcement-dismiss", children: (0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }))] }));
90
89
  }
91
90
  // Canonical alias
92
91
  exports.AnnouncementBar = EditableAnnouncementBar;
@@ -5,7 +5,15 @@ export interface EditableContactFormProps extends React.FormHTMLAttributes<HTMLF
5
5
  formTitlePath?: string;
6
6
  submitButtonText?: string;
7
7
  submitLabelPath?: string;
8
+ nameLabelPath?: string;
9
+ namePlaceholderPath?: string;
10
+ emailLabelPath?: string;
11
+ emailPlaceholderPath?: string;
12
+ phoneLabelPath?: string;
13
+ phonePlaceholderPath?: string;
14
+ messageLabelPath?: string;
15
+ messagePlaceholderPath?: string;
8
16
  successMessage?: string;
9
17
  showPhone?: boolean;
10
18
  }
11
- export declare function EditableContactForm({ endpoint, formTitle, formTitlePath, submitButtonText, submitLabelPath, successMessage, showPhone, className, style, ...props }: EditableContactFormProps): React.JSX.Element;
19
+ export declare function EditableContactForm({ endpoint, formTitle, formTitlePath, submitButtonText, submitLabelPath, nameLabelPath, namePlaceholderPath, emailLabelPath, emailPlaceholderPath, phoneLabelPath, phonePlaceholderPath, messageLabelPath, messagePlaceholderPath, successMessage, showPhone, className, style, ...props }: EditableContactFormProps): React.JSX.Element;
@@ -4,13 +4,21 @@ exports.EditableContactForm = EditableContactForm;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const SiteDataProvider_1 = require("./SiteDataProvider");
7
- function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact', formTitle, formTitlePath, submitButtonText = 'Send Message', submitLabelPath = 'contact.submitLabel', successMessage = 'Thank you! Your message has been sent successfully.', showPhone = false, className = '', style, ...props }) {
7
+ function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact', formTitle, formTitlePath, submitButtonText = 'Send Message', submitLabelPath = 'contact.submitLabel', nameLabelPath = 'contact.nameLabel', namePlaceholderPath = 'contact.namePlaceholder', emailLabelPath = 'contact.emailLabel', emailPlaceholderPath = 'contact.emailPlaceholder', phoneLabelPath = 'contact.phoneLabel', phonePlaceholderPath = 'contact.phonePlaceholder', messageLabelPath = 'contact.messageLabel', messagePlaceholderPath = 'contact.messagePlaceholder', successMessage = 'Thank you! Your message has been sent successfully.', showPhone = false, className = '', style, ...props }) {
8
8
  const siteData = (0, SiteDataProvider_1.useSiteData)();
9
9
  const [status, setStatus] = (0, react_1.useState)('idle');
10
10
  const [errorMessage, setErrorMessage] = (0, react_1.useState)('');
11
11
  const contactContent = siteData?.content?.contact;
12
12
  const resolvedSubmitText = String(contactContent?.submitLabel || submitButtonText);
13
13
  const resolvedFormTitle = formTitle || contactContent?.formTitle;
14
+ const resolvedNameLabel = String(contactContent?.nameLabel || 'Your Name');
15
+ const resolvedNamePlaceholder = String(contactContent?.namePlaceholder || 'John Doe');
16
+ const resolvedEmailLabel = String(contactContent?.emailLabel || 'Email Address');
17
+ const resolvedEmailPlaceholder = String(contactContent?.emailPlaceholder || 'john@example.com');
18
+ const resolvedPhoneLabel = String(contactContent?.phoneLabel || 'Phone Number');
19
+ const resolvedPhonePlaceholder = String(contactContent?.phonePlaceholder || '+1 (555) 000-0000');
20
+ const resolvedMessageLabel = String(contactContent?.messageLabel || 'Message');
21
+ const resolvedMessagePlaceholder = String(contactContent?.messagePlaceholder || 'Tell us how we can help...');
14
22
  const handleSubmit = async (e) => {
15
23
  e.preventDefault();
16
24
  setStatus('submitting');
@@ -51,13 +59,13 @@ function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact',
51
59
  fontWeight: 700,
52
60
  color: 'var(--heading-color, #0f172a)',
53
61
  margin: '0 0 0.5rem 0',
54
- }, children: resolvedFormTitle })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-name", "data-preview-static": "contact-label-name", style: {
62
+ }, children: resolvedFormTitle })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-name", "data-preview-field-path": nameLabelPath, style: {
55
63
  display: 'block',
56
64
  fontSize: '0.875rem',
57
65
  fontWeight: 600,
58
66
  marginBottom: '0.375rem',
59
67
  color: 'var(--heading-color, #0f172a)',
60
- }, children: "Your Name" }), (0, jsx_runtime_1.jsx)("input", { id: "contact-name", name: "name", type: "text", required: true, placeholder: "John Doe", style: {
68
+ }, children: resolvedNameLabel }), (0, jsx_runtime_1.jsx)("input", { id: "contact-name", name: "name", type: "text", required: true, placeholder: resolvedNamePlaceholder, "data-preview-field-path": namePlaceholderPath, style: {
61
69
  width: '100%',
62
70
  padding: '0.75rem 1rem',
63
71
  borderRadius: '10px',
@@ -66,13 +74,13 @@ function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact',
66
74
  outline: 'none',
67
75
  backgroundColor: '#ffffff',
68
76
  boxSizing: 'border-box',
69
- } })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-email", "data-preview-static": "contact-label-email", style: {
77
+ } })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-email", "data-preview-field-path": emailLabelPath, style: {
70
78
  display: 'block',
71
79
  fontSize: '0.875rem',
72
80
  fontWeight: 600,
73
81
  marginBottom: '0.375rem',
74
82
  color: 'var(--heading-color, #0f172a)',
75
- }, children: "Email Address" }), (0, jsx_runtime_1.jsx)("input", { id: "contact-email", name: "email", type: "email", required: true, placeholder: "john@example.com", style: {
83
+ }, children: resolvedEmailLabel }), (0, jsx_runtime_1.jsx)("input", { id: "contact-email", name: "email", type: "email", required: true, placeholder: resolvedEmailPlaceholder, "data-preview-field-path": emailPlaceholderPath, style: {
76
84
  width: '100%',
77
85
  padding: '0.75rem 1rem',
78
86
  borderRadius: '10px',
@@ -81,13 +89,13 @@ function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact',
81
89
  outline: 'none',
82
90
  backgroundColor: '#ffffff',
83
91
  boxSizing: 'border-box',
84
- } })] }), showPhone && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-phone", "data-preview-static": "contact-label-phone", style: {
92
+ } })] }), showPhone && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-phone", "data-preview-field-path": phoneLabelPath, style: {
85
93
  display: 'block',
86
94
  fontSize: '0.875rem',
87
95
  fontWeight: 600,
88
96
  marginBottom: '0.375rem',
89
97
  color: 'var(--heading-color, #0f172a)',
90
- }, children: "Phone Number" }), (0, jsx_runtime_1.jsx)("input", { id: "contact-phone", name: "phone", type: "tel", placeholder: "+1 (555) 000-0000", style: {
98
+ }, children: resolvedPhoneLabel }), (0, jsx_runtime_1.jsx)("input", { id: "contact-phone", name: "phone", type: "tel", placeholder: resolvedPhonePlaceholder, "data-preview-field-path": phonePlaceholderPath, style: {
91
99
  width: '100%',
92
100
  padding: '0.75rem 1rem',
93
101
  borderRadius: '10px',
@@ -96,13 +104,13 @@ function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact',
96
104
  outline: 'none',
97
105
  backgroundColor: '#ffffff',
98
106
  boxSizing: 'border-box',
99
- } })] })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-message", "data-preview-static": "contact-label-message", style: {
107
+ } })] })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "contact-message", "data-preview-field-path": messageLabelPath, style: {
100
108
  display: 'block',
101
109
  fontSize: '0.875rem',
102
110
  fontWeight: 600,
103
111
  marginBottom: '0.375rem',
104
112
  color: 'var(--heading-color, #0f172a)',
105
- }, children: "Message" }), (0, jsx_runtime_1.jsx)("textarea", { id: "contact-message", name: "message", rows: 5, required: true, placeholder: "Tell us how we can help...", style: {
113
+ }, children: resolvedMessageLabel }), (0, jsx_runtime_1.jsx)("textarea", { id: "contact-message", name: "message", rows: 5, required: true, placeholder: resolvedMessagePlaceholder, "data-preview-field-path": messagePlaceholderPath, style: {
106
114
  width: '100%',
107
115
  padding: '0.75rem 1rem',
108
116
  borderRadius: '10px',
@@ -82,17 +82,12 @@ function EditableDialog({ open = false, onClose, title, description, titleFieldP
82
82
  alignItems: 'flex-start',
83
83
  justifyContent: 'space-between',
84
84
  marginBottom: description || descriptionFieldPath ? '0.5rem' : '1.25rem',
85
- }, children: [titleFieldPath ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h2", id: titleFieldPath, defaultValue: title, style: {
85
+ }, children: [title ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h2", id: titleFieldPath || 'common.dialogTitle', defaultValue: title, style: {
86
86
  fontSize: '1.35rem',
87
87
  fontWeight: 700,
88
88
  color: 'var(--heading-color, #0f172a)',
89
89
  margin: 0,
90
- } })) : title ? ((0, jsx_runtime_1.jsx)("h2", { "data-preview-static": "dialog-title", style: {
91
- fontSize: '1.35rem',
92
- fontWeight: 700,
93
- color: 'var(--heading-color, #0f172a)',
94
- margin: 0,
95
- }, children: title })) : ((0, jsx_runtime_1.jsx)("div", {})), showCloseButton && onClose && ((0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "dialog-close-btn", onClick: onClose, "aria-label": "Close dialog", style: {
90
+ } })) : ((0, jsx_runtime_1.jsx)("div", {})), showCloseButton && onClose && ((0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "dialog-close-btn", onClick: onClose, "aria-label": "Close dialog", style: {
96
91
  background: 'none',
97
92
  border: 'none',
98
93
  padding: '0.375rem',
@@ -109,18 +104,13 @@ function EditableDialog({ open = false, onClose, title, description, titleFieldP
109
104
  }, onMouseLeave: (e) => {
110
105
  e.currentTarget.style.backgroundColor = 'transparent';
111
106
  e.currentTarget.style.color = '#94a3b8';
112
- }, children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }))] })), descriptionFieldPath ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: descriptionFieldPath, defaultValue: description, style: {
113
- fontSize: '0.925rem',
114
- color: 'var(--muted-text, #64748b)',
115
- marginBottom: '1.5rem',
116
- lineHeight: 1.5,
117
- } })) : description ? ((0, jsx_runtime_1.jsx)("p", { "data-preview-static": "dialog-description", style: {
107
+ }, children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }))] })), description ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: descriptionFieldPath || 'common.dialogDescription', defaultValue: description, style: {
118
108
  fontSize: '0.925rem',
119
109
  color: 'var(--muted-text, #64748b)',
120
110
  marginBottom: '1.5rem',
121
111
  lineHeight: 1.5,
122
112
  margin: '0 0 1.5rem 0',
123
- }, children: description })) : null, (0, jsx_runtime_1.jsx)("div", { style: { flex: 1, overflowY: 'auto' }, children: children }), footerSlot && ((0, jsx_runtime_1.jsx)("div", { style: {
113
+ } })) : null, (0, jsx_runtime_1.jsx)("div", { style: { flex: 1, overflowY: 'auto' }, children: children }), footerSlot && ((0, jsx_runtime_1.jsx)("div", { style: {
124
114
  marginTop: '1.75rem',
125
115
  paddingTop: '1rem',
126
116
  borderTop: '1px solid #f1f5f9',
@@ -9,6 +9,9 @@ export interface EditableFooterProps extends React.HTMLAttributes<HTMLElement> {
9
9
  links?: FooterLink[];
10
10
  basePath?: string;
11
11
  showNewsletter?: boolean;
12
+ socialMedia?: Record<string, string>;
13
+ whatsappUrl?: string;
14
+ directMessageText?: string;
12
15
  }
13
16
  /**
14
17
  * Next-Level DENEB UI Footer
@@ -6,12 +6,47 @@ exports.EditableFooter = EditableFooter;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("react");
8
8
  const SiteDataProvider_1 = require("./SiteDataProvider");
9
+ const EditableText_1 = require("./EditableText");
9
10
  const DEFAULT_FOOTER_PAGES = [
10
11
  { id: 'home', label: 'Home', route: '/' },
11
12
  { id: 'about_us', label: 'About', route: '/about_us' },
12
13
  { id: 'services', label: 'Services', route: '/services' },
13
14
  { id: 'contact', label: 'Contact', route: '/contact' },
14
15
  ];
16
+ const SOCIAL_ICONS = {
17
+ twitter: {
18
+ label: 'X (Twitter)',
19
+ icon: ((0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) })),
20
+ },
21
+ x: {
22
+ label: 'X (Twitter)',
23
+ icon: ((0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) })),
24
+ },
25
+ github: {
26
+ label: 'GitHub',
27
+ icon: ((0, jsx_runtime_1.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" }) })),
28
+ },
29
+ linkedin: {
30
+ label: 'LinkedIn',
31
+ icon: ((0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" }) })),
32
+ },
33
+ instagram: {
34
+ label: 'Instagram',
35
+ icon: ((0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("rect", { width: "20", height: "20", x: "2", y: "2", rx: "5", ry: "5" }), (0, jsx_runtime_1.jsx)("path", { d: "M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" }), (0, jsx_runtime_1.jsx)("line", { x1: "17.5", x2: "17.51", y1: "6.5", y2: "6.5" })] })),
36
+ },
37
+ facebook: {
38
+ label: 'Facebook',
39
+ icon: ((0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" }) })),
40
+ },
41
+ youtube: {
42
+ label: 'YouTube',
43
+ icon: ((0, jsx_runtime_1.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" }) })),
44
+ },
45
+ whatsapp: {
46
+ label: 'WhatsApp',
47
+ icon: ((0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: [(0, jsx_runtime_1.jsx)("path", { d: "M12.031 6.172c-3.181 0-5.767 2.586-5.768 5.766-.001 1.298.38 2.27 1.019 3.287l-.582 2.128 2.182-.573c.978.58 1.911.928 3.145.929 3.178 0 5.767-2.587 5.768-5.766.001-3.187-2.575-5.77-5.764-5.771zm3.392 8.244c-.144.405-.837.774-1.17.824-.312.045-.634.072-1.849-.434-1.464-.61-2.41-2.096-2.484-2.195-.072-.099-.6-0.798-.6-1.523 0-.726.379-1.084.514-1.231.135-.148.297-.185.396-.185.099 0 .198.002.284.006.091.004.213-.035.333.253.123.297.42 1.024.457 1.099.037.074.062.16.012.259-.049.099-.074.16-.148.247-.074.086-.156.193-.223.259-.074.074-.152.155-.065.304.086.148.384.633.824 1.024.567.505 1.045.661 1.194.735.148.074.235.062.321-.037.086-.099.37-.432.469-.58.099-.148.198-.123.333-.074.135.049.864.407 1.012.481.148.074.247.111.284.173.037.062.037.358-.107.763z" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 2C6.48 2 2 6.48 2 12c0 1.82.49 3.53 1.34 5L2 22l5.16-1.32c1.42.8 3.06 1.32 4.84 1.32 5.52 0 10-4.48 10-10S17.52 2 12 2zm0 18.2c-1.59 0-3.07-.46-4.32-1.26l-.31-.2-3.06.78.82-2.98-.22-.33C4.05 14.93 3.6 13.51 3.6 12c0-4.63 3.77-8.4 8.4-8.4s8.4 3.77 8.4 8.4-3.77 8.4-8.4 8.4z" })] })),
48
+ },
49
+ };
15
50
  /**
16
51
  * Next-Level DENEB UI Footer
17
52
  *
@@ -35,6 +70,7 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
35
70
  const [subscribed, setSubscribed] = (0, react_1.useState)(false);
36
71
  const content = (siteData?.content || {});
37
72
  const common = (content?.common || {});
73
+ const contact = (content?.contact || {});
38
74
  const business = (common?.business || {});
39
75
  // Auto-synchronized with Header
40
76
  const siteName = String(common?.websiteTitle || common?.siteName || 'Storefront');
@@ -45,9 +81,23 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
45
81
  const footerHeading = String(common?.footerHeading || 'Stay Connected');
46
82
  const copyright = String(common?.copyright || `© ${new Date().getFullYear()} ${siteName}. All rights reserved.`);
47
83
  // Contact / business values
48
- const phone = String(business?.phone || common?.phone || '');
49
- const emailContact = String(business?.email || common?.email || '');
50
- const address = String(business?.location?.address || common?.address || '');
84
+ const phone = String(business?.phone || common?.phone || contact?.phone || '');
85
+ const emailContact = String(business?.email || common?.email || contact?.email || '');
86
+ const address = String(business?.location?.address || common?.address || contact?.address || '');
87
+ // Social media mapping with live editable URL bindings
88
+ const rawSocial = (common?.socialMedia || content?.socialMedia || props.socialMedia || {});
89
+ const socialPlatforms = Object.keys(rawSocial).length > 0
90
+ ? Object.keys(rawSocial)
91
+ : ['twitter', 'github', 'linkedin', 'instagram'];
92
+ // Direct message / WhatsApp action
93
+ const directMessageLabel = String(contact?.directMessageText || common?.directMessageText || props.directMessageText || 'Send us a direct message');
94
+ const rawWhatsapp = String(contact?.whatsapp || contact?.whatsappUrl || common?.whatsapp || business?.whatsapp || props.whatsappUrl || phone || '');
95
+ const cleanDigits = rawWhatsapp.replace(/[^\d]/g, '');
96
+ const whatsappHref = rawWhatsapp.startsWith('http')
97
+ ? rawWhatsapp
98
+ : cleanDigits
99
+ ? `https://wa.me/${cleanDigits}`
100
+ : 'https://wa.me/';
51
101
  // Route filtering
52
102
  const navigationItems = links || defaultLinks;
53
103
  const requiredPages = Array.isArray(siteData?.requirements?.requiredPages)
@@ -118,14 +168,14 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
118
168
  padding: 0,
119
169
  cursor: 'pointer',
120
170
  textAlign: 'left',
121
- }, className: "inline-flex items-center gap-3 group border-0 bg-transparent p-0 cursor-pointer", children: [(0, jsx_runtime_1.jsx)("img", { src: withBase(logoUrl || '/placeholder.svg'), alt: siteName, "data-preview-static": "footer-brand-logo", style: {
171
+ }, className: "inline-flex items-center gap-3 group border-0 bg-transparent p-0 cursor-pointer", children: [(0, jsx_runtime_1.jsx)("img", { src: withBase(logoUrl || '/placeholder.svg'), alt: siteName, "data-preview-field-path": "common.logoUrl", style: {
122
172
  height: '32px',
123
173
  width: 'auto',
124
174
  maxWidth: '120px',
125
175
  objectFit: 'contain',
126
176
  borderRadius: '6px',
127
177
  filter: 'brightness(1.1)',
128
- }, className: "h-8 w-auto max-w-[120px] object-contain rounded-md group-hover:scale-105 transition-transform" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-static": "footer-brand-title", style: {
178
+ }, className: "h-8 w-auto max-w-[120px] object-contain rounded-md group-hover:scale-105 transition-transform" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "common.websiteTitle", style: {
129
179
  fontSize: '1.25rem',
130
180
  fontWeight: 700,
131
181
  letterSpacing: '-0.025em',
@@ -136,12 +186,20 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
136
186
  color: '#94a3b8', // slate-400
137
187
  margin: 0,
138
188
  maxWidth: '320px',
139
- }, className: "text-sm text-slate-400 leading-relaxed max-w-sm mt-1", children: shortDescription }), (0, jsx_runtime_1.jsxs)("div", { style: {
189
+ }, className: "text-sm text-slate-400 leading-relaxed max-w-sm mt-1", children: shortDescription }), (0, jsx_runtime_1.jsx)("div", { style: {
140
190
  display: 'flex',
141
191
  alignItems: 'center',
192
+ flexWrap: 'wrap',
142
193
  gap: '0.625rem',
143
194
  marginTop: '0.75rem',
144
- }, className: "flex items-center gap-2.5 mt-3", children: [(0, jsx_runtime_1.jsx)("a", { href: "https://twitter.com", target: "_blank", rel: "noreferrer", "data-preview-static": "social-twitter", "aria-label": "Twitter", style: {
195
+ }, className: "flex items-center flex-wrap gap-2.5 mt-3", children: socialPlatforms.map((platformKey) => {
196
+ const key = platformKey.toLowerCase();
197
+ const iconConfig = SOCIAL_ICONS[key] || {
198
+ label: platformKey,
199
+ icon: ((0, jsx_runtime_1.jsx)("span", { style: { fontSize: '10px', fontWeight: 700, textTransform: 'uppercase' }, children: platformKey.slice(0, 2) })),
200
+ };
201
+ const url = rawSocial[platformKey] || rawSocial[key] || `https://${key}.com`;
202
+ return ((0, jsx_runtime_1.jsx)("a", { href: url, target: "_blank", rel: "noopener noreferrer", "data-preview-field-path": `common.socialMedia.${key}`, "aria-label": iconConfig.label, title: `Edit ${iconConfig.label} URL in Fivora`, style: {
145
203
  width: '34px',
146
204
  height: '34px',
147
205
  borderRadius: '8px',
@@ -153,31 +211,8 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
153
211
  color: '#94a3b8',
154
212
  textDecoration: 'none',
155
213
  transition: 'all 0.15s ease',
156
- }, className: "w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-white hover:border-slate-700 hover:bg-slate-800 transition-all", children: (0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }) }), (0, jsx_runtime_1.jsx)("a", { href: "https://github.com", target: "_blank", rel: "noreferrer", "data-preview-static": "social-github", "aria-label": "GitHub", style: {
157
- width: '34px',
158
- height: '34px',
159
- borderRadius: '8px',
160
- backgroundColor: 'rgba(255, 255, 255, 0.05)',
161
- border: '1px solid rgba(255, 255, 255, 0.1)',
162
- display: 'flex',
163
- alignItems: 'center',
164
- justifyContent: 'center',
165
- color: '#94a3b8',
166
- textDecoration: 'none',
167
- transition: 'all 0.15s ease',
168
- }, className: "w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-white hover:border-slate-700 hover:bg-slate-800 transition-all", children: (0, jsx_runtime_1.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" }) }) }), (0, jsx_runtime_1.jsx)("a", { href: "https://linkedin.com", target: "_blank", rel: "noreferrer", "data-preview-static": "social-linkedin", "aria-label": "LinkedIn", style: {
169
- width: '34px',
170
- height: '34px',
171
- borderRadius: '8px',
172
- backgroundColor: 'rgba(255, 255, 255, 0.05)',
173
- border: '1px solid rgba(255, 255, 255, 0.1)',
174
- display: 'flex',
175
- alignItems: 'center',
176
- justifyContent: 'center',
177
- color: '#94a3b8',
178
- textDecoration: 'none',
179
- transition: 'all 0.15s ease',
180
- }, className: "w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-white hover:border-slate-700 hover:bg-slate-800 transition-all", children: (0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" }) }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { "data-preview-static": "footer-explore-heading", style: {
214
+ }, className: "w-8 h-8 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-white hover:border-slate-700 hover:bg-slate-800 transition-all", children: iconConfig.icon }, platformKey));
215
+ }) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { "data-preview-static": "footer-explore-heading", style: {
181
216
  fontSize: '0.8125rem',
182
217
  fontWeight: 700,
183
218
  textTransform: 'uppercase',
@@ -229,19 +264,20 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
229
264
  gap: '0.875rem',
230
265
  fontSize: '0.875rem',
231
266
  color: '#94a3b8',
232
- }, className: "flex flex-col gap-3.5 text-sm text-slate-400", children: [emailContact && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-500", children: [(0, jsx_runtime_1.jsx)("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }), (0, jsx_runtime_1.jsx)("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })] }), (0, jsx_runtime_1.jsx)("a", { href: `mailto:${emailContact}`, "data-preview-static": "contact-email", className: "hover:text-white transition-colors", style: { color: 'inherit', textDecoration: 'none' }, children: emailContact })] })), phone && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-500", children: (0, jsx_runtime_1.jsx)("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }), (0, jsx_runtime_1.jsx)("a", { href: `tel:${phone}`, "data-preview-static": "contact-phone", className: "hover:text-white transition-colors", style: { color: 'inherit', textDecoration: 'none' }, children: phone })] })), address && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'flex-start', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-500 mt-0.5", children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "10", r: "3" })] }), (0, jsx_runtime_1.jsx)("span", { "data-preview-static": "contact-address", children: address })] })), hasContact && ((0, jsx_runtime_1.jsx)("div", { style: { marginTop: '0.5rem' }, children: (0, jsx_runtime_1.jsx)("span", { "data-target-page": "contact", children: (0, jsx_runtime_1.jsxs)("button", { type: "button", "data-preview-static": "contact-cta-btn", onClick: () => navigate('/contact'), style: {
233
- display: 'inline-flex',
234
- alignItems: 'center',
235
- gap: '0.375rem',
236
- fontSize: '0.8125rem',
237
- fontWeight: 600,
238
- color: '#818cf8', // indigo-400
239
- background: 'transparent',
240
- border: 0,
241
- padding: 0,
242
- cursor: 'pointer',
243
- transition: 'color 0.15s ease',
244
- }, className: "inline-flex items-center gap-1.5 text-xs font-semibold text-indigo-400 hover:text-indigo-300 transition-colors border-0 bg-transparent p-0 cursor-pointer", children: ["Send us a direct message", (0, jsx_runtime_1.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M5 12h14M12 5l7 7-7 7" }) })] }) }) }))] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { "data-preview-field-path": "common.footerHeading", style: {
267
+ }, className: "flex flex-col gap-3.5 text-sm text-slate-400", children: [emailContact && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-500", children: [(0, jsx_runtime_1.jsx)("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }), (0, jsx_runtime_1.jsx)("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })] }), (0, jsx_runtime_1.jsx)("a", { href: `mailto:${emailContact}`, "data-preview-field-path": "contact.email", className: "hover:text-white transition-colors", style: { color: 'inherit', textDecoration: 'none' }, children: emailContact })] })), phone && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-500", children: (0, jsx_runtime_1.jsx)("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }), (0, jsx_runtime_1.jsx)("a", { href: `tel:${phone}`, "data-preview-field-path": "contact.phone", className: "hover:text-white transition-colors", style: { color: 'inherit', textDecoration: 'none' }, children: phone })] })), address && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'flex-start', gap: '0.5rem' }, children: [(0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-slate-500 mt-0.5", children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "10", r: "3" })] }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "contact.address", children: address })] })), hasContact && ((0, jsx_runtime_1.jsx)("div", { style: { marginTop: '0.5rem' }, children: (0, jsx_runtime_1.jsxs)("a", { href: whatsappHref, target: "_blank", rel: "noopener noreferrer", "data-preview-field-path": "contact.whatsapp", "aria-label": "Direct message on WhatsApp", style: {
268
+ display: 'inline-flex',
269
+ alignItems: 'center',
270
+ gap: '0.375rem',
271
+ fontSize: '0.8125rem',
272
+ fontWeight: 600,
273
+ color: '#34d399', // emerald-400
274
+ background: 'transparent',
275
+ border: 0,
276
+ padding: 0,
277
+ cursor: 'pointer',
278
+ textDecoration: 'none',
279
+ transition: 'color 0.15s ease',
280
+ }, className: "inline-flex items-center gap-1.5 text-xs font-semibold text-emerald-400 hover:text-emerald-300 transition-colors border-0 bg-transparent p-0 cursor-pointer", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", style: { flexShrink: 0 }, children: [(0, jsx_runtime_1.jsx)("path", { d: "M12.031 6.172c-3.181 0-5.767 2.586-5.768 5.766-.001 1.298.38 2.27 1.019 3.287l-.582 2.128 2.182-.573c.978.58 1.911.928 3.145.929 3.178 0 5.767-2.587 5.768-5.766.001-3.187-2.575-5.77-5.764-5.771zm3.392 8.244c-.144.405-.837.774-1.17.824-.312.045-.634.072-1.849-.434-1.464-.61-2.41-2.096-2.484-2.195-.072-.099-.6-0.798-.6-1.523 0-.726.379-1.084.514-1.231.135-.148.297-.185.396-.185.099 0 .198.002.284.006.091.004.213-.035.333.253.123.297.42 1.024.457 1.099.037.074.062.16.012.259-.049.099-.074.16-.148.247-.074.086-.156.193-.223.259-.074.074-.152.155-.065.304.086.148.384.633.824 1.024.567.505 1.045.661 1.194.735.148.074.235.062.321-.037.086-.099.37-.432.469-.58.099-.148.198-.123.333-.074.135.049.864.407 1.012.481.148.074.247.111.284.173.037.062.037.358-.107.763z" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 2C6.48 2 2 6.48 2 12c0 1.82.49 3.53 1.34 5L2 22l5.16-1.32c1.42.8 3.06 1.32 4.84 1.32 5.52 0 10-4.48 10-10S17.52 2 12 2zm0 18.2c-1.59 0-3.07-.46-4.32-1.26l-.31-.2-3.06.78.82-2.98-.22-.33C4.05 14.93 3.6 13.51 3.6 12c0-4.63 3.77-8.4 8.4-8.4s8.4 3.77 8.4 8.4-3.77 8.4-8.4 8.4z" })] }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: "contact.directMessageText", defaultValue: directMessageLabel, style: { color: 'inherit', fontWeight: 600 } }), (0, jsx_runtime_1.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M5 12h14M12 5l7 7-7 7" }) })] }) }))] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { "data-preview-field-path": "common.footerHeading", style: {
245
281
  fontSize: '0.8125rem',
246
282
  fontWeight: 700,
247
283
  textTransform: 'uppercase',
@@ -313,7 +349,7 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
313
349
  padding: '0.15rem 0.5rem',
314
350
  borderRadius: '6px',
315
351
  letterSpacing: '0.025em',
316
- }, className: "inline-flex items-center gap-1 font-semibold text-slate-200 bg-slate-900 border border-slate-800 px-2 py-0.5 rounded-md text-xs shadow-inner", children: [(0, jsx_runtime_1.jsx)("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", className: "text-indigo-400", children: (0, jsx_runtime_1.jsx)("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" }) }), "DENEB UI"] })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "back-to-top", onClick: scrollToTop, "aria-label": "Back to top", style: {
352
+ }, className: "inline-flex items-center gap-1 font-semibold text-slate-200 bg-slate-900 border border-slate-800 px-2 py-0.5 rounded-md text-xs shadow-inner", children: [(0, jsx_runtime_1.jsx)("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", className: "text-cyan-400", children: (0, jsx_runtime_1.jsx)("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" }) }), "Fivora"] })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "back-to-top", onClick: scrollToTop, "aria-label": "Back to top", style: {
317
353
  display: 'inline-flex',
318
354
  alignItems: 'center',
319
355
  justifyContent: 'center',
@@ -171,7 +171,7 @@ function EditableNavbar({ defaultLinks = DEFAULT_PAGES, sticky = true, activeRou
171
171
  cursor: 'pointer',
172
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
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));
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-field-path": `common.navLabels.${link.id}`, children: label }) }) }, link.id));
175
175
  }) }))] }));
176
176
  }
177
177
  exports.Navbar = EditableNavbar;
@@ -51,10 +51,18 @@ export interface EditableProductCardProps extends React.HTMLAttributes<HTMLEleme
51
51
  * Optional custom action slot (e.g. Add to Cart button).
52
52
  */
53
53
  actionSlot?: React.ReactNode;
54
+ /**
55
+ * Label for the action button (default: 'Buy Now' or product.buttonText).
56
+ */
57
+ actionLabel?: string;
58
+ /**
59
+ * Custom field path for the action button label.
60
+ */
61
+ actionLabelPath?: string;
54
62
  }
55
63
  /**
56
64
  * EditableProductCard is an elite, auto-balancing commerce card supporting
57
65
  * four visual variants (modern-glass, classic, minimal, horizontal) and
58
66
  * strict Fivora visual editing synchronization.
59
67
  */
60
- export declare function EditableProductCard({ itemPath, product, cardVariant, imageFallback, as: Component, showPrice, showDescription, showCategory, actionSlot, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
68
+ export declare function EditableProductCard({ itemPath, product, cardVariant, imageFallback, as: Component, showPrice, showDescription, showCategory, actionSlot, actionLabel, actionLabelPath, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
@@ -10,7 +10,7 @@ const EditableText_2 = require("./EditableText");
10
10
  * four visual variants (modern-glass, classic, minimal, horizontal) and
11
11
  * strict Fivora visual editing synchronization.
12
12
  */
13
- function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', showPrice = true, showDescription = true, showCategory = true, actionSlot, className = '', style, ...props }) {
13
+ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', showPrice = true, showDescription = true, showCategory = true, actionSlot, actionLabel, actionLabelPath, className = '', style, ...props }) {
14
14
  const name = String(product?.name || product?.title || '');
15
15
  const price = product?.price !== undefined ? String(product.price) : '';
16
16
  const originalPrice = product?.originalPrice !== undefined ? String(product.originalPrice) : '';
@@ -102,7 +102,7 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
102
102
  fontSize: '0.875rem',
103
103
  textDecoration: 'line-through',
104
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: {
105
+ } })) : null] })), actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsx)("button", { type: "button", style: {
106
106
  backgroundColor: 'var(--brand-color, #2563eb)',
107
107
  color: '#ffffff',
108
108
  border: 'none',
@@ -112,5 +112,5 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
112
112
  fontWeight: 600,
113
113
  cursor: 'pointer',
114
114
  transition: 'opacity 0.2s ease',
115
- }, children: "Buy Now" }))] })] })] }));
115
+ }, children: (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: actionLabelPath || `${itemPath}.buttonText`, defaultValue: actionLabel || product?.buttonText || 'Buy Now', style: { color: '#ffffff', fontWeight: 600 } }) }))] })] })] }));
116
116
  }
@@ -32,6 +32,11 @@ export interface EditableTextProps extends React.HTMLAttributes<HTMLElement> {
32
32
  */
33
33
  'data-preview-field-path'?: string;
34
34
  defaultValue?: string;
35
+ /**
36
+ * Placeholder text displayed when defaultValue or children is empty.
37
+ * Remains 100% interactive and editable inside the Fivora live editor.
38
+ */
39
+ placeholder?: string;
35
40
  as?: React.ElementType;
36
41
  /**
37
42
  * Semantic typography variant providing instant preset styles (h1-h6, p, lead, eyebrow, caption, badge).
@@ -76,7 +81,7 @@ export interface EditableTextProps extends React.HTMLAttributes<HTMLElement> {
76
81
  * EditableText provides full typography controls (color, size, weight, line-height, alignment, transform, variants)
77
82
  * alongside strict Fivora visual editing bindings.
78
83
  */
79
- export declare function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, ...props }: EditableTextProps): React.JSX.Element;
84
+ export declare function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, placeholder, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, ...props }: EditableTextProps): React.JSX.Element;
80
85
  export interface EditableHeadingProps extends Omit<EditableTextProps, 'variant'> {
81
86
  level?: 1 | 2 | 3 | 4 | 5 | 6;
82
87
  }
@@ -106,9 +106,14 @@ function toCssUnit(value) {
106
106
  * EditableText provides full typography controls (color, size, weight, line-height, alignment, transform, variants)
107
107
  * alongside strict Fivora visual editing bindings.
108
108
  */
109
- function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, ...props }) {
109
+ function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, placeholder, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, ...props }) {
110
110
  const path = previewFieldPath || id;
111
- const content = children !== undefined ? children : defaultValue;
111
+ const rawContent = children !== undefined ? children : defaultValue;
112
+ const isContentEmpty = rawContent === undefined ||
113
+ rawContent === null ||
114
+ (typeof rawContent === 'string' && rawContent.trim() === '');
115
+ const isPlaceholderActive = isContentEmpty && Boolean(placeholder);
116
+ const displayContent = isPlaceholderActive ? placeholder : rawContent;
112
117
  const dynamicStyle = (0, SiteDataProvider_1.useFieldStyle)(path);
113
118
  const variantDefaults = variant ? exports.VARIANT_DEFAULTS[variant] : undefined;
114
119
  const Component = ComponentOverride || variantDefaults?.as || 'span';
@@ -148,6 +153,11 @@ function EditableText({ id, 'data-preview-field-path': previewFieldPath, default
148
153
  const dynamicMarginLeft = toCssUnit(dynamicStyle?.spacingLeft);
149
154
  const dynamicMarginRight = toCssUnit(dynamicStyle?.spacingRight);
150
155
  const typographyStyle = {
156
+ // Minimum dimensions ensure empty/placeholder elements never collapse to 0x0 and remain 100% clickable in Fivora
157
+ minHeight: '1.2em',
158
+ minWidth: '1.5ch',
159
+ ...(Component === 'span' || ComponentOverride === 'span' ? { display: 'inline-block' } : {}),
160
+ ...(isPlaceholderActive ? { opacity: 0.55, fontStyle: 'italic' } : {}),
151
161
  ...(resolvedColor ? { color: resolvedColor } : {}),
152
162
  ...(resolvedSize ? { fontSize: resolvedSize } : {}),
153
163
  ...(resolvedWeight ? { fontWeight: resolvedWeight } : {}),
@@ -168,7 +178,7 @@ function EditableText({ id, 'data-preview-field-path': previewFieldPath, default
168
178
  ...(dynamicMarginLeft !== undefined ? { marginLeft: dynamicMarginLeft } : {}),
169
179
  ...(dynamicMarginRight !== undefined ? { marginRight: dynamicMarginRight } : {}),
170
180
  };
171
- return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-field-path": path, style: typographyStyle, ...props, children: content }));
181
+ return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-field-path": path, "data-preview-placeholder": isPlaceholderActive ? 'true' : undefined, style: typographyStyle, ...props, children: displayContent }));
172
182
  }
173
183
  function EditableHeading({ level = 2, as, ...props }) {
174
184
  const variant = `h${level}`;
@@ -67,7 +67,7 @@ function BusinessHours({ hours, title = 'Business Hours', fieldPath = 'common.bu
67
67
  backgroundColor: 'var(--color-surface, #ffffff)',
68
68
  ...style,
69
69
  };
70
- return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-business-hours ${className}`.trim(), style: containerStyles, children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '1rem' }, children: [(0, jsx_runtime_1.jsx)("h4", { style: { margin: 0, fontSize: '1.1rem', fontWeight: 600, color: 'var(--color-text, #0f172a)' }, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-static": "business-hours-title", children: title }) }), showStatusBadge && currentStatus && ((0, jsx_runtime_1.jsxs)("span", { "data-preview-static": "business-hours-status", style: {
70
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-business-hours ${className}`.trim(), style: containerStyles, children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '1rem' }, children: [(0, jsx_runtime_1.jsx)("h4", { style: { margin: 0, fontSize: '1.1rem', fontWeight: 600, color: 'var(--color-text, #0f172a)' }, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": fieldPath ? `${fieldPath}.title` : 'contact.businessHoursTitle', children: title }) }), showStatusBadge && currentStatus && ((0, jsx_runtime_1.jsxs)("span", { "data-preview-static": "business-hours-status", style: {
71
71
  display: 'inline-flex',
72
72
  alignItems: 'center',
73
73
  gap: '0.35rem',
@@ -37,5 +37,5 @@ function LocationCard({ title = 'Our Location', titleFieldPath, address, city, c
37
37
  alignItems: 'center',
38
38
  justifyContent: 'center',
39
39
  };
40
- return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-location-card ${className}`.trim(), style: cardStyles, children: [(0, jsx_runtime_1.jsx)("div", { style: iconCircleStyles, children: (0, jsx_runtime_1.jsxs)("svg", { "data-preview-static": "location-card-icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "10", r: "3" })] }) }), titleFieldPath ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: titleFieldPath, defaultValue: title, style: { margin: 0, fontSize: '1.25rem', fontWeight: 600, color: 'var(--color-text, #0f172a)' } })) : ((0, jsx_runtime_1.jsx)("h3", { "data-preview-static": "location-card-title", style: { margin: 0, fontSize: '1.25rem', fontWeight: 600, color: 'var(--color-text, #0f172a)' }, children: title })), (0, jsx_runtime_1.jsx)(Address_1.Address, { address: address, city: city, country: country, postalCode: postalCode, fieldPath: fieldPath, addressFieldPath: addressFieldPath }), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: '0.5rem', width: '100%' }, children: (0, jsx_runtime_1.jsx)(MapLink_1.MapLink, { mapUrl: mapUrl, address: address, city: city, country: country, label: directionsLabel, fieldPath: mapUrlFieldPath, variant: "primary", size: "md", style: { width: '100%' } }) })] }));
40
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-location-card ${className}`.trim(), style: cardStyles, children: [(0, jsx_runtime_1.jsx)("div", { style: iconCircleStyles, children: (0, jsx_runtime_1.jsxs)("svg", { "data-preview-static": "location-card-icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "10", r: "3" })] }) }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: titleFieldPath || (fieldPath ? `${fieldPath}.title` : 'contact.locationTitle'), defaultValue: title, style: { margin: 0, fontSize: '1.25rem', fontWeight: 600, color: 'var(--color-text, #0f172a)' } }), (0, jsx_runtime_1.jsx)(Address_1.Address, { address: address, city: city, country: country, postalCode: postalCode, fieldPath: fieldPath, addressFieldPath: addressFieldPath }), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: '0.5rem', width: '100%' }, children: (0, jsx_runtime_1.jsx)(MapLink_1.MapLink, { mapUrl: mapUrl, address: address, city: city, country: country, label: directionsLabel, fieldPath: mapUrlFieldPath, variant: "primary", size: "md", style: { width: '100%' } }) })] }));
41
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deneb-ui/ui",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "DENEB UI - The premier visual-first React component framework for the modern web. Created by Chamika Gayashan & Induranga Kawishwara.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",