@damarkuncoro/landing-page 0.1.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/dist/index.js ADDED
@@ -0,0 +1,2282 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ createCtaSection: () => createCtaSection,
34
+ createFaqSection: () => createFaqSection,
35
+ createFeaturesSection: () => createFeaturesSection,
36
+ createFooterSection: () => createFooterSection,
37
+ createHeaderSection: () => createHeaderSection,
38
+ createHeroSection: () => createHeroSection,
39
+ createPricingSection: () => createPricingSection,
40
+ createReactRenderer: () => createReactRenderer,
41
+ createStatsSection: () => createStatsSection,
42
+ createTestimonialsSection: () => createTestimonialsSection,
43
+ defaultTheme: () => defaultTheme,
44
+ defineLandingPage: () => defineLandingPage,
45
+ landingPageSchema: () => landingPageSchema,
46
+ sectionConfigSchemas: () => sectionConfigSchemas,
47
+ validateConfig: () => validateConfig,
48
+ validateSection: () => validateSection2
49
+ });
50
+ module.exports = __toCommonJS(src_exports);
51
+
52
+ // src/core/theme.ts
53
+ var defaultTheme = {
54
+ colors: {
55
+ primary: "#3b82f6",
56
+ secondary: "#8b5cf6",
57
+ accent: "#10b981",
58
+ background: "#ffffff",
59
+ text: "#1f2937",
60
+ muted: "#6b7280"
61
+ },
62
+ spacing: {
63
+ xs: "0.25rem",
64
+ sm: "0.5rem",
65
+ md: "1rem",
66
+ lg: "1.5rem",
67
+ xl: "2rem"
68
+ },
69
+ fonts: {
70
+ heading: "system-ui, -apple-system, sans-serif",
71
+ body: "system-ui, -apple-system, sans-serif",
72
+ mono: "monospace"
73
+ },
74
+ breakpoints: {
75
+ sm: "640px",
76
+ md: "768px",
77
+ lg: "1024px",
78
+ xl: "1280px"
79
+ }
80
+ };
81
+ function createTheme(config) {
82
+ return {
83
+ ...defaultTheme,
84
+ ...config,
85
+ colors: {
86
+ ...defaultTheme.colors,
87
+ ...config?.colors
88
+ },
89
+ spacing: {
90
+ ...defaultTheme.spacing,
91
+ ...config?.spacing
92
+ },
93
+ fonts: {
94
+ ...defaultTheme.fonts,
95
+ ...config?.fonts
96
+ },
97
+ breakpoints: {
98
+ ...defaultTheme.breakpoints,
99
+ ...config?.breakpoints
100
+ }
101
+ };
102
+ }
103
+
104
+ // src/schema/validate.ts
105
+ var import_ajv = __toESM(require("ajv"));
106
+ var import_ajv_formats = __toESM(require("ajv-formats"));
107
+
108
+ // src/schema/landingPageSchema.ts
109
+ var landingPageSchema = {
110
+ $id: "urn:landing-page:schema",
111
+ title: "Landing Page",
112
+ description: "Configuration for a config-driven landing page",
113
+ type: "object",
114
+ properties: {
115
+ id: {
116
+ type: "string",
117
+ description: "Unique identifier for the landing page"
118
+ },
119
+ className: {
120
+ type: "string",
121
+ description: "CSS class name for the landing page container"
122
+ },
123
+ title: {
124
+ type: "string",
125
+ description: "Page title for SEO and accessibility",
126
+ minLength: 1
127
+ },
128
+ description: {
129
+ type: "string",
130
+ description: "Page description for SEO",
131
+ minLength: 1
132
+ },
133
+ sections: {
134
+ type: "array",
135
+ description: "Sections that make up the landing page",
136
+ minItems: 1,
137
+ items: {
138
+ $ref: "#/definitions/Section"
139
+ }
140
+ },
141
+ theme: {
142
+ $ref: "#/definitions/Theme"
143
+ }
144
+ },
145
+ required: ["title", "description", "sections"],
146
+ definitions: {
147
+ Section: {
148
+ type: "object",
149
+ properties: {
150
+ id: {
151
+ type: "string",
152
+ description: "Unique identifier for the section"
153
+ },
154
+ className: {
155
+ type: "string",
156
+ description: "CSS class name for the section"
157
+ },
158
+ type: {
159
+ type: "string",
160
+ description: "Section type",
161
+ enum: ["hero", "features", "testimonials", "pricing", "cta", "footer", "stats", "faq", "header"]
162
+ },
163
+ config: {
164
+ type: "object",
165
+ description: "Section configuration"
166
+ }
167
+ },
168
+ required: ["type", "config"]
169
+ },
170
+ Theme: {
171
+ type: "object",
172
+ properties: {
173
+ colors: {
174
+ $ref: "#/definitions/Colors"
175
+ },
176
+ spacing: {
177
+ $ref: "#/definitions/Spacing"
178
+ },
179
+ fonts: {
180
+ $ref: "#/definitions/Fonts"
181
+ },
182
+ breakpoints: {
183
+ $ref: "#/definitions/Breakpoints"
184
+ }
185
+ }
186
+ },
187
+ Colors: {
188
+ type: "object",
189
+ properties: {
190
+ primary: {
191
+ type: "string",
192
+ description: "Primary brand color",
193
+ pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
194
+ },
195
+ secondary: {
196
+ type: "string",
197
+ description: "Secondary brand color",
198
+ pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
199
+ },
200
+ accent: {
201
+ type: "string",
202
+ description: "Accent color",
203
+ pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
204
+ },
205
+ background: {
206
+ type: "string",
207
+ description: "Background color",
208
+ pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
209
+ },
210
+ text: {
211
+ type: "string",
212
+ description: "Text color",
213
+ pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
214
+ },
215
+ muted: {
216
+ type: "string",
217
+ description: "Muted text color",
218
+ pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
219
+ }
220
+ },
221
+ required: ["primary", "secondary", "accent", "background", "text", "muted"]
222
+ },
223
+ Spacing: {
224
+ type: "object",
225
+ properties: {
226
+ xs: {
227
+ type: "string",
228
+ description: 'Extra small spacing unit (e.g., "4px")'
229
+ },
230
+ sm: {
231
+ type: "string",
232
+ description: 'Small spacing unit (e.g., "8px")'
233
+ },
234
+ md: {
235
+ type: "string",
236
+ description: 'Medium spacing unit (e.g., "16px")'
237
+ },
238
+ lg: {
239
+ type: "string",
240
+ description: 'Large spacing unit (e.g., "24px")'
241
+ },
242
+ xl: {
243
+ type: "string",
244
+ description: 'Extra large spacing unit (e.g., "32px")'
245
+ }
246
+ },
247
+ required: ["xs", "sm", "md", "lg", "xl"]
248
+ },
249
+ Fonts: {
250
+ type: "object",
251
+ properties: {
252
+ heading: {
253
+ type: "string",
254
+ description: 'Font family for headings (e.g., "Roboto, sans-serif")'
255
+ },
256
+ body: {
257
+ type: "string",
258
+ description: 'Font family for body text (e.g., "Open Sans, sans-serif")'
259
+ },
260
+ mono: {
261
+ type: "string",
262
+ description: 'Font family for monospace text (e.g., "Fira Code, monospace")'
263
+ }
264
+ },
265
+ required: ["heading", "body", "mono"]
266
+ },
267
+ Breakpoints: {
268
+ type: "object",
269
+ properties: {
270
+ sm: {
271
+ type: "string",
272
+ description: 'Small breakpoint (e.g., "640px")'
273
+ },
274
+ md: {
275
+ type: "string",
276
+ description: 'Medium breakpoint (e.g., "768px")'
277
+ },
278
+ lg: {
279
+ type: "string",
280
+ description: 'Large breakpoint (e.g., "1024px")'
281
+ },
282
+ xl: {
283
+ type: "string",
284
+ description: 'Extra large breakpoint (e.g., "1280px")'
285
+ }
286
+ },
287
+ required: ["sm", "md", "lg", "xl"]
288
+ },
289
+ ButtonConfig: {
290
+ type: "object",
291
+ properties: {
292
+ text: { type: "string" },
293
+ url: { type: "string", format: "uri" },
294
+ variant: { type: "string", enum: ["primary", "secondary", "outline", "ghost"] },
295
+ size: { type: "string", enum: ["sm", "md", "lg"] },
296
+ target: { type: "string", enum: ["_blank", "_self"] }
297
+ },
298
+ required: ["text", "url", "variant", "size"]
299
+ }
300
+ }
301
+ };
302
+
303
+ // src/schema/sectionConfigSchemas.ts
304
+ var sectionConfigSchemas = {
305
+ // Placeholder for individual section schemas
306
+ // These will be populated with actual JSON schemas for each section type (HeroConfig, FeatureConfig, etc.)
307
+ hero: {
308
+ type: "object",
309
+ properties: {
310
+ title: { type: "string" },
311
+ subtitle: { type: "string" },
312
+ image: { type: "string", format: "uri" },
313
+ video: { type: "string", format: "uri" },
314
+ buttons: {
315
+ type: "array",
316
+ items: { $ref: "urn:landing-page:schema#/definitions/ButtonConfig" }
317
+ },
318
+ alignment: { type: "string", enum: ["left", "center", "right"] }
319
+ },
320
+ required: ["title", "subtitle", "buttons"]
321
+ },
322
+ features: {
323
+ type: "object",
324
+ properties: {
325
+ title: { type: "string" },
326
+ description: { type: "string" },
327
+ icon: { type: "string" },
328
+ image: { type: "string", format: "uri" }
329
+ },
330
+ required: ["title", "description"]
331
+ },
332
+ testimonials: {
333
+ type: "object",
334
+ properties: {
335
+ quote: { type: "string" },
336
+ author: { type: "string" },
337
+ role: { type: "string" },
338
+ avatar: { type: "string", format: "uri" }
339
+ },
340
+ required: ["quote", "author"]
341
+ },
342
+ pricing: {
343
+ type: "object",
344
+ properties: {
345
+ plans: {
346
+ type: "array",
347
+ items: {
348
+ type: "object",
349
+ properties: {
350
+ id: { type: "string" },
351
+ title: { type: "string" },
352
+ description: { type: "string" },
353
+ price: { type: "number" },
354
+ period: { type: "string" },
355
+ features: {
356
+ type: "array",
357
+ items: { type: "string" }
358
+ },
359
+ button: { $ref: "urn:landing-page:schema#/definitions/ButtonConfig" },
360
+ featured: { type: "boolean" }
361
+ },
362
+ required: ["title", "description", "price", "features", "button"]
363
+ }
364
+ }
365
+ },
366
+ required: ["plans"]
367
+ },
368
+ cta: {
369
+ type: "object",
370
+ properties: {
371
+ title: { type: "string" },
372
+ description: { type: "string" },
373
+ button: { $ref: "urn:landing-page:schema#/definitions/ButtonConfig" },
374
+ image: { type: "string", format: "uri" }
375
+ },
376
+ required: ["title", "description", "button"]
377
+ },
378
+ footer: {
379
+ type: "object",
380
+ properties: {
381
+ logo: { type: "string", format: "uri" },
382
+ title: { type: "string" },
383
+ description: { type: "string" },
384
+ links: {
385
+ type: "array",
386
+ items: {
387
+ type: "object",
388
+ properties: {
389
+ title: { type: "string" },
390
+ items: {
391
+ type: "array",
392
+ items: {
393
+ type: "object",
394
+ properties: {
395
+ text: { type: "string" },
396
+ url: { type: "string", format: "uri" },
397
+ target: { type: "string", enum: ["_blank", "_self"] }
398
+ },
399
+ required: ["text", "url"]
400
+ }
401
+ }
402
+ },
403
+ required: ["title", "items"]
404
+ }
405
+ },
406
+ socialLinks: {
407
+ type: "array",
408
+ items: {
409
+ type: "object",
410
+ properties: {
411
+ platform: { type: "string" },
412
+ url: { type: "string", format: "uri" },
413
+ icon: { type: "string" }
414
+ },
415
+ required: ["platform", "url"]
416
+ }
417
+ },
418
+ copyright: { type: "string" }
419
+ },
420
+ required: ["links", "socialLinks"]
421
+ },
422
+ stats: {
423
+ type: "object",
424
+ properties: {
425
+ number: { type: "string" },
426
+ label: { type: "string" },
427
+ icon: { type: "string" },
428
+ prefix: { type: "string" },
429
+ suffix: { type: "string" }
430
+ },
431
+ required: ["number", "label"]
432
+ },
433
+ faq: {
434
+ type: "object",
435
+ properties: {
436
+ items: {
437
+ type: "array",
438
+ items: {
439
+ type: "object",
440
+ properties: {
441
+ id: { type: "string" },
442
+ question: { type: "string" },
443
+ answer: { type: "string" }
444
+ },
445
+ required: ["question", "answer"]
446
+ }
447
+ }
448
+ },
449
+ required: ["items"]
450
+ },
451
+ header: {
452
+ type: "object",
453
+ properties: {
454
+ logo: { type: "string", format: "uri" },
455
+ title: { type: "string" },
456
+ links: {
457
+ type: "array",
458
+ items: {
459
+ type: "object",
460
+ properties: {
461
+ id: { type: "string" },
462
+ text: { type: "string" },
463
+ url: { type: "string", format: "uri" },
464
+ target: { type: "string", enum: ["_blank", "_self"] }
465
+ },
466
+ required: ["text", "url"]
467
+ }
468
+ }
469
+ },
470
+ required: ["links"]
471
+ }
472
+ };
473
+
474
+ // src/schema/validate.ts
475
+ var ajv = new import_ajv.default({ allErrors: true });
476
+ (0, import_ajv_formats.default)(ajv);
477
+ var validateLandingPage = ajv.compile(landingPageSchema);
478
+ var validateSection = {
479
+ hero: ajv.compile(sectionConfigSchemas.hero),
480
+ features: ajv.compile(sectionConfigSchemas.features),
481
+ testimonials: ajv.compile(sectionConfigSchemas.testimonials),
482
+ pricing: ajv.compile(sectionConfigSchemas.pricing),
483
+ cta: ajv.compile(sectionConfigSchemas.cta),
484
+ footer: ajv.compile(sectionConfigSchemas.footer),
485
+ stats: ajv.compile(sectionConfigSchemas.stats),
486
+ faq: ajv.compile(sectionConfigSchemas.faq),
487
+ header: ajv.compile(sectionConfigSchemas.header)
488
+ };
489
+ var validateSectionConfig = (type, config) => {
490
+ if (validateSection[type]) {
491
+ const valid = validateSection[type](config);
492
+ if (!valid && validateSection[type].errors) {
493
+ return validateSection[type].errors.map((err) => ({
494
+ field: err.instancePath || "root",
495
+ message: err.message,
496
+ type: err.keyword
497
+ }));
498
+ }
499
+ }
500
+ return null;
501
+ };
502
+
503
+ // src/core/validators.ts
504
+ function validateConfig(config) {
505
+ const errors = [];
506
+ if (!config.title)
507
+ errors.push("Title is required");
508
+ if (!config.description)
509
+ errors.push("Description is required");
510
+ if (!config.sections || config.sections.length === 0)
511
+ errors.push("At least one section is required");
512
+ config.sections?.forEach((section, index) => {
513
+ if (!section.id)
514
+ errors.push(`Section ${index} is missing an id`);
515
+ if (!section.type)
516
+ errors.push(`Section ${section.id || index} is missing a type`);
517
+ const sectionErrors = validateSection2(section);
518
+ sectionErrors.forEach((error) => errors.push(`Section ${section.id || index}: ${error}`));
519
+ });
520
+ return errors;
521
+ }
522
+ function validateSection2(section) {
523
+ const errors = [];
524
+ if (!section.type) {
525
+ errors.push("Section type is required");
526
+ return errors;
527
+ }
528
+ if (!section.config) {
529
+ errors.push("Section config is required");
530
+ return errors;
531
+ }
532
+ try {
533
+ const validationResult = validateSectionConfig(section.type, section.config);
534
+ if (validationResult) {
535
+ errors.push(...validationResult.map((err) => `${err.field}: ${err.message}`));
536
+ }
537
+ } catch (error) {
538
+ errors.push(`Invalid section configuration: ${error.message}`);
539
+ }
540
+ return errors;
541
+ }
542
+
543
+ // src/core/define.ts
544
+ function defineLandingPage(config) {
545
+ const errors = validateConfig(config);
546
+ if (errors.length > 0) {
547
+ throw new Error(`Invalid landing page configuration: ${errors.join(", ")}`);
548
+ }
549
+ const landingPage = {
550
+ ...config,
551
+ theme: createTheme(config.theme),
552
+ // Methods
553
+ getSection(id) {
554
+ return this.sections.find((section) => section.id === id);
555
+ },
556
+ addSection(section) {
557
+ const sectionErrors = validateSection2(section);
558
+ if (sectionErrors.length > 0) {
559
+ throw new Error(`Invalid section: ${sectionErrors.join(", ")}`);
560
+ }
561
+ this.sections.push(section);
562
+ return this;
563
+ },
564
+ removeSection(id) {
565
+ this.sections = this.sections.filter((section) => section.id !== id);
566
+ return this;
567
+ },
568
+ updateSection(id, updates) {
569
+ const index = this.sections.findIndex((section) => section.id === id);
570
+ if (index !== -1) {
571
+ const updatedSection = { ...this.sections[index], ...updates };
572
+ const sectionErrors = validateSection2(updatedSection);
573
+ if (sectionErrors.length > 0) {
574
+ throw new Error(`Invalid section updates: ${sectionErrors.join(", ")}`);
575
+ }
576
+ this.sections[index] = updatedSection;
577
+ }
578
+ return this;
579
+ },
580
+ // Render method - returns the raw config for consumption by renderers
581
+ toJSON() {
582
+ return JSON.parse(JSON.stringify(this));
583
+ },
584
+ // Validate the landing page configuration
585
+ validate() {
586
+ return validateConfig(this);
587
+ },
588
+ // Get section by type
589
+ getSectionsByType(type) {
590
+ return this.sections.filter((section) => section.type === type);
591
+ },
592
+ // Check if configuration is valid
593
+ isValid() {
594
+ return this.validate().length === 0;
595
+ }
596
+ };
597
+ return landingPage;
598
+ }
599
+
600
+ // src/core/sections/header.ts
601
+ function createHeaderSection(config, id, className) {
602
+ return {
603
+ id: id || `header-${Date.now()}`,
604
+ className,
605
+ type: "header",
606
+ config
607
+ };
608
+ }
609
+
610
+ // src/core/sections/hero.ts
611
+ function createHeroSection(config, id, className) {
612
+ return {
613
+ id: id || `hero-${Date.now()}`,
614
+ className,
615
+ type: "hero",
616
+ config
617
+ };
618
+ }
619
+
620
+ // src/core/sections/features.ts
621
+ function createFeaturesSection(config, id, className) {
622
+ return {
623
+ id: id || `features-${Date.now()}`,
624
+ className,
625
+ type: "features",
626
+ config
627
+ };
628
+ }
629
+
630
+ // src/core/sections/testimonials.ts
631
+ function createTestimonialsSection(config, id, className) {
632
+ return {
633
+ id: id || `testimonials-${Date.now()}`,
634
+ className,
635
+ type: "testimonials",
636
+ config
637
+ };
638
+ }
639
+
640
+ // src/core/sections/pricing.ts
641
+ function createPricingSection(config, id, className) {
642
+ return {
643
+ id: id || `pricing-${Date.now()}`,
644
+ className,
645
+ type: "pricing",
646
+ config
647
+ };
648
+ }
649
+
650
+ // src/core/sections/cta.ts
651
+ function createCtaSection(config, id, className) {
652
+ return {
653
+ id: id || `cta-${Date.now()}`,
654
+ className,
655
+ type: "cta",
656
+ config
657
+ };
658
+ }
659
+
660
+ // src/core/sections/footer.ts
661
+ function createFooterSection(config, id, className) {
662
+ return {
663
+ id: id || `footer-${Date.now()}`,
664
+ className,
665
+ type: "footer",
666
+ config
667
+ };
668
+ }
669
+
670
+ // src/core/sections/stats.ts
671
+ function createStatsSection(config, id, className) {
672
+ return {
673
+ id: id || `stats-${Date.now()}`,
674
+ className,
675
+ type: "stats",
676
+ config
677
+ };
678
+ }
679
+
680
+ // src/core/sections/faq.ts
681
+ function createFaqSection(config, id, className) {
682
+ return {
683
+ id: id || `faq-${Date.now()}`,
684
+ className,
685
+ type: "faq",
686
+ config
687
+ };
688
+ }
689
+
690
+ // src/renderers/react/index.tsx
691
+ var import_react15 = __toESM(require("react"));
692
+
693
+ // src/renderers/react/skins/HeaderSkin.tsx
694
+ var import_react5 = require("react");
695
+
696
+ // src/renderers/react/base/HeaderBase.tsx
697
+ var import_react4 = __toESM(require("react"));
698
+
699
+ // src/renderers/react/base/NavbarBase.tsx
700
+ var import_react2 = __toESM(require("react"));
701
+
702
+ // src/renderers/react/base/LayoutBase.tsx
703
+ var import_react = __toESM(require("react"));
704
+ var import_jsx_runtime = require("react/jsx-runtime");
705
+ var Box = import_react.default.forwardRef((props, ref) => {
706
+ const { as: Component = "div", children, className, style, ...rest } = props;
707
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ref, className, style, ...rest, children });
708
+ });
709
+ var Flex = import_react.default.forwardRef((props, ref) => {
710
+ const {
711
+ as: Component = "div",
712
+ children,
713
+ className,
714
+ style,
715
+ direction = "row",
716
+ justify = "flex-start",
717
+ align = "stretch",
718
+ gap = 0,
719
+ wrap = "nowrap",
720
+ ...rest
721
+ } = props;
722
+ const flexStyle = {
723
+ display: "flex",
724
+ flexDirection: direction,
725
+ justifyContent: justify,
726
+ alignItems: align,
727
+ gap: typeof gap === "number" ? `${gap}px` : gap,
728
+ flexWrap: wrap,
729
+ ...style
730
+ };
731
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ref, className, style: flexStyle, ...rest, children });
732
+ });
733
+ var Container = import_react.default.forwardRef((props, ref) => {
734
+ const {
735
+ as: Component = "div",
736
+ children,
737
+ className,
738
+ style,
739
+ maxWidth = "1200px",
740
+ padding = "0 1rem",
741
+ center = true,
742
+ ...rest
743
+ } = props;
744
+ const containerStyle = {
745
+ maxWidth,
746
+ padding,
747
+ margin: center ? "0 auto" : void 0,
748
+ ...style
749
+ };
750
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ref, className, style: containerStyle, ...rest, children });
751
+ });
752
+ Box.displayName = "Box";
753
+ Flex.displayName = "Flex";
754
+ Container.displayName = "Container";
755
+
756
+ // src/renderers/react/base/NavbarBase.tsx
757
+ var import_jsx_runtime2 = require("react/jsx-runtime");
758
+ var NavbarBase = import_react2.default.forwardRef((props, ref) => {
759
+ const {
760
+ links,
761
+ isMobile,
762
+ isOpen,
763
+ className,
764
+ style,
765
+ linkStyle,
766
+ onLinkMouseEnter,
767
+ onLinkMouseLeave
768
+ } = props;
769
+ if (isMobile && !isOpen)
770
+ return null;
771
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box, { as: "nav", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Flex, { as: "ul", direction: isMobile ? "column" : "row", gap: "1.5rem", style: { listStyle: "none", padding: 0 }, children: links.map((link, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box, { as: "li", style: { marginBottom: isMobile ? "0.5rem" : 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
772
+ "a",
773
+ {
774
+ href: link.url,
775
+ target: link.target || "_self",
776
+ rel: link.target === "_blank" ? "noopener noreferrer" : void 0,
777
+ style: linkStyle,
778
+ onMouseEnter: (e) => onLinkMouseEnter?.(e, link),
779
+ onMouseLeave: (e) => onLinkMouseLeave?.(e, link),
780
+ onFocus: (e) => {
781
+ e.currentTarget.style.outline = "2px solid currentColor";
782
+ e.currentTarget.style.outlineOffset = "2px";
783
+ },
784
+ onBlur: (e) => {
785
+ e.currentTarget.style.outline = "none";
786
+ },
787
+ children: link.text
788
+ }
789
+ ) }, index)) }) });
790
+ });
791
+ NavbarBase.displayName = "NavbarBase";
792
+
793
+ // src/renderers/react/skins/NavbarSkin.tsx
794
+ var import_jsx_runtime3 = require("react/jsx-runtime");
795
+ var NavbarSkin = (props) => {
796
+ const { theme, ...config } = props;
797
+ const navbarStyle = {
798
+ marginTop: config.isMobile ? theme.spacing.md : 0,
799
+ ...config.style
800
+ };
801
+ const linkStyle = {
802
+ color: theme.colors.muted,
803
+ textDecoration: "none",
804
+ transition: "color 0.2s ease",
805
+ display: "block",
806
+ padding: config.isMobile ? `${theme.spacing.sm} ${theme.spacing.md}` : "0.25rem 0",
807
+ borderRadius: config.isMobile ? "0.5rem" : 0,
808
+ fontSize: "1rem",
809
+ fontWeight: "500",
810
+ ...config.linkStyle
811
+ };
812
+ const handleMouseEnter = (e) => {
813
+ const el = e.currentTarget;
814
+ el.style.color = theme.colors.primary;
815
+ config.onLinkMouseEnter?.(e, {});
816
+ };
817
+ const handleMouseLeave = (e) => {
818
+ const el = e.currentTarget;
819
+ el.style.color = theme.colors.muted;
820
+ config.onLinkMouseLeave?.(e, {});
821
+ };
822
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
823
+ NavbarBase,
824
+ {
825
+ ...config,
826
+ style: navbarStyle,
827
+ linkStyle,
828
+ onLinkMouseEnter: handleMouseEnter,
829
+ onLinkMouseLeave: handleMouseLeave
830
+ }
831
+ );
832
+ };
833
+
834
+ // src/renderers/react/Navbar.tsx
835
+ var import_jsx_runtime4 = require("react/jsx-runtime");
836
+ var Navbar = ({
837
+ links,
838
+ theme,
839
+ isMobile,
840
+ isOpen,
841
+ className,
842
+ style
843
+ }) => {
844
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
845
+ NavbarSkin,
846
+ {
847
+ links,
848
+ theme,
849
+ isMobile,
850
+ isOpen,
851
+ className,
852
+ style
853
+ }
854
+ );
855
+ };
856
+ var Navbar_default = Navbar;
857
+
858
+ // src/renderers/react/base/MenuToggleBase.tsx
859
+ var import_react3 = __toESM(require("react"));
860
+ var import_jsx_runtime5 = require("react/jsx-runtime");
861
+ var MenuToggleBase = import_react3.default.forwardRef((props, ref) => {
862
+ const {
863
+ isOpen,
864
+ onClick,
865
+ ariaLabel = "Toggle menu",
866
+ className,
867
+ style,
868
+ iconOpen = "\u2630",
869
+ iconClose = "\u2715"
870
+ } = props;
871
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
872
+ Box,
873
+ {
874
+ as: "button",
875
+ ref,
876
+ onClick,
877
+ style,
878
+ className,
879
+ "aria-label": isOpen ? "Close menu" : ariaLabel,
880
+ children: isOpen ? iconClose : iconOpen
881
+ }
882
+ );
883
+ });
884
+ MenuToggleBase.displayName = "MenuToggleBase";
885
+
886
+ // src/renderers/react/skins/MenuToggleSkin.tsx
887
+ var import_jsx_runtime6 = require("react/jsx-runtime");
888
+ var MenuToggleSkin = (props) => {
889
+ const { theme, ...config } = props;
890
+ const toggleStyle = {
891
+ backgroundColor: "transparent",
892
+ border: "none",
893
+ color: theme.colors.text,
894
+ fontSize: "1.5rem",
895
+ cursor: "pointer",
896
+ padding: theme.spacing.sm,
897
+ display: "flex",
898
+ alignItems: "center",
899
+ justifyContent: "center",
900
+ transition: "color 0.2s ease",
901
+ ...config.style
902
+ };
903
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
904
+ MenuToggleBase,
905
+ {
906
+ ...config,
907
+ style: toggleStyle
908
+ }
909
+ );
910
+ };
911
+
912
+ // src/renderers/react/MenuToggle.tsx
913
+ var import_jsx_runtime7 = require("react/jsx-runtime");
914
+ var MenuToggle = ({
915
+ isOpen,
916
+ onClick,
917
+ theme,
918
+ className,
919
+ style
920
+ }) => {
921
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
922
+ MenuToggleSkin,
923
+ {
924
+ isOpen,
925
+ onClick,
926
+ theme,
927
+ className,
928
+ style
929
+ }
930
+ );
931
+ };
932
+ var MenuToggle_default = MenuToggle;
933
+
934
+ // src/renderers/react/base/HeaderBase.tsx
935
+ var import_jsx_runtime8 = require("react/jsx-runtime");
936
+ var HeaderBase = import_react4.default.forwardRef((props, ref) => {
937
+ const {
938
+ logo,
939
+ title,
940
+ links,
941
+ className,
942
+ isMobileMenuOpen = false,
943
+ onMobileMenuToggle,
944
+ style,
945
+ containerStyle,
946
+ theme
947
+ } = props;
948
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { as: "header", ref, style, className, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Container, { style: containerStyle, children: [
949
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Flex, { justify: "space-between", align: "center", children: [
950
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Flex, { align: "center", gap: "1rem", children: [
951
+ logo && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
952
+ "img",
953
+ {
954
+ src: logo,
955
+ alt: title || "Logo",
956
+ style: { height: "40px" },
957
+ loading: "lazy"
958
+ }
959
+ ),
960
+ title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: { fontSize: "1.5rem", color: theme.colors.text }, children: title })
961
+ ] }),
962
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { style: { display: "none" } }),
963
+ onMobileMenuToggle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
964
+ MenuToggle_default,
965
+ {
966
+ isOpen: isMobileMenuOpen,
967
+ onClick: onMobileMenuToggle,
968
+ theme
969
+ }
970
+ )
971
+ ] }),
972
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
973
+ Navbar_default,
974
+ {
975
+ links,
976
+ theme,
977
+ isMobile: true,
978
+ isOpen: isMobileMenuOpen
979
+ }
980
+ )
981
+ ] }) });
982
+ });
983
+ HeaderBase.displayName = "HeaderBase";
984
+
985
+ // src/renderers/react/skins/HeaderSkin.tsx
986
+ var import_jsx_runtime9 = require("react/jsx-runtime");
987
+ var HeaderSkin = (props) => {
988
+ const { theme, ...config } = props;
989
+ const [mobileMenuOpen, setMobileMenuOpen] = (0, import_react5.useState)(false);
990
+ const headerStyle = {
991
+ padding: "1rem 0",
992
+ backgroundColor: theme.colors.background,
993
+ borderBottom: `1px solid ${theme.colors.muted}20`,
994
+ ...config.style
995
+ };
996
+ const containerStyle = {
997
+ maxWidth: "1200px",
998
+ margin: "0 auto",
999
+ padding: "0 1rem",
1000
+ ...config.containerStyle
1001
+ };
1002
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1003
+ HeaderBase,
1004
+ {
1005
+ ...config,
1006
+ theme,
1007
+ style: headerStyle,
1008
+ containerStyle,
1009
+ isMobileMenuOpen: mobileMenuOpen,
1010
+ onMobileMenuToggle: () => setMobileMenuOpen(!mobileMenuOpen)
1011
+ }
1012
+ );
1013
+ };
1014
+
1015
+ // src/renderers/react/Header.tsx
1016
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1017
+ var Header = ({ config, theme }) => {
1018
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1019
+ HeaderSkin,
1020
+ {
1021
+ ...config,
1022
+ theme
1023
+ }
1024
+ );
1025
+ };
1026
+ var Header_default = Header;
1027
+
1028
+ // src/renderers/react/base/HeroBase.tsx
1029
+ var import_react7 = __toESM(require("react"));
1030
+
1031
+ // src/renderers/react/base/ButtonBase.tsx
1032
+ var import_react6 = __toESM(require("react"));
1033
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1034
+ var ButtonBase = import_react6.default.forwardRef((props, ref) => {
1035
+ const {
1036
+ text,
1037
+ url,
1038
+ target = "_self",
1039
+ variant,
1040
+ size,
1041
+ className,
1042
+ style,
1043
+ onMouseEnter,
1044
+ onMouseLeave,
1045
+ onFocus,
1046
+ onBlur,
1047
+ onKeyDown,
1048
+ ...rest
1049
+ } = props;
1050
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1051
+ "a",
1052
+ {
1053
+ ref,
1054
+ href: url,
1055
+ target,
1056
+ rel: target === "_blank" ? "noopener noreferrer" : void 0,
1057
+ style,
1058
+ className,
1059
+ onMouseEnter,
1060
+ onMouseLeave,
1061
+ onFocus,
1062
+ onBlur,
1063
+ onKeyDown,
1064
+ role: "button",
1065
+ tabIndex: 0,
1066
+ ...rest,
1067
+ children: text
1068
+ }
1069
+ );
1070
+ });
1071
+ ButtonBase.displayName = "ButtonBase";
1072
+
1073
+ // src/core/utils/contrast.ts
1074
+ function hexToRgb(hex) {
1075
+ const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
1076
+ const fullHex = hex.replace(shorthandRegex, (_, r, g, b) => r + r + g + g + b + b);
1077
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(fullHex);
1078
+ return result ? {
1079
+ r: parseInt(result[1], 16),
1080
+ g: parseInt(result[2], 16),
1081
+ b: parseInt(result[3], 16)
1082
+ } : null;
1083
+ }
1084
+ function getRelativeLuminance(r, g, b) {
1085
+ const [rs, gs, bs] = [r, g, b].map((c) => {
1086
+ const s = c / 255;
1087
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
1088
+ });
1089
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
1090
+ }
1091
+ function getContrastRatio(hex1, hex2) {
1092
+ const rgb1 = hexToRgb(hex1);
1093
+ const rgb2 = hexToRgb(hex2);
1094
+ if (!rgb1 || !rgb2)
1095
+ return 1;
1096
+ const l1 = getRelativeLuminance(rgb1.r, rgb1.g, rgb1.b);
1097
+ const l2 = getRelativeLuminance(rgb2.r, rgb2.g, rgb2.b);
1098
+ const lighter = Math.max(l1, l2);
1099
+ const darker = Math.min(l1, l2);
1100
+ return (lighter + 0.05) / (darker + 0.05);
1101
+ }
1102
+ function getBestContrastColor(bgColor, lightColor = "#ffffff", darkColor = "#000000") {
1103
+ const ratioLight = getContrastRatio(bgColor, lightColor);
1104
+ const ratioDark = getContrastRatio(bgColor, darkColor);
1105
+ return ratioLight > ratioDark ? lightColor : darkColor;
1106
+ }
1107
+
1108
+ // src/renderers/react/skins/ButtonSkin.tsx
1109
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1110
+ var ButtonSkin = (props) => {
1111
+ const { theme, ...config } = props;
1112
+ const backgroundColor = config.variant === "primary" ? theme.colors.primary : config.variant === "secondary" ? theme.colors.secondary : "transparent";
1113
+ const textColor = config.variant === "primary" || config.variant === "secondary" ? getBestContrastColor(backgroundColor) : theme.colors.primary;
1114
+ const buttonStyles = {
1115
+ padding: theme.spacing[config.size === "sm" ? "sm" : config.size === "lg" ? "xl" : "md"],
1116
+ backgroundColor,
1117
+ color: textColor,
1118
+ border: config.variant === "outline" ? `2px solid ${theme.colors.primary}` : "none",
1119
+ borderRadius: "0.5rem",
1120
+ fontSize: config.size === "sm" ? "0.875rem" : config.size === "lg" ? "1.125rem" : "1rem",
1121
+ fontWeight: "600",
1122
+ cursor: "pointer",
1123
+ textDecoration: "none",
1124
+ display: "inline-block",
1125
+ textAlign: "center",
1126
+ transition: "all 0.2s ease",
1127
+ ...config.style
1128
+ };
1129
+ const adjustBrightness = (color, amount) => {
1130
+ if (!color || color === "transparent")
1131
+ return color;
1132
+ try {
1133
+ const num = parseInt(color.replace("#", ""), 16);
1134
+ const amt = Math.round(2.55 * amount);
1135
+ const R = Math.max(0, Math.min(255, (num >> 16) + amt));
1136
+ const G = Math.max(0, Math.min(255, (num >> 8 & 255) + amt));
1137
+ const B = Math.max(0, Math.min(255, (num & 255) + amt));
1138
+ return "#" + (16777216 + R * 65536 + G * 256 + B).toString(16).slice(1);
1139
+ } catch (e) {
1140
+ return color;
1141
+ }
1142
+ };
1143
+ const handleMouseEnter = (e) => {
1144
+ const el = e.currentTarget;
1145
+ if (config.variant === "primary") {
1146
+ el.style.backgroundColor = adjustBrightness(theme.colors.primary, -20);
1147
+ el.style.transform = "translateY(-2px)";
1148
+ el.style.boxShadow = "0 10px 15px -3px rgba(0, 0, 0, 0.1)";
1149
+ } else if (config.variant === "secondary") {
1150
+ el.style.backgroundColor = adjustBrightness(theme.colors.secondary, -20);
1151
+ el.style.transform = "translateY(-2px)";
1152
+ el.style.boxShadow = "0 10px 15px -3px rgba(0, 0, 0, 0.1)";
1153
+ } else if (config.variant === "outline") {
1154
+ el.style.backgroundColor = theme.colors.primary;
1155
+ el.style.color = theme.colors.primary === "#ffffff" ? theme.colors.text : "#ffffff";
1156
+ } else if (config.variant === "ghost") {
1157
+ el.style.backgroundColor = `${theme.colors.primary}10`;
1158
+ }
1159
+ config.onMouseEnter?.(e);
1160
+ };
1161
+ const handleMouseLeave = (e) => {
1162
+ const el = e.currentTarget;
1163
+ el.style.backgroundColor = buttonStyles.backgroundColor;
1164
+ el.style.color = buttonStyles.color;
1165
+ el.style.transform = "translateY(0)";
1166
+ el.style.boxShadow = "none";
1167
+ config.onMouseLeave?.(e);
1168
+ };
1169
+ const handleKeyDown = (e) => {
1170
+ if (e.key === "Enter" || e.key === " ") {
1171
+ e.preventDefault();
1172
+ window.location.href = config.url;
1173
+ }
1174
+ config.onKeyDown?.(e);
1175
+ };
1176
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1177
+ ButtonBase,
1178
+ {
1179
+ ...config,
1180
+ style: buttonStyles,
1181
+ onMouseEnter: handleMouseEnter,
1182
+ onMouseLeave: handleMouseLeave,
1183
+ onKeyDown: handleKeyDown,
1184
+ onFocus: (e) => {
1185
+ e.currentTarget.style.outline = `2px solid ${theme.colors.primary}`;
1186
+ e.currentTarget.style.outlineOffset = "2px";
1187
+ config.onFocus?.(e);
1188
+ },
1189
+ onBlur: (e) => {
1190
+ e.currentTarget.style.outline = "none";
1191
+ config.onBlur?.(e);
1192
+ }
1193
+ }
1194
+ );
1195
+ };
1196
+
1197
+ // src/renderers/react/Button.tsx
1198
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1199
+ var Button = ({ config, theme }) => {
1200
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1201
+ ButtonSkin,
1202
+ {
1203
+ ...config,
1204
+ theme
1205
+ }
1206
+ );
1207
+ };
1208
+ var Button_default = Button;
1209
+
1210
+ // src/renderers/react/base/HeroBase.tsx
1211
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1212
+ var HeroBase = import_react7.default.forwardRef((props, ref) => {
1213
+ const {
1214
+ title,
1215
+ subtitle,
1216
+ buttons,
1217
+ image,
1218
+ video,
1219
+ alignment = "center",
1220
+ className,
1221
+ style,
1222
+ containerStyle,
1223
+ contentStyle,
1224
+ theme
1225
+ } = props;
1226
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1227
+ Flex,
1228
+ {
1229
+ direction: "column",
1230
+ gap: theme.spacing.xl,
1231
+ align: alignment === "center" ? "center" : alignment === "right" ? "flex-end" : "flex-start",
1232
+ style: { textAlign: alignment, ...contentStyle },
1233
+ children: [
1234
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box, { children: [
1235
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { style: {
1236
+ fontSize: "3rem",
1237
+ fontWeight: "bold",
1238
+ color: theme.colors.text,
1239
+ marginBottom: theme.spacing.md,
1240
+ lineHeight: "1.2"
1241
+ }, children: title }),
1242
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: {
1243
+ fontSize: "1.25rem",
1244
+ color: theme.colors.muted,
1245
+ marginBottom: theme.spacing.lg,
1246
+ maxWidth: "600px",
1247
+ marginLeft: alignment === "center" ? "auto" : "0",
1248
+ marginRight: alignment === "center" ? "auto" : "0"
1249
+ }, children: subtitle })
1250
+ ] }),
1251
+ image && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1252
+ "img",
1253
+ {
1254
+ src: image,
1255
+ alt: title || "Hero",
1256
+ style: {
1257
+ maxWidth: "100%",
1258
+ borderRadius: "0.5rem",
1259
+ boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)"
1260
+ },
1261
+ loading: "lazy"
1262
+ }
1263
+ ),
1264
+ video && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1265
+ "video",
1266
+ {
1267
+ src: video,
1268
+ controls: true,
1269
+ style: {
1270
+ maxWidth: "100%",
1271
+ borderRadius: "0.5rem",
1272
+ boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)"
1273
+ }
1274
+ }
1275
+ ),
1276
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Flex, { gap: theme.spacing.md, wrap: "wrap", justify: alignment === "center" ? "center" : "flex-start", children: buttons.map((button) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button_default, { config: button, theme }, button.id)) })
1277
+ ]
1278
+ }
1279
+ ) }) });
1280
+ });
1281
+ HeroBase.displayName = "HeroBase";
1282
+
1283
+ // src/renderers/react/skins/HeroSkin.tsx
1284
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1285
+ var HeroSkin = (props) => {
1286
+ const { theme, ...config } = props;
1287
+ const sectionStyle = {
1288
+ padding: "4rem 0",
1289
+ ...config.style
1290
+ };
1291
+ const containerStyle = {
1292
+ maxWidth: "1200px",
1293
+ margin: "0 auto",
1294
+ padding: "0 1rem",
1295
+ ...config.containerStyle
1296
+ };
1297
+ const contentStyle = {
1298
+ display: "flex",
1299
+ flexDirection: "column",
1300
+ gap: theme.spacing.xl,
1301
+ alignItems: config.alignment || "center",
1302
+ textAlign: config.alignment || "center",
1303
+ ...config.contentStyle
1304
+ };
1305
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1306
+ HeroBase,
1307
+ {
1308
+ ...config,
1309
+ theme,
1310
+ style: sectionStyle,
1311
+ containerStyle,
1312
+ contentStyle
1313
+ }
1314
+ );
1315
+ };
1316
+
1317
+ // src/renderers/react/Hero.tsx
1318
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1319
+ var Hero = ({ config, theme }) => {
1320
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1321
+ HeroSkin,
1322
+ {
1323
+ ...config,
1324
+ theme
1325
+ }
1326
+ );
1327
+ };
1328
+ var Hero_default = Hero;
1329
+
1330
+ // src/renderers/react/base/FeaturesBase.tsx
1331
+ var import_react8 = __toESM(require("react"));
1332
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1333
+ var FeaturesBase = import_react8.default.forwardRef((props, ref) => {
1334
+ const {
1335
+ features,
1336
+ className,
1337
+ style,
1338
+ containerStyle,
1339
+ gridStyle,
1340
+ featureStyle,
1341
+ iconStyle,
1342
+ titleStyle,
1343
+ descriptionStyle,
1344
+ onFeatureMouseEnter,
1345
+ onFeatureMouseLeave,
1346
+ theme
1347
+ } = props;
1348
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box, { style: gridStyle, children: features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1349
+ Box,
1350
+ {
1351
+ className: feature.className,
1352
+ style: featureStyle,
1353
+ onMouseEnter: onFeatureMouseEnter,
1354
+ onMouseLeave: onFeatureMouseLeave,
1355
+ children: [
1356
+ feature.icon && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box, { style: iconStyle, children: feature.icon }),
1357
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box, { as: "h3", style: titleStyle, children: feature.title }),
1358
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box, { as: "p", style: descriptionStyle, children: feature.description })
1359
+ ]
1360
+ },
1361
+ feature.id
1362
+ )) }) }) });
1363
+ });
1364
+ FeaturesBase.displayName = "FeaturesBase";
1365
+
1366
+ // src/renderers/react/skins/FeaturesSkin.tsx
1367
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1368
+ var FeaturesSkin = (props) => {
1369
+ const { theme, ...config } = props;
1370
+ const sectionStyle = {
1371
+ padding: "4rem 0",
1372
+ ...config.style
1373
+ };
1374
+ const containerStyle = {
1375
+ maxWidth: "1200px",
1376
+ margin: "0 auto",
1377
+ padding: "0 1rem",
1378
+ ...config.containerStyle
1379
+ };
1380
+ const gridStyle = {
1381
+ display: "grid",
1382
+ gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
1383
+ gap: theme.spacing.xl,
1384
+ ...config.gridStyle
1385
+ };
1386
+ const featureStyle = {
1387
+ padding: theme.spacing.lg,
1388
+ border: `1px solid ${theme.colors.muted}20`,
1389
+ borderRadius: "0.5rem",
1390
+ backgroundColor: theme.colors.background,
1391
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
1392
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
1393
+ cursor: "pointer",
1394
+ ...config.featureStyle
1395
+ };
1396
+ const iconStyle = {
1397
+ marginBottom: theme.spacing.md,
1398
+ ...config.iconStyle
1399
+ };
1400
+ const titleStyle = {
1401
+ fontSize: "1.5rem",
1402
+ marginBottom: theme.spacing.md,
1403
+ color: theme.colors.text,
1404
+ ...config.titleStyle
1405
+ };
1406
+ const descriptionStyle = {
1407
+ color: theme.colors.muted,
1408
+ lineHeight: "1.6",
1409
+ ...config.descriptionStyle
1410
+ };
1411
+ const handleMouseEnter = (e) => {
1412
+ e.currentTarget.style.transform = "translateY(-4px)";
1413
+ e.currentTarget.style.boxShadow = "0 20px 25px -5px rgba(0, 0, 0, 0.1)";
1414
+ config.onFeatureMouseEnter?.(e);
1415
+ };
1416
+ const handleMouseLeave = (e) => {
1417
+ e.currentTarget.style.transform = "translateY(0)";
1418
+ e.currentTarget.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1)";
1419
+ config.onFeatureMouseLeave?.(e);
1420
+ };
1421
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1422
+ FeaturesBase,
1423
+ {
1424
+ ...config,
1425
+ theme,
1426
+ style: sectionStyle,
1427
+ containerStyle,
1428
+ gridStyle,
1429
+ featureStyle,
1430
+ iconStyle,
1431
+ titleStyle,
1432
+ descriptionStyle,
1433
+ onFeatureMouseEnter: handleMouseEnter,
1434
+ onFeatureMouseLeave: handleMouseLeave
1435
+ }
1436
+ );
1437
+ };
1438
+
1439
+ // src/renderers/react/Features.tsx
1440
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1441
+ var Features = ({ config, theme }) => {
1442
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1443
+ FeaturesSkin,
1444
+ {
1445
+ ...config,
1446
+ theme
1447
+ }
1448
+ );
1449
+ };
1450
+ var Features_default = Features;
1451
+
1452
+ // src/renderers/react/base/TestimonialsBase.tsx
1453
+ var import_react9 = __toESM(require("react"));
1454
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1455
+ var TestimonialsBase = import_react9.default.forwardRef((props, ref) => {
1456
+ const {
1457
+ testimonials,
1458
+ className,
1459
+ style,
1460
+ containerStyle,
1461
+ gridStyle,
1462
+ testimonialStyle,
1463
+ quoteIconStyle,
1464
+ quoteStyle,
1465
+ authorContainerStyle,
1466
+ avatarStyle,
1467
+ authorInfoStyle,
1468
+ authorNameStyle,
1469
+ authorRoleStyle,
1470
+ onTestimonialMouseEnter,
1471
+ onTestimonialMouseLeave,
1472
+ theme
1473
+ } = props;
1474
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Box, { style: gridStyle, children: testimonials.map((testimonial) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1475
+ Box,
1476
+ {
1477
+ className: testimonial.className,
1478
+ style: testimonialStyle,
1479
+ onMouseEnter: onTestimonialMouseEnter,
1480
+ onMouseLeave: onTestimonialMouseLeave,
1481
+ children: [
1482
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Box, { style: quoteIconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1483
+ "svg",
1484
+ {
1485
+ width: "24",
1486
+ height: "24",
1487
+ viewBox: "0 0 24 24",
1488
+ fill: "none",
1489
+ stroke: theme.colors.primary,
1490
+ strokeWidth: "2",
1491
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
1492
+ }
1493
+ ) }),
1494
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Box, { as: "blockquote", style: quoteStyle, children: testimonial.quote }),
1495
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Flex, { align: "center", gap: theme.spacing.md, style: authorContainerStyle, children: [
1496
+ testimonial.avatar && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1497
+ "img",
1498
+ {
1499
+ src: testimonial.avatar,
1500
+ alt: testimonial.author,
1501
+ style: avatarStyle,
1502
+ loading: "lazy"
1503
+ }
1504
+ ),
1505
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Box, { style: authorInfoStyle, children: [
1506
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Box, { as: "p", style: authorNameStyle, children: testimonial.author }),
1507
+ testimonial.role && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Box, { as: "p", style: authorRoleStyle, children: testimonial.role })
1508
+ ] })
1509
+ ] })
1510
+ ]
1511
+ },
1512
+ testimonial.id
1513
+ )) }) }) });
1514
+ });
1515
+ TestimonialsBase.displayName = "TestimonialsBase";
1516
+
1517
+ // src/renderers/react/skins/TestimonialsSkin.tsx
1518
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1519
+ var TestimonialsSkin = (props) => {
1520
+ const { theme, ...config } = props;
1521
+ const sectionStyle = {
1522
+ padding: "4rem 0",
1523
+ ...config.style
1524
+ };
1525
+ const containerStyle = {
1526
+ maxWidth: "1200px",
1527
+ margin: "0 auto",
1528
+ padding: "0 1rem",
1529
+ ...config.containerStyle
1530
+ };
1531
+ const gridStyle = {
1532
+ display: "grid",
1533
+ gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
1534
+ gap: theme.spacing.xl,
1535
+ ...config.gridStyle
1536
+ };
1537
+ const testimonialStyle = {
1538
+ padding: theme.spacing.lg,
1539
+ backgroundColor: theme.colors.background,
1540
+ border: `1px solid ${theme.colors.muted}20`,
1541
+ borderRadius: "0.5rem",
1542
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
1543
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
1544
+ cursor: "pointer",
1545
+ ...config.testimonialStyle
1546
+ };
1547
+ const quoteIconStyle = {
1548
+ marginBottom: theme.spacing.md,
1549
+ ...config.quoteIconStyle
1550
+ };
1551
+ const quoteStyle = {
1552
+ fontSize: "1.125rem",
1553
+ fontStyle: "italic",
1554
+ color: theme.colors.text,
1555
+ ...config.quoteStyle
1556
+ };
1557
+ const authorContainerStyle = {
1558
+ marginTop: theme.spacing.md,
1559
+ ...config.authorContainerStyle
1560
+ };
1561
+ const avatarStyle = {
1562
+ width: "48px",
1563
+ height: "48px",
1564
+ borderRadius: "50%",
1565
+ objectFit: "cover",
1566
+ ...config.avatarStyle
1567
+ };
1568
+ const authorInfoStyle = {
1569
+ ...config.authorInfoStyle
1570
+ };
1571
+ const authorNameStyle = {
1572
+ fontWeight: "bold",
1573
+ color: theme.colors.text,
1574
+ ...config.authorNameStyle
1575
+ };
1576
+ const authorRoleStyle = {
1577
+ fontSize: "0.875rem",
1578
+ color: theme.colors.muted,
1579
+ ...config.authorRoleStyle
1580
+ };
1581
+ const handleMouseEnter = (e) => {
1582
+ e.currentTarget.style.transform = "translateY(-4px)";
1583
+ e.currentTarget.style.boxShadow = "0 20px 25px -5px rgba(0, 0, 0, 0.1)";
1584
+ config.onTestimonialMouseEnter?.(e);
1585
+ };
1586
+ const handleMouseLeave = (e) => {
1587
+ e.currentTarget.style.transform = "translateY(0)";
1588
+ e.currentTarget.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1)";
1589
+ config.onTestimonialMouseLeave?.(e);
1590
+ };
1591
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1592
+ TestimonialsBase,
1593
+ {
1594
+ ...config,
1595
+ theme,
1596
+ style: sectionStyle,
1597
+ containerStyle,
1598
+ gridStyle,
1599
+ testimonialStyle,
1600
+ quoteIconStyle,
1601
+ quoteStyle,
1602
+ authorContainerStyle,
1603
+ avatarStyle,
1604
+ authorInfoStyle,
1605
+ authorNameStyle,
1606
+ authorRoleStyle,
1607
+ onTestimonialMouseEnter: handleMouseEnter,
1608
+ onTestimonialMouseLeave: handleMouseLeave
1609
+ }
1610
+ );
1611
+ };
1612
+
1613
+ // src/renderers/react/Testimonials.tsx
1614
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1615
+ var Testimonials = ({ config, theme }) => {
1616
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1617
+ TestimonialsSkin,
1618
+ {
1619
+ ...config,
1620
+ theme
1621
+ }
1622
+ );
1623
+ };
1624
+ var Testimonials_default = Testimonials;
1625
+
1626
+ // src/renderers/react/base/PricingBase.tsx
1627
+ var import_react10 = __toESM(require("react"));
1628
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1629
+ var PricingBase = import_react10.default.forwardRef((props, ref) => {
1630
+ const {
1631
+ plans,
1632
+ className,
1633
+ style,
1634
+ containerStyle,
1635
+ gridStyle,
1636
+ planStyle,
1637
+ featuredBadgeStyle,
1638
+ titleStyle,
1639
+ descriptionStyle,
1640
+ priceContainerStyle,
1641
+ priceStyle,
1642
+ periodStyle,
1643
+ featuresListStyle,
1644
+ featureItemStyle,
1645
+ checkIcon,
1646
+ theme
1647
+ } = props;
1648
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { style: gridStyle, children: plans.map((plan) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1649
+ Box,
1650
+ {
1651
+ className: plan.className,
1652
+ style: typeof planStyle === "function" ? planStyle(plan) : planStyle,
1653
+ children: [
1654
+ plan.featured && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { style: featuredBadgeStyle, children: "Popular" }),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { as: "h3", style: titleStyle, children: plan.title }),
1656
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { as: "p", style: descriptionStyle, children: plan.description }),
1657
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Box, { style: priceContainerStyle, children: [
1658
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { as: "span", style: priceStyle, children: plan.price }),
1659
+ plan.period && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Box, { as: "span", style: periodStyle, children: [
1660
+ "/",
1661
+ plan.period
1662
+ ] })
1663
+ ] }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box, { as: "ul", style: featuresListStyle, children: plan.features.map((feature, index) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Box, { as: "li", style: featureItemStyle, children: [
1665
+ checkIcon || /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1666
+ "svg",
1667
+ {
1668
+ width: "20",
1669
+ height: "20",
1670
+ viewBox: "0 0 24 24",
1671
+ fill: "none",
1672
+ stroke: theme.colors.accent,
1673
+ strokeWidth: "2",
1674
+ children: [
1675
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
1677
+ ]
1678
+ }
1679
+ ),
1680
+ feature
1681
+ ] }, index)) }),
1682
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Button_default, { config: plan.button, theme })
1683
+ ]
1684
+ },
1685
+ plan.id
1686
+ )) }) }) });
1687
+ });
1688
+ PricingBase.displayName = "PricingBase";
1689
+
1690
+ // src/renderers/react/skins/PricingSkin.tsx
1691
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1692
+ var PricingSkin = (props) => {
1693
+ const { theme, ...config } = props;
1694
+ const sectionStyle = {
1695
+ padding: "4rem 0",
1696
+ ...config.style
1697
+ };
1698
+ const containerStyle = {
1699
+ maxWidth: "1200px",
1700
+ margin: "0 auto",
1701
+ padding: "0 1rem",
1702
+ ...config.containerStyle
1703
+ };
1704
+ const gridStyle = {
1705
+ display: "grid",
1706
+ gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))",
1707
+ gap: theme.spacing.xl,
1708
+ maxWidth: "1000px",
1709
+ margin: "0 auto",
1710
+ ...config.gridStyle
1711
+ };
1712
+ const planStyle = (plan) => ({
1713
+ padding: theme.spacing.lg,
1714
+ backgroundColor: theme.colors.background,
1715
+ border: `2px solid ${plan.featured ? theme.colors.primary : `${theme.colors.muted}20`}`,
1716
+ borderRadius: "0.5rem",
1717
+ boxShadow: plan.featured ? "0 20px 25px -5px rgba(0, 0, 0, 0.1)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
1718
+ position: "relative",
1719
+ display: "flex",
1720
+ flexDirection: "column",
1721
+ ...config.planStyle?.(plan)
1722
+ });
1723
+ const featuredBadgeStyle = {
1724
+ position: "absolute",
1725
+ top: "-12px",
1726
+ left: "50%",
1727
+ transform: "translateX(-50%)",
1728
+ backgroundColor: theme.colors.primary,
1729
+ color: "#ffffff",
1730
+ padding: "0.25rem 0.75rem",
1731
+ borderRadius: "9999px",
1732
+ fontSize: "0.75rem",
1733
+ fontWeight: "bold",
1734
+ ...config.featuredBadgeStyle
1735
+ };
1736
+ const titleStyle = {
1737
+ fontSize: "1.5rem",
1738
+ marginBottom: theme.spacing.md,
1739
+ color: theme.colors.text,
1740
+ ...config.titleStyle
1741
+ };
1742
+ const descriptionStyle = {
1743
+ color: theme.colors.muted,
1744
+ marginBottom: theme.spacing.md,
1745
+ ...config.descriptionStyle
1746
+ };
1747
+ const priceContainerStyle = {
1748
+ marginBottom: theme.spacing.lg,
1749
+ ...config.priceContainerStyle
1750
+ };
1751
+ const priceStyle = {
1752
+ fontSize: "3rem",
1753
+ fontWeight: "bold",
1754
+ color: theme.colors.text,
1755
+ ...config.priceStyle
1756
+ };
1757
+ const periodStyle = {
1758
+ color: theme.colors.muted,
1759
+ ...config.periodStyle
1760
+ };
1761
+ const featuresListStyle = {
1762
+ marginBottom: theme.spacing.lg,
1763
+ listStyle: "none",
1764
+ padding: 0,
1765
+ flex: 1,
1766
+ ...config.featuresListStyle
1767
+ };
1768
+ const featureItemStyle = {
1769
+ padding: `${theme.spacing.sm} 0`,
1770
+ color: theme.colors.text,
1771
+ display: "flex",
1772
+ alignItems: "center",
1773
+ gap: theme.spacing.sm,
1774
+ ...config.featureItemStyle
1775
+ };
1776
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1777
+ PricingBase,
1778
+ {
1779
+ ...config,
1780
+ theme,
1781
+ style: sectionStyle,
1782
+ containerStyle,
1783
+ gridStyle,
1784
+ planStyle,
1785
+ featuredBadgeStyle,
1786
+ titleStyle,
1787
+ descriptionStyle,
1788
+ priceContainerStyle,
1789
+ priceStyle,
1790
+ periodStyle,
1791
+ featuresListStyle,
1792
+ featureItemStyle
1793
+ }
1794
+ );
1795
+ };
1796
+
1797
+ // src/renderers/react/Pricing.tsx
1798
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1799
+ var Pricing = ({ config, theme }) => {
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1801
+ PricingSkin,
1802
+ {
1803
+ ...config,
1804
+ theme
1805
+ }
1806
+ );
1807
+ };
1808
+ var Pricing_default = Pricing;
1809
+
1810
+ // src/renderers/react/base/CtaBase.tsx
1811
+ var import_react11 = __toESM(require("react"));
1812
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1813
+ var CtaBase = import_react11.default.forwardRef((props, ref) => {
1814
+ const {
1815
+ title,
1816
+ description,
1817
+ button,
1818
+ image,
1819
+ className,
1820
+ style,
1821
+ containerStyle,
1822
+ contentStyle,
1823
+ theme
1824
+ } = props;
1825
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Box, { style: contentStyle, children: [
1826
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { fontSize: "2rem", marginBottom: theme.spacing.md }, children: title }),
1827
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { style: {
1828
+ fontSize: "1.125rem",
1829
+ marginBottom: theme.spacing.lg,
1830
+ maxWidth: "600px",
1831
+ marginLeft: "auto",
1832
+ marginRight: "auto"
1833
+ }, children: description }),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button_default, { config: button, theme })
1835
+ ] }) }) });
1836
+ });
1837
+ CtaBase.displayName = "CtaBase";
1838
+
1839
+ // src/renderers/react/skins/CtaSkin.tsx
1840
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1841
+ var CtaSkin = (props) => {
1842
+ const { theme, ...config } = props;
1843
+ const backgroundColor = theme.colors.primary;
1844
+ const textColor = getBestContrastColor(backgroundColor);
1845
+ const sectionStyle = {
1846
+ padding: "4rem 0",
1847
+ ...config.style
1848
+ };
1849
+ const containerStyle = {
1850
+ maxWidth: "1200px",
1851
+ margin: "0 auto",
1852
+ padding: "0 1rem",
1853
+ ...config.containerStyle
1854
+ };
1855
+ const contentStyle = {
1856
+ textAlign: "center",
1857
+ padding: "4rem 2rem",
1858
+ backgroundColor,
1859
+ color: textColor,
1860
+ borderRadius: "0.5rem",
1861
+ ...config.contentStyle
1862
+ };
1863
+ const buttonConfig = {
1864
+ ...config.button,
1865
+ variant: config.button.variant === "primary" ? "outline" : config.button.variant
1866
+ };
1867
+ const buttonTheme = {
1868
+ ...theme,
1869
+ colors: {
1870
+ ...theme.colors,
1871
+ primary: textColor,
1872
+ // Warna outline tombol mengikuti warna teks CTA yang kontras
1873
+ text: backgroundColor
1874
+ // Warna teks saat hover tombol mengikuti warna background CTA
1875
+ }
1876
+ };
1877
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
1878
+ CtaBase,
1879
+ {
1880
+ ...config,
1881
+ button: buttonConfig,
1882
+ theme: buttonTheme,
1883
+ style: sectionStyle,
1884
+ containerStyle,
1885
+ contentStyle
1886
+ }
1887
+ );
1888
+ };
1889
+
1890
+ // src/renderers/react/Cta.tsx
1891
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1892
+ var Cta = ({ config, theme }) => {
1893
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1894
+ CtaSkin,
1895
+ {
1896
+ ...config,
1897
+ theme
1898
+ }
1899
+ );
1900
+ };
1901
+ var Cta_default = Cta;
1902
+
1903
+ // src/renderers/react/base/FooterBase.tsx
1904
+ var import_react12 = __toESM(require("react"));
1905
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1906
+ var FooterBase = import_react12.default.forwardRef((props, ref) => {
1907
+ const {
1908
+ logo,
1909
+ title,
1910
+ description,
1911
+ links,
1912
+ socialLinks,
1913
+ copyright,
1914
+ className,
1915
+ style,
1916
+ containerStyle,
1917
+ gridStyle,
1918
+ columnStyle,
1919
+ linkStyle,
1920
+ onLinkMouseEnter,
1921
+ onLinkMouseLeave,
1922
+ theme
1923
+ } = props;
1924
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "footer", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Container, { style: containerStyle, children: [
1925
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Box, { style: gridStyle, children: [
1926
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Box, { style: columnStyle, children: [
1927
+ logo && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("img", { src: logo, alt: title || "Logo", style: { marginBottom: theme.spacing.md }, loading: "lazy" }),
1928
+ title && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "h3", style: { fontSize: "1.25rem", marginBottom: theme.spacing.md, color: theme.colors.text }, children: title }),
1929
+ description && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "p", style: { color: theme.colors.muted, lineHeight: "1.6" }, children: description })
1930
+ ] }),
1931
+ links.map((linkGroup) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Box, { style: columnStyle, children: [
1932
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "h4", style: { marginBottom: theme.spacing.md, color: theme.colors.text }, children: linkGroup.title }),
1933
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "ul", style: { listStyle: "none", padding: 0 }, children: linkGroup.items.map((link, index) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "li", style: { marginBottom: theme.spacing.sm }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1934
+ "a",
1935
+ {
1936
+ href: link.url,
1937
+ target: link.target || "_self",
1938
+ rel: link.target === "_blank" ? "noopener noreferrer" : void 0,
1939
+ style: linkStyle,
1940
+ onMouseEnter: onLinkMouseEnter,
1941
+ onMouseLeave: onLinkMouseLeave,
1942
+ children: link.text
1943
+ }
1944
+ ) }, index)) })
1945
+ ] }, linkGroup.title))
1946
+ ] }),
1947
+ copyright && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { style: { marginTop: "4rem", paddingTop: "2rem", borderTop: `1px solid ${theme.colors.muted}20`, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Box, { as: "p", style: { color: theme.colors.muted }, children: copyright }) })
1948
+ ] }) });
1949
+ });
1950
+ FooterBase.displayName = "FooterBase";
1951
+
1952
+ // src/renderers/react/skins/FooterSkin.tsx
1953
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1954
+ var FooterSkin = (props) => {
1955
+ const { theme, ...config } = props;
1956
+ const sectionStyle = {
1957
+ padding: "4rem 0",
1958
+ backgroundColor: theme.colors.background,
1959
+ borderTop: `1px solid ${theme.colors.muted}20`,
1960
+ ...config.style
1961
+ };
1962
+ const containerStyle = {
1963
+ maxWidth: "1200px",
1964
+ margin: "0 auto",
1965
+ padding: "0 1rem",
1966
+ ...config.containerStyle
1967
+ };
1968
+ const gridStyle = {
1969
+ display: "grid",
1970
+ gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
1971
+ gap: theme.spacing.xl,
1972
+ marginBottom: theme.spacing.lg,
1973
+ ...config.gridStyle
1974
+ };
1975
+ const columnStyle = {
1976
+ ...config.columnStyle
1977
+ };
1978
+ const linkStyle = {
1979
+ color: theme.colors.muted,
1980
+ textDecoration: "none",
1981
+ transition: "color 0.2s ease",
1982
+ ...config.linkStyle
1983
+ };
1984
+ const handleMouseEnter = (e) => {
1985
+ e.currentTarget.style.color = theme.colors.primary;
1986
+ config.onLinkMouseEnter?.(e);
1987
+ };
1988
+ const handleMouseLeave = (e) => {
1989
+ e.currentTarget.style.color = theme.colors.muted;
1990
+ config.onLinkMouseLeave?.(e);
1991
+ };
1992
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1993
+ FooterBase,
1994
+ {
1995
+ ...config,
1996
+ theme,
1997
+ style: sectionStyle,
1998
+ containerStyle,
1999
+ gridStyle,
2000
+ columnStyle,
2001
+ linkStyle,
2002
+ onLinkMouseEnter: handleMouseEnter,
2003
+ onLinkMouseLeave: handleMouseLeave
2004
+ }
2005
+ );
2006
+ };
2007
+
2008
+ // src/renderers/react/Footer.tsx
2009
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2010
+ var Footer = ({ config, theme }) => {
2011
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2012
+ FooterSkin,
2013
+ {
2014
+ ...config,
2015
+ theme
2016
+ }
2017
+ );
2018
+ };
2019
+ var Footer_default = Footer;
2020
+
2021
+ // src/renderers/react/base/StatsBase.tsx
2022
+ var import_react13 = __toESM(require("react"));
2023
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2024
+ var StatsBase = import_react13.default.forwardRef((props, ref) => {
2025
+ const {
2026
+ stats,
2027
+ className,
2028
+ style,
2029
+ containerStyle,
2030
+ gridStyle,
2031
+ statStyle,
2032
+ iconStyle,
2033
+ numberContainerStyle,
2034
+ numberStyle,
2035
+ labelStyle,
2036
+ theme
2037
+ } = props;
2038
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { style: gridStyle, children: stats.map((stat) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Box, { className: stat.className, style: statStyle, children: [
2039
+ stat.icon && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { style: iconStyle, children: stat.icon }),
2040
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Box, { style: numberContainerStyle, children: [
2041
+ stat.prefix && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { as: "span", style: numberStyle, children: stat.prefix }),
2042
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { as: "span", style: numberStyle, children: stat.number }),
2043
+ stat.suffix && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { as: "span", style: numberStyle, children: stat.suffix })
2044
+ ] }),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box, { as: "p", style: labelStyle, children: stat.label })
2046
+ ] }, stat.id)) }) }) });
2047
+ });
2048
+ StatsBase.displayName = "StatsBase";
2049
+
2050
+ // src/renderers/react/skins/StatsSkin.tsx
2051
+ var import_jsx_runtime33 = require("react/jsx-runtime");
2052
+ var StatsSkin = (props) => {
2053
+ const { theme, ...config } = props;
2054
+ const sectionStyle = {
2055
+ padding: "4rem 0",
2056
+ ...config.style
2057
+ };
2058
+ const containerStyle = {
2059
+ maxWidth: "1200px",
2060
+ margin: "0 auto",
2061
+ padding: "0 1rem",
2062
+ ...config.containerStyle
2063
+ };
2064
+ const gridStyle = {
2065
+ display: "grid",
2066
+ gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
2067
+ gap: theme.spacing.xl,
2068
+ textAlign: "center",
2069
+ ...config.gridStyle
2070
+ };
2071
+ const statStyle = {
2072
+ padding: theme.spacing.lg,
2073
+ borderRadius: "0.5rem",
2074
+ backgroundColor: theme.colors.background,
2075
+ ...config.statStyle
2076
+ };
2077
+ const iconStyle = {
2078
+ fontSize: "2rem",
2079
+ marginBottom: theme.spacing.md,
2080
+ ...config.iconStyle
2081
+ };
2082
+ const numberContainerStyle = {
2083
+ marginBottom: theme.spacing.sm,
2084
+ ...config.numberContainerStyle
2085
+ };
2086
+ const numberStyle = {
2087
+ fontSize: "3rem",
2088
+ fontWeight: "bold",
2089
+ color: theme.colors.primary,
2090
+ ...config.numberStyle
2091
+ };
2092
+ const labelStyle = {
2093
+ fontSize: "1.125rem",
2094
+ color: theme.colors.muted,
2095
+ ...config.labelStyle
2096
+ };
2097
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2098
+ StatsBase,
2099
+ {
2100
+ ...config,
2101
+ theme,
2102
+ style: sectionStyle,
2103
+ containerStyle,
2104
+ gridStyle,
2105
+ statStyle,
2106
+ iconStyle,
2107
+ numberContainerStyle,
2108
+ numberStyle,
2109
+ labelStyle
2110
+ }
2111
+ );
2112
+ };
2113
+
2114
+ // src/renderers/react/Stats.tsx
2115
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2116
+ var Stats = ({ config, theme }) => {
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2118
+ StatsSkin,
2119
+ {
2120
+ ...config,
2121
+ theme
2122
+ }
2123
+ );
2124
+ };
2125
+ var Stats_default = Stats;
2126
+
2127
+ // src/renderers/react/base/FaqBase.tsx
2128
+ var import_react14 = __toESM(require("react"));
2129
+ var import_jsx_runtime35 = require("react/jsx-runtime");
2130
+ var FaqBase = import_react14.default.forwardRef((props, ref) => {
2131
+ const {
2132
+ items,
2133
+ className,
2134
+ style,
2135
+ containerStyle,
2136
+ itemStyle,
2137
+ questionStyle,
2138
+ answerStyle,
2139
+ theme
2140
+ } = props;
2141
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Box, { as: "section", ref, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Container, { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Box, { style: { maxWidth: "800px", margin: "0 auto" }, children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Box, { style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("details", { style: { padding: theme.spacing.md }, children: [
2142
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("summary", { style: questionStyle, children: item.question }),
2143
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { style: answerStyle, children: item.answer })
2144
+ ] }) }, item.id)) }) }) });
2145
+ });
2146
+ FaqBase.displayName = "FaqBase";
2147
+
2148
+ // src/renderers/react/skins/FaqSkin.tsx
2149
+ var import_jsx_runtime36 = require("react/jsx-runtime");
2150
+ var FaqSkin = (props) => {
2151
+ const { theme, ...config } = props;
2152
+ const sectionStyle = {
2153
+ padding: "4rem 0",
2154
+ ...config.style
2155
+ };
2156
+ const containerStyle = {
2157
+ maxWidth: "1200px",
2158
+ margin: "0 auto",
2159
+ padding: "0 1rem",
2160
+ ...config.containerStyle
2161
+ };
2162
+ const itemStyle = {
2163
+ marginBottom: theme.spacing.lg,
2164
+ border: `1px solid ${theme.colors.muted}20`,
2165
+ borderRadius: "0.5rem",
2166
+ overflow: "hidden",
2167
+ ...config.itemStyle
2168
+ };
2169
+ const questionStyle = {
2170
+ fontSize: "1.125rem",
2171
+ fontWeight: "bold",
2172
+ color: theme.colors.text,
2173
+ cursor: "pointer",
2174
+ listStyle: "none",
2175
+ ...config.questionStyle
2176
+ };
2177
+ const answerStyle = {
2178
+ marginTop: theme.spacing.md,
2179
+ color: theme.colors.muted,
2180
+ lineHeight: "1.6",
2181
+ ...config.answerStyle
2182
+ };
2183
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2184
+ FaqBase,
2185
+ {
2186
+ ...config,
2187
+ theme,
2188
+ style: sectionStyle,
2189
+ containerStyle,
2190
+ itemStyle,
2191
+ questionStyle,
2192
+ answerStyle
2193
+ }
2194
+ );
2195
+ };
2196
+
2197
+ // src/renderers/react/Faq.tsx
2198
+ var import_jsx_runtime37 = require("react/jsx-runtime");
2199
+ var Faq = ({ config, theme }) => {
2200
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2201
+ FaqSkin,
2202
+ {
2203
+ ...config,
2204
+ theme
2205
+ }
2206
+ );
2207
+ };
2208
+ var Faq_default = Faq;
2209
+
2210
+ // src/renderers/react/index.tsx
2211
+ var import_jsx_runtime38 = require("react/jsx-runtime");
2212
+ var createReactRenderer = () => {
2213
+ const SectionRenderer = ({ section, theme }) => {
2214
+ switch (section.type) {
2215
+ case "header":
2216
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Header_default, { config: section.config, theme }, section.id);
2217
+ case "hero":
2218
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Hero_default, { config: section.config, theme }, section.id);
2219
+ case "features":
2220
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Features_default, { config: section.config, theme }, section.id);
2221
+ case "testimonials":
2222
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Testimonials_default, { config: section.config, theme }, section.id);
2223
+ case "pricing":
2224
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Pricing_default, { config: section.config, theme }, section.id);
2225
+ case "cta":
2226
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Cta_default, { config: section.config, theme }, section.id);
2227
+ case "footer":
2228
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Footer_default, { config: section.config, theme }, section.id);
2229
+ case "stats":
2230
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Stats_default, { config: section.config, theme }, section.id);
2231
+ case "faq":
2232
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Faq_default, { config: section.config, theme }, section.id);
2233
+ default:
2234
+ console.warn(`Unknown section type: ${section.type}`);
2235
+ return null;
2236
+ }
2237
+ };
2238
+ const LandingPage = ({ config }) => {
2239
+ import_react15.default.useEffect(() => {
2240
+ const style = document.createElement("style");
2241
+ style.textContent = `
2242
+ * {
2243
+ margin: 0;
2244
+ padding: 0;
2245
+ box-sizing: border-box;
2246
+ }
2247
+ body {
2248
+ font-family: ${config.theme?.fonts?.body || "system-ui, sans-serif"};
2249
+ background-color: ${config.theme?.colors?.background || "#ffffff"};
2250
+ color: ${config.theme?.colors?.text || "#000000"};
2251
+ line-height: 1.6;
2252
+ }
2253
+ `;
2254
+ document.head.appendChild(style);
2255
+ return () => {
2256
+ document.head.removeChild(style);
2257
+ };
2258
+ }, [config]);
2259
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Box, { children: config.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(SectionRenderer, { section, theme: config.theme }, section.id)) });
2260
+ };
2261
+ return LandingPage;
2262
+ };
2263
+ // Annotate the CommonJS export names for ESM import in node:
2264
+ 0 && (module.exports = {
2265
+ createCtaSection,
2266
+ createFaqSection,
2267
+ createFeaturesSection,
2268
+ createFooterSection,
2269
+ createHeaderSection,
2270
+ createHeroSection,
2271
+ createPricingSection,
2272
+ createReactRenderer,
2273
+ createStatsSection,
2274
+ createTestimonialsSection,
2275
+ defaultTheme,
2276
+ defineLandingPage,
2277
+ landingPageSchema,
2278
+ sectionConfigSchemas,
2279
+ validateConfig,
2280
+ validateSection
2281
+ });
2282
+ //# sourceMappingURL=index.js.map