@deneb-ui/ui 2.0.22 → 2.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +77 -155
  2. package/dist/DenebComponentStyles.d.ts +6 -0
  3. package/dist/DenebComponentStyles.js +84 -0
  4. package/dist/EditableCard.js +5 -1
  5. package/dist/EditableContactForm.js +1 -1
  6. package/dist/EditableFilterSidebar.js +12 -11
  7. package/dist/EditableFooter.js +1 -1
  8. package/dist/EditableGrid.js +15 -12
  9. package/dist/EditableNavbar.js +32 -19
  10. package/dist/EditablePricingCard.js +1 -1
  11. package/dist/EditableProductCard.js +4 -4
  12. package/dist/EditableProductDetail.js +2 -2
  13. package/dist/EditableProductGrid.js +1 -1
  14. package/dist/EditableSection.js +7 -10
  15. package/dist/EditableText.d.ts +1 -1
  16. package/dist/EditableText.js +8 -33
  17. package/dist/ResponsiveBaseStyles.d.ts +7 -0
  18. package/dist/ResponsiveBaseStyles.js +136 -0
  19. package/dist/SiteDataProvider.d.ts +2 -0
  20. package/dist/SiteDataProvider.js +22 -4
  21. package/dist/StickyMobileBar.js +1 -1
  22. package/dist/ThemeStyles.js +2 -1
  23. package/dist/TrustBadges.js +1 -1
  24. package/dist/contact/FloatingContactWidget.js +3 -2
  25. package/dist/fonts/FontLoader.d.ts +13 -0
  26. package/dist/fonts/FontLoader.js +43 -0
  27. package/dist/fonts/useDenebFonts.d.ts +6 -0
  28. package/dist/fonts/useDenebFonts.js +29 -0
  29. package/dist/hooks/useComponentStyle.d.ts +8 -0
  30. package/dist/hooks/useComponentStyle.js +46 -0
  31. package/dist/index.d.ts +8 -0
  32. package/dist/index.js +33 -1
  33. package/dist/utils/index.d.ts +1 -0
  34. package/dist/utils/index.js +1 -0
  35. package/dist/utils/responsive.d.ts +33 -0
  36. package/dist/utils/responsive.js +100 -0
  37. package/package.json +21 -8
  38. package/scripts/setup-fonts.cjs +26 -0
package/README.md CHANGED
@@ -1,182 +1,104 @@
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
- > Proudly presented by **DENEB-UI Collaborate with FIVORA**.
8
-
9
- [![Framework: DENEB UI](https://img.shields.io/badge/Framework-DENEB_UI_v2.0-blue.svg)](https://github.com/deneb-ui/ui)
10
- [![License: MIT](https://img.shields.io/badge/License-MIT-orange.svg)](https://opensource.org/licenses/MIT)
1
+ <p align="center">
2
+ <a href="https://deneb.fivora.site">
3
+ <img src="https://img.shields.io/badge/DENEB_UI-Visual--First_React_Components-6366F1?style=for-the-badge&labelColor=0f172a" alt="DENEB UI" />
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@deneb-ui/ui"><img src="https://img.shields.io/npm/v/@deneb-ui/ui.svg?style=flat-square&color=6366F1" alt="npm version" /></a>
9
+ <a href="https://www.npmjs.com/package/@deneb-ui/ui"><img src="https://img.shields.io/npm/dm/@deneb-ui/ui.svg?style=flat-square&color=6366F1" alt="npm downloads" /></a>
10
+ <img src="https://img.shields.io/badge/React-18%20%7C%2019-61DAFB?style=flat-square&logo=react&logoColor=white" alt="React" />
11
+ <img src="https://img.shields.io/badge/TypeScript-Ready-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" />
12
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-emerald?style=flat-square" alt="MIT License" /></a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <strong>Build beautiful, editable storefronts — on mobile, tablet, and desktop.</strong><br />
17
+ The visual-first React component library for Next.js commerce and Fivora live editing.
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://deneb.fivora.site/docs/introduction"><strong>Documentation</strong></a> ·
22
+ <a href="https://deneb.fivora.site/docs/components/button"><strong>Components</strong></a> ·
23
+ <a href="https://deneb.fivora.site/docs/responsive-design"><strong>Responsive Design</strong></a> ·
24
+ <a href="https://github.com/deneb-ui/core"><strong>GitHub</strong></a>
25
+ </p>
11
26
 
12
27
  ---
13
28
 
14
- ## Quick Installation
29
+ ## Getting Started
30
+
31
+ ### Install
15
32
 
16
33
  ```bash
17
34
  npm install @deneb-ui/ui
18
- # Or with yarn / pnpm
19
- pnpm add @deneb-ui/ui
35
+ # pnpm add @deneb-ui/ui
36
+ # yarn add @deneb-ui/ui
20
37
  ```
21
38
 
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
- ```
39
+ ### Minimal example
34
40
 
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.
41
+ ```tsx
42
+ import { SiteDataProvider, Navbar, Hero, Footer, Grid, ProductCard } from "@deneb-ui/ui";
43
+ import siteData from "@/data/site-data.json";
47
44
 
48
- ---
45
+ export default function Page() {
46
+ return (
47
+ <SiteDataProvider initialSiteData={siteData}>
48
+ <Navbar />
49
+ <Hero />
50
+ <Grid columns={{ mobile: 1, tablet: 2, desktop: 3 }} gap="lg">
51
+ {/* ProductCard items */}
52
+ </Grid>
53
+ <Footer />
54
+ </SiteDataProvider>
55
+ );
56
+ }
57
+ ```
49
58
 
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.
59
+ `SiteDataProvider` automatically injects **ResponsiveBaseStyles** — every component adapts across phone, tablet, and desktop without extra setup.
88
60
 
89
61
  ---
90
62
 
91
- ## URL Utility Layer
63
+ ## Features
92
64
 
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
- ```
65
+ | Capability | Description |
66
+ | :--- | :--- |
67
+ | **Visual editing native** | Built-in `data-preview-field-path` bindings for Fivora and DENEB preview protocol |
68
+ | **Responsive by default** | Mobile drawer nav, collapsible filters, fluid grids, `clamp()` section spacing |
69
+ | **Smart commerce actions** | WhatsApp, phone, email, maps — auto-hide when merchant data is missing |
70
+ | **Zero styling lock-in** | Inline CSS + optional Tailwind; works in any React 18/19 app |
71
+ | **40+ components** | Navbar, Hero, ProductGrid, CartDrawer, ContactForm, BusinessHours, and more |
116
72
 
117
73
  ---
118
74
 
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 />
75
+ ## Documentation
144
76
 
145
- <main data-preview-page-key="home">
146
- <Hero />
77
+ | Guide | Link |
78
+ | :--- | :--- |
79
+ | Introduction | [deneb.fivora.site/docs/introduction](https://deneb.fivora.site/docs/introduction) |
80
+ | Installation & CLI init | [deneb.fivora.site/docs/installation](https://deneb.fivora.site/docs/installation) |
81
+ | Responsive design | [deneb.fivora.site/docs/responsive-design](https://deneb.fivora.site/docs/responsive-design) |
82
+ | Theming & tokens | [deneb.fivora.site/docs/theming](https://deneb.fivora.site/docs/theming) |
83
+ | Component catalog | [deneb.fivora.site/docs/components/button](https://deneb.fivora.site/docs/components/button) |
147
84
 
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
- />
85
+ ---
155
86
 
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
- />
87
+ ## Related packages
163
88
 
164
- <BusinessHours hours={business.hours} />
165
- </div>
89
+ | Package | Purpose |
90
+ | :--- | :--- |
91
+ | [`@deneb-ui/cli`](https://www.npmjs.com/package/@deneb-ui/cli) | Convert, validate, and package storefront templates |
92
+ | [`@deneb-ui/create-template`](https://www.npmjs.com/package/@deneb-ui/create-template) | Scaffold a new DENEB storefront in one command |
166
93
 
167
- <SocialLinks social={business.social} />
168
- </section>
169
- </main>
94
+ ---
170
95
 
171
- <Footer />
172
- </SiteDataProvider>
173
- );
174
- }
175
- ```
96
+ ## Authors
176
97
 
177
- ---
98
+ Created and maintained by **[Chamika Gayashan](https://github.com/chamikathereal)** and **[Induranga Kawishwara](https://github.com/Induranga-kawishwara)**.
178
99
 
179
- ## Author & Credits
100
+ Part of the **DENEB UI** ecosystem · Collaborate with **[Fivora](https://fivora.site)**.
180
101
 
181
- Created and architected by **Chamika Gayashan & Induranga Kawishwara**.
182
- Built for the global React and storefront developer ecosystem.
102
+ <p align="center">
103
+ <sub>MIT © DENEB UI</sub>
104
+ </p>
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ /**
3
+ * Base CSS variable mappings for real-time visual style editing.
4
+ * Components apply `--deneb-*` vars via useComponentStyle; this sheet defines fallbacks.
5
+ */
6
+ export declare function DenebComponentStyles(): React.JSX.Element;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DenebComponentStyles = DenebComponentStyles;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /**
6
+ * Base CSS variable mappings for real-time visual style editing.
7
+ * Components apply `--deneb-*` vars via useComponentStyle; this sheet defines fallbacks.
8
+ */
9
+ function DenebComponentStyles() {
10
+ const css = `
11
+ .deneb-card {
12
+ width: var(--deneb-card-width, auto);
13
+ min-width: var(--deneb-card-min-width, unset);
14
+ max-width: var(--deneb-card-max-width, 100%);
15
+ height: var(--deneb-card-height, auto);
16
+ aspect-ratio: var(--deneb-card-aspect-ratio, auto);
17
+ padding-top: var(--deneb-card-pt, 1.25rem);
18
+ padding-bottom: var(--deneb-card-pb, 1.25rem);
19
+ padding-left: var(--deneb-card-pl, 1.25rem);
20
+ padding-right: var(--deneb-card-pr, 1.25rem);
21
+ border-radius: var(--deneb-card-radius, 0.75rem);
22
+ border-width: var(--deneb-card-border-w, 0);
23
+ border-style: var(--deneb-card-border-s, solid);
24
+ border-color: var(--deneb-card-border-c, rgba(0, 0, 0, 0.08));
25
+ background-color: var(--deneb-card-bg, transparent);
26
+ background-image: var(--deneb-card-bg-gradient, none);
27
+ box-shadow: var(--deneb-card-shadow, none);
28
+ backdrop-filter: blur(var(--deneb-card-blur, 0px));
29
+ gap: var(--deneb-card-gap, unset);
30
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
31
+ }
32
+ .deneb-card-balance {
33
+ display: flex;
34
+ flex-direction: column;
35
+ flex: 1 1 0%;
36
+ min-width: 0;
37
+ height: 100%;
38
+ }
39
+ .deneb-text {
40
+ font-family: var(--deneb-font-family, inherit);
41
+ font-size: var(--deneb-font-size, inherit);
42
+ font-weight: var(--deneb-font-weight, inherit);
43
+ line-height: var(--deneb-line-height, inherit);
44
+ letter-spacing: var(--deneb-letter-spacing, inherit);
45
+ color: var(--deneb-color, inherit);
46
+ text-align: var(--deneb-text-align, inherit);
47
+ text-transform: var(--deneb-text-transform, inherit);
48
+ margin-top: var(--deneb-margin-top, 0);
49
+ margin-bottom: var(--deneb-margin-bottom, 0);
50
+ margin-left: var(--deneb-margin-left, 0);
51
+ margin-right: var(--deneb-margin-right, 0);
52
+ }
53
+ .deneb-btn {
54
+ border-radius: var(--deneb-btn-radius, inherit);
55
+ padding-left: var(--deneb-btn-px, inherit);
56
+ padding-right: var(--deneb-btn-px, inherit);
57
+ padding-top: var(--deneb-btn-py, inherit);
58
+ padding-bottom: var(--deneb-btn-py, inherit);
59
+ background-color: var(--deneb-btn-bg, inherit);
60
+ color: var(--deneb-btn-color, inherit);
61
+ border-color: var(--deneb-btn-border-c, inherit);
62
+ }
63
+ .deneb-btn:hover {
64
+ background-color: var(--deneb-btn-hover-bg, inherit);
65
+ color: var(--deneb-btn-hover-color, inherit);
66
+ }
67
+ .deneb-grid {
68
+ grid-template-columns: var(--deneb-grid-cols, inherit);
69
+ column-gap: var(--deneb-grid-gap-x, inherit);
70
+ row-gap: var(--deneb-grid-gap-y, inherit);
71
+ align-items: var(--deneb-grid-equal-height, inherit);
72
+ }
73
+ .deneb-section {
74
+ padding-top: var(--deneb-section-pt, inherit);
75
+ padding-bottom: var(--deneb-section-pb, inherit);
76
+ padding-left: var(--deneb-section-px, inherit);
77
+ padding-right: var(--deneb-section-px, inherit);
78
+ max-width: var(--deneb-section-max-w, inherit);
79
+ background-color: var(--deneb-section-bg, inherit);
80
+ background-image: var(--deneb-section-bg-image, none);
81
+ }
82
+ `;
83
+ return (0, jsx_runtime_1.jsx)("style", { "data-deneb-component-styles": true, children: css });
84
+ }
@@ -4,6 +4,7 @@ exports.EditableCard = EditableCard;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const EditableText_1 = require("./EditableText");
6
6
  const EditableImage_1 = require("./EditableImage");
7
+ const useComponentStyle_1 = require("./hooks/useComponentStyle");
7
8
  const RADIUS_MAP = {
8
9
  none: '0px',
9
10
  sm: '4px',
@@ -57,6 +58,8 @@ function EditableCard({ itemPath, item, titleKey = 'title', bodyKey = 'body', im
57
58
  : typeof border === 'string'
58
59
  ? border
59
60
  : undefined;
61
+ const stylePath = `${itemPath}.card`;
62
+ const { cssVars: styleVars } = (0, useComponentStyle_1.useComponentStyle)(stylePath, 'card');
60
63
  const cardStyle = {
61
64
  ...(width !== undefined ? { width } : {}),
62
65
  ...(minWidth !== undefined ? { minWidth } : {}),
@@ -79,7 +82,8 @@ function EditableCard({ itemPath, item, titleKey = 'title', bodyKey = 'body', im
79
82
  ...(resolvedBorder ? { border: resolvedBorder } : {}),
80
83
  ...(resolvedPadding ? { padding: resolvedPadding } : {}),
81
84
  ...(align ? { textAlign: align } : {}),
85
+ ...styleVars,
82
86
  ...style,
83
87
  };
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" })] })) })] }));
88
+ return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, "data-preview-style-target": stylePath, "data-preview-style-type": "card", className: `deneb-card editable-card ${balance ? 'deneb-card-balance' : ''} ${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
89
  }
@@ -54,7 +54,7 @@ function EditableContactForm({ endpoint = 'https://api.fivora.com/site-contact',
54
54
  flexDirection: 'column',
55
55
  gap: '1.25rem',
56
56
  ...style,
57
- }, className: `editable-contact-form ${className}`.trim(), ...props, children: [(resolvedFormTitle || formTitlePath) && ((0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": formTitlePath || 'contact.formTitle', style: {
57
+ }, className: `editable-contact-form ${className}`.trim(), ...props, children: [(resolvedFormTitle || formTitlePath) && ((0, jsx_runtime_1.jsx)("h2", { className: "deneb-contact-form-title", "data-preview-field-path": formTitlePath || 'contact.formTitle', style: {
58
58
  fontSize: '1.5rem',
59
59
  fontWeight: 700,
60
60
  color: 'var(--heading-color, #0f172a)',
@@ -12,6 +12,7 @@ function EditableFilterSidebar({ basePath = 'filters', categories = ['All', 'Run
12
12
  const [currentPrice, setCurrentPrice] = (0, react_1.useState)(initialFilters?.priceRange ? initialFilters.priceRange[1] : maxPrice);
13
13
  const [selectedSizes, setSelectedSizes] = (0, react_1.useState)(initialFilters?.selectedSizes || []);
14
14
  const [inStockOnly, setInStockOnly] = (0, react_1.useState)(initialFilters?.inStockOnly || false);
15
+ const [mobileOpen, setMobileOpen] = (0, react_1.useState)(false);
15
16
  const getContent = (key, fallback) => {
16
17
  const section = siteData?.content?.[basePath];
17
18
  return section?.[key] || fallback;
@@ -69,16 +70,16 @@ function EditableFilterSidebar({ basePath = 'filters', categories = ['All', 'Run
69
70
  const availabilityTitle = getContent('availabilityTitle', 'Availability');
70
71
  const inStockLabel = getContent('inStockLabel', 'In Stock Only');
71
72
  const clearAllText = getContent('clearAllText', 'Clear All');
72
- return ((0, jsx_runtime_1.jsxs)("aside", { className: `deneb-filter-sidebar w-full rounded-2xl border border-neutral-800 bg-neutral-900/80 backdrop-blur-md p-6 text-white shadow-xl ${className}`, "aria-label": "Product Filters", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between border-b border-neutral-800 pb-4 mb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold tracking-tight text-white", "data-preview-field-path": fieldPath('title'), children: title }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", "data-preview-static": "filter-active-count", children: activeFiltersCount }))] }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClearAll, className: "text-xs font-medium text-neutral-400 hover:text-white transition-colors", "data-preview-static": "filter-clear-all", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": fieldPath('clearAllText'), children: clearAllText }) }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath('categoryTitle'), children: categoryTitle }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap gap-2", children: categories.map((cat) => {
73
- const isSelected = selectedCategories.includes(cat);
74
- return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => toggleCategory(cat), "data-preview-static": "filter-cat-btn", className: `rounded-lg px-3 py-1.5 text-xs font-medium transition-all ${isSelected
75
- ? 'bg-white text-black shadow-md'
76
- : 'bg-neutral-800 text-neutral-300 hover:bg-neutral-700 hover:text-white'}`, children: cat }, cat));
77
- }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400", "data-preview-field-path": fieldPath('priceTitle'), children: priceTitle }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-semibold text-emerald-400", "data-preview-static": "filter-price-display", children: ["Up to ", currency, currentPrice] })] }), (0, jsx_runtime_1.jsx)("input", { type: "range", min: minPrice, max: maxPrice, step: 5, value: currentPrice, onChange: handlePriceChange, "data-preview-static": "filter-price-slider", className: "w-full accent-emerald-500 bg-neutral-800 h-1.5 rounded-lg cursor-pointer" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-xs text-neutral-500 mt-1", children: [(0, jsx_runtime_1.jsxs)("span", { children: [currency, minPrice] }), (0, jsx_runtime_1.jsxs)("span", { children: [currency, maxPrice] })] })] }), sizes.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath('sizeTitle'), children: sizeTitle }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-3 gap-2", children: sizes.map((size) => {
78
- const isSelected = selectedSizes.includes(size);
79
- return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => toggleSize(size), "data-preview-static": "filter-size-btn", className: `rounded-lg py-2 text-xs font-semibold transition-all border ${isSelected
80
- ? 'border-white bg-white text-black'
81
- : 'border-neutral-800 bg-neutral-800/50 text-neutral-300 hover:border-neutral-700'}`, children: size }, size));
82
- }) })] })), (0, jsx_runtime_1.jsx)("div", { className: "border-t border-neutral-800/80 pt-6", children: (0, jsx_runtime_1.jsxs)("label", { className: "flex items-center justify-between cursor-pointer group", "data-preview-static": "filter-instock-toggle", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-neutral-300 group-hover:text-white transition-colors", "data-preview-field-path": fieldPath('inStockLabel'), children: inStockLabel }), (0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: inStockOnly, onChange: toggleInStock, className: "h-4 w-4 rounded border-neutral-700 bg-neutral-800 text-emerald-500 accent-emerald-500 cursor-pointer" })] }) })] })] }));
73
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-filter-sidebar-wrap w-full ${className}`, children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "deneb-filter-mobile-toggle mb-3 rounded-xl border border-neutral-800 bg-neutral-900/90 px-4 py-3 text-sm font-semibold text-white", onClick: () => setMobileOpen((open) => !open), "aria-expanded": mobileOpen, "aria-controls": "deneb-filter-panel", "data-preview-static": "filter-mobile-toggle", children: [(0, jsx_runtime_1.jsx)("span", { children: title }), (0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2 text-neutral-400", children: [activeFiltersCount > 0 ? ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", children: activeFiltersCount })) : null, mobileOpen ? '−' : '+'] })] }), (0, jsx_runtime_1.jsxs)("aside", { id: "deneb-filter-panel", className: `deneb-filter-sidebar deneb-filter-sidebar-panel w-full rounded-2xl border border-neutral-800 bg-neutral-900/80 backdrop-blur-md p-6 text-white shadow-xl ${mobileOpen ? 'is-open' : ''}`, "aria-label": "Product Filters", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between border-b border-neutral-800 pb-4 mb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold tracking-tight text-white", "data-preview-field-path": fieldPath('title'), children: title }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", "data-preview-static": "filter-active-count", children: activeFiltersCount }))] }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClearAll, className: "text-xs font-medium text-neutral-400 hover:text-white transition-colors", "data-preview-static": "filter-clear-all", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": fieldPath('clearAllText'), children: clearAllText }) }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath('categoryTitle'), children: categoryTitle }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap gap-2", children: categories.map((cat) => {
74
+ const isSelected = selectedCategories.includes(cat);
75
+ return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => toggleCategory(cat), "data-preview-static": "filter-cat-btn", className: `rounded-lg px-3 py-1.5 text-xs font-medium transition-all ${isSelected
76
+ ? 'bg-white text-black shadow-md'
77
+ : 'bg-neutral-800 text-neutral-300 hover:bg-neutral-700 hover:text-white'}`, children: cat }, cat));
78
+ }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400", "data-preview-field-path": fieldPath('priceTitle'), children: priceTitle }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-semibold text-emerald-400", "data-preview-static": "filter-price-display", children: ["Up to ", currency, currentPrice] })] }), (0, jsx_runtime_1.jsx)("input", { type: "range", min: minPrice, max: maxPrice, step: 5, value: currentPrice, onChange: handlePriceChange, "data-preview-static": "filter-price-slider", className: "w-full accent-emerald-500 bg-neutral-800 h-1.5 rounded-lg cursor-pointer" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-xs text-neutral-500 mt-1", children: [(0, jsx_runtime_1.jsxs)("span", { children: [currency, minPrice] }), (0, jsx_runtime_1.jsxs)("span", { children: [currency, maxPrice] })] })] }), sizes.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath('sizeTitle'), children: sizeTitle }), (0, jsx_runtime_1.jsx)("div", { className: "deneb-filter-size-grid grid grid-cols-3 gap-2", children: sizes.map((size) => {
79
+ const isSelected = selectedSizes.includes(size);
80
+ return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => toggleSize(size), "data-preview-static": "filter-size-btn", className: `rounded-lg py-2 text-xs font-semibold transition-all border ${isSelected
81
+ ? 'border-white bg-white text-black'
82
+ : 'border-neutral-800 bg-neutral-800/50 text-neutral-300 hover:border-neutral-700'}`, children: size }, size));
83
+ }) })] })), (0, jsx_runtime_1.jsx)("div", { className: "border-t border-neutral-800/80 pt-6", children: (0, jsx_runtime_1.jsxs)("label", { className: "flex items-center justify-between cursor-pointer group", "data-preview-static": "filter-instock-toggle", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-neutral-300 group-hover:text-white transition-colors", "data-preview-field-path": fieldPath('inStockLabel'), children: inStockLabel }), (0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: inStockOnly, onChange: toggleInStock, className: "h-4 w-4 rounded border-neutral-700 bg-neutral-800 text-emerald-500 accent-emerald-500 cursor-pointer" })] }) })] })] })] }));
83
84
  }
84
85
  exports.FilterSidebar = EditableFilterSidebar;
@@ -159,7 +159,7 @@ function EditableFooter({ defaultLinks = DEFAULT_FOOTER_PAGES, links, basePath =
159
159
  gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))',
160
160
  gap: '3rem',
161
161
  marginBottom: '4rem',
162
- }, className: "grid grid-cols-1 gap-10 md:grid-cols-2 lg:grid-cols-4 lg:gap-8 mb-16", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", "data-preview-static": "footer-brand-link", onClick: () => navigate('/'), style: {
162
+ }, className: "deneb-footer-grid grid grid-cols-1 gap-10 md:grid-cols-2 lg:grid-cols-4 lg:gap-8 mb-16", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", "data-preview-static": "footer-brand-link", onClick: () => navigate('/'), style: {
163
163
  display: 'inline-flex',
164
164
  alignItems: 'center',
165
165
  gap: '0.75rem',
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EditableGrid = EditableGrid;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const useComponentStyle_1 = require("./hooks/useComponentStyle");
6
+ const responsive_1 = require("./utils/responsive");
5
7
  const SPACING_MAP = {
6
8
  none: '0',
7
9
  xs: '0.5rem',
@@ -17,23 +19,24 @@ const SPACING_MAP = {
17
19
  */
18
20
  function EditableGrid({ as: Component = 'div', id, 'data-preview-list-path': previewListPath, 'data-preview-static': previewStatic, minCardWidth = '280px', columns, gap = 'md', equalHeight = true, align = 'stretch', style, className = '', children, ...props }) {
19
21
  const resolvedGap = gap !== undefined ? (SPACING_MAP[String(gap)] || String(gap)) : '1.25rem';
20
- let templateCols;
21
- if (typeof columns === 'number') {
22
- templateCols = `repeat(${columns}, minmax(0, 1fr))`;
23
- }
24
- else if (columns && typeof columns === 'object') {
25
- templateCols = `repeat(auto-fit, minmax(${minCardWidth}, 1fr))`;
26
- }
27
- else {
28
- // Default auto-balancing formula
29
- templateCols = `repeat(auto-fit, minmax(${minCardWidth}, 1fr))`;
30
- }
22
+ const { template: templateCols, dataAttrs } = (0, responsive_1.resolveResponsiveColumns)(columns, minCardWidth);
23
+ const listPath = previewListPath || id;
24
+ const stylePath = listPath ? `${listPath}.grid` : undefined;
25
+ const { cssVars: styleVars } = (0, useComponentStyle_1.useComponentStyle)(stylePath, 'grid');
31
26
  const gridStyle = {
32
27
  display: 'grid',
33
28
  gridTemplateColumns: templateCols,
34
29
  gap: resolvedGap,
35
30
  alignItems: equalHeight ? 'stretch' : align,
31
+ ...(dataAttrs
32
+ ? {
33
+ '--deneb-cols': dataAttrs['data-cols-mobile'],
34
+ '--deneb-cols-tablet': dataAttrs['data-cols-tablet'],
35
+ '--deneb-cols-desktop': dataAttrs['data-cols-desktop'],
36
+ }
37
+ : {}),
38
+ ...styleVars,
36
39
  ...style,
37
40
  };
38
- return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-list-path": previewListPath || id, className: `editable-grid ${className}`.trim(), style: gridStyle, ...props, children: children }));
41
+ return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-list-path": listPath, "data-preview-style-target": stylePath, "data-preview-style-type": "grid", className: `deneb-grid editable-grid ${className}`.trim(), style: gridStyle, ...(dataAttrs || {}), ...props, children: children }));
39
42
  }
@@ -98,7 +98,6 @@ function EditableNavbar({ defaultLinks = DEFAULT_PAGES, sticky = true, activeRou
98
98
  letterSpacing: '-0.025em',
99
99
  color: 'var(--color-text, #0f172a)',
100
100
  }, className: "deneb-site-title text-xl font-bold tracking-tight text-slate-900 dark:text-white", children: siteName })] }), (0, jsx_runtime_1.jsx)("nav", { style: {
101
- display: 'flex',
102
101
  alignItems: 'center',
103
102
  gap: '0.375rem',
104
103
  }, className: "deneb-desktop-nav flex items-center gap-1.5", children: activeLinks.map((link) => {
@@ -133,8 +132,7 @@ function EditableNavbar({ defaultLinks = DEFAULT_PAGES, sticky = true, activeRou
133
132
  cursor: 'pointer',
134
133
  boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
135
134
  transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
136
- }, className: "deneb-header-cta inline-flex items-center justify-center px-4 py-2 rounded-full text-sm font-semibold bg-slate-900 text-white shadow-sm hover:bg-slate-800 hover:shadow-md transition-all border-0 cursor-pointer dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel }) }) })) : ((0, jsx_runtime_1.jsx)("span", { "data-target-page": "contact", className: "deneb-header-cta unavailable", "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel })), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "mobile-menu-toggle", onClick: () => setMobileMenuOpen(!mobileMenuOpen), "aria-label": "Toggle Navigation Menu", style: {
137
- display: 'flex',
135
+ }, className: "deneb-header-cta inline-flex items-center justify-center px-4 py-2 rounded-full text-sm font-semibold bg-slate-900 text-white shadow-sm hover:bg-slate-800 hover:shadow-md transition-all border-0 cursor-pointer dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel }) }) })) : ((0, jsx_runtime_1.jsx)("span", { "data-target-page": "contact", className: "deneb-header-cta unavailable", "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel })), (0, jsx_runtime_1.jsx)("button", { type: "button", "data-preview-static": "mobile-menu-toggle", onClick: () => setMobileMenuOpen(!mobileMenuOpen), "aria-label": "Toggle Navigation Menu", "aria-expanded": mobileMenuOpen, style: {
138
136
  alignItems: 'center',
139
137
  justifyContent: 'center',
140
138
  width: '40px',
@@ -144,35 +142,50 @@ function EditableNavbar({ defaultLinks = DEFAULT_PAGES, sticky = true, activeRou
144
142
  backgroundColor: 'transparent',
145
143
  color: 'var(--color-text, #0f172a)',
146
144
  cursor: 'pointer',
147
- }, className: "deneb-mobile-toggle md:hidden flex items-center justify-center w-10 h-10 rounded-lg border border-slate-200 text-slate-700 hover:bg-slate-100 dark:border-slate-800 dark:text-slate-300 dark:hover:bg-slate-800 transition-colors", children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: mobileMenuOpen ? ((0, jsx_runtime_1.jsx)("path", { d: "M18 6L6 18M6 6l12 12" })) : ((0, jsx_runtime_1.jsx)("path", { d: "M4 6h16M4 12h16M4 18h16" })) }) })] })] }), mobileMenuOpen && ((0, jsx_runtime_1.jsx)("div", { style: {
145
+ }, className: "deneb-mobile-toggle md:hidden flex items-center justify-center w-10 h-10 rounded-lg border border-slate-200 text-slate-700 hover:bg-slate-100 dark:border-slate-800 dark:text-slate-300 dark:hover:bg-slate-800 transition-colors", children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: mobileMenuOpen ? ((0, jsx_runtime_1.jsx)("path", { d: "M18 6L6 18M6 6l12 12" })) : ((0, jsx_runtime_1.jsx)("path", { d: "M4 6h16M4 12h16M4 18h16" })) }) })] })] }), mobileMenuOpen && ((0, jsx_runtime_1.jsxs)("div", { style: {
148
146
  borderTop: '1px solid var(--color-border, #e2e8f0)',
149
147
  backgroundColor: 'rgba(255, 255, 255, 0.98)',
150
148
  padding: '1.25rem 1.5rem',
151
149
  display: 'flex',
152
150
  flexDirection: 'column',
153
151
  gap: '0.625rem',
154
- }, className: "deneb-mobile-drawer md:hidden border-t border-slate-200 bg-white/95 backdrop-blur-lg px-4 py-5 flex flex-col gap-2.5 dark:border-slate-800 dark:bg-slate-950/95", children: activeLinks.map((link) => {
155
- const label = navLabels[link.id] || link.label;
156
- const isActive = activeRoute === link.route;
157
- return ((0, jsx_runtime_1.jsx)("span", { "data-target-page": link.id, children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
152
+ }, className: "deneb-mobile-drawer md:hidden border-t border-slate-200 bg-white/95 backdrop-blur-lg px-4 py-5 flex flex-col gap-2.5 dark:border-slate-800 dark:bg-slate-950/95", children: [activeLinks.map((link) => {
153
+ const label = navLabels[link.id] || link.label;
154
+ const isActive = activeRoute === link.route;
155
+ return ((0, jsx_runtime_1.jsx)("span", { "data-target-page": link.id, children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
156
+ setMobileMenuOpen(false);
157
+ navigate(link.route);
158
+ }, style: {
159
+ display: 'block',
160
+ width: '100%',
161
+ textAlign: 'left',
162
+ padding: '0.625rem 0.875rem',
163
+ borderRadius: '8px',
164
+ fontSize: '0.95rem',
165
+ fontWeight: isActive ? 600 : 500,
166
+ color: isActive ? 'var(--color-primary, #0f172a)' : 'var(--color-text, #0f172a)',
167
+ backgroundColor: isActive ? 'var(--color-secondary, #f1f5f9)' : 'transparent',
168
+ border: 0,
169
+ cursor: 'pointer',
170
+ }, 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
171
+ ? 'bg-slate-100 text-slate-900 font-semibold dark:bg-slate-800 dark:text-white'
172
+ : '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 }) }) }, `mobile-${link.id}`));
173
+ }), hasContact ? ((0, jsx_runtime_1.jsx)("span", { "data-target-page": "contact", style: { marginTop: '0.5rem', paddingTop: '0.75rem', borderTop: '1px solid rgba(226,232,240,0.8)' }, children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
158
174
  setMobileMenuOpen(false);
159
- navigate(link.route);
175
+ navigate('/contact');
160
176
  }, style: {
161
177
  display: 'block',
162
178
  width: '100%',
163
- textAlign: 'left',
164
- padding: '0.625rem 0.875rem',
165
- borderRadius: '8px',
179
+ textAlign: 'center',
180
+ backgroundColor: 'var(--color-primary, #0f172a)',
181
+ color: '#ffffff',
182
+ padding: '0.75rem 1rem',
183
+ borderRadius: '9999px',
166
184
  fontSize: '0.95rem',
167
- fontWeight: isActive ? 600 : 500,
168
- color: isActive ? 'var(--color-primary, #0f172a)' : 'var(--color-text, #0f172a)',
169
- backgroundColor: isActive ? 'var(--color-secondary, #f1f5f9)' : 'transparent',
185
+ fontWeight: 600,
170
186
  border: 0,
171
187
  cursor: 'pointer',
172
- }, className: `block w-full text-left px-3.5 py-2.5 rounded-lg text-base font-medium transition-colors border-0 cursor-pointer ${isActive
173
- ? 'bg-slate-100 text-slate-900 font-semibold dark:bg-slate-800 dark:text-white'
174
- : 'bg-transparent text-slate-700 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800'}`, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `common.navLabels.${link.id}`, children: label }) }) }, link.id));
175
- }) }))] }));
188
+ }, className: "deneb-mobile-drawer-cta w-full text-center px-4 py-3 rounded-full text-base font-semibold bg-slate-900 text-white border-0 cursor-pointer", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": "common.headerCtaLabel", children: headerCtaLabel }) }) })) : null] }))] }));
176
189
  }
177
190
  exports.Navbar = EditableNavbar;
178
191
  exports.Header = EditableNavbar;
@@ -43,7 +43,7 @@ function EditablePricingCard({ itemPath, item, as: Component = 'div', isPopular
43
43
  color: 'var(--muted-text, #64748b)',
44
44
  marginBottom: '1.5rem',
45
45
  lineHeight: 1.5,
46
- } }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.25rem', marginBottom: '1.5rem' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, defaultValue: price, style: {
46
+ } }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.25rem', marginBottom: '1.5rem' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, defaultValue: price, className: "deneb-pricing-amount", style: {
47
47
  fontSize: '2.75rem',
48
48
  fontWeight: 800,
49
49
  letterSpacing: '-0.03em',