@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.
- package/README.md +182 -0
- package/dist/EditableBox.d.ts +56 -0
- package/dist/EditableBox.js +113 -0
- package/dist/EditableCard.d.ts +48 -0
- package/dist/EditableCard.js +85 -0
- package/dist/EditableContactForm.d.ts +11 -0
- package/dist/EditableContactForm.js +146 -0
- package/dist/EditableDialog.d.ts +25 -0
- package/dist/EditableDialog.js +145 -0
- package/dist/EditableFAQAccordion.d.ts +19 -0
- package/dist/EditableFAQAccordion.js +62 -0
- package/dist/EditableFooter.d.ts +31 -0
- package/dist/EditableFooter.js +330 -0
- package/dist/EditableGrid.d.ts +40 -0
- package/dist/EditableGrid.js +39 -0
- package/dist/EditableHero.d.ts +27 -0
- package/dist/EditableHero.js +154 -0
- package/dist/EditableImage.d.ts +13 -0
- package/dist/EditableImage.js +38 -0
- package/dist/EditableList.d.ts +33 -0
- package/dist/EditableList.js +19 -0
- package/dist/EditableNavbar.d.ts +28 -0
- package/dist/EditableNavbar.js +178 -0
- package/dist/EditablePricingCard.d.ts +31 -0
- package/dist/EditablePricingCard.js +93 -0
- package/dist/EditableProductCard.d.ts +60 -0
- package/dist/EditableProductCard.js +116 -0
- package/dist/EditableSection.d.ts +35 -0
- package/dist/EditableSection.js +34 -0
- package/dist/EditableServiceCard.d.ts +38 -0
- package/dist/EditableServiceCard.js +28 -0
- package/dist/EditableTestimonialCard.d.ts +17 -0
- package/dist/EditableTestimonialCard.js +46 -0
- package/dist/EditableText.d.ts +117 -0
- package/dist/EditableText.js +319 -0
- package/dist/SiteDataProvider.d.ts +61 -0
- package/dist/SiteDataProvider.js +316 -0
- package/dist/ThemeStyles.d.ts +46 -0
- package/dist/ThemeStyles.js +181 -0
- package/dist/business/BusinessHours.d.ts +20 -0
- package/dist/business/BusinessHours.js +109 -0
- package/dist/business/index.d.ts +1 -0
- package/dist/business/index.js +17 -0
- package/dist/contact/ContactActions.d.ts +24 -0
- package/dist/contact/ContactActions.js +30 -0
- package/dist/contact/ContactButton.d.ts +15 -0
- package/dist/contact/ContactButton.js +94 -0
- package/dist/contact/EmailButton.d.ts +6 -0
- package/dist/contact/EmailButton.js +12 -0
- package/dist/contact/PhoneButton.d.ts +6 -0
- package/dist/contact/PhoneButton.js +12 -0
- package/dist/contact/WhatsAppButton.d.ts +6 -0
- package/dist/contact/WhatsAppButton.js +13 -0
- package/dist/contact/index.d.ts +5 -0
- package/dist/contact/index.js +21 -0
- package/dist/core/DenebAction.d.ts +19 -0
- package/dist/core/DenebAction.js +107 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +17 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +106 -0
- package/dist/location/Address.d.ts +14 -0
- package/dist/location/Address.js +26 -0
- package/dist/location/LocationCard.d.ts +20 -0
- package/dist/location/LocationCard.js +41 -0
- package/dist/location/LocationLink.d.ts +18 -0
- package/dist/location/LocationLink.js +23 -0
- package/dist/location/MapEmbed.d.ts +18 -0
- package/dist/location/MapEmbed.js +30 -0
- package/dist/location/MapLink.d.ts +13 -0
- package/dist/location/MapLink.js +63 -0
- package/dist/location/index.d.ts +5 -0
- package/dist/location/index.js +21 -0
- package/dist/social/SocialButton.d.ts +11 -0
- package/dist/social/SocialButton.js +112 -0
- package/dist/social/SocialLinks.d.ts +14 -0
- package/dist/social/SocialLinks.js +42 -0
- package/dist/social/index.d.ts +2 -0
- package/dist/social/index.js +18 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +17 -0
- package/dist/utils/urls.d.ts +32 -0
- package/dist/utils/urls.js +91 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# DENEB
|
|
2
|
+
|
|
3
|
+
### A modern UI system for the web.
|
|
4
|
+
|
|
5
|
+
> **DENEB UI — Build beautiful interfaces, effortlessly.**
|
|
6
|
+
> The premier visual-first React component ecosystem.
|
|
7
|
+
> Created by **Chamika Gayashan (CEE G)**.
|
|
8
|
+
|
|
9
|
+
[](https://github.com/chamikathereal)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @deneb-ui/ui
|
|
18
|
+
# Or with yarn / pnpm
|
|
19
|
+
pnpm add @deneb-ui/ui
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import {
|
|
24
|
+
Button,
|
|
25
|
+
Card,
|
|
26
|
+
Dialog,
|
|
27
|
+
ContactActions,
|
|
28
|
+
WhatsAppButton,
|
|
29
|
+
LocationCard,
|
|
30
|
+
SocialLinks,
|
|
31
|
+
BusinessHours,
|
|
32
|
+
} from "@deneb-ui/ui";
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What is DENEB UI?
|
|
38
|
+
|
|
39
|
+
**DENEB UI** is a modern, modular design system and component framework engineered specifically for live visual editing, dynamic theming, and high-converting commerce storefronts.
|
|
40
|
+
|
|
41
|
+
Every component in DENEB UI:
|
|
42
|
+
- **Zero-Breakage Visual Editing**: Automatically connects to the bidirectional live editor protocol (`DENEB_PREVIEW_SITE_DATA` / `FIVORA_PREVIEW_SITE_DATA`, `DENEB_PREVIEW_READY`, `DENEB_PREVIEW_FOCUS_PAGE`).
|
|
43
|
+
- **Auto-Balancing Layouts**: Columns and card heights automatically adapt across desktop, tablet, and mobile regardless of content length.
|
|
44
|
+
- **Smart Contact & Location Actions**: One-click WhatsApp, call, email, and Google Maps generation from raw phone numbers and addresses.
|
|
45
|
+
- **Dynamic Tokenized Theming**: Fully integrated with tokenized custom properties (`--color-primary`, `--color-secondary`, fonts, spacing) and AI-assisted restyling.
|
|
46
|
+
- **Selected-Page Route Guard**: Automatically respects `requirements.requiredPages`, ensuring zero dead links or validation warnings.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Component Catalog
|
|
51
|
+
|
|
52
|
+
### 1. Smart Template & Action Components
|
|
53
|
+
- `<ContactActions />` — Auto-detects and renders active communication channels (`phone`, `whatsapp`, `email`). When a merchant adds a phone number in `site-data.json`, the button appears automatically with zero template changes.
|
|
54
|
+
- `<WhatsAppButton />` — One-click WhatsApp click-to-chat button with built-in SVG icon and automatic `https://wa.me/...` URL generation from raw phone numbers.
|
|
55
|
+
- `<PhoneButton />` — One-click calling button with `tel:` handler and raw number editing bindings.
|
|
56
|
+
- `<EmailButton />` — One-click email button with `mailto:` handler and optional subject lines.
|
|
57
|
+
- `<ContactButton />` — Base unified action button supporting WhatsApp, phone, email, and forms.
|
|
58
|
+
- `<LocationCard />` — High-converting location card with pin icon, formatted address, and Google Maps directions button.
|
|
59
|
+
- `<LocationLink />` — Semantic address display paired with a "Get Directions" action.
|
|
60
|
+
- `<MapLink />` — Direct link button to open Google Maps directions or search queries.
|
|
61
|
+
- `<MapEmbed />` — Responsive map embed iframe with safe graceful fallback to `MapLink` when embed URLs are unconfigured.
|
|
62
|
+
- `<Address />` — Structured `<address>` component with individual street, locality, and country field markers.
|
|
63
|
+
- `<SocialLinks />` — Smart social media container that filters out unconfigured platforms automatically.
|
|
64
|
+
- `<SocialButton />` — Brand-colored social button with built-in SVGs (Instagram, Facebook, TikTok, YouTube, LinkedIn, X, Twitter, Pinterest, GitHub).
|
|
65
|
+
- `<BusinessHours />` — Weekly operating schedule renderer with a dynamic live **Open Now** / **Closed** status badge.
|
|
66
|
+
- `<DenebAction />` (or `<ActionLink />`) — Universal action primitive connecting action types, URL generation, and visual editing markers.
|
|
67
|
+
|
|
68
|
+
### 2. Interactive Primitives
|
|
69
|
+
- `<Button />` (or `<EditableButton />`) — Modern button with `primary`, `secondary`, `accent`, `glass`, `ghost` styles and `targetPage` guard.
|
|
70
|
+
- `<Dialog />` (or `<EditableDialog />`) — Accessible popup modal with backdrop blur, smooth entrance, keyboard ESC exit, title, description, and footer actions.
|
|
71
|
+
- `<Card />` (or `<EditableCard />`) — Flexible surface card with auto-balancing content layout.
|
|
72
|
+
- `<Text />`, `<Heading />`, `<Paragraph />` — Typography components with responsive sizing and live editor binding.
|
|
73
|
+
- `<Badge />` — Status indicators, tags, and promotional pills (`primary`, `secondary`, `accent`, `glass`, `glow`).
|
|
74
|
+
- `<Link />` — Route link that automatically validates against `requirements.requiredPages`.
|
|
75
|
+
- `<Quote />` — Editorial pull quotes and callouts.
|
|
76
|
+
|
|
77
|
+
### 3. Sections & Commerce
|
|
78
|
+
- `<ProductCard />` — 4 visual variants (`modern-glass`, `classic`, `minimal`, `horizontal`) with discount tags and pricing.
|
|
79
|
+
- `<PricingCard />` — Subscription/pricing tiers with feature checklist.
|
|
80
|
+
- `<TestimonialCard />` — Customer reviews with 1–5 stars and author avatar.
|
|
81
|
+
- `<ContactForm />` — Direct submission form connected to shared API endpoint.
|
|
82
|
+
- `<Navbar />` — Sticky header with logo, mobile drawer, and filtered navigation.
|
|
83
|
+
- `<Footer />` — Responsive footer with copyright and route filtering.
|
|
84
|
+
- `<Hero />` & `<HeroSplit />` — High-impact hero sections with eyebrow badges and dual CTAs.
|
|
85
|
+
- `<Grid />` — Auto-balancing CSS grid with equal height.
|
|
86
|
+
- `<Accordion />` / `<FAQ />` — Collapsible Q&A list.
|
|
87
|
+
- `<Image />` — Aspect ratio locked image with SVG fallback placeholder.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## URL Utility Layer
|
|
92
|
+
|
|
93
|
+
DENEB UI exports a dedicated utility suite for URL formatting and generation:
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import {
|
|
97
|
+
createWhatsAppUrl,
|
|
98
|
+
createPhoneUrl,
|
|
99
|
+
createEmailUrl,
|
|
100
|
+
createMapUrl,
|
|
101
|
+
isSafeExternalLink,
|
|
102
|
+
} from "@deneb-ui/ui";
|
|
103
|
+
|
|
104
|
+
// Generates: https://wa.me/94771234567?text=Hello%20Store
|
|
105
|
+
const waUrl = createWhatsAppUrl("+94 77 123 4567", "Hello Store");
|
|
106
|
+
|
|
107
|
+
// Generates: tel:+94112345678
|
|
108
|
+
const telUrl = createPhoneUrl("+94 11 234 5678");
|
|
109
|
+
|
|
110
|
+
// Generates: mailto:hello@store.com?subject=Enquiry
|
|
111
|
+
const mailUrl = createEmailUrl("hello@store.com", "Enquiry");
|
|
112
|
+
|
|
113
|
+
// Generates Google Maps directions search URL
|
|
114
|
+
const mapUrl = createMapUrl({ address: "123 Main Street", city: "Colombo", country: "Sri Lanka" });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Example Usage
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import {
|
|
123
|
+
SiteDataProvider,
|
|
124
|
+
Navbar,
|
|
125
|
+
Hero,
|
|
126
|
+
ProductCard,
|
|
127
|
+
ContactActions,
|
|
128
|
+
LocationCard,
|
|
129
|
+
BusinessHours,
|
|
130
|
+
SocialLinks,
|
|
131
|
+
Footer,
|
|
132
|
+
useSiteData,
|
|
133
|
+
} from '@deneb-ui/ui';
|
|
134
|
+
|
|
135
|
+
import siteData from '@/data/site-data.json';
|
|
136
|
+
|
|
137
|
+
export default function HomePage() {
|
|
138
|
+
const data = useSiteData();
|
|
139
|
+
const business = data.content?.common?.business || {};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<SiteDataProvider initialSiteData={siteData}>
|
|
143
|
+
<Navbar />
|
|
144
|
+
|
|
145
|
+
<main data-preview-page-key="home">
|
|
146
|
+
<Hero />
|
|
147
|
+
|
|
148
|
+
{/* Smart Contact & Actions */}
|
|
149
|
+
<section className="py-12 max-w-5xl mx-auto px-6 flex flex-col items-center gap-6">
|
|
150
|
+
<ContactActions
|
|
151
|
+
phone={business.phone}
|
|
152
|
+
whatsapp={business.whatsapp}
|
|
153
|
+
email={business.email}
|
|
154
|
+
/>
|
|
155
|
+
|
|
156
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 w-full mt-6">
|
|
157
|
+
<LocationCard
|
|
158
|
+
address={business.location?.address}
|
|
159
|
+
city={business.location?.city}
|
|
160
|
+
country={business.location?.country}
|
|
161
|
+
mapUrl={business.location?.mapUrl}
|
|
162
|
+
/>
|
|
163
|
+
|
|
164
|
+
<BusinessHours hours={business.hours} />
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<SocialLinks social={business.social} />
|
|
168
|
+
</section>
|
|
169
|
+
</main>
|
|
170
|
+
|
|
171
|
+
<Footer />
|
|
172
|
+
</SiteDataProvider>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Author & Credits
|
|
180
|
+
|
|
181
|
+
Created and architected by **Chamika Gayashan (CEE G)**.
|
|
182
|
+
Built for the global React and storefront developer ecosystem.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type BoxRadius = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | (string & {}) | number;
|
|
3
|
+
export type BoxShadow = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | (string & {});
|
|
4
|
+
export type BoxSpacing = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | (string & {}) | number;
|
|
5
|
+
export type BoxAspectRatio = '1/1' | '16/9' | '4/3' | '3/4' | '9/16' | '2/3' | '3/2' | 'square' | 'video' | 'portrait' | 'landscape' | (string & {});
|
|
6
|
+
export interface EditableBoxProps extends React.HTMLAttributes<HTMLElement> {
|
|
7
|
+
as?: React.ElementType;
|
|
8
|
+
/**
|
|
9
|
+
* Field path or item path in siteData.
|
|
10
|
+
*/
|
|
11
|
+
id?: string;
|
|
12
|
+
'data-preview-field-path'?: string;
|
|
13
|
+
'data-preview-item-path'?: string;
|
|
14
|
+
'data-preview-static'?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Sizing controls
|
|
17
|
+
*/
|
|
18
|
+
width?: string | number;
|
|
19
|
+
minWidth?: string | number;
|
|
20
|
+
maxWidth?: string | number;
|
|
21
|
+
height?: string | number;
|
|
22
|
+
minHeight?: string | number;
|
|
23
|
+
maxHeight?: string | number;
|
|
24
|
+
aspectRatio?: BoxAspectRatio;
|
|
25
|
+
/**
|
|
26
|
+
* Auto-balance: expands and balances item within flex/grid rows to match available space evenly.
|
|
27
|
+
*/
|
|
28
|
+
balance?: boolean;
|
|
29
|
+
grow?: boolean | number;
|
|
30
|
+
shrink?: boolean | number;
|
|
31
|
+
/**
|
|
32
|
+
* Spacing & styling
|
|
33
|
+
*/
|
|
34
|
+
padding?: BoxSpacing;
|
|
35
|
+
margin?: BoxSpacing;
|
|
36
|
+
bg?: string;
|
|
37
|
+
color?: string;
|
|
38
|
+
radius?: BoxRadius;
|
|
39
|
+
shadow?: BoxShadow;
|
|
40
|
+
border?: string | boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Visual layout & alignment
|
|
43
|
+
*/
|
|
44
|
+
display?: 'block' | 'flex' | 'grid' | 'inline-block' | 'inline-flex';
|
|
45
|
+
direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
|
|
46
|
+
wrap?: boolean | 'wrap' | 'nowrap' | 'wrap-reverse';
|
|
47
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
48
|
+
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
|
|
49
|
+
gap?: BoxSpacing;
|
|
50
|
+
overflow?: 'visible' | 'hidden' | 'auto' | 'scroll';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* EditableBox is a flexible, smart container ("div-like") component with built-in
|
|
54
|
+
* width/height resizing, aspect-ratio controls, and auto-balancing for fivora cards.
|
|
55
|
+
*/
|
|
56
|
+
export declare function EditableBox({ as: Component, id, 'data-preview-field-path': previewFieldPath, 'data-preview-item-path': previewItemPath, 'data-preview-static': previewStatic, width, minWidth, maxWidth, height, minHeight, maxHeight, aspectRatio, balance, grow, shrink, padding, margin, bg, color, radius, shadow, border, display, direction, wrap, align, justify, gap, overflow, style, children, className, ...props }: EditableBoxProps): React.JSX.Element;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EditableBox = EditableBox;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const SiteDataProvider_1 = require("./SiteDataProvider");
|
|
6
|
+
const RADIUS_MAP = {
|
|
7
|
+
none: '0px',
|
|
8
|
+
sm: '4px',
|
|
9
|
+
md: '8px',
|
|
10
|
+
lg: '12px',
|
|
11
|
+
xl: '16px',
|
|
12
|
+
'2xl': '24px',
|
|
13
|
+
full: '9999px',
|
|
14
|
+
};
|
|
15
|
+
const SHADOW_MAP = {
|
|
16
|
+
none: 'none',
|
|
17
|
+
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
|
18
|
+
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
|
|
19
|
+
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)',
|
|
20
|
+
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
|
|
21
|
+
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
|
22
|
+
};
|
|
23
|
+
const SPACING_MAP = {
|
|
24
|
+
none: '0',
|
|
25
|
+
xs: '0.25rem',
|
|
26
|
+
sm: '0.5rem',
|
|
27
|
+
md: '1rem',
|
|
28
|
+
lg: '1.5rem',
|
|
29
|
+
xl: '2rem',
|
|
30
|
+
'2xl': '3rem',
|
|
31
|
+
};
|
|
32
|
+
const ASPECT_MAP = {
|
|
33
|
+
square: '1 / 1',
|
|
34
|
+
'1/1': '1 / 1',
|
|
35
|
+
video: '16 / 9',
|
|
36
|
+
'16/9': '16 / 9',
|
|
37
|
+
portrait: '3 / 4',
|
|
38
|
+
'3/4': '3 / 4',
|
|
39
|
+
'4/3': '4 / 3',
|
|
40
|
+
landscape: '4 / 3',
|
|
41
|
+
'9/16': '9 / 16',
|
|
42
|
+
'2/3': '2 / 3',
|
|
43
|
+
'3/2': '3 / 2',
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* EditableBox is a flexible, smart container ("div-like") component with built-in
|
|
47
|
+
* width/height resizing, aspect-ratio controls, and auto-balancing for fivora cards.
|
|
48
|
+
*/
|
|
49
|
+
function EditableBox({ as: Component = 'div', id, 'data-preview-field-path': previewFieldPath, 'data-preview-item-path': previewItemPath, 'data-preview-static': previewStatic, width, minWidth, maxWidth, height, minHeight, maxHeight, aspectRatio, balance, grow, shrink, padding, margin, bg, color, radius, shadow, border, display, direction, wrap, align, justify, gap, overflow, style, children, className = '', ...props }) {
|
|
50
|
+
const resolvedRadius = radius !== undefined ? (RADIUS_MAP[String(radius)] || String(radius)) : undefined;
|
|
51
|
+
const resolvedShadow = shadow ? (SHADOW_MAP[shadow] || shadow) : undefined;
|
|
52
|
+
const resolvedPadding = padding !== undefined ? (SPACING_MAP[String(padding)] || String(padding)) : undefined;
|
|
53
|
+
const resolvedMargin = margin !== undefined ? (SPACING_MAP[String(margin)] || String(margin)) : undefined;
|
|
54
|
+
const resolvedGap = gap !== undefined ? (SPACING_MAP[String(gap)] || String(gap)) : undefined;
|
|
55
|
+
const resolvedAspect = aspectRatio ? (ASPECT_MAP[aspectRatio] || aspectRatio) : undefined;
|
|
56
|
+
const resolvedAlign = align === 'start' ? 'flex-start' : align === 'end' ? 'flex-end' : align;
|
|
57
|
+
const resolvedJustify = justify === 'start'
|
|
58
|
+
? 'flex-start'
|
|
59
|
+
: justify === 'end'
|
|
60
|
+
? 'flex-end'
|
|
61
|
+
: justify === 'between'
|
|
62
|
+
? 'space-between'
|
|
63
|
+
: justify === 'around'
|
|
64
|
+
? 'space-around'
|
|
65
|
+
: justify === 'evenly'
|
|
66
|
+
? 'space-evenly'
|
|
67
|
+
: justify;
|
|
68
|
+
const resolvedWrap = typeof wrap === 'boolean' ? (wrap ? 'wrap' : 'nowrap') : wrap;
|
|
69
|
+
const resolvedBorder = border === true
|
|
70
|
+
? '1px solid var(--border-color, rgba(226, 232, 240, 0.8))'
|
|
71
|
+
: typeof border === 'string'
|
|
72
|
+
? border
|
|
73
|
+
: undefined;
|
|
74
|
+
const path = previewFieldPath || id || previewItemPath;
|
|
75
|
+
const dynamicStyle = (0, SiteDataProvider_1.useFieldStyle)(path);
|
|
76
|
+
const dynamicMarginTop = dynamicStyle?.spacingTop !== undefined && dynamicStyle?.spacingTop !== '' ? `${dynamicStyle.spacingTop}px` : undefined;
|
|
77
|
+
const dynamicMarginBottom = dynamicStyle?.spacingBottom !== undefined && dynamicStyle?.spacingBottom !== '' ? `${dynamicStyle.spacingBottom}px` : undefined;
|
|
78
|
+
const dynamicMarginLeft = dynamicStyle?.spacingLeft !== undefined && dynamicStyle?.spacingLeft !== '' ? `${dynamicStyle.spacingLeft}px` : undefined;
|
|
79
|
+
const dynamicMarginRight = dynamicStyle?.spacingRight !== undefined && dynamicStyle?.spacingRight !== '' ? `${dynamicStyle.spacingRight}px` : undefined;
|
|
80
|
+
const boxStyle = {
|
|
81
|
+
...(width !== undefined ? { width } : {}),
|
|
82
|
+
...(minWidth !== undefined ? { minWidth } : {}),
|
|
83
|
+
...(maxWidth !== undefined ? { maxWidth } : {}),
|
|
84
|
+
...(height !== undefined ? { height } : {}),
|
|
85
|
+
...(minHeight !== undefined ? { minHeight } : {}),
|
|
86
|
+
...(maxHeight !== undefined ? { maxHeight } : {}),
|
|
87
|
+
...(resolvedAspect ? { aspectRatio: resolvedAspect } : {}),
|
|
88
|
+
...(balance ? { flex: '1 1 0%', minWidth: 0, height: '100%' } : {}),
|
|
89
|
+
...(grow !== undefined ? { flexGrow: typeof grow === 'boolean' ? (grow ? 1 : 0) : grow } : {}),
|
|
90
|
+
...(shrink !== undefined ? { flexShrink: typeof shrink === 'boolean' ? (shrink ? 1 : 0) : shrink } : {}),
|
|
91
|
+
...(bg ? { background: bg } : {}),
|
|
92
|
+
...(color ? { color } : {}),
|
|
93
|
+
...(resolvedRadius ? { borderRadius: resolvedRadius } : {}),
|
|
94
|
+
...(resolvedShadow ? { boxShadow: resolvedShadow } : {}),
|
|
95
|
+
...(resolvedBorder ? { border: resolvedBorder } : {}),
|
|
96
|
+
...(resolvedPadding ? { padding: resolvedPadding } : {}),
|
|
97
|
+
...(resolvedMargin ? { margin: resolvedMargin } : {}),
|
|
98
|
+
...(display ? { display } : {}),
|
|
99
|
+
...(direction ? { flexDirection: direction } : {}),
|
|
100
|
+
...(resolvedWrap ? { flexWrap: resolvedWrap } : {}),
|
|
101
|
+
...(resolvedAlign ? { alignItems: resolvedAlign } : {}),
|
|
102
|
+
...(resolvedJustify ? { justifyContent: resolvedJustify } : {}),
|
|
103
|
+
...(resolvedGap ? { gap: resolvedGap } : {}),
|
|
104
|
+
...(overflow ? { overflow } : {}),
|
|
105
|
+
...style,
|
|
106
|
+
...(dynamicMarginTop ? { marginTop: dynamicMarginTop } : {}),
|
|
107
|
+
...(dynamicMarginBottom ? { marginBottom: dynamicMarginBottom } : {}),
|
|
108
|
+
...(dynamicMarginLeft ? { marginLeft: dynamicMarginLeft } : {}),
|
|
109
|
+
...(dynamicMarginRight ? { marginRight: dynamicMarginRight } : {}),
|
|
110
|
+
...(dynamicStyle?.color ? { color: String(dynamicStyle.color) } : {}),
|
|
111
|
+
};
|
|
112
|
+
return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-field-path": previewFieldPath || id, "data-preview-item-path": previewItemPath, "data-preview-static": previewStatic, className: `editable-box ${className}`.trim(), style: boxStyle, ...props, children: children }));
|
|
113
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BoxAspectRatio, BoxRadius, BoxShadow, BoxSpacing } from './EditableBox';
|
|
3
|
+
export interface CardItem {
|
|
4
|
+
id?: string | number;
|
|
5
|
+
title?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
body?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
imageUrl?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface EditableCardProps extends React.HTMLAttributes<HTMLElement> {
|
|
13
|
+
itemPath: string;
|
|
14
|
+
item: CardItem;
|
|
15
|
+
titleKey?: string;
|
|
16
|
+
bodyKey?: string;
|
|
17
|
+
imageKey?: string;
|
|
18
|
+
imageFallback?: string;
|
|
19
|
+
as?: React.ElementType;
|
|
20
|
+
/**
|
|
21
|
+
* Card sizing and dimension controls
|
|
22
|
+
*/
|
|
23
|
+
width?: string | number;
|
|
24
|
+
minWidth?: string | number;
|
|
25
|
+
maxWidth?: string | number;
|
|
26
|
+
height?: string | number;
|
|
27
|
+
minHeight?: string | number;
|
|
28
|
+
maxHeight?: string | number;
|
|
29
|
+
aspectRatio?: BoxAspectRatio;
|
|
30
|
+
/**
|
|
31
|
+
* Auto-balance: ensures card stretches evenly in flex/grid to match adjacent cards.
|
|
32
|
+
*/
|
|
33
|
+
balance?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Styling controls
|
|
36
|
+
*/
|
|
37
|
+
radius?: BoxRadius;
|
|
38
|
+
shadow?: BoxShadow;
|
|
39
|
+
bg?: string;
|
|
40
|
+
border?: string | boolean;
|
|
41
|
+
padding?: BoxSpacing;
|
|
42
|
+
align?: 'left' | 'center' | 'right';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Reusable card for services, features, or list items across pages with
|
|
46
|
+
* responsive width/height sizing and auto-balancing space support.
|
|
47
|
+
*/
|
|
48
|
+
export declare function EditableCard({ itemPath, item, titleKey, bodyKey, imageKey, imageFallback, as: Component, width, minWidth, maxWidth, height, minHeight, maxHeight, aspectRatio, balance, radius, shadow, bg, border, padding, align, className, style, children, ...props }: EditableCardProps): React.JSX.Element;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EditableCard = EditableCard;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const EditableText_1 = require("./EditableText");
|
|
6
|
+
const EditableImage_1 = require("./EditableImage");
|
|
7
|
+
const RADIUS_MAP = {
|
|
8
|
+
none: '0px',
|
|
9
|
+
sm: '4px',
|
|
10
|
+
md: '8px',
|
|
11
|
+
lg: '12px',
|
|
12
|
+
xl: '16px',
|
|
13
|
+
'2xl': '24px',
|
|
14
|
+
full: '9999px',
|
|
15
|
+
};
|
|
16
|
+
const SHADOW_MAP = {
|
|
17
|
+
none: 'none',
|
|
18
|
+
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
|
19
|
+
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
|
|
20
|
+
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)',
|
|
21
|
+
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
|
|
22
|
+
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
|
23
|
+
};
|
|
24
|
+
const SPACING_MAP = {
|
|
25
|
+
none: '0',
|
|
26
|
+
xs: '0.25rem',
|
|
27
|
+
sm: '0.5rem',
|
|
28
|
+
md: '1rem',
|
|
29
|
+
lg: '1.5rem',
|
|
30
|
+
xl: '2rem',
|
|
31
|
+
'2xl': '3rem',
|
|
32
|
+
};
|
|
33
|
+
const ASPECT_MAP = {
|
|
34
|
+
square: '1 / 1',
|
|
35
|
+
'1/1': '1 / 1',
|
|
36
|
+
video: '16 / 9',
|
|
37
|
+
'16/9': '16 / 9',
|
|
38
|
+
portrait: '3 / 4',
|
|
39
|
+
'3/4': '3 / 4',
|
|
40
|
+
'4/3': '4 / 3',
|
|
41
|
+
landscape: '4 / 3',
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Reusable card for services, features, or list items across pages with
|
|
45
|
+
* responsive width/height sizing and auto-balancing space support.
|
|
46
|
+
*/
|
|
47
|
+
function EditableCard({ itemPath, item, titleKey = 'title', bodyKey = 'body', imageKey = 'imageUrl', imageFallback = '/placeholder.svg', as: Component = 'article', width, minWidth, maxWidth, height, minHeight, maxHeight, aspectRatio, balance, radius, shadow, bg, border, padding, align, className = '', style, children, ...props }) {
|
|
48
|
+
const title = String(item?.[titleKey] ?? item?.name ?? '');
|
|
49
|
+
const body = String(item?.[bodyKey] ?? item?.description ?? '');
|
|
50
|
+
const imageUrl = item?.[imageKey] !== undefined ? String(item[imageKey]) : undefined;
|
|
51
|
+
const resolvedRadius = radius !== undefined ? (RADIUS_MAP[String(radius)] || String(radius)) : undefined;
|
|
52
|
+
const resolvedShadow = shadow ? (SHADOW_MAP[shadow] || shadow) : undefined;
|
|
53
|
+
const resolvedPadding = padding !== undefined ? (SPACING_MAP[String(padding)] || String(padding)) : undefined;
|
|
54
|
+
const resolvedAspect = aspectRatio ? (ASPECT_MAP[aspectRatio] || aspectRatio) : undefined;
|
|
55
|
+
const resolvedBorder = border === true
|
|
56
|
+
? '1px solid var(--border-color, rgba(226, 232, 240, 0.8))'
|
|
57
|
+
: typeof border === 'string'
|
|
58
|
+
? border
|
|
59
|
+
: undefined;
|
|
60
|
+
const cardStyle = {
|
|
61
|
+
...(width !== undefined ? { width } : {}),
|
|
62
|
+
...(minWidth !== undefined ? { minWidth } : {}),
|
|
63
|
+
...(maxWidth !== undefined ? { maxWidth } : {}),
|
|
64
|
+
...(height !== undefined ? { height } : {}),
|
|
65
|
+
...(minHeight !== undefined ? { minHeight } : {}),
|
|
66
|
+
...(maxHeight !== undefined ? { maxHeight } : {}),
|
|
67
|
+
...(resolvedAspect ? { aspectRatio: resolvedAspect } : {}),
|
|
68
|
+
...(balance
|
|
69
|
+
? {
|
|
70
|
+
display: 'flex',
|
|
71
|
+
flexDirection: 'column',
|
|
72
|
+
height: '100%',
|
|
73
|
+
flex: '1 1 0%',
|
|
74
|
+
}
|
|
75
|
+
: {}),
|
|
76
|
+
...(bg ? { background: bg } : {}),
|
|
77
|
+
...(resolvedRadius ? { borderRadius: resolvedRadius } : {}),
|
|
78
|
+
...(resolvedShadow ? { boxShadow: resolvedShadow } : {}),
|
|
79
|
+
...(resolvedBorder ? { border: resolvedBorder } : {}),
|
|
80
|
+
...(resolvedPadding ? { padding: resolvedPadding } : {}),
|
|
81
|
+
...(align ? { textAlign: align } : {}),
|
|
82
|
+
...style,
|
|
83
|
+
};
|
|
84
|
+
return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, className: `editable-card ${className}`.trim(), style: cardStyle, ...props, children: [imageUrl !== undefined && ((0, jsx_runtime_1.jsx)("div", { className: "editable-card-image-wrap", children: (0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.${imageKey}`, src: imageUrl, fallbackSrc: imageFallback, alt: title, className: "editable-card-image" }) })), (0, jsx_runtime_1.jsx)("div", { className: "editable-card-body", style: balance ? { display: 'flex', flexDirection: 'column', flex: '1 1 auto' } : undefined, children: children ? (children) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { variant: "h3", color: "heading", id: `${itemPath}.${titleKey}`, "data-preview-field-path": `${itemPath}.${titleKey}`, defaultValue: title, className: "editable-card-title" }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { variant: "p", color: "muted", id: `${itemPath}.${bodyKey}`, "data-preview-field-path": `${itemPath}.${bodyKey}`, defaultValue: body, className: "editable-card-body-text" })] })) })] }));
|
|
85
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface EditableContactFormProps extends React.FormHTMLAttributes<HTMLFormElement> {
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
formTitle?: string;
|
|
5
|
+
formTitlePath?: string;
|
|
6
|
+
submitButtonText?: string;
|
|
7
|
+
submitLabelPath?: string;
|
|
8
|
+
successMessage?: string;
|
|
9
|
+
showPhone?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function EditableContactForm({ endpoint, formTitle, formTitlePath, submitButtonText, submitLabelPath, successMessage, showPhone, className, style, ...props }: EditableContactFormProps): React.JSX.Element;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EditableContactForm = EditableContactForm;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
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 }) {
|
|
8
|
+
const siteData = (0, SiteDataProvider_1.useSiteData)();
|
|
9
|
+
const [status, setStatus] = (0, react_1.useState)('idle');
|
|
10
|
+
const [errorMessage, setErrorMessage] = (0, react_1.useState)('');
|
|
11
|
+
const contactContent = siteData?.content?.contact;
|
|
12
|
+
const resolvedSubmitText = String(contactContent?.submitLabel || submitButtonText);
|
|
13
|
+
const resolvedFormTitle = formTitle || contactContent?.formTitle;
|
|
14
|
+
const handleSubmit = async (e) => {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
setStatus('submitting');
|
|
17
|
+
setErrorMessage('');
|
|
18
|
+
const form = e.currentTarget;
|
|
19
|
+
const formData = new FormData(form);
|
|
20
|
+
const payload = {
|
|
21
|
+
projectId: siteData?.project?.id || 'demo-project',
|
|
22
|
+
name: formData.get('name'),
|
|
23
|
+
email: formData.get('email'),
|
|
24
|
+
phone: showPhone ? formData.get('phone') : undefined,
|
|
25
|
+
message: formData.get('message'),
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(endpoint, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'Content-Type': 'application/json' },
|
|
31
|
+
body: JSON.stringify(payload),
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(`Submission error: ${res.statusText || 'Unable to send message'}`);
|
|
35
|
+
}
|
|
36
|
+
setStatus('success');
|
|
37
|
+
form.reset();
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
setStatus('error');
|
|
41
|
+
setErrorMessage(err.message || 'Something went wrong. Please try again.');
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, "data-fivora-contact-disabled": true, style: {
|
|
45
|
+
display: 'flex',
|
|
46
|
+
flexDirection: 'column',
|
|
47
|
+
gap: '1.25rem',
|
|
48
|
+
...style,
|
|
49
|
+
}, className: `editable-contact-form ${className}`.trim(), ...props, children: [(resolvedFormTitle || formTitlePath) && ((0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": formTitlePath || 'contact.formTitle', style: {
|
|
50
|
+
fontSize: '1.5rem',
|
|
51
|
+
fontWeight: 700,
|
|
52
|
+
color: 'var(--heading-color, #0f172a)',
|
|
53
|
+
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: {
|
|
55
|
+
display: 'block',
|
|
56
|
+
fontSize: '0.875rem',
|
|
57
|
+
fontWeight: 600,
|
|
58
|
+
marginBottom: '0.375rem',
|
|
59
|
+
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: {
|
|
61
|
+
width: '100%',
|
|
62
|
+
padding: '0.75rem 1rem',
|
|
63
|
+
borderRadius: '10px',
|
|
64
|
+
border: '1px solid #cbd5e1',
|
|
65
|
+
fontSize: '0.95rem',
|
|
66
|
+
outline: 'none',
|
|
67
|
+
backgroundColor: '#ffffff',
|
|
68
|
+
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: {
|
|
70
|
+
display: 'block',
|
|
71
|
+
fontSize: '0.875rem',
|
|
72
|
+
fontWeight: 600,
|
|
73
|
+
marginBottom: '0.375rem',
|
|
74
|
+
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: {
|
|
76
|
+
width: '100%',
|
|
77
|
+
padding: '0.75rem 1rem',
|
|
78
|
+
borderRadius: '10px',
|
|
79
|
+
border: '1px solid #cbd5e1',
|
|
80
|
+
fontSize: '0.95rem',
|
|
81
|
+
outline: 'none',
|
|
82
|
+
backgroundColor: '#ffffff',
|
|
83
|
+
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: {
|
|
85
|
+
display: 'block',
|
|
86
|
+
fontSize: '0.875rem',
|
|
87
|
+
fontWeight: 600,
|
|
88
|
+
marginBottom: '0.375rem',
|
|
89
|
+
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: {
|
|
91
|
+
width: '100%',
|
|
92
|
+
padding: '0.75rem 1rem',
|
|
93
|
+
borderRadius: '10px',
|
|
94
|
+
border: '1px solid #cbd5e1',
|
|
95
|
+
fontSize: '0.95rem',
|
|
96
|
+
outline: 'none',
|
|
97
|
+
backgroundColor: '#ffffff',
|
|
98
|
+
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: {
|
|
100
|
+
display: 'block',
|
|
101
|
+
fontSize: '0.875rem',
|
|
102
|
+
fontWeight: 600,
|
|
103
|
+
marginBottom: '0.375rem',
|
|
104
|
+
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: {
|
|
106
|
+
width: '100%',
|
|
107
|
+
padding: '0.75rem 1rem',
|
|
108
|
+
borderRadius: '10px',
|
|
109
|
+
border: '1px solid #cbd5e1',
|
|
110
|
+
fontSize: '0.95rem',
|
|
111
|
+
outline: 'none',
|
|
112
|
+
backgroundColor: '#ffffff',
|
|
113
|
+
boxSizing: 'border-box',
|
|
114
|
+
fontFamily: 'inherit',
|
|
115
|
+
} })] }), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: status === 'submitting', style: {
|
|
116
|
+
padding: '0.875rem 1.5rem',
|
|
117
|
+
borderRadius: '10px',
|
|
118
|
+
border: 'none',
|
|
119
|
+
backgroundColor: 'var(--brand-color, #2563eb)',
|
|
120
|
+
color: '#ffffff',
|
|
121
|
+
fontSize: '1rem',
|
|
122
|
+
fontWeight: 600,
|
|
123
|
+
cursor: status === 'submitting' ? 'not-allowed' : 'pointer',
|
|
124
|
+
opacity: status === 'submitting' ? 0.7 : 1,
|
|
125
|
+
boxShadow: '0 4px 14px 0 rgba(37, 99, 235, 0.35)',
|
|
126
|
+
transition: 'all 0.2s ease',
|
|
127
|
+
}, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": submitLabelPath, children: status === 'submitting' ? 'Sending Message...' : resolvedSubmitText }) }), status === 'success' && ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
128
|
+
padding: '1rem',
|
|
129
|
+
borderRadius: '10px',
|
|
130
|
+
backgroundColor: 'rgba(34, 197, 94, 0.1)',
|
|
131
|
+
border: '1px solid rgba(34, 197, 94, 0.3)',
|
|
132
|
+
color: '#15803d',
|
|
133
|
+
fontSize: '0.925rem',
|
|
134
|
+
fontWeight: 500,
|
|
135
|
+
textAlign: 'center',
|
|
136
|
+
}, children: successMessage })), status === 'error' && ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
137
|
+
padding: '1rem',
|
|
138
|
+
borderRadius: '10px',
|
|
139
|
+
backgroundColor: 'rgba(239, 68, 68, 0.1)',
|
|
140
|
+
border: '1px solid rgba(239, 68, 68, 0.3)',
|
|
141
|
+
color: '#b91c1c',
|
|
142
|
+
fontSize: '0.925rem',
|
|
143
|
+
fontWeight: 500,
|
|
144
|
+
textAlign: 'center',
|
|
145
|
+
}, children: errorMessage }))] }));
|
|
146
|
+
}
|