react-tailwind-email-editor 0.0.1

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.mjs ADDED
@@ -0,0 +1,4626 @@
1
+ import * as React9 from 'react';
2
+ import React9__default, { createContext, useContext, useMemo, useEffect, useCallback, useState } from 'react';
3
+ import { useEditor, useNode, Element, Editor, Frame } from '@craftjs/core';
4
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
5
+ import { ChevronDown, X, ChevronRight, Check, Circle, Table, Variable, Quote, Tag, Timer, Share2, List, PlayCircle, MousePointer2, Image, Type, Minus, ArrowUpDown, Columns, LayoutTemplate, PanelBottom, PanelTop, Layers, ChevronUp, Copy, Trash2, Settings2, Paintbrush, Move, ArrowUp, Palette, Settings, Undo2, Redo2, Eye, Code, Download } from 'lucide-react';
6
+ import { clsx } from 'clsx';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
+ import { Slot } from '@radix-ui/react-slot';
10
+ import { cva } from 'class-variance-authority';
11
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
12
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
13
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
14
+
15
+ // src/components/editor/EmailEditor.tsx
16
+ function cn(...inputs) {
17
+ return twMerge(clsx(inputs));
18
+ }
19
+ var Accordion = AccordionPrimitive.Root;
20
+ var AccordionItem = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21
+ AccordionPrimitive.Item,
22
+ {
23
+ ref,
24
+ className: cn("border-b", className),
25
+ ...props
26
+ }
27
+ ));
28
+ AccordionItem.displayName = "AccordionItem";
29
+ var AccordionTrigger = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(AccordionPrimitive.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
30
+ AccordionPrimitive.Trigger,
31
+ {
32
+ ref,
33
+ className: cn(
34
+ "flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
35
+ className
36
+ ),
37
+ ...props,
38
+ children: [
39
+ children,
40
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform duration-200" })
41
+ ]
42
+ }
43
+ ) }));
44
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
45
+ var AccordionContent = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
46
+ AccordionPrimitive.Content,
47
+ {
48
+ ref,
49
+ className: "overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
50
+ ...props,
51
+ children: /* @__PURE__ */ jsx("div", { className: cn("pb-4 pt-0", className), children })
52
+ }
53
+ ));
54
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
55
+ var defaultTheme = {
56
+ paperWidth: 600,
57
+ paperMinHeight: 800,
58
+ paperBackground: "#ffffff"
59
+ };
60
+ var EditorContext = createContext({
61
+ components: {},
62
+ theme: defaultTheme,
63
+ slots: {},
64
+ templates: [],
65
+ callbacks: {},
66
+ htmlRenderers: {},
67
+ title: "Email Editor",
68
+ showToolbar: true,
69
+ showToolbox: true,
70
+ showSettingsPanel: true
71
+ });
72
+ var useEditorConfig = () => useContext(EditorContext);
73
+ var EditorProvider = ({ children, value }) => {
74
+ const mergedTheme = useMemo(
75
+ () => ({ ...defaultTheme, ...value.theme }),
76
+ [value.theme]
77
+ );
78
+ const ctx = useMemo(
79
+ () => ({ ...value, theme: mergedTheme }),
80
+ [value, mergedTheme]
81
+ );
82
+ return /* @__PURE__ */ jsx(EditorContext.Provider, { value: ctx, children });
83
+ };
84
+ var ToolboxItem = ({ name, config }) => {
85
+ const { connectors } = useEditor();
86
+ const Component = config.component;
87
+ const element = config.createElement ? config.createElement() : /* @__PURE__ */ jsx(Component, {});
88
+ const IconComp = config.icon;
89
+ return /* @__PURE__ */ jsxs(
90
+ "div",
91
+ {
92
+ ref: (ref) => ref && connectors.create(ref, element),
93
+ className: "flex items-center gap-3 p-2.5 border rounded-lg cursor-grab hover:bg-accent hover:border-primary/50 transition-all group",
94
+ title: config.description,
95
+ children: [
96
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-9 h-9 rounded-md bg-muted flex items-center justify-center text-muted-foreground group-hover:bg-primary/10 group-hover:text-primary transition-colors", children: IconComp && /* @__PURE__ */ jsx(IconComp, { className: "h-4 w-4" }) }),
97
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
98
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground block truncate", children: config.label }),
99
+ config.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground block truncate", children: config.description })
100
+ ] })
101
+ ]
102
+ }
103
+ );
104
+ };
105
+ var Toolbox = () => {
106
+ const { components } = useEditorConfig();
107
+ const grouped = React9__default.useMemo(() => {
108
+ const map = {};
109
+ for (const [name, config] of Object.entries(components)) {
110
+ const cat = config.category || "Other";
111
+ if (!map[cat]) map[cat] = [];
112
+ map[cat].push([name, config]);
113
+ }
114
+ return map;
115
+ }, [components]);
116
+ const categoryKeys = Object.keys(grouped);
117
+ return /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsx(Accordion, { type: "multiple", defaultValue: categoryKeys, children: categoryKeys.map((category, idx) => /* @__PURE__ */ jsxs(
118
+ AccordionItem,
119
+ {
120
+ value: category,
121
+ className: idx < categoryKeys.length - 1 ? "border-b" : "border-b-0",
122
+ children: [
123
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground hover:no-underline", children: category }),
124
+ /* @__PURE__ */ jsxs(AccordionContent, { className: "pb-3", children: [
125
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: grouped[category].map(([name, config]) => /* @__PURE__ */ jsx(ToolboxItem, { name, config }, name)) }),
126
+ category === "Dynamic" && /* @__PURE__ */ jsx("div", { className: "mt-3 p-3 bg-muted/50 rounded-lg", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
127
+ "Use variables like",
128
+ " ",
129
+ /* @__PURE__ */ jsx("code", { className: "bg-primary/10 text-primary px-1 rounded", children: "{{first_name}}" }),
130
+ " ",
131
+ "for personalized emails"
132
+ ] }) })
133
+ ] })
134
+ ]
135
+ },
136
+ category
137
+ )) }) });
138
+ };
139
+ var buttonVariants = cva(
140
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
141
+ {
142
+ variants: {
143
+ variant: {
144
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
145
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
146
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
147
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
148
+ ghost: "hover:bg-accent hover:text-accent-foreground",
149
+ link: "text-primary underline-offset-4 hover:underline"
150
+ },
151
+ size: {
152
+ default: "h-10 px-4 py-2",
153
+ sm: "h-9 rounded-md px-3",
154
+ lg: "h-11 rounded-md px-8",
155
+ icon: "h-10 w-10"
156
+ }
157
+ },
158
+ defaultVariants: {
159
+ variant: "default",
160
+ size: "default"
161
+ }
162
+ }
163
+ );
164
+ var Button = React9.forwardRef(
165
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
166
+ const Comp = asChild ? Slot : "button";
167
+ return /* @__PURE__ */ jsx(
168
+ Comp,
169
+ {
170
+ className: cn(buttonVariants({ variant, size, className })),
171
+ ref,
172
+ ...props
173
+ }
174
+ );
175
+ }
176
+ );
177
+ Button.displayName = "Button";
178
+ var ScrollArea = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
179
+ ScrollAreaPrimitive.Root,
180
+ {
181
+ ref,
182
+ className: cn("relative overflow-hidden", className),
183
+ ...props,
184
+ children: [
185
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
186
+ /* @__PURE__ */ jsx(ScrollBar, {}),
187
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
188
+ ]
189
+ }
190
+ ));
191
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
192
+ var ScrollBar = React9.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx(
193
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
194
+ {
195
+ ref,
196
+ orientation,
197
+ className: cn(
198
+ "flex touch-none select-none transition-colors",
199
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
200
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
201
+ className
202
+ ),
203
+ ...props,
204
+ children: /* @__PURE__ */ jsx(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
205
+ }
206
+ ));
207
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
208
+ var SettingsPanel = () => {
209
+ const { slots } = useEditorConfig();
210
+ const { selected, actions, query } = useEditor((state) => {
211
+ var _a;
212
+ const [currentNodeId] = state.events.selected;
213
+ let selected2;
214
+ if (currentNodeId) {
215
+ selected2 = {
216
+ id: currentNodeId,
217
+ name: state.nodes[currentNodeId].data.name,
218
+ displayName: state.nodes[currentNodeId].data.displayName || state.nodes[currentNodeId].data.name,
219
+ settings: (_a = state.nodes[currentNodeId].related) == null ? void 0 : _a.settings,
220
+ isDeletable: state.nodes[currentNodeId].data.name !== "Paper",
221
+ parent: state.nodes[currentNodeId].data.parent,
222
+ props: state.nodes[currentNodeId].data.props
223
+ };
224
+ }
225
+ return { selected: selected2 };
226
+ });
227
+ const handleDuplicate = () => {
228
+ if (!selected || !selected.isDeletable) return;
229
+ const node = query.node(selected.id).get();
230
+ const parent = node.data.parent;
231
+ if (parent) {
232
+ try {
233
+ const serializedNode = query.node(selected.id).toSerializedNode();
234
+ const parentNode = query.node(parent).get();
235
+ const siblings = parentNode.data.nodes || [];
236
+ const currentIndex = siblings.indexOf(selected.id);
237
+ const newNode = query.parseSerializedNode(serializedNode).toNode((node2) => {
238
+ node2.id = `${node2.data.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
239
+ return node2;
240
+ });
241
+ actions.addNodeTree(
242
+ { rootNodeId: newNode.id, nodes: { [newNode.id]: newNode } },
243
+ parent,
244
+ currentIndex + 1
245
+ );
246
+ } catch (e) {
247
+ console.log("Duplicate error:", e);
248
+ }
249
+ }
250
+ };
251
+ const handleMoveUp = () => {
252
+ if (!selected || !selected.parent) return;
253
+ const parentNode = query.node(selected.parent).get();
254
+ const siblings = parentNode.data.nodes || [];
255
+ const currentIndex = siblings.indexOf(selected.id);
256
+ if (currentIndex > 0) {
257
+ actions.move(selected.id, selected.parent, currentIndex - 1);
258
+ }
259
+ };
260
+ const handleMoveDown = () => {
261
+ if (!selected || !selected.parent) return;
262
+ const parentNode = query.node(selected.parent).get();
263
+ const siblings = parentNode.data.nodes || [];
264
+ const currentIndex = siblings.indexOf(selected.id);
265
+ if (currentIndex < siblings.length - 1) {
266
+ actions.move(selected.id, selected.parent, currentIndex + 2);
267
+ }
268
+ };
269
+ if (slots.settingsPanel && selected) {
270
+ return React9__default.createElement(slots.settingsPanel, {
271
+ selectedId: selected.id,
272
+ selectedName: selected.displayName || selected.name,
273
+ //@ts-ignore
274
+ selectedSettings: selected.settings,
275
+ onDelete: selected.isDeletable ? () => actions.delete(selected.id) : void 0,
276
+ onDuplicate: handleDuplicate,
277
+ onMoveUp: handleMoveUp,
278
+ onMoveDown: handleMoveDown
279
+ });
280
+ }
281
+ if (!selected) {
282
+ if (slots.settingsEmptyState) {
283
+ return React9__default.createElement(slots.settingsEmptyState);
284
+ }
285
+ return /* @__PURE__ */ jsxs("div", { className: "p-6 text-center", children: [
286
+ /* @__PURE__ */ jsx("div", { className: "w-16 h-16 mx-auto mb-4 rounded-full bg-muted flex items-center justify-center", children: /* @__PURE__ */ jsx(Layers, { className: "h-8 w-8 text-muted-foreground" }) }),
287
+ /* @__PURE__ */ jsx("h3", { className: "font-medium text-foreground mb-2", children: "No Element Selected" }),
288
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Click on a component in the canvas to edit its properties" })
289
+ ] });
290
+ }
291
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col", children: [
292
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border-b bg-muted/30", children: [
293
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
294
+ /* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-full bg-primary" }),
295
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-sm", children: selected.displayName || selected.name })
296
+ ] }) }),
297
+ selected.isDeletable && /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
298
+ /* @__PURE__ */ jsxs(
299
+ Button,
300
+ {
301
+ variant: "outline",
302
+ size: "sm",
303
+ className: "flex-1 h-8 text-xs",
304
+ onClick: handleMoveUp,
305
+ title: "Move Up",
306
+ children: [
307
+ /* @__PURE__ */ jsx(ChevronUp, { className: "h-3.5 w-3.5 mr-1" }),
308
+ " Up"
309
+ ]
310
+ }
311
+ ),
312
+ /* @__PURE__ */ jsxs(
313
+ Button,
314
+ {
315
+ variant: "outline",
316
+ size: "sm",
317
+ className: "flex-1 h-8 text-xs",
318
+ onClick: handleMoveDown,
319
+ title: "Move Down",
320
+ children: [
321
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 mr-1" }),
322
+ " Down"
323
+ ]
324
+ }
325
+ ),
326
+ /* @__PURE__ */ jsxs(
327
+ Button,
328
+ {
329
+ variant: "outline",
330
+ size: "sm",
331
+ className: "flex-1 h-8 text-xs",
332
+ onClick: handleDuplicate,
333
+ title: "Duplicate",
334
+ children: [
335
+ /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5 mr-1" }),
336
+ " Copy"
337
+ ]
338
+ }
339
+ ),
340
+ /* @__PURE__ */ jsx(
341
+ Button,
342
+ {
343
+ variant: "destructive",
344
+ size: "sm",
345
+ className: "h-8 w-8 p-0",
346
+ onClick: () => actions.delete(selected.id),
347
+ title: "Delete",
348
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
349
+ }
350
+ )
351
+ ] })
352
+ ] }),
353
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-4", children: selected.settings ? /* @__PURE__ */ jsx(Accordion, { type: "multiple", defaultValue: ["content"], children: /* @__PURE__ */ jsxs(AccordionItem, { value: "content", className: "border-b", children: [
354
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "py-3 text-sm hover:no-underline", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
355
+ /* @__PURE__ */ jsx(Settings2, { className: "h-4 w-4 text-muted-foreground" }),
356
+ /* @__PURE__ */ jsx("span", { children: "Properties" })
357
+ ] }) }),
358
+ /* @__PURE__ */ jsx(AccordionContent, { className: "pb-4", children: React9__default.createElement(selected.settings) })
359
+ ] }) }) : /* @__PURE__ */ jsxs("div", { className: "text-center text-muted-foreground text-sm py-8", children: [
360
+ /* @__PURE__ */ jsx(Paintbrush, { className: "h-8 w-8 mx-auto mb-2 opacity-50" }),
361
+ /* @__PURE__ */ jsx("p", { children: "No editable properties" })
362
+ ] }) }) }),
363
+ /* @__PURE__ */ jsx("div", { className: "p-3 border-t bg-muted/20 text-xs text-muted-foreground", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
364
+ /* @__PURE__ */ jsxs("span", { children: [
365
+ "Component: ",
366
+ selected.name
367
+ ] }),
368
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px]", children: selected.id.slice(0, 8) })
369
+ ] }) })
370
+ ] });
371
+ };
372
+ var Paper = ({ children, background }) => {
373
+ const { connectors: { connect } } = useNode();
374
+ const { theme } = useEditorConfig();
375
+ const bg = background || theme.paperBackground || "#ffffff";
376
+ return /* @__PURE__ */ jsx(
377
+ "div",
378
+ {
379
+ ref: (ref) => connect(ref),
380
+ style: {
381
+ width: `${theme.paperWidth || 600}px`,
382
+ minHeight: `${theme.paperMinHeight || 800}px`,
383
+ margin: "0 auto",
384
+ backgroundColor: bg,
385
+ boxShadow: "0 4px 20px rgba(0, 0, 0, 0.15)",
386
+ position: "relative"
387
+ },
388
+ children
389
+ }
390
+ );
391
+ };
392
+ var PaperSettings = () => {
393
+ const { actions: { setProp }, background } = useNode((node) => ({
394
+ background: node.data.props.background
395
+ }));
396
+ return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { children: [
397
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Email Background" }),
398
+ /* @__PURE__ */ jsx(
399
+ "input",
400
+ {
401
+ type: "color",
402
+ value: background || "#ffffff",
403
+ onChange: (e) => setProp((props) => props.background = e.target.value),
404
+ className: "w-full h-10 rounded border cursor-pointer"
405
+ }
406
+ )
407
+ ] }) });
408
+ };
409
+ Paper.craft = {
410
+ props: {
411
+ background: "#ffffff"
412
+ },
413
+ related: {
414
+ settings: PaperSettings
415
+ }
416
+ };
417
+ var RenderNode = ({ render }) => {
418
+ const { id } = useNode();
419
+ const { actions, query, isActive } = useEditor((_, query2) => ({
420
+ isActive: query2.getEvent("selected").contains(id)
421
+ }));
422
+ const {
423
+ isHover,
424
+ dom,
425
+ name,
426
+ moveable,
427
+ deletable,
428
+ connectors: { drag },
429
+ parent
430
+ } = useNode((node) => ({
431
+ isHover: node.events.hovered,
432
+ dom: node.dom,
433
+ name: node.data.custom.displayName || node.data.displayName,
434
+ moveable: query.node(node.id).isDraggable(),
435
+ deletable: query.node(node.id).isDeletable(),
436
+ parent: node.data.parent
437
+ }));
438
+ useEffect(() => {
439
+ if (dom) {
440
+ if (isActive || isHover) {
441
+ dom.classList.add("component-selected");
442
+ } else {
443
+ dom.classList.remove("component-selected");
444
+ }
445
+ }
446
+ }, [dom, isActive, isHover]);
447
+ const getPos = useCallback((dom2) => {
448
+ const { top, left, bottom } = dom2 ? dom2.getBoundingClientRect() : { top: 0, left: 0, bottom: 0 };
449
+ return {
450
+ top: `${top > 0 ? top : bottom}px`,
451
+ left: `${left}px`
452
+ };
453
+ }, []);
454
+ const scroll = useCallback(() => {
455
+ const currentDOM = dom;
456
+ if (!currentDOM) return;
457
+ const { top, left } = getPos(currentDOM);
458
+ }, [dom, getPos]);
459
+ useEffect(() => {
460
+ var _a;
461
+ (_a = document.querySelector(".craftjs-renderer")) == null ? void 0 : _a.addEventListener("scroll", scroll);
462
+ return () => {
463
+ var _a2;
464
+ (_a2 = document.querySelector(".craftjs-renderer")) == null ? void 0 : _a2.removeEventListener("scroll", scroll);
465
+ };
466
+ }, [scroll]);
467
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
468
+ isHover || isActive ? /* @__PURE__ */ jsxs(
469
+ "div",
470
+ {
471
+ className: "absolute -top-7 left-0 bg-primary text-primary-foreground text-xs px-2 py-1 rounded flex items-center gap-1 z-50",
472
+ style: {
473
+ pointerEvents: "auto"
474
+ },
475
+ children: [
476
+ moveable && /* @__PURE__ */ jsx(
477
+ "span",
478
+ {
479
+ ref: (ref) => ref && drag(ref),
480
+ className: "cursor-grab",
481
+ children: /* @__PURE__ */ jsx(Move, { className: "h-3 w-3" })
482
+ }
483
+ ),
484
+ /* @__PURE__ */ jsx("span", { children: name }),
485
+ parent && /* @__PURE__ */ jsx(
486
+ "button",
487
+ {
488
+ onClick: () => actions.selectNode(parent),
489
+ className: "ml-1 hover:bg-primary-foreground/20 rounded p-0.5",
490
+ children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3" })
491
+ }
492
+ )
493
+ ]
494
+ }
495
+ ) : null,
496
+ render
497
+ ] });
498
+ };
499
+ var Container = ({ background = "#ffffff", padding = 20, children }) => {
500
+ const { connectors: { connect, drag } } = useNode();
501
+ return /* @__PURE__ */ jsx(
502
+ "div",
503
+ {
504
+ ref: (ref) => connect(drag(ref)),
505
+ style: {
506
+ background,
507
+ padding: `${padding}px`,
508
+ minHeight: "50px",
509
+ width: "100%"
510
+ },
511
+ children
512
+ }
513
+ );
514
+ };
515
+ var ContainerSettings = () => {
516
+ const { actions: { setProp }, background, padding } = useNode((node) => ({
517
+ background: node.data.props.background,
518
+ padding: node.data.props.padding
519
+ }));
520
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
521
+ /* @__PURE__ */ jsxs("div", { children: [
522
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
523
+ /* @__PURE__ */ jsx(
524
+ "input",
525
+ {
526
+ type: "color",
527
+ value: background || "#ffffff",
528
+ onChange: (e) => setProp((props) => props.background = e.target.value),
529
+ className: "w-full h-10 rounded border cursor-pointer"
530
+ }
531
+ )
532
+ ] }),
533
+ /* @__PURE__ */ jsxs("div", { children: [
534
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
535
+ /* @__PURE__ */ jsx(
536
+ "input",
537
+ {
538
+ type: "range",
539
+ min: 0,
540
+ max: 60,
541
+ value: padding || 20,
542
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
543
+ className: "w-full"
544
+ }
545
+ ),
546
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
547
+ padding,
548
+ "px"
549
+ ] })
550
+ ] })
551
+ ] });
552
+ };
553
+ Container.craft = {
554
+ props: {
555
+ background: "#ffffff",
556
+ padding: 20
557
+ },
558
+ related: {
559
+ settings: ContainerSettings
560
+ }
561
+ };
562
+ var EmailHeader = ({
563
+ logoUrl = "",
564
+ companyName = "Your Company",
565
+ backgroundColor = "#1a1a2e",
566
+ textColor = "#ffffff",
567
+ padding = 24
568
+ }) => {
569
+ const { connectors: { connect, drag } } = useNode();
570
+ return /* @__PURE__ */ jsxs(
571
+ "div",
572
+ {
573
+ ref: (ref) => connect(drag(ref)),
574
+ style: {
575
+ backgroundColor,
576
+ padding: `${padding}px`,
577
+ textAlign: "center"
578
+ },
579
+ children: [
580
+ logoUrl && /* @__PURE__ */ jsx(
581
+ "img",
582
+ {
583
+ src: logoUrl,
584
+ alt: "Logo",
585
+ style: { maxHeight: "60px", marginBottom: "12px" }
586
+ }
587
+ ),
588
+ /* @__PURE__ */ jsx(
589
+ "h1",
590
+ {
591
+ style: {
592
+ color: textColor,
593
+ fontSize: "24px",
594
+ fontWeight: "bold",
595
+ margin: 0,
596
+ fontFamily: "Arial, sans-serif"
597
+ },
598
+ children: companyName
599
+ }
600
+ )
601
+ ]
602
+ }
603
+ );
604
+ };
605
+ var EmailHeaderSettings = () => {
606
+ const { actions: { setProp }, logoUrl, companyName, backgroundColor, textColor, padding } = useNode((node) => ({
607
+ logoUrl: node.data.props.logoUrl,
608
+ companyName: node.data.props.companyName,
609
+ backgroundColor: node.data.props.backgroundColor,
610
+ textColor: node.data.props.textColor,
611
+ padding: node.data.props.padding
612
+ }));
613
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
614
+ /* @__PURE__ */ jsxs("div", { children: [
615
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Company Name" }),
616
+ /* @__PURE__ */ jsx(
617
+ "input",
618
+ {
619
+ type: "text",
620
+ value: companyName || "",
621
+ onChange: (e) => setProp((props) => props.companyName = e.target.value),
622
+ className: "w-full px-3 py-2 border rounded-md text-sm"
623
+ }
624
+ )
625
+ ] }),
626
+ /* @__PURE__ */ jsxs("div", { children: [
627
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Logo URL" }),
628
+ /* @__PURE__ */ jsx(
629
+ "input",
630
+ {
631
+ type: "text",
632
+ value: logoUrl || "",
633
+ onChange: (e) => setProp((props) => props.logoUrl = e.target.value),
634
+ className: "w-full px-3 py-2 border rounded-md text-sm",
635
+ placeholder: "https://example.com/logo.png"
636
+ }
637
+ )
638
+ ] }),
639
+ /* @__PURE__ */ jsxs("div", { children: [
640
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
641
+ /* @__PURE__ */ jsx(
642
+ "input",
643
+ {
644
+ type: "color",
645
+ value: backgroundColor || "#1a1a2e",
646
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
647
+ className: "w-full h-10 rounded border cursor-pointer"
648
+ }
649
+ )
650
+ ] }),
651
+ /* @__PURE__ */ jsxs("div", { children: [
652
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Color" }),
653
+ /* @__PURE__ */ jsx(
654
+ "input",
655
+ {
656
+ type: "color",
657
+ value: textColor || "#ffffff",
658
+ onChange: (e) => setProp((props) => props.textColor = e.target.value),
659
+ className: "w-full h-10 rounded border cursor-pointer"
660
+ }
661
+ )
662
+ ] }),
663
+ /* @__PURE__ */ jsxs("div", { children: [
664
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
665
+ /* @__PURE__ */ jsx(
666
+ "input",
667
+ {
668
+ type: "range",
669
+ min: 0,
670
+ max: 60,
671
+ value: padding || 24,
672
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
673
+ className: "w-full"
674
+ }
675
+ ),
676
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
677
+ padding,
678
+ "px"
679
+ ] })
680
+ ] })
681
+ ] });
682
+ };
683
+ EmailHeader.craft = {
684
+ props: {
685
+ logoUrl: "",
686
+ companyName: "Your Company",
687
+ backgroundColor: "#1a1a2e",
688
+ textColor: "#ffffff",
689
+ padding: 24
690
+ },
691
+ related: {
692
+ settings: EmailHeaderSettings
693
+ }
694
+ };
695
+ var EmailFooter = ({
696
+ companyName = "Your Company",
697
+ address = "123 Business St, City, Country",
698
+ email = "info@company.com",
699
+ phone = "+1 234 567 890",
700
+ backgroundColor = "#f5f5f5",
701
+ textColor = "#666666",
702
+ padding = 24
703
+ }) => {
704
+ const { connectors: { connect, drag } } = useNode();
705
+ return /* @__PURE__ */ jsxs(
706
+ "div",
707
+ {
708
+ ref: (ref) => connect(drag(ref)),
709
+ style: {
710
+ backgroundColor,
711
+ padding: `${padding}px`,
712
+ textAlign: "center",
713
+ fontFamily: "Arial, sans-serif"
714
+ },
715
+ children: [
716
+ /* @__PURE__ */ jsx("p", { style: { color: textColor, fontSize: "14px", margin: "0 0 8px 0", fontWeight: "bold" }, children: companyName }),
717
+ /* @__PURE__ */ jsx("p", { style: { color: textColor, fontSize: "12px", margin: "0 0 4px 0" }, children: address }),
718
+ /* @__PURE__ */ jsxs("p", { style: { color: textColor, fontSize: "12px", margin: "0 0 4px 0" }, children: [
719
+ "Email: ",
720
+ email,
721
+ " | Phone: ",
722
+ phone
723
+ ] }),
724
+ /* @__PURE__ */ jsxs("p", { style: { color: textColor, fontSize: "11px", margin: "12px 0 0 0", opacity: 0.7 }, children: [
725
+ "\xA9 ",
726
+ (/* @__PURE__ */ new Date()).getFullYear(),
727
+ " ",
728
+ companyName,
729
+ ". All rights reserved."
730
+ ] })
731
+ ]
732
+ }
733
+ );
734
+ };
735
+ var EmailFooterSettings = () => {
736
+ const { actions: { setProp }, companyName, address, email, phone, backgroundColor, textColor, padding } = useNode((node) => ({
737
+ companyName: node.data.props.companyName,
738
+ address: node.data.props.address,
739
+ email: node.data.props.email,
740
+ phone: node.data.props.phone,
741
+ backgroundColor: node.data.props.backgroundColor,
742
+ textColor: node.data.props.textColor,
743
+ padding: node.data.props.padding
744
+ }));
745
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
746
+ /* @__PURE__ */ jsxs("div", { children: [
747
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Company Name" }),
748
+ /* @__PURE__ */ jsx(
749
+ "input",
750
+ {
751
+ type: "text",
752
+ value: companyName || "",
753
+ onChange: (e) => setProp((props) => props.companyName = e.target.value),
754
+ className: "w-full px-3 py-2 border rounded-md text-sm"
755
+ }
756
+ )
757
+ ] }),
758
+ /* @__PURE__ */ jsxs("div", { children: [
759
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Address" }),
760
+ /* @__PURE__ */ jsx(
761
+ "input",
762
+ {
763
+ type: "text",
764
+ value: address || "",
765
+ onChange: (e) => setProp((props) => props.address = e.target.value),
766
+ className: "w-full px-3 py-2 border rounded-md text-sm"
767
+ }
768
+ )
769
+ ] }),
770
+ /* @__PURE__ */ jsxs("div", { children: [
771
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Email" }),
772
+ /* @__PURE__ */ jsx(
773
+ "input",
774
+ {
775
+ type: "email",
776
+ value: email || "",
777
+ onChange: (e) => setProp((props) => props.email = e.target.value),
778
+ className: "w-full px-3 py-2 border rounded-md text-sm"
779
+ }
780
+ )
781
+ ] }),
782
+ /* @__PURE__ */ jsxs("div", { children: [
783
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Phone" }),
784
+ /* @__PURE__ */ jsx(
785
+ "input",
786
+ {
787
+ type: "text",
788
+ value: phone || "",
789
+ onChange: (e) => setProp((props) => props.phone = e.target.value),
790
+ className: "w-full px-3 py-2 border rounded-md text-sm"
791
+ }
792
+ )
793
+ ] }),
794
+ /* @__PURE__ */ jsxs("div", { children: [
795
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
796
+ /* @__PURE__ */ jsx(
797
+ "input",
798
+ {
799
+ type: "color",
800
+ value: backgroundColor || "#f5f5f5",
801
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
802
+ className: "w-full h-10 rounded border cursor-pointer"
803
+ }
804
+ )
805
+ ] }),
806
+ /* @__PURE__ */ jsxs("div", { children: [
807
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Color" }),
808
+ /* @__PURE__ */ jsx(
809
+ "input",
810
+ {
811
+ type: "color",
812
+ value: textColor || "#666666",
813
+ onChange: (e) => setProp((props) => props.textColor = e.target.value),
814
+ className: "w-full h-10 rounded border cursor-pointer"
815
+ }
816
+ )
817
+ ] }),
818
+ /* @__PURE__ */ jsxs("div", { children: [
819
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
820
+ /* @__PURE__ */ jsx(
821
+ "input",
822
+ {
823
+ type: "range",
824
+ min: 0,
825
+ max: 60,
826
+ value: padding || 24,
827
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
828
+ className: "w-full"
829
+ }
830
+ ),
831
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
832
+ padding,
833
+ "px"
834
+ ] })
835
+ ] })
836
+ ] });
837
+ };
838
+ EmailFooter.craft = {
839
+ props: {
840
+ companyName: "Your Company",
841
+ address: "123 Business St, City, Country",
842
+ email: "info@company.com",
843
+ phone: "+1 234 567 890",
844
+ backgroundColor: "#f5f5f5",
845
+ textColor: "#666666",
846
+ padding: 24
847
+ },
848
+ related: {
849
+ settings: EmailFooterSettings
850
+ }
851
+ };
852
+ var EmailButton = ({
853
+ text = "Click Here",
854
+ href = "#",
855
+ backgroundColor = "#0066cc",
856
+ textColor = "#ffffff",
857
+ borderRadius = 6,
858
+ paddingX = 24,
859
+ paddingY = 12,
860
+ fontSize = 16,
861
+ align = "center"
862
+ }) => {
863
+ const { connectors: { connect, drag } } = useNode();
864
+ return /* @__PURE__ */ jsx(
865
+ "div",
866
+ {
867
+ ref: (ref) => connect(drag(ref)),
868
+ style: {
869
+ textAlign: align,
870
+ padding: "10px 0"
871
+ },
872
+ children: /* @__PURE__ */ jsx(
873
+ "a",
874
+ {
875
+ href,
876
+ style: {
877
+ display: "inline-block",
878
+ backgroundColor,
879
+ color: textColor,
880
+ padding: `${paddingY}px ${paddingX}px`,
881
+ borderRadius: `${borderRadius}px`,
882
+ textDecoration: "none",
883
+ fontSize: `${fontSize}px`,
884
+ fontWeight: "bold",
885
+ fontFamily: "Arial, sans-serif"
886
+ },
887
+ children: text
888
+ }
889
+ )
890
+ }
891
+ );
892
+ };
893
+ var EmailButtonSettings = () => {
894
+ const { actions: { setProp }, text, href, backgroundColor, textColor, borderRadius, paddingX, paddingY, fontSize, align } = useNode((node) => ({
895
+ text: node.data.props.text,
896
+ href: node.data.props.href,
897
+ backgroundColor: node.data.props.backgroundColor,
898
+ textColor: node.data.props.textColor,
899
+ borderRadius: node.data.props.borderRadius,
900
+ paddingX: node.data.props.paddingX,
901
+ paddingY: node.data.props.paddingY,
902
+ fontSize: node.data.props.fontSize,
903
+ align: node.data.props.align
904
+ }));
905
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
906
+ /* @__PURE__ */ jsxs("div", { children: [
907
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Button Text" }),
908
+ /* @__PURE__ */ jsx(
909
+ "input",
910
+ {
911
+ type: "text",
912
+ value: text || "",
913
+ onChange: (e) => setProp((props) => props.text = e.target.value),
914
+ className: "w-full px-3 py-2 border rounded-md text-sm"
915
+ }
916
+ )
917
+ ] }),
918
+ /* @__PURE__ */ jsxs("div", { children: [
919
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Link URL" }),
920
+ /* @__PURE__ */ jsx(
921
+ "input",
922
+ {
923
+ type: "text",
924
+ value: href || "",
925
+ onChange: (e) => setProp((props) => props.href = e.target.value),
926
+ className: "w-full px-3 py-2 border rounded-md text-sm"
927
+ }
928
+ )
929
+ ] }),
930
+ /* @__PURE__ */ jsxs("div", { children: [
931
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alignment" }),
932
+ /* @__PURE__ */ jsxs(
933
+ "select",
934
+ {
935
+ value: align || "center",
936
+ onChange: (e) => setProp((props) => props.align = e.target.value),
937
+ className: "w-full px-3 py-2 border rounded-md text-sm",
938
+ children: [
939
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
940
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Center" }),
941
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
942
+ ]
943
+ }
944
+ )
945
+ ] }),
946
+ /* @__PURE__ */ jsxs("div", { children: [
947
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
948
+ /* @__PURE__ */ jsx(
949
+ "input",
950
+ {
951
+ type: "color",
952
+ value: backgroundColor || "#0066cc",
953
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
954
+ className: "w-full h-10 rounded border cursor-pointer"
955
+ }
956
+ )
957
+ ] }),
958
+ /* @__PURE__ */ jsxs("div", { children: [
959
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Color" }),
960
+ /* @__PURE__ */ jsx(
961
+ "input",
962
+ {
963
+ type: "color",
964
+ value: textColor || "#ffffff",
965
+ onChange: (e) => setProp((props) => props.textColor = e.target.value),
966
+ className: "w-full h-10 rounded border cursor-pointer"
967
+ }
968
+ )
969
+ ] }),
970
+ /* @__PURE__ */ jsxs("div", { children: [
971
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Border Radius" }),
972
+ /* @__PURE__ */ jsx(
973
+ "input",
974
+ {
975
+ type: "range",
976
+ min: 0,
977
+ max: 30,
978
+ value: borderRadius || 6,
979
+ onChange: (e) => setProp((props) => props.borderRadius = parseInt(e.target.value)),
980
+ className: "w-full"
981
+ }
982
+ ),
983
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
984
+ borderRadius,
985
+ "px"
986
+ ] })
987
+ ] }),
988
+ /* @__PURE__ */ jsxs("div", { children: [
989
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Font Size" }),
990
+ /* @__PURE__ */ jsx(
991
+ "input",
992
+ {
993
+ type: "range",
994
+ min: 12,
995
+ max: 24,
996
+ value: fontSize || 16,
997
+ onChange: (e) => setProp((props) => props.fontSize = parseInt(e.target.value)),
998
+ className: "w-full"
999
+ }
1000
+ ),
1001
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1002
+ fontSize,
1003
+ "px"
1004
+ ] })
1005
+ ] })
1006
+ ] });
1007
+ };
1008
+ EmailButton.craft = {
1009
+ props: {
1010
+ text: "Click Here",
1011
+ href: "#",
1012
+ backgroundColor: "#0066cc",
1013
+ textColor: "#ffffff",
1014
+ borderRadius: 6,
1015
+ paddingX: 24,
1016
+ paddingY: 12,
1017
+ fontSize: 16,
1018
+ align: "center"
1019
+ },
1020
+ related: {
1021
+ settings: EmailButtonSettings
1022
+ }
1023
+ };
1024
+ var TextBlock = ({
1025
+ text = "Enter your text here...",
1026
+ fontSize = 14,
1027
+ fontWeight = "normal",
1028
+ color = "#333333",
1029
+ align = "left",
1030
+ padding = 10,
1031
+ lineHeight = 1.6
1032
+ }) => {
1033
+ const { connectors: { connect, drag } } = useNode();
1034
+ return /* @__PURE__ */ jsx(
1035
+ "div",
1036
+ {
1037
+ ref: (ref) => connect(drag(ref)),
1038
+ style: {
1039
+ padding: `${padding}px`
1040
+ },
1041
+ children: /* @__PURE__ */ jsx(
1042
+ "p",
1043
+ {
1044
+ style: {
1045
+ fontSize: `${fontSize}px`,
1046
+ fontWeight,
1047
+ color,
1048
+ textAlign: align,
1049
+ lineHeight,
1050
+ margin: 0,
1051
+ fontFamily: "Arial, sans-serif"
1052
+ },
1053
+ children: text
1054
+ }
1055
+ )
1056
+ }
1057
+ );
1058
+ };
1059
+ var TextBlockSettings = () => {
1060
+ const { actions: { setProp }, text, fontSize, fontWeight, color, align, padding, lineHeight } = useNode((node) => ({
1061
+ text: node.data.props.text,
1062
+ fontSize: node.data.props.fontSize,
1063
+ fontWeight: node.data.props.fontWeight,
1064
+ color: node.data.props.color,
1065
+ align: node.data.props.align,
1066
+ padding: node.data.props.padding,
1067
+ lineHeight: node.data.props.lineHeight
1068
+ }));
1069
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1070
+ /* @__PURE__ */ jsxs("div", { children: [
1071
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Content" }),
1072
+ /* @__PURE__ */ jsx(
1073
+ "textarea",
1074
+ {
1075
+ value: text || "",
1076
+ onChange: (e) => setProp((props) => props.text = e.target.value),
1077
+ className: "w-full px-3 py-2 border rounded-md text-sm min-h-[80px]"
1078
+ }
1079
+ )
1080
+ ] }),
1081
+ /* @__PURE__ */ jsxs("div", { children: [
1082
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Font Size" }),
1083
+ /* @__PURE__ */ jsx(
1084
+ "input",
1085
+ {
1086
+ type: "range",
1087
+ min: 10,
1088
+ max: 32,
1089
+ value: fontSize || 14,
1090
+ onChange: (e) => setProp((props) => props.fontSize = parseInt(e.target.value)),
1091
+ className: "w-full"
1092
+ }
1093
+ ),
1094
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1095
+ fontSize,
1096
+ "px"
1097
+ ] })
1098
+ ] }),
1099
+ /* @__PURE__ */ jsxs("div", { children: [
1100
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Font Weight" }),
1101
+ /* @__PURE__ */ jsxs(
1102
+ "select",
1103
+ {
1104
+ value: fontWeight || "normal",
1105
+ onChange: (e) => setProp((props) => props.fontWeight = e.target.value),
1106
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1107
+ children: [
1108
+ /* @__PURE__ */ jsx("option", { value: "normal", children: "Normal" }),
1109
+ /* @__PURE__ */ jsx("option", { value: "bold", children: "Bold" })
1110
+ ]
1111
+ }
1112
+ )
1113
+ ] }),
1114
+ /* @__PURE__ */ jsxs("div", { children: [
1115
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Color" }),
1116
+ /* @__PURE__ */ jsx(
1117
+ "input",
1118
+ {
1119
+ type: "color",
1120
+ value: color || "#333333",
1121
+ onChange: (e) => setProp((props) => props.color = e.target.value),
1122
+ className: "w-full h-10 rounded border cursor-pointer"
1123
+ }
1124
+ )
1125
+ ] }),
1126
+ /* @__PURE__ */ jsxs("div", { children: [
1127
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alignment" }),
1128
+ /* @__PURE__ */ jsxs(
1129
+ "select",
1130
+ {
1131
+ value: align || "left",
1132
+ onChange: (e) => setProp((props) => props.align = e.target.value),
1133
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1134
+ children: [
1135
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
1136
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Center" }),
1137
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
1138
+ ]
1139
+ }
1140
+ )
1141
+ ] }),
1142
+ /* @__PURE__ */ jsxs("div", { children: [
1143
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
1144
+ /* @__PURE__ */ jsx(
1145
+ "input",
1146
+ {
1147
+ type: "range",
1148
+ min: 0,
1149
+ max: 40,
1150
+ value: padding || 10,
1151
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
1152
+ className: "w-full"
1153
+ }
1154
+ ),
1155
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1156
+ padding,
1157
+ "px"
1158
+ ] })
1159
+ ] }),
1160
+ /* @__PURE__ */ jsxs("div", { children: [
1161
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Line Height" }),
1162
+ /* @__PURE__ */ jsx(
1163
+ "input",
1164
+ {
1165
+ type: "range",
1166
+ min: 1,
1167
+ max: 2.5,
1168
+ step: 0.1,
1169
+ value: lineHeight || 1.6,
1170
+ onChange: (e) => setProp((props) => props.lineHeight = parseFloat(e.target.value)),
1171
+ className: "w-full"
1172
+ }
1173
+ ),
1174
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: lineHeight })
1175
+ ] })
1176
+ ] });
1177
+ };
1178
+ TextBlock.craft = {
1179
+ props: {
1180
+ text: "Enter your text here...",
1181
+ fontSize: 14,
1182
+ fontWeight: "normal",
1183
+ color: "#333333",
1184
+ align: "left",
1185
+ padding: 10,
1186
+ lineHeight: 1.6
1187
+ },
1188
+ related: {
1189
+ settings: TextBlockSettings
1190
+ }
1191
+ };
1192
+ var ImageBlock = ({
1193
+ src = "https://via.placeholder.com/400x200",
1194
+ alt = "Image",
1195
+ width = "100%",
1196
+ align = "center",
1197
+ padding = 10,
1198
+ borderRadius = 0
1199
+ }) => {
1200
+ const { connectors: { connect, drag } } = useNode();
1201
+ return /* @__PURE__ */ jsx(
1202
+ "div",
1203
+ {
1204
+ ref: (ref) => connect(drag(ref)),
1205
+ style: {
1206
+ textAlign: align,
1207
+ padding: `${padding}px`
1208
+ },
1209
+ children: /* @__PURE__ */ jsx(
1210
+ "img",
1211
+ {
1212
+ src,
1213
+ alt,
1214
+ style: {
1215
+ width,
1216
+ maxWidth: "100%",
1217
+ borderRadius: `${borderRadius}px`,
1218
+ display: "inline-block"
1219
+ }
1220
+ }
1221
+ )
1222
+ }
1223
+ );
1224
+ };
1225
+ var ImageBlockSettings = () => {
1226
+ const { actions: { setProp }, src, alt, width, align, padding, borderRadius } = useNode((node) => ({
1227
+ src: node.data.props.src,
1228
+ alt: node.data.props.alt,
1229
+ width: node.data.props.width,
1230
+ align: node.data.props.align,
1231
+ padding: node.data.props.padding,
1232
+ borderRadius: node.data.props.borderRadius
1233
+ }));
1234
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1235
+ /* @__PURE__ */ jsxs("div", { children: [
1236
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Image URL" }),
1237
+ /* @__PURE__ */ jsx(
1238
+ "input",
1239
+ {
1240
+ type: "text",
1241
+ value: src || "",
1242
+ onChange: (e) => setProp((props) => props.src = e.target.value),
1243
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1244
+ placeholder: "https://example.com/image.png"
1245
+ }
1246
+ )
1247
+ ] }),
1248
+ /* @__PURE__ */ jsxs("div", { children: [
1249
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alt Text" }),
1250
+ /* @__PURE__ */ jsx(
1251
+ "input",
1252
+ {
1253
+ type: "text",
1254
+ value: alt || "",
1255
+ onChange: (e) => setProp((props) => props.alt = e.target.value),
1256
+ className: "w-full px-3 py-2 border rounded-md text-sm"
1257
+ }
1258
+ )
1259
+ ] }),
1260
+ /* @__PURE__ */ jsxs("div", { children: [
1261
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Width" }),
1262
+ /* @__PURE__ */ jsx(
1263
+ "input",
1264
+ {
1265
+ type: "text",
1266
+ value: width || "100%",
1267
+ onChange: (e) => setProp((props) => props.width = e.target.value),
1268
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1269
+ placeholder: "100% or 300px"
1270
+ }
1271
+ )
1272
+ ] }),
1273
+ /* @__PURE__ */ jsxs("div", { children: [
1274
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alignment" }),
1275
+ /* @__PURE__ */ jsxs(
1276
+ "select",
1277
+ {
1278
+ value: align || "center",
1279
+ onChange: (e) => setProp((props) => props.align = e.target.value),
1280
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1281
+ children: [
1282
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
1283
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Center" }),
1284
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
1285
+ ]
1286
+ }
1287
+ )
1288
+ ] }),
1289
+ /* @__PURE__ */ jsxs("div", { children: [
1290
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
1291
+ /* @__PURE__ */ jsx(
1292
+ "input",
1293
+ {
1294
+ type: "range",
1295
+ min: 0,
1296
+ max: 40,
1297
+ value: padding || 10,
1298
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
1299
+ className: "w-full"
1300
+ }
1301
+ ),
1302
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1303
+ padding,
1304
+ "px"
1305
+ ] })
1306
+ ] }),
1307
+ /* @__PURE__ */ jsxs("div", { children: [
1308
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Border Radius" }),
1309
+ /* @__PURE__ */ jsx(
1310
+ "input",
1311
+ {
1312
+ type: "range",
1313
+ min: 0,
1314
+ max: 30,
1315
+ value: borderRadius || 0,
1316
+ onChange: (e) => setProp((props) => props.borderRadius = parseInt(e.target.value)),
1317
+ className: "w-full"
1318
+ }
1319
+ ),
1320
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1321
+ borderRadius,
1322
+ "px"
1323
+ ] })
1324
+ ] })
1325
+ ] });
1326
+ };
1327
+ ImageBlock.craft = {
1328
+ props: {
1329
+ src: "https://via.placeholder.com/400x200",
1330
+ alt: "Image",
1331
+ width: "100%",
1332
+ align: "center",
1333
+ padding: 10,
1334
+ borderRadius: 0
1335
+ },
1336
+ related: {
1337
+ settings: ImageBlockSettings
1338
+ }
1339
+ };
1340
+ var Divider = ({
1341
+ color = "#e0e0e0",
1342
+ thickness = 1,
1343
+ margin = 20,
1344
+ width = "100%"
1345
+ }) => {
1346
+ const { connectors: { connect, drag } } = useNode();
1347
+ return /* @__PURE__ */ jsx(
1348
+ "div",
1349
+ {
1350
+ ref: (ref) => connect(drag(ref)),
1351
+ style: {
1352
+ padding: `${margin}px 0`,
1353
+ textAlign: "center"
1354
+ },
1355
+ children: /* @__PURE__ */ jsx(
1356
+ "hr",
1357
+ {
1358
+ style: {
1359
+ border: "none",
1360
+ borderTop: `${thickness}px solid ${color}`,
1361
+ width,
1362
+ margin: "0 auto"
1363
+ }
1364
+ }
1365
+ )
1366
+ }
1367
+ );
1368
+ };
1369
+ var DividerSettings = () => {
1370
+ const { actions: { setProp }, color, thickness, margin, width } = useNode((node) => ({
1371
+ color: node.data.props.color,
1372
+ thickness: node.data.props.thickness,
1373
+ margin: node.data.props.margin,
1374
+ width: node.data.props.width
1375
+ }));
1376
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1377
+ /* @__PURE__ */ jsxs("div", { children: [
1378
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Color" }),
1379
+ /* @__PURE__ */ jsx(
1380
+ "input",
1381
+ {
1382
+ type: "color",
1383
+ value: color || "#e0e0e0",
1384
+ onChange: (e) => setProp((props) => props.color = e.target.value),
1385
+ className: "w-full h-10 rounded border cursor-pointer"
1386
+ }
1387
+ )
1388
+ ] }),
1389
+ /* @__PURE__ */ jsxs("div", { children: [
1390
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Thickness" }),
1391
+ /* @__PURE__ */ jsx(
1392
+ "input",
1393
+ {
1394
+ type: "range",
1395
+ min: 1,
1396
+ max: 10,
1397
+ value: thickness || 1,
1398
+ onChange: (e) => setProp((props) => props.thickness = parseInt(e.target.value)),
1399
+ className: "w-full"
1400
+ }
1401
+ ),
1402
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1403
+ thickness,
1404
+ "px"
1405
+ ] })
1406
+ ] }),
1407
+ /* @__PURE__ */ jsxs("div", { children: [
1408
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Margin (Top/Bottom)" }),
1409
+ /* @__PURE__ */ jsx(
1410
+ "input",
1411
+ {
1412
+ type: "range",
1413
+ min: 0,
1414
+ max: 40,
1415
+ value: margin || 20,
1416
+ onChange: (e) => setProp((props) => props.margin = parseInt(e.target.value)),
1417
+ className: "w-full"
1418
+ }
1419
+ ),
1420
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1421
+ margin,
1422
+ "px"
1423
+ ] })
1424
+ ] }),
1425
+ /* @__PURE__ */ jsxs("div", { children: [
1426
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Width" }),
1427
+ /* @__PURE__ */ jsx(
1428
+ "input",
1429
+ {
1430
+ type: "text",
1431
+ value: width || "100%",
1432
+ onChange: (e) => setProp((props) => props.width = e.target.value),
1433
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1434
+ placeholder: "100% or 80%"
1435
+ }
1436
+ )
1437
+ ] })
1438
+ ] });
1439
+ };
1440
+ Divider.craft = {
1441
+ props: {
1442
+ color: "#e0e0e0",
1443
+ thickness: 1,
1444
+ margin: 20,
1445
+ width: "100%"
1446
+ },
1447
+ related: {
1448
+ settings: DividerSettings
1449
+ }
1450
+ };
1451
+ var InvoiceTable = ({
1452
+ items = [
1453
+ { description: "Service Item 1", quantity: 1, unitPrice: 100 },
1454
+ { description: "Service Item 2", quantity: 2, unitPrice: 50 }
1455
+ ],
1456
+ headerBg = "#1a1a2e",
1457
+ headerColor = "#ffffff",
1458
+ borderColor = "#e0e0e0",
1459
+ showTotal = true,
1460
+ currency = "$"
1461
+ }) => {
1462
+ const {
1463
+ connectors: { connect, drag }
1464
+ } = useNode();
1465
+ const total = items.reduce(
1466
+ (sum, item) => sum + item.quantity * item.unitPrice,
1467
+ 0
1468
+ );
1469
+ const cellStyle = {
1470
+ padding: "12px 16px",
1471
+ borderBottom: `1px solid ${borderColor}`,
1472
+ fontFamily: "Arial, sans-serif",
1473
+ fontSize: "14px"
1474
+ };
1475
+ const headerStyle = {
1476
+ ...cellStyle,
1477
+ backgroundColor: headerBg,
1478
+ color: headerColor,
1479
+ fontWeight: "bold",
1480
+ textAlign: "left"
1481
+ };
1482
+ return /* @__PURE__ */ jsx("div", { ref: (ref) => connect(drag(ref)), style: { padding: "10px" }, children: /* @__PURE__ */ jsxs(
1483
+ "table",
1484
+ {
1485
+ style: {
1486
+ width: "100%",
1487
+ borderCollapse: "collapse",
1488
+ border: `1px solid ${borderColor}`
1489
+ },
1490
+ children: [
1491
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
1492
+ /* @__PURE__ */ jsx("th", { style: headerStyle, children: "Description" }),
1493
+ /* @__PURE__ */ jsx("th", { style: { ...headerStyle, textAlign: "center", width: "80px" }, children: "Qty" }),
1494
+ /* @__PURE__ */ jsx("th", { style: { ...headerStyle, textAlign: "right", width: "100px" }, children: "Unit Price" }),
1495
+ /* @__PURE__ */ jsx("th", { style: { ...headerStyle, textAlign: "right", width: "100px" }, children: "Amount" })
1496
+ ] }) }),
1497
+ /* @__PURE__ */ jsx("tbody", { children: items.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [
1498
+ /* @__PURE__ */ jsx("td", { style: cellStyle, children: item.description }),
1499
+ /* @__PURE__ */ jsx("td", { style: { ...cellStyle, textAlign: "center" }, children: item.quantity }),
1500
+ /* @__PURE__ */ jsxs("td", { style: { ...cellStyle, textAlign: "right" }, children: [
1501
+ currency,
1502
+ item.unitPrice.toFixed(2)
1503
+ ] }),
1504
+ /* @__PURE__ */ jsxs("td", { style: { ...cellStyle, textAlign: "right" }, children: [
1505
+ currency,
1506
+ (item.quantity * item.unitPrice).toFixed(2)
1507
+ ] })
1508
+ ] }, index)) }),
1509
+ showTotal && /* @__PURE__ */ jsx("tfoot", { children: /* @__PURE__ */ jsxs("tr", { children: [
1510
+ /* @__PURE__ */ jsx(
1511
+ "td",
1512
+ {
1513
+ colSpan: 3,
1514
+ style: { ...cellStyle, textAlign: "right", fontWeight: "bold" },
1515
+ children: "Total:"
1516
+ }
1517
+ ),
1518
+ /* @__PURE__ */ jsxs(
1519
+ "td",
1520
+ {
1521
+ style: {
1522
+ ...cellStyle,
1523
+ textAlign: "right",
1524
+ fontWeight: "bold",
1525
+ backgroundColor: "#f5f5f5"
1526
+ },
1527
+ children: [
1528
+ currency,
1529
+ total.toFixed(2)
1530
+ ]
1531
+ }
1532
+ )
1533
+ ] }) })
1534
+ ]
1535
+ }
1536
+ ) });
1537
+ };
1538
+ var InvoiceTableSettings = () => {
1539
+ const {
1540
+ actions: { setProp },
1541
+ items,
1542
+ headerBg,
1543
+ headerColor,
1544
+ borderColor,
1545
+ showTotal,
1546
+ currency
1547
+ } = useNode((node) => ({
1548
+ items: node.data.props.items,
1549
+ headerBg: node.data.props.headerBg,
1550
+ headerColor: node.data.props.headerColor,
1551
+ borderColor: node.data.props.borderColor,
1552
+ showTotal: node.data.props.showTotal,
1553
+ currency: node.data.props.currency
1554
+ }));
1555
+ const updateItem = (index, field, value) => {
1556
+ setProp((props) => {
1557
+ const newItems = [...props.items || []];
1558
+ newItems[index] = { ...newItems[index], [field]: value };
1559
+ props.items = newItems;
1560
+ });
1561
+ };
1562
+ const addItem = () => {
1563
+ setProp((props) => {
1564
+ props.items = [
1565
+ ...props.items || [],
1566
+ { description: "New Item", quantity: 1, unitPrice: 0 }
1567
+ ];
1568
+ });
1569
+ };
1570
+ const removeItem = (index) => {
1571
+ setProp((props) => {
1572
+ props.items = (props.items || []).filter((_, i) => i !== index);
1573
+ });
1574
+ };
1575
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1576
+ /* @__PURE__ */ jsxs("div", { children: [
1577
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-2", children: "Invoice Items" }),
1578
+ (items || []).map((item, index) => /* @__PURE__ */ jsxs("div", { className: "mb-3 p-3 border rounded-md bg-muted/30", children: [
1579
+ /* @__PURE__ */ jsx(
1580
+ "input",
1581
+ {
1582
+ type: "text",
1583
+ value: item.description,
1584
+ onChange: (e) => updateItem(index, "description", e.target.value),
1585
+ className: "w-full px-2 py-1 border rounded text-sm mb-2",
1586
+ placeholder: "Description"
1587
+ }
1588
+ ),
1589
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1590
+ /* @__PURE__ */ jsx(
1591
+ "input",
1592
+ {
1593
+ type: "number",
1594
+ value: item.quantity,
1595
+ onChange: (e) => updateItem(index, "quantity", parseInt(e.target.value) || 0),
1596
+ className: "w-20 px-2 py-1 border rounded text-sm",
1597
+ placeholder: "Qty"
1598
+ }
1599
+ ),
1600
+ /* @__PURE__ */ jsx(
1601
+ "input",
1602
+ {
1603
+ type: "number",
1604
+ value: item.unitPrice,
1605
+ onChange: (e) => updateItem(
1606
+ index,
1607
+ "unitPrice",
1608
+ parseFloat(e.target.value) || 0
1609
+ ),
1610
+ className: "flex-1 px-2 py-1 border rounded text-sm",
1611
+ placeholder: "Price"
1612
+ }
1613
+ ),
1614
+ /* @__PURE__ */ jsx(
1615
+ "button",
1616
+ {
1617
+ onClick: () => removeItem(index),
1618
+ className: "px-2 py-1 bg-destructive text-destructive-foreground rounded text-sm",
1619
+ children: "\xD7"
1620
+ }
1621
+ )
1622
+ ] })
1623
+ ] }, index)),
1624
+ /* @__PURE__ */ jsx(
1625
+ "button",
1626
+ {
1627
+ onClick: addItem,
1628
+ className: "w-full py-2 border-2 border-dashed rounded-md text-sm text-muted-foreground hover:bg-muted/50",
1629
+ children: "+ Add Item"
1630
+ }
1631
+ )
1632
+ ] }),
1633
+ /* @__PURE__ */ jsxs("div", { children: [
1634
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Currency Symbol" }),
1635
+ /* @__PURE__ */ jsx(
1636
+ "input",
1637
+ {
1638
+ type: "text",
1639
+ value: currency || "$",
1640
+ onChange: (e) => setProp(
1641
+ (props) => props.currency = e.target.value
1642
+ ),
1643
+ className: "w-full px-3 py-2 border rounded-md text-sm"
1644
+ }
1645
+ )
1646
+ ] }),
1647
+ /* @__PURE__ */ jsxs("div", { children: [
1648
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Header Background" }),
1649
+ /* @__PURE__ */ jsx(
1650
+ "input",
1651
+ {
1652
+ type: "color",
1653
+ value: headerBg || "#1a1a2e",
1654
+ onChange: (e) => setProp(
1655
+ (props) => props.headerBg = e.target.value
1656
+ ),
1657
+ className: "w-full h-10 rounded border cursor-pointer"
1658
+ }
1659
+ )
1660
+ ] }),
1661
+ /* @__PURE__ */ jsxs("div", { children: [
1662
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Header Text Color" }),
1663
+ /* @__PURE__ */ jsx(
1664
+ "input",
1665
+ {
1666
+ type: "color",
1667
+ value: headerColor || "#ffffff",
1668
+ onChange: (e) => setProp(
1669
+ (props) => props.headerColor = e.target.value
1670
+ ),
1671
+ className: "w-full h-10 rounded border cursor-pointer"
1672
+ }
1673
+ )
1674
+ ] }),
1675
+ /* @__PURE__ */ jsxs("div", { children: [
1676
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Border Color" }),
1677
+ /* @__PURE__ */ jsx(
1678
+ "input",
1679
+ {
1680
+ type: "color",
1681
+ value: borderColor || "#e0e0e0",
1682
+ onChange: (e) => setProp(
1683
+ (props) => props.borderColor = e.target.value
1684
+ ),
1685
+ className: "w-full h-10 rounded border cursor-pointer"
1686
+ }
1687
+ )
1688
+ ] }),
1689
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1690
+ /* @__PURE__ */ jsx(
1691
+ "input",
1692
+ {
1693
+ type: "checkbox",
1694
+ checked: showTotal != null ? showTotal : true,
1695
+ onChange: (e) => setProp(
1696
+ (props) => props.showTotal = e.target.checked
1697
+ ),
1698
+ className: "rounded"
1699
+ }
1700
+ ),
1701
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Show Total Row" })
1702
+ ] })
1703
+ ] });
1704
+ };
1705
+ InvoiceTable.craft = {
1706
+ props: {
1707
+ items: [
1708
+ { description: "Service Item 1", quantity: 1, unitPrice: 100 },
1709
+ { description: "Service Item 2", quantity: 2, unitPrice: 50 }
1710
+ ],
1711
+ headerBg: "#1a1a2e",
1712
+ headerColor: "#ffffff",
1713
+ borderColor: "#e0e0e0",
1714
+ showTotal: true,
1715
+ currency: "$"
1716
+ },
1717
+ related: {
1718
+ settings: InvoiceTableSettings
1719
+ }
1720
+ };
1721
+ var Spacer = ({ height = 20 }) => {
1722
+ const { connectors: { connect, drag } } = useNode();
1723
+ return /* @__PURE__ */ jsx(
1724
+ "div",
1725
+ {
1726
+ ref: (ref) => connect(drag(ref)),
1727
+ style: {
1728
+ height: `${height}px`,
1729
+ width: "100%",
1730
+ backgroundColor: "transparent"
1731
+ }
1732
+ }
1733
+ );
1734
+ };
1735
+ var SpacerSettings = () => {
1736
+ const { actions: { setProp }, height } = useNode((node) => ({
1737
+ height: node.data.props.height
1738
+ }));
1739
+ return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { children: [
1740
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Height" }),
1741
+ /* @__PURE__ */ jsx(
1742
+ "input",
1743
+ {
1744
+ type: "range",
1745
+ min: 5,
1746
+ max: 100,
1747
+ value: height || 20,
1748
+ onChange: (e) => setProp((props) => props.height = parseInt(e.target.value)),
1749
+ className: "w-full"
1750
+ }
1751
+ ),
1752
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1753
+ height,
1754
+ "px"
1755
+ ] })
1756
+ ] }) });
1757
+ };
1758
+ Spacer.craft = {
1759
+ props: {
1760
+ height: 20
1761
+ },
1762
+ related: {
1763
+ settings: SpacerSettings
1764
+ }
1765
+ };
1766
+ var socialIcons = {
1767
+ facebook: "https://cdn-icons-png.flaticon.com/128/733/733547.png",
1768
+ twitter: "https://cdn-icons-png.flaticon.com/128/733/733579.png",
1769
+ instagram: "https://cdn-icons-png.flaticon.com/128/2111/2111463.png",
1770
+ linkedin: "https://cdn-icons-png.flaticon.com/128/3536/3536505.png",
1771
+ youtube: "https://cdn-icons-png.flaticon.com/128/1384/1384060.png",
1772
+ tiktok: "https://cdn-icons-png.flaticon.com/128/3046/3046121.png"
1773
+ };
1774
+ var SocialLinks = ({
1775
+ links = [
1776
+ { platform: "facebook", url: "#" },
1777
+ { platform: "twitter", url: "#" },
1778
+ { platform: "instagram", url: "#" },
1779
+ { platform: "linkedin", url: "#" }
1780
+ ],
1781
+ iconSize = 32,
1782
+ iconColor = "#333333",
1783
+ backgroundColor = "transparent",
1784
+ align = "center",
1785
+ padding = 16,
1786
+ gap = 16
1787
+ }) => {
1788
+ const { connectors: { connect, drag } } = useNode();
1789
+ return /* @__PURE__ */ jsx(
1790
+ "div",
1791
+ {
1792
+ ref: (ref) => connect(drag(ref)),
1793
+ style: {
1794
+ textAlign: align,
1795
+ padding: `${padding}px`,
1796
+ backgroundColor
1797
+ },
1798
+ children: /* @__PURE__ */ jsx("div", { style: { display: "inline-flex", gap: `${gap}px` }, children: links.map((link, index) => /* @__PURE__ */ jsx(
1799
+ "a",
1800
+ {
1801
+ href: link.url,
1802
+ style: {
1803
+ display: "inline-block",
1804
+ width: iconSize,
1805
+ height: iconSize
1806
+ },
1807
+ children: /* @__PURE__ */ jsx(
1808
+ "img",
1809
+ {
1810
+ src: socialIcons[link.platform],
1811
+ alt: link.platform,
1812
+ style: {
1813
+ width: "100%",
1814
+ height: "100%",
1815
+ objectFit: "contain"
1816
+ }
1817
+ }
1818
+ )
1819
+ },
1820
+ index
1821
+ )) })
1822
+ }
1823
+ );
1824
+ };
1825
+ var SocialLinksSettings = () => {
1826
+ const { actions: { setProp }, links, iconSize, align, padding, gap, backgroundColor } = useNode((node) => ({
1827
+ links: node.data.props.links,
1828
+ iconSize: node.data.props.iconSize,
1829
+ align: node.data.props.align,
1830
+ padding: node.data.props.padding,
1831
+ gap: node.data.props.gap,
1832
+ backgroundColor: node.data.props.backgroundColor
1833
+ }));
1834
+ const platforms = ["facebook", "twitter", "instagram", "linkedin", "youtube", "tiktok"];
1835
+ const currentLinks = links || [];
1836
+ const togglePlatform = (platform) => {
1837
+ const exists = currentLinks.find((l) => l.platform === platform);
1838
+ if (exists) {
1839
+ setProp((props) => {
1840
+ props.links = currentLinks.filter((l) => l.platform !== platform);
1841
+ });
1842
+ } else {
1843
+ setProp((props) => {
1844
+ props.links = [...currentLinks, { platform, url: "#" }];
1845
+ });
1846
+ }
1847
+ };
1848
+ const updateUrl = (platform, url) => {
1849
+ setProp((props) => {
1850
+ props.links = currentLinks.map(
1851
+ (l) => l.platform === platform ? { ...l, url } : l
1852
+ );
1853
+ });
1854
+ };
1855
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1856
+ /* @__PURE__ */ jsxs("div", { children: [
1857
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-2", children: "Platforms" }),
1858
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: platforms.map((platform) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm cursor-pointer", children: [
1859
+ /* @__PURE__ */ jsx(
1860
+ "input",
1861
+ {
1862
+ type: "checkbox",
1863
+ checked: currentLinks.some((l) => l.platform === platform),
1864
+ onChange: () => togglePlatform(platform),
1865
+ className: "rounded"
1866
+ }
1867
+ ),
1868
+ /* @__PURE__ */ jsx("span", { className: "capitalize", children: platform })
1869
+ ] }, platform)) })
1870
+ ] }),
1871
+ currentLinks.map((link) => /* @__PURE__ */ jsxs("div", { children: [
1872
+ /* @__PURE__ */ jsxs("label", { className: "block text-sm font-medium mb-1 capitalize", children: [
1873
+ link.platform,
1874
+ " URL"
1875
+ ] }),
1876
+ /* @__PURE__ */ jsx(
1877
+ "input",
1878
+ {
1879
+ type: "text",
1880
+ value: link.url,
1881
+ onChange: (e) => updateUrl(link.platform, e.target.value),
1882
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1883
+ placeholder: "https://..."
1884
+ }
1885
+ )
1886
+ ] }, link.platform)),
1887
+ /* @__PURE__ */ jsxs("div", { children: [
1888
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Icon Size" }),
1889
+ /* @__PURE__ */ jsx(
1890
+ "input",
1891
+ {
1892
+ type: "range",
1893
+ min: 20,
1894
+ max: 48,
1895
+ value: iconSize || 32,
1896
+ onChange: (e) => setProp((props) => props.iconSize = parseInt(e.target.value)),
1897
+ className: "w-full"
1898
+ }
1899
+ ),
1900
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1901
+ iconSize,
1902
+ "px"
1903
+ ] })
1904
+ ] }),
1905
+ /* @__PURE__ */ jsxs("div", { children: [
1906
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Gap" }),
1907
+ /* @__PURE__ */ jsx(
1908
+ "input",
1909
+ {
1910
+ type: "range",
1911
+ min: 8,
1912
+ max: 32,
1913
+ value: gap || 16,
1914
+ onChange: (e) => setProp((props) => props.gap = parseInt(e.target.value)),
1915
+ className: "w-full"
1916
+ }
1917
+ ),
1918
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1919
+ gap,
1920
+ "px"
1921
+ ] })
1922
+ ] }),
1923
+ /* @__PURE__ */ jsxs("div", { children: [
1924
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alignment" }),
1925
+ /* @__PURE__ */ jsxs(
1926
+ "select",
1927
+ {
1928
+ value: align || "center",
1929
+ onChange: (e) => setProp((props) => props.align = e.target.value),
1930
+ className: "w-full px-3 py-2 border rounded-md text-sm",
1931
+ children: [
1932
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
1933
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Center" }),
1934
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
1935
+ ]
1936
+ }
1937
+ )
1938
+ ] }),
1939
+ /* @__PURE__ */ jsxs("div", { children: [
1940
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
1941
+ /* @__PURE__ */ jsx(
1942
+ "input",
1943
+ {
1944
+ type: "color",
1945
+ value: backgroundColor || "#ffffff",
1946
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
1947
+ className: "w-full h-10 rounded border cursor-pointer"
1948
+ }
1949
+ )
1950
+ ] }),
1951
+ /* @__PURE__ */ jsxs("div", { children: [
1952
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
1953
+ /* @__PURE__ */ jsx(
1954
+ "input",
1955
+ {
1956
+ type: "range",
1957
+ min: 0,
1958
+ max: 40,
1959
+ value: padding || 16,
1960
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
1961
+ className: "w-full"
1962
+ }
1963
+ ),
1964
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
1965
+ padding,
1966
+ "px"
1967
+ ] })
1968
+ ] })
1969
+ ] });
1970
+ };
1971
+ SocialLinks.craft = {
1972
+ props: {
1973
+ links: [
1974
+ { platform: "facebook", url: "#" },
1975
+ { platform: "twitter", url: "#" },
1976
+ { platform: "instagram", url: "#" },
1977
+ { platform: "linkedin", url: "#" }
1978
+ ],
1979
+ iconSize: 32,
1980
+ iconColor: "#333333",
1981
+ backgroundColor: "transparent",
1982
+ align: "center",
1983
+ padding: 16,
1984
+ gap: 16
1985
+ },
1986
+ related: {
1987
+ settings: SocialLinksSettings
1988
+ }
1989
+ };
1990
+ var TwoColumn = ({
1991
+ leftWidth = 50,
1992
+ gap = 20,
1993
+ padding = 10,
1994
+ backgroundColor = "#ffffff"
1995
+ }) => {
1996
+ const { connectors: { connect, drag } } = useNode();
1997
+ return /* @__PURE__ */ jsxs(
1998
+ "div",
1999
+ {
2000
+ ref: (ref) => connect(drag(ref)),
2001
+ style: {
2002
+ display: "flex",
2003
+ gap: `${gap}px`,
2004
+ padding: `${padding}px`,
2005
+ backgroundColor,
2006
+ width: "100%"
2007
+ },
2008
+ children: [
2009
+ /* @__PURE__ */ jsx("div", { style: { width: `${leftWidth}%` }, children: /* @__PURE__ */ jsx(Element, { id: "left-column", is: Container, canvas: true, background: "#f9f9f9", padding: 10 }) }),
2010
+ /* @__PURE__ */ jsx("div", { style: { width: `${100 - leftWidth}%` }, children: /* @__PURE__ */ jsx(Element, { id: "right-column", is: Container, canvas: true, background: "#f9f9f9", padding: 10 }) })
2011
+ ]
2012
+ }
2013
+ );
2014
+ };
2015
+ var TwoColumnSettings = () => {
2016
+ const { actions: { setProp }, leftWidth, gap, padding, backgroundColor } = useNode((node) => ({
2017
+ leftWidth: node.data.props.leftWidth,
2018
+ gap: node.data.props.gap,
2019
+ padding: node.data.props.padding,
2020
+ backgroundColor: node.data.props.backgroundColor
2021
+ }));
2022
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2023
+ /* @__PURE__ */ jsxs("div", { children: [
2024
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Left Column Width" }),
2025
+ /* @__PURE__ */ jsx(
2026
+ "input",
2027
+ {
2028
+ type: "range",
2029
+ min: 20,
2030
+ max: 80,
2031
+ value: leftWidth || 50,
2032
+ onChange: (e) => setProp((props) => props.leftWidth = parseInt(e.target.value)),
2033
+ className: "w-full"
2034
+ }
2035
+ ),
2036
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-sm text-muted-foreground", children: [
2037
+ /* @__PURE__ */ jsxs("span", { children: [
2038
+ "Left: ",
2039
+ leftWidth,
2040
+ "%"
2041
+ ] }),
2042
+ /* @__PURE__ */ jsxs("span", { children: [
2043
+ "Right: ",
2044
+ 100 - (leftWidth || 50),
2045
+ "%"
2046
+ ] })
2047
+ ] })
2048
+ ] }),
2049
+ /* @__PURE__ */ jsxs("div", { children: [
2050
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Gap" }),
2051
+ /* @__PURE__ */ jsx(
2052
+ "input",
2053
+ {
2054
+ type: "range",
2055
+ min: 0,
2056
+ max: 40,
2057
+ value: gap || 20,
2058
+ onChange: (e) => setProp((props) => props.gap = parseInt(e.target.value)),
2059
+ className: "w-full"
2060
+ }
2061
+ ),
2062
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
2063
+ gap,
2064
+ "px"
2065
+ ] })
2066
+ ] }),
2067
+ /* @__PURE__ */ jsxs("div", { children: [
2068
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
2069
+ /* @__PURE__ */ jsx(
2070
+ "input",
2071
+ {
2072
+ type: "range",
2073
+ min: 0,
2074
+ max: 40,
2075
+ value: padding || 10,
2076
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
2077
+ className: "w-full"
2078
+ }
2079
+ ),
2080
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
2081
+ padding,
2082
+ "px"
2083
+ ] })
2084
+ ] }),
2085
+ /* @__PURE__ */ jsxs("div", { children: [
2086
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
2087
+ /* @__PURE__ */ jsx(
2088
+ "input",
2089
+ {
2090
+ type: "color",
2091
+ value: backgroundColor || "#ffffff",
2092
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
2093
+ className: "w-full h-10 rounded border cursor-pointer"
2094
+ }
2095
+ )
2096
+ ] })
2097
+ ] });
2098
+ };
2099
+ TwoColumn.craft = {
2100
+ props: {
2101
+ leftWidth: 50,
2102
+ gap: 20,
2103
+ padding: 10,
2104
+ backgroundColor: "#ffffff"
2105
+ },
2106
+ related: {
2107
+ settings: TwoColumnSettings
2108
+ }
2109
+ };
2110
+ var Countdown = ({
2111
+ title = "Sale Ends In",
2112
+ days = 3,
2113
+ hours = 12,
2114
+ minutes = 45,
2115
+ seconds = 30,
2116
+ backgroundColor = "#ff6b6b",
2117
+ numberColor = "#ffffff",
2118
+ labelColor = "#ffffff",
2119
+ titleColor = "#ffffff",
2120
+ boxBackground = "rgba(0,0,0,0.2)",
2121
+ padding = 24
2122
+ }) => {
2123
+ const { connectors: { connect, drag } } = useNode();
2124
+ const TimeBox = ({ value, label }) => /* @__PURE__ */ jsxs(
2125
+ "div",
2126
+ {
2127
+ style: {
2128
+ background: boxBackground,
2129
+ padding: "12px 16px",
2130
+ borderRadius: "8px",
2131
+ textAlign: "center",
2132
+ minWidth: "60px"
2133
+ },
2134
+ children: [
2135
+ /* @__PURE__ */ jsx(
2136
+ "div",
2137
+ {
2138
+ style: {
2139
+ fontSize: "28px",
2140
+ fontWeight: "bold",
2141
+ color: numberColor,
2142
+ fontFamily: "Arial, sans-serif",
2143
+ lineHeight: 1.2
2144
+ },
2145
+ children: String(value).padStart(2, "0")
2146
+ }
2147
+ ),
2148
+ /* @__PURE__ */ jsx(
2149
+ "div",
2150
+ {
2151
+ style: {
2152
+ fontSize: "11px",
2153
+ color: labelColor,
2154
+ textTransform: "uppercase",
2155
+ letterSpacing: "1px",
2156
+ marginTop: "4px"
2157
+ },
2158
+ children: label
2159
+ }
2160
+ )
2161
+ ]
2162
+ }
2163
+ );
2164
+ return /* @__PURE__ */ jsxs(
2165
+ "div",
2166
+ {
2167
+ ref: (ref) => connect(drag(ref)),
2168
+ style: {
2169
+ backgroundColor,
2170
+ padding: `${padding}px`,
2171
+ textAlign: "center"
2172
+ },
2173
+ children: [
2174
+ title && /* @__PURE__ */ jsx(
2175
+ "h3",
2176
+ {
2177
+ style: {
2178
+ color: titleColor,
2179
+ fontSize: "18px",
2180
+ fontWeight: "bold",
2181
+ marginBottom: "16px",
2182
+ fontFamily: "Arial, sans-serif",
2183
+ margin: "0 0 16px 0"
2184
+ },
2185
+ children: title
2186
+ }
2187
+ ),
2188
+ /* @__PURE__ */ jsxs(
2189
+ "div",
2190
+ {
2191
+ style: {
2192
+ display: "inline-flex",
2193
+ gap: "12px",
2194
+ justifyContent: "center"
2195
+ },
2196
+ children: [
2197
+ /* @__PURE__ */ jsx(TimeBox, { value: days, label: "Days" }),
2198
+ /* @__PURE__ */ jsx(TimeBox, { value: hours, label: "Hours" }),
2199
+ /* @__PURE__ */ jsx(TimeBox, { value: minutes, label: "Mins" }),
2200
+ /* @__PURE__ */ jsx(TimeBox, { value: seconds, label: "Secs" })
2201
+ ]
2202
+ }
2203
+ )
2204
+ ]
2205
+ }
2206
+ );
2207
+ };
2208
+ var CountdownSettings = () => {
2209
+ const {
2210
+ actions: { setProp },
2211
+ title,
2212
+ days,
2213
+ hours,
2214
+ minutes,
2215
+ seconds,
2216
+ backgroundColor,
2217
+ numberColor,
2218
+ labelColor,
2219
+ titleColor,
2220
+ boxBackground,
2221
+ padding
2222
+ } = useNode((node) => ({
2223
+ title: node.data.props.title,
2224
+ days: node.data.props.days,
2225
+ hours: node.data.props.hours,
2226
+ minutes: node.data.props.minutes,
2227
+ seconds: node.data.props.seconds,
2228
+ backgroundColor: node.data.props.backgroundColor,
2229
+ numberColor: node.data.props.numberColor,
2230
+ labelColor: node.data.props.labelColor,
2231
+ titleColor: node.data.props.titleColor,
2232
+ boxBackground: node.data.props.boxBackground,
2233
+ padding: node.data.props.padding
2234
+ }));
2235
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2236
+ /* @__PURE__ */ jsxs("div", { children: [
2237
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Title" }),
2238
+ /* @__PURE__ */ jsx(
2239
+ "input",
2240
+ {
2241
+ type: "text",
2242
+ value: title || "",
2243
+ onChange: (e) => setProp((props) => props.title = e.target.value),
2244
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2245
+ }
2246
+ )
2247
+ ] }),
2248
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
2249
+ /* @__PURE__ */ jsxs("div", { children: [
2250
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Days" }),
2251
+ /* @__PURE__ */ jsx(
2252
+ "input",
2253
+ {
2254
+ type: "number",
2255
+ min: 0,
2256
+ value: days || 0,
2257
+ onChange: (e) => setProp((props) => props.days = parseInt(e.target.value)),
2258
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2259
+ }
2260
+ )
2261
+ ] }),
2262
+ /* @__PURE__ */ jsxs("div", { children: [
2263
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Hours" }),
2264
+ /* @__PURE__ */ jsx(
2265
+ "input",
2266
+ {
2267
+ type: "number",
2268
+ min: 0,
2269
+ max: 23,
2270
+ value: hours || 0,
2271
+ onChange: (e) => setProp((props) => props.hours = parseInt(e.target.value)),
2272
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2273
+ }
2274
+ )
2275
+ ] }),
2276
+ /* @__PURE__ */ jsxs("div", { children: [
2277
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Minutes" }),
2278
+ /* @__PURE__ */ jsx(
2279
+ "input",
2280
+ {
2281
+ type: "number",
2282
+ min: 0,
2283
+ max: 59,
2284
+ value: minutes || 0,
2285
+ onChange: (e) => setProp((props) => props.minutes = parseInt(e.target.value)),
2286
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2287
+ }
2288
+ )
2289
+ ] }),
2290
+ /* @__PURE__ */ jsxs("div", { children: [
2291
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Seconds" }),
2292
+ /* @__PURE__ */ jsx(
2293
+ "input",
2294
+ {
2295
+ type: "number",
2296
+ min: 0,
2297
+ max: 59,
2298
+ value: seconds || 0,
2299
+ onChange: (e) => setProp((props) => props.seconds = parseInt(e.target.value)),
2300
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2301
+ }
2302
+ )
2303
+ ] })
2304
+ ] }),
2305
+ /* @__PURE__ */ jsxs("div", { children: [
2306
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
2307
+ /* @__PURE__ */ jsx(
2308
+ "input",
2309
+ {
2310
+ type: "color",
2311
+ value: backgroundColor || "#ff6b6b",
2312
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
2313
+ className: "w-full h-10 rounded border cursor-pointer"
2314
+ }
2315
+ )
2316
+ ] }),
2317
+ /* @__PURE__ */ jsxs("div", { children: [
2318
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Title Color" }),
2319
+ /* @__PURE__ */ jsx(
2320
+ "input",
2321
+ {
2322
+ type: "color",
2323
+ value: titleColor || "#ffffff",
2324
+ onChange: (e) => setProp((props) => props.titleColor = e.target.value),
2325
+ className: "w-full h-10 rounded border cursor-pointer"
2326
+ }
2327
+ )
2328
+ ] }),
2329
+ /* @__PURE__ */ jsxs("div", { children: [
2330
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Number Color" }),
2331
+ /* @__PURE__ */ jsx(
2332
+ "input",
2333
+ {
2334
+ type: "color",
2335
+ value: numberColor || "#ffffff",
2336
+ onChange: (e) => setProp((props) => props.numberColor = e.target.value),
2337
+ className: "w-full h-10 rounded border cursor-pointer"
2338
+ }
2339
+ )
2340
+ ] }),
2341
+ /* @__PURE__ */ jsxs("div", { children: [
2342
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
2343
+ /* @__PURE__ */ jsx(
2344
+ "input",
2345
+ {
2346
+ type: "range",
2347
+ min: 8,
2348
+ max: 48,
2349
+ value: padding || 24,
2350
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
2351
+ className: "w-full"
2352
+ }
2353
+ ),
2354
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
2355
+ padding,
2356
+ "px"
2357
+ ] })
2358
+ ] })
2359
+ ] });
2360
+ };
2361
+ Countdown.craft = {
2362
+ props: {
2363
+ title: "Sale Ends In",
2364
+ days: 3,
2365
+ hours: 12,
2366
+ minutes: 45,
2367
+ seconds: 30,
2368
+ backgroundColor: "#ff6b6b",
2369
+ numberColor: "#ffffff",
2370
+ labelColor: "#ffffff",
2371
+ titleColor: "#ffffff",
2372
+ boxBackground: "rgba(0,0,0,0.2)",
2373
+ padding: 24
2374
+ },
2375
+ related: {
2376
+ settings: CountdownSettings
2377
+ }
2378
+ };
2379
+ var PromoCode = ({
2380
+ title = "\u{1F389} Special Offer!",
2381
+ code = "SAVE20",
2382
+ description = "Use this code at checkout to get 20% off your order",
2383
+ backgroundColor = "#fff8e1",
2384
+ borderColor = "#ffc107",
2385
+ codeBackground = "#ffffff",
2386
+ textColor = "#333333",
2387
+ codeColor = "#e65100",
2388
+ padding = 24,
2389
+ borderStyle = "dashed"
2390
+ }) => {
2391
+ const { connectors: { connect, drag } } = useNode();
2392
+ return /* @__PURE__ */ jsxs(
2393
+ "div",
2394
+ {
2395
+ ref: (ref) => connect(drag(ref)),
2396
+ style: {
2397
+ backgroundColor,
2398
+ border: `2px ${borderStyle} ${borderColor}`,
2399
+ borderRadius: "8px",
2400
+ padding: `${padding}px`,
2401
+ textAlign: "center",
2402
+ margin: "10px"
2403
+ },
2404
+ children: [
2405
+ title && /* @__PURE__ */ jsx(
2406
+ "div",
2407
+ {
2408
+ style: {
2409
+ fontSize: "18px",
2410
+ fontWeight: "bold",
2411
+ color: textColor,
2412
+ marginBottom: "12px",
2413
+ fontFamily: "Arial, sans-serif"
2414
+ },
2415
+ children: title
2416
+ }
2417
+ ),
2418
+ /* @__PURE__ */ jsx(
2419
+ "div",
2420
+ {
2421
+ style: {
2422
+ display: "inline-block",
2423
+ backgroundColor: codeBackground,
2424
+ border: `1px solid ${borderColor}`,
2425
+ borderRadius: "6px",
2426
+ padding: "12px 24px",
2427
+ marginBottom: "12px"
2428
+ },
2429
+ children: /* @__PURE__ */ jsx(
2430
+ "span",
2431
+ {
2432
+ style: {
2433
+ fontSize: "24px",
2434
+ fontWeight: "bold",
2435
+ fontFamily: "monospace",
2436
+ letterSpacing: "3px",
2437
+ color: codeColor
2438
+ },
2439
+ children: code
2440
+ }
2441
+ )
2442
+ }
2443
+ ),
2444
+ description && /* @__PURE__ */ jsx(
2445
+ "div",
2446
+ {
2447
+ style: {
2448
+ fontSize: "14px",
2449
+ color: textColor,
2450
+ fontFamily: "Arial, sans-serif",
2451
+ opacity: 0.8
2452
+ },
2453
+ children: description
2454
+ }
2455
+ )
2456
+ ]
2457
+ }
2458
+ );
2459
+ };
2460
+ var PromoCodeSettings = () => {
2461
+ const {
2462
+ actions: { setProp },
2463
+ title,
2464
+ code,
2465
+ description,
2466
+ backgroundColor,
2467
+ borderColor,
2468
+ codeBackground,
2469
+ textColor,
2470
+ codeColor,
2471
+ padding,
2472
+ borderStyle
2473
+ } = useNode((node) => ({
2474
+ title: node.data.props.title,
2475
+ code: node.data.props.code,
2476
+ description: node.data.props.description,
2477
+ backgroundColor: node.data.props.backgroundColor,
2478
+ borderColor: node.data.props.borderColor,
2479
+ codeBackground: node.data.props.codeBackground,
2480
+ textColor: node.data.props.textColor,
2481
+ codeColor: node.data.props.codeColor,
2482
+ padding: node.data.props.padding,
2483
+ borderStyle: node.data.props.borderStyle
2484
+ }));
2485
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2486
+ /* @__PURE__ */ jsxs("div", { children: [
2487
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Title" }),
2488
+ /* @__PURE__ */ jsx(
2489
+ "input",
2490
+ {
2491
+ type: "text",
2492
+ value: title || "",
2493
+ onChange: (e) => setProp((props) => props.title = e.target.value),
2494
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2495
+ }
2496
+ )
2497
+ ] }),
2498
+ /* @__PURE__ */ jsxs("div", { children: [
2499
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Promo Code" }),
2500
+ /* @__PURE__ */ jsx(
2501
+ "input",
2502
+ {
2503
+ type: "text",
2504
+ value: code || "",
2505
+ onChange: (e) => setProp((props) => props.code = e.target.value.toUpperCase()),
2506
+ className: "w-full px-3 py-2 border rounded-md text-sm font-mono"
2507
+ }
2508
+ )
2509
+ ] }),
2510
+ /* @__PURE__ */ jsxs("div", { children: [
2511
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Description" }),
2512
+ /* @__PURE__ */ jsx(
2513
+ "textarea",
2514
+ {
2515
+ value: description || "",
2516
+ onChange: (e) => setProp((props) => props.description = e.target.value),
2517
+ className: "w-full px-3 py-2 border rounded-md text-sm min-h-[60px]"
2518
+ }
2519
+ )
2520
+ ] }),
2521
+ /* @__PURE__ */ jsxs("div", { children: [
2522
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Border Style" }),
2523
+ /* @__PURE__ */ jsxs(
2524
+ "select",
2525
+ {
2526
+ value: borderStyle || "dashed",
2527
+ onChange: (e) => setProp((props) => props.borderStyle = e.target.value),
2528
+ className: "w-full px-3 py-2 border rounded-md text-sm",
2529
+ children: [
2530
+ /* @__PURE__ */ jsx("option", { value: "solid", children: "Solid" }),
2531
+ /* @__PURE__ */ jsx("option", { value: "dashed", children: "Dashed" }),
2532
+ /* @__PURE__ */ jsx("option", { value: "dotted", children: "Dotted" })
2533
+ ]
2534
+ }
2535
+ )
2536
+ ] }),
2537
+ /* @__PURE__ */ jsxs("div", { children: [
2538
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
2539
+ /* @__PURE__ */ jsx(
2540
+ "input",
2541
+ {
2542
+ type: "color",
2543
+ value: backgroundColor || "#fff8e1",
2544
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
2545
+ className: "w-full h-10 rounded border cursor-pointer"
2546
+ }
2547
+ )
2548
+ ] }),
2549
+ /* @__PURE__ */ jsxs("div", { children: [
2550
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Border Color" }),
2551
+ /* @__PURE__ */ jsx(
2552
+ "input",
2553
+ {
2554
+ type: "color",
2555
+ value: borderColor || "#ffc107",
2556
+ onChange: (e) => setProp((props) => props.borderColor = e.target.value),
2557
+ className: "w-full h-10 rounded border cursor-pointer"
2558
+ }
2559
+ )
2560
+ ] }),
2561
+ /* @__PURE__ */ jsxs("div", { children: [
2562
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Code Color" }),
2563
+ /* @__PURE__ */ jsx(
2564
+ "input",
2565
+ {
2566
+ type: "color",
2567
+ value: codeColor || "#e65100",
2568
+ onChange: (e) => setProp((props) => props.codeColor = e.target.value),
2569
+ className: "w-full h-10 rounded border cursor-pointer"
2570
+ }
2571
+ )
2572
+ ] }),
2573
+ /* @__PURE__ */ jsxs("div", { children: [
2574
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
2575
+ /* @__PURE__ */ jsx(
2576
+ "input",
2577
+ {
2578
+ type: "range",
2579
+ min: 12,
2580
+ max: 48,
2581
+ value: padding || 24,
2582
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
2583
+ className: "w-full"
2584
+ }
2585
+ ),
2586
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
2587
+ padding,
2588
+ "px"
2589
+ ] })
2590
+ ] })
2591
+ ] });
2592
+ };
2593
+ PromoCode.craft = {
2594
+ props: {
2595
+ title: "\u{1F389} Special Offer!",
2596
+ code: "SAVE20",
2597
+ description: "Use this code at checkout to get 20% off your order",
2598
+ backgroundColor: "#fff8e1",
2599
+ borderColor: "#ffc107",
2600
+ codeBackground: "#ffffff",
2601
+ textColor: "#333333",
2602
+ codeColor: "#e65100",
2603
+ padding: 24,
2604
+ borderStyle: "dashed"
2605
+ },
2606
+ related: {
2607
+ settings: PromoCodeSettings
2608
+ }
2609
+ };
2610
+ var Testimonial = ({
2611
+ quote = "This product has completely transformed how we do business. The results have been incredible!",
2612
+ authorName = "Sarah Johnson",
2613
+ authorTitle = "CEO, TechCorp",
2614
+ authorImage = "",
2615
+ backgroundColor = "#f8f9fa",
2616
+ quoteColor = "#333333",
2617
+ authorColor = "#666666",
2618
+ accentColor = "#0066cc",
2619
+ padding = 24,
2620
+ showQuoteIcon = true
2621
+ }) => {
2622
+ const { connectors: { connect, drag } } = useNode();
2623
+ return /* @__PURE__ */ jsxs(
2624
+ "div",
2625
+ {
2626
+ ref: (ref) => connect(drag(ref)),
2627
+ style: {
2628
+ backgroundColor,
2629
+ padding: `${padding}px`,
2630
+ borderLeft: `4px solid ${accentColor}`,
2631
+ margin: "10px"
2632
+ },
2633
+ children: [
2634
+ showQuoteIcon && /* @__PURE__ */ jsx(
2635
+ "div",
2636
+ {
2637
+ style: {
2638
+ fontSize: "48px",
2639
+ color: accentColor,
2640
+ opacity: 0.3,
2641
+ lineHeight: 1,
2642
+ marginBottom: "-20px",
2643
+ fontFamily: "Georgia, serif"
2644
+ },
2645
+ children: '"'
2646
+ }
2647
+ ),
2648
+ /* @__PURE__ */ jsx(
2649
+ "p",
2650
+ {
2651
+ style: {
2652
+ fontSize: "16px",
2653
+ fontStyle: "italic",
2654
+ color: quoteColor,
2655
+ lineHeight: 1.7,
2656
+ margin: "0 0 16px 0",
2657
+ fontFamily: "Georgia, serif"
2658
+ },
2659
+ children: quote
2660
+ }
2661
+ ),
2662
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [
2663
+ authorImage && /* @__PURE__ */ jsx(
2664
+ "img",
2665
+ {
2666
+ src: authorImage,
2667
+ alt: authorName,
2668
+ style: {
2669
+ width: "48px",
2670
+ height: "48px",
2671
+ borderRadius: "50%",
2672
+ objectFit: "cover"
2673
+ }
2674
+ }
2675
+ ),
2676
+ /* @__PURE__ */ jsxs("div", { children: [
2677
+ /* @__PURE__ */ jsx(
2678
+ "div",
2679
+ {
2680
+ style: {
2681
+ fontSize: "14px",
2682
+ fontWeight: "bold",
2683
+ color: quoteColor,
2684
+ fontFamily: "Arial, sans-serif"
2685
+ },
2686
+ children: authorName
2687
+ }
2688
+ ),
2689
+ authorTitle && /* @__PURE__ */ jsx(
2690
+ "div",
2691
+ {
2692
+ style: {
2693
+ fontSize: "12px",
2694
+ color: authorColor,
2695
+ fontFamily: "Arial, sans-serif"
2696
+ },
2697
+ children: authorTitle
2698
+ }
2699
+ )
2700
+ ] })
2701
+ ] })
2702
+ ]
2703
+ }
2704
+ );
2705
+ };
2706
+ var TestimonialSettings = () => {
2707
+ const {
2708
+ actions: { setProp },
2709
+ quote,
2710
+ authorName,
2711
+ authorTitle,
2712
+ authorImage,
2713
+ backgroundColor,
2714
+ quoteColor,
2715
+ authorColor,
2716
+ accentColor,
2717
+ padding,
2718
+ showQuoteIcon
2719
+ } = useNode((node) => ({
2720
+ quote: node.data.props.quote,
2721
+ authorName: node.data.props.authorName,
2722
+ authorTitle: node.data.props.authorTitle,
2723
+ authorImage: node.data.props.authorImage,
2724
+ backgroundColor: node.data.props.backgroundColor,
2725
+ quoteColor: node.data.props.quoteColor,
2726
+ authorColor: node.data.props.authorColor,
2727
+ accentColor: node.data.props.accentColor,
2728
+ padding: node.data.props.padding,
2729
+ showQuoteIcon: node.data.props.showQuoteIcon
2730
+ }));
2731
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2732
+ /* @__PURE__ */ jsxs("div", { children: [
2733
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Quote" }),
2734
+ /* @__PURE__ */ jsx(
2735
+ "textarea",
2736
+ {
2737
+ value: quote || "",
2738
+ onChange: (e) => setProp((props) => props.quote = e.target.value),
2739
+ className: "w-full px-3 py-2 border rounded-md text-sm min-h-[80px]"
2740
+ }
2741
+ )
2742
+ ] }),
2743
+ /* @__PURE__ */ jsxs("div", { children: [
2744
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Author Name" }),
2745
+ /* @__PURE__ */ jsx(
2746
+ "input",
2747
+ {
2748
+ type: "text",
2749
+ value: authorName || "",
2750
+ onChange: (e) => setProp((props) => props.authorName = e.target.value),
2751
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2752
+ }
2753
+ )
2754
+ ] }),
2755
+ /* @__PURE__ */ jsxs("div", { children: [
2756
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Author Title" }),
2757
+ /* @__PURE__ */ jsx(
2758
+ "input",
2759
+ {
2760
+ type: "text",
2761
+ value: authorTitle || "",
2762
+ onChange: (e) => setProp((props) => props.authorTitle = e.target.value),
2763
+ className: "w-full px-3 py-2 border rounded-md text-sm"
2764
+ }
2765
+ )
2766
+ ] }),
2767
+ /* @__PURE__ */ jsxs("div", { children: [
2768
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Author Image URL" }),
2769
+ /* @__PURE__ */ jsx(
2770
+ "input",
2771
+ {
2772
+ type: "text",
2773
+ value: authorImage || "",
2774
+ onChange: (e) => setProp((props) => props.authorImage = e.target.value),
2775
+ className: "w-full px-3 py-2 border rounded-md text-sm",
2776
+ placeholder: "https://..."
2777
+ }
2778
+ )
2779
+ ] }),
2780
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm cursor-pointer", children: [
2781
+ /* @__PURE__ */ jsx(
2782
+ "input",
2783
+ {
2784
+ type: "checkbox",
2785
+ checked: showQuoteIcon !== false,
2786
+ onChange: (e) => setProp((props) => props.showQuoteIcon = e.target.checked),
2787
+ className: "rounded"
2788
+ }
2789
+ ),
2790
+ "Show Quote Icon"
2791
+ ] }) }),
2792
+ /* @__PURE__ */ jsxs("div", { children: [
2793
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Background Color" }),
2794
+ /* @__PURE__ */ jsx(
2795
+ "input",
2796
+ {
2797
+ type: "color",
2798
+ value: backgroundColor || "#f8f9fa",
2799
+ onChange: (e) => setProp((props) => props.backgroundColor = e.target.value),
2800
+ className: "w-full h-10 rounded border cursor-pointer"
2801
+ }
2802
+ )
2803
+ ] }),
2804
+ /* @__PURE__ */ jsxs("div", { children: [
2805
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Accent Color" }),
2806
+ /* @__PURE__ */ jsx(
2807
+ "input",
2808
+ {
2809
+ type: "color",
2810
+ value: accentColor || "#0066cc",
2811
+ onChange: (e) => setProp((props) => props.accentColor = e.target.value),
2812
+ className: "w-full h-10 rounded border cursor-pointer"
2813
+ }
2814
+ )
2815
+ ] }),
2816
+ /* @__PURE__ */ jsxs("div", { children: [
2817
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Quote Color" }),
2818
+ /* @__PURE__ */ jsx(
2819
+ "input",
2820
+ {
2821
+ type: "color",
2822
+ value: quoteColor || "#333333",
2823
+ onChange: (e) => setProp((props) => props.quoteColor = e.target.value),
2824
+ className: "w-full h-10 rounded border cursor-pointer"
2825
+ }
2826
+ )
2827
+ ] }),
2828
+ /* @__PURE__ */ jsxs("div", { children: [
2829
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
2830
+ /* @__PURE__ */ jsx(
2831
+ "input",
2832
+ {
2833
+ type: "range",
2834
+ min: 12,
2835
+ max: 48,
2836
+ value: padding || 24,
2837
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
2838
+ className: "w-full"
2839
+ }
2840
+ ),
2841
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
2842
+ padding,
2843
+ "px"
2844
+ ] })
2845
+ ] })
2846
+ ] });
2847
+ };
2848
+ Testimonial.craft = {
2849
+ props: {
2850
+ quote: "This product has completely transformed how we do business. The results have been incredible!",
2851
+ authorName: "Sarah Johnson",
2852
+ authorTitle: "CEO, TechCorp",
2853
+ authorImage: "",
2854
+ backgroundColor: "#f8f9fa",
2855
+ quoteColor: "#333333",
2856
+ authorColor: "#666666",
2857
+ accentColor: "#0066cc",
2858
+ padding: 24,
2859
+ showQuoteIcon: true
2860
+ },
2861
+ related: {
2862
+ settings: TestimonialSettings
2863
+ }
2864
+ };
2865
+ var VideoPlaceholder = ({
2866
+ thumbnailUrl = "https://images.unsplash.com/photo-1611162617474-5b21e879e113?w=600&h=338&fit=crop",
2867
+ videoUrl = "#",
2868
+ width = "100%",
2869
+ align = "center",
2870
+ padding = 10,
2871
+ borderRadius = 8,
2872
+ playButtonColor = "#ffffff",
2873
+ overlayOpacity = 0.3
2874
+ }) => {
2875
+ const { connectors: { connect, drag } } = useNode();
2876
+ return /* @__PURE__ */ jsx(
2877
+ "div",
2878
+ {
2879
+ ref: (ref) => connect(drag(ref)),
2880
+ style: {
2881
+ textAlign: align,
2882
+ padding: `${padding}px`
2883
+ },
2884
+ children: /* @__PURE__ */ jsx(
2885
+ "a",
2886
+ {
2887
+ href: videoUrl,
2888
+ style: {
2889
+ display: "inline-block",
2890
+ position: "relative",
2891
+ width,
2892
+ maxWidth: "100%"
2893
+ },
2894
+ children: /* @__PURE__ */ jsxs(
2895
+ "div",
2896
+ {
2897
+ style: {
2898
+ position: "relative",
2899
+ borderRadius: `${borderRadius}px`,
2900
+ overflow: "hidden"
2901
+ },
2902
+ children: [
2903
+ /* @__PURE__ */ jsx(
2904
+ "img",
2905
+ {
2906
+ src: thumbnailUrl,
2907
+ alt: "Video thumbnail",
2908
+ style: {
2909
+ width: "100%",
2910
+ display: "block"
2911
+ }
2912
+ }
2913
+ ),
2914
+ /* @__PURE__ */ jsx(
2915
+ "div",
2916
+ {
2917
+ style: {
2918
+ position: "absolute",
2919
+ top: 0,
2920
+ left: 0,
2921
+ right: 0,
2922
+ bottom: 0,
2923
+ backgroundColor: `rgba(0,0,0,${overlayOpacity})`,
2924
+ display: "flex",
2925
+ alignItems: "center",
2926
+ justifyContent: "center"
2927
+ },
2928
+ children: /* @__PURE__ */ jsx(
2929
+ "div",
2930
+ {
2931
+ style: {
2932
+ width: "64px",
2933
+ height: "64px",
2934
+ backgroundColor: "rgba(0,0,0,0.6)",
2935
+ borderRadius: "50%",
2936
+ display: "flex",
2937
+ alignItems: "center",
2938
+ justifyContent: "center",
2939
+ border: `3px solid ${playButtonColor}`
2940
+ },
2941
+ children: /* @__PURE__ */ jsx(
2942
+ "div",
2943
+ {
2944
+ style: {
2945
+ width: 0,
2946
+ height: 0,
2947
+ borderTop: "12px solid transparent",
2948
+ borderBottom: "12px solid transparent",
2949
+ borderLeft: `20px solid ${playButtonColor}`,
2950
+ marginLeft: "4px"
2951
+ }
2952
+ }
2953
+ )
2954
+ }
2955
+ )
2956
+ }
2957
+ )
2958
+ ]
2959
+ }
2960
+ )
2961
+ }
2962
+ )
2963
+ }
2964
+ );
2965
+ };
2966
+ var VideoPlaceholderSettings = () => {
2967
+ const {
2968
+ actions: { setProp },
2969
+ thumbnailUrl,
2970
+ videoUrl,
2971
+ width,
2972
+ align,
2973
+ padding,
2974
+ borderRadius,
2975
+ playButtonColor,
2976
+ overlayOpacity
2977
+ } = useNode((node) => ({
2978
+ thumbnailUrl: node.data.props.thumbnailUrl,
2979
+ videoUrl: node.data.props.videoUrl,
2980
+ width: node.data.props.width,
2981
+ align: node.data.props.align,
2982
+ padding: node.data.props.padding,
2983
+ borderRadius: node.data.props.borderRadius,
2984
+ playButtonColor: node.data.props.playButtonColor,
2985
+ overlayOpacity: node.data.props.overlayOpacity
2986
+ }));
2987
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2988
+ /* @__PURE__ */ jsxs("div", { children: [
2989
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Thumbnail URL" }),
2990
+ /* @__PURE__ */ jsx(
2991
+ "input",
2992
+ {
2993
+ type: "text",
2994
+ value: thumbnailUrl || "",
2995
+ onChange: (e) => setProp((props) => props.thumbnailUrl = e.target.value),
2996
+ className: "w-full px-3 py-2 border rounded-md text-sm",
2997
+ placeholder: "https://..."
2998
+ }
2999
+ )
3000
+ ] }),
3001
+ /* @__PURE__ */ jsxs("div", { children: [
3002
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Video URL" }),
3003
+ /* @__PURE__ */ jsx(
3004
+ "input",
3005
+ {
3006
+ type: "text",
3007
+ value: videoUrl || "",
3008
+ onChange: (e) => setProp((props) => props.videoUrl = e.target.value),
3009
+ className: "w-full px-3 py-2 border rounded-md text-sm",
3010
+ placeholder: "https://youtube.com/watch?v=..."
3011
+ }
3012
+ )
3013
+ ] }),
3014
+ /* @__PURE__ */ jsxs("div", { children: [
3015
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Width" }),
3016
+ /* @__PURE__ */ jsx(
3017
+ "input",
3018
+ {
3019
+ type: "text",
3020
+ value: width || "100%",
3021
+ onChange: (e) => setProp((props) => props.width = e.target.value),
3022
+ className: "w-full px-3 py-2 border rounded-md text-sm",
3023
+ placeholder: "100% or 400px"
3024
+ }
3025
+ )
3026
+ ] }),
3027
+ /* @__PURE__ */ jsxs("div", { children: [
3028
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alignment" }),
3029
+ /* @__PURE__ */ jsxs(
3030
+ "select",
3031
+ {
3032
+ value: align || "center",
3033
+ onChange: (e) => setProp((props) => props.align = e.target.value),
3034
+ className: "w-full px-3 py-2 border rounded-md text-sm",
3035
+ children: [
3036
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
3037
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Center" }),
3038
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
3039
+ ]
3040
+ }
3041
+ )
3042
+ ] }),
3043
+ /* @__PURE__ */ jsxs("div", { children: [
3044
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Play Button Color" }),
3045
+ /* @__PURE__ */ jsx(
3046
+ "input",
3047
+ {
3048
+ type: "color",
3049
+ value: playButtonColor || "#ffffff",
3050
+ onChange: (e) => setProp((props) => props.playButtonColor = e.target.value),
3051
+ className: "w-full h-10 rounded border cursor-pointer"
3052
+ }
3053
+ )
3054
+ ] }),
3055
+ /* @__PURE__ */ jsxs("div", { children: [
3056
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Overlay Opacity" }),
3057
+ /* @__PURE__ */ jsx(
3058
+ "input",
3059
+ {
3060
+ type: "range",
3061
+ min: 0,
3062
+ max: 0.8,
3063
+ step: 0.1,
3064
+ value: overlayOpacity || 0.3,
3065
+ onChange: (e) => setProp((props) => props.overlayOpacity = parseFloat(e.target.value)),
3066
+ className: "w-full"
3067
+ }
3068
+ ),
3069
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: (overlayOpacity || 0.3).toFixed(1) })
3070
+ ] }),
3071
+ /* @__PURE__ */ jsxs("div", { children: [
3072
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Border Radius" }),
3073
+ /* @__PURE__ */ jsx(
3074
+ "input",
3075
+ {
3076
+ type: "range",
3077
+ min: 0,
3078
+ max: 24,
3079
+ value: borderRadius || 8,
3080
+ onChange: (e) => setProp((props) => props.borderRadius = parseInt(e.target.value)),
3081
+ className: "w-full"
3082
+ }
3083
+ ),
3084
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3085
+ borderRadius,
3086
+ "px"
3087
+ ] })
3088
+ ] }),
3089
+ /* @__PURE__ */ jsxs("div", { children: [
3090
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
3091
+ /* @__PURE__ */ jsx(
3092
+ "input",
3093
+ {
3094
+ type: "range",
3095
+ min: 0,
3096
+ max: 40,
3097
+ value: padding || 10,
3098
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
3099
+ className: "w-full"
3100
+ }
3101
+ ),
3102
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3103
+ padding,
3104
+ "px"
3105
+ ] })
3106
+ ] })
3107
+ ] });
3108
+ };
3109
+ VideoPlaceholder.craft = {
3110
+ props: {
3111
+ thumbnailUrl: "https://images.unsplash.com/photo-1611162617474-5b21e879e113?w=600&h=338&fit=crop",
3112
+ videoUrl: "#",
3113
+ width: "100%",
3114
+ align: "center",
3115
+ padding: 10,
3116
+ borderRadius: 8,
3117
+ playButtonColor: "#ffffff",
3118
+ overlayOpacity: 0.3
3119
+ },
3120
+ related: {
3121
+ settings: VideoPlaceholderSettings
3122
+ }
3123
+ };
3124
+ var AVAILABLE_VARIABLES = [
3125
+ { key: "{{first_name}}", label: "First Name", preview: "John" },
3126
+ { key: "{{last_name}}", label: "Last Name", preview: "Doe" },
3127
+ { key: "{{full_name}}", label: "Full Name", preview: "John Doe" },
3128
+ { key: "{{email}}", label: "Email", preview: "john@example.com" },
3129
+ { key: "{{company}}", label: "Company", preview: "Acme Inc" },
3130
+ { key: "{{invoice_number}}", label: "Invoice #", preview: "INV-001" },
3131
+ { key: "{{invoice_date}}", label: "Invoice Date", preview: "2024-01-15" },
3132
+ { key: "{{due_date}}", label: "Due Date", preview: "2024-01-30" },
3133
+ { key: "{{total_amount}}", label: "Total Amount", preview: "$1,500.00" },
3134
+ { key: "{{order_number}}", label: "Order #", preview: "ORD-12345" }
3135
+ ];
3136
+ var renderWithVariables = (text) => {
3137
+ let rendered = text;
3138
+ AVAILABLE_VARIABLES.forEach(({ key, preview }) => {
3139
+ rendered = rendered.replace(
3140
+ new RegExp(key.replace(/[{}]/g, "\\$&"), "g"),
3141
+ `<span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 2px 6px; border-radius: 4px; font-size: 0.9em;">${preview}</span>`
3142
+ );
3143
+ });
3144
+ return rendered;
3145
+ };
3146
+ var VariableText = ({
3147
+ text = "Hello {{first_name}}, thank you for your order {{order_number}}!",
3148
+ fontSize = 14,
3149
+ fontWeight = "normal",
3150
+ color = "#333333",
3151
+ align = "left",
3152
+ padding = 10,
3153
+ lineHeight = 1.6
3154
+ }) => {
3155
+ const { connectors: { connect, drag } } = useNode();
3156
+ return /* @__PURE__ */ jsx(
3157
+ "div",
3158
+ {
3159
+ ref: (ref) => connect(drag(ref)),
3160
+ style: {
3161
+ padding: `${padding}px`
3162
+ },
3163
+ children: /* @__PURE__ */ jsx(
3164
+ "p",
3165
+ {
3166
+ style: {
3167
+ fontSize: `${fontSize}px`,
3168
+ fontWeight,
3169
+ color,
3170
+ textAlign: align,
3171
+ lineHeight,
3172
+ margin: 0,
3173
+ fontFamily: "Arial, sans-serif"
3174
+ },
3175
+ dangerouslySetInnerHTML: { __html: renderWithVariables(text) }
3176
+ }
3177
+ )
3178
+ }
3179
+ );
3180
+ };
3181
+ var VariableTextSettings = () => {
3182
+ const { actions: { setProp }, text, fontSize, fontWeight, color, align, padding, lineHeight } = useNode((node) => ({
3183
+ text: node.data.props.text,
3184
+ fontSize: node.data.props.fontSize,
3185
+ fontWeight: node.data.props.fontWeight,
3186
+ color: node.data.props.color,
3187
+ align: node.data.props.align,
3188
+ padding: node.data.props.padding,
3189
+ lineHeight: node.data.props.lineHeight
3190
+ }));
3191
+ const insertVariable = (variable) => {
3192
+ setProp((props) => {
3193
+ props.text = (props.text || "") + variable;
3194
+ });
3195
+ };
3196
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
3197
+ /* @__PURE__ */ jsxs("div", { children: [
3198
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Content" }),
3199
+ /* @__PURE__ */ jsx(
3200
+ "textarea",
3201
+ {
3202
+ value: text || "",
3203
+ onChange: (e) => setProp((props) => props.text = e.target.value),
3204
+ className: "w-full px-3 py-2 border rounded-md text-sm min-h-[80px] font-mono"
3205
+ }
3206
+ )
3207
+ ] }),
3208
+ /* @__PURE__ */ jsxs("div", { children: [
3209
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-2", children: "Insert Variable" }),
3210
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: AVAILABLE_VARIABLES.map((v) => /* @__PURE__ */ jsx(
3211
+ "button",
3212
+ {
3213
+ onClick: () => insertVariable(v.key),
3214
+ className: "px-2 py-1 text-xs bg-primary/10 hover:bg-primary/20 text-primary rounded border border-primary/20 transition-colors",
3215
+ children: v.label
3216
+ },
3217
+ v.key
3218
+ )) })
3219
+ ] }),
3220
+ /* @__PURE__ */ jsxs("div", { children: [
3221
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Font Size" }),
3222
+ /* @__PURE__ */ jsx(
3223
+ "input",
3224
+ {
3225
+ type: "range",
3226
+ min: 10,
3227
+ max: 32,
3228
+ value: fontSize || 14,
3229
+ onChange: (e) => setProp((props) => props.fontSize = parseInt(e.target.value)),
3230
+ className: "w-full"
3231
+ }
3232
+ ),
3233
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3234
+ fontSize,
3235
+ "px"
3236
+ ] })
3237
+ ] }),
3238
+ /* @__PURE__ */ jsxs("div", { children: [
3239
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Font Weight" }),
3240
+ /* @__PURE__ */ jsxs(
3241
+ "select",
3242
+ {
3243
+ value: fontWeight || "normal",
3244
+ onChange: (e) => setProp((props) => props.fontWeight = e.target.value),
3245
+ className: "w-full px-3 py-2 border rounded-md text-sm",
3246
+ children: [
3247
+ /* @__PURE__ */ jsx("option", { value: "normal", children: "Normal" }),
3248
+ /* @__PURE__ */ jsx("option", { value: "bold", children: "Bold" })
3249
+ ]
3250
+ }
3251
+ )
3252
+ ] }),
3253
+ /* @__PURE__ */ jsxs("div", { children: [
3254
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Color" }),
3255
+ /* @__PURE__ */ jsx(
3256
+ "input",
3257
+ {
3258
+ type: "color",
3259
+ value: color || "#333333",
3260
+ onChange: (e) => setProp((props) => props.color = e.target.value),
3261
+ className: "w-full h-10 rounded border cursor-pointer"
3262
+ }
3263
+ )
3264
+ ] }),
3265
+ /* @__PURE__ */ jsxs("div", { children: [
3266
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Alignment" }),
3267
+ /* @__PURE__ */ jsxs(
3268
+ "select",
3269
+ {
3270
+ value: align || "left",
3271
+ onChange: (e) => setProp((props) => props.align = e.target.value),
3272
+ className: "w-full px-3 py-2 border rounded-md text-sm",
3273
+ children: [
3274
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
3275
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Center" }),
3276
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
3277
+ ]
3278
+ }
3279
+ )
3280
+ ] }),
3281
+ /* @__PURE__ */ jsxs("div", { children: [
3282
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
3283
+ /* @__PURE__ */ jsx(
3284
+ "input",
3285
+ {
3286
+ type: "range",
3287
+ min: 0,
3288
+ max: 40,
3289
+ value: padding || 10,
3290
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
3291
+ className: "w-full"
3292
+ }
3293
+ ),
3294
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3295
+ padding,
3296
+ "px"
3297
+ ] })
3298
+ ] }),
3299
+ /* @__PURE__ */ jsxs("div", { children: [
3300
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Line Height" }),
3301
+ /* @__PURE__ */ jsx(
3302
+ "input",
3303
+ {
3304
+ type: "range",
3305
+ min: 1,
3306
+ max: 2.5,
3307
+ step: 0.1,
3308
+ value: lineHeight || 1.6,
3309
+ onChange: (e) => setProp((props) => props.lineHeight = parseFloat(e.target.value)),
3310
+ className: "w-full"
3311
+ }
3312
+ ),
3313
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: lineHeight })
3314
+ ] })
3315
+ ] });
3316
+ };
3317
+ VariableText.craft = {
3318
+ props: {
3319
+ text: "Hello {{first_name}}, thank you for your order {{order_number}}!",
3320
+ fontSize: 14,
3321
+ fontWeight: "normal",
3322
+ color: "#333333",
3323
+ align: "left",
3324
+ padding: 10,
3325
+ lineHeight: 1.6
3326
+ },
3327
+ related: {
3328
+ settings: VariableTextSettings
3329
+ }
3330
+ };
3331
+ var ICONS = {
3332
+ check: "\u2713",
3333
+ star: "\u2605",
3334
+ arrow: "\u2192",
3335
+ bullet: "\u2022",
3336
+ heart: "\u2764",
3337
+ fire: "\u{1F525}",
3338
+ rocket: "\u{1F680}",
3339
+ sparkle: "\u2728",
3340
+ gift: "\u{1F381}",
3341
+ clock: "\u23F0"
3342
+ };
3343
+ var IconList = ({
3344
+ items = [
3345
+ { icon: "check", text: "Fast and reliable delivery" },
3346
+ { icon: "check", text: "Premium quality products" },
3347
+ { icon: "check", text: "24/7 customer support" },
3348
+ { icon: "check", text: "30-day money back guarantee" }
3349
+ ],
3350
+ iconColor = "#22c55e",
3351
+ textColor = "#333333",
3352
+ backgroundColor = "transparent",
3353
+ fontSize = 14,
3354
+ iconSize = 18,
3355
+ gap = 12,
3356
+ padding = 16
3357
+ }) => {
3358
+ const { connectors: { connect, drag } } = useNode();
3359
+ return /* @__PURE__ */ jsx(
3360
+ "div",
3361
+ {
3362
+ ref: (ref) => connect(drag(ref)),
3363
+ style: {
3364
+ padding: `${padding}px`,
3365
+ backgroundColor
3366
+ },
3367
+ children: /* @__PURE__ */ jsx(
3368
+ "ul",
3369
+ {
3370
+ style: {
3371
+ listStyle: "none",
3372
+ margin: 0,
3373
+ padding: 0,
3374
+ display: "flex",
3375
+ flexDirection: "column",
3376
+ gap: `${gap}px`
3377
+ },
3378
+ children: items.map((item, index) => /* @__PURE__ */ jsxs(
3379
+ "li",
3380
+ {
3381
+ style: {
3382
+ display: "flex",
3383
+ alignItems: "flex-start",
3384
+ gap: "10px",
3385
+ fontFamily: "Arial, sans-serif"
3386
+ },
3387
+ children: [
3388
+ /* @__PURE__ */ jsx(
3389
+ "span",
3390
+ {
3391
+ style: {
3392
+ color: iconColor,
3393
+ fontSize: `${iconSize}px`,
3394
+ lineHeight: 1.4,
3395
+ flexShrink: 0
3396
+ },
3397
+ children: ICONS[item.icon] || item.icon
3398
+ }
3399
+ ),
3400
+ /* @__PURE__ */ jsx(
3401
+ "span",
3402
+ {
3403
+ style: {
3404
+ color: textColor,
3405
+ fontSize: `${fontSize}px`,
3406
+ lineHeight: 1.5
3407
+ },
3408
+ children: item.text
3409
+ }
3410
+ )
3411
+ ]
3412
+ },
3413
+ index
3414
+ ))
3415
+ }
3416
+ )
3417
+ }
3418
+ );
3419
+ };
3420
+ var IconListSettings = () => {
3421
+ const {
3422
+ actions: { setProp },
3423
+ items,
3424
+ iconColor,
3425
+ textColor,
3426
+ backgroundColor,
3427
+ fontSize,
3428
+ iconSize,
3429
+ gap,
3430
+ padding
3431
+ } = useNode((node) => ({
3432
+ items: node.data.props.items,
3433
+ iconColor: node.data.props.iconColor,
3434
+ textColor: node.data.props.textColor,
3435
+ backgroundColor: node.data.props.backgroundColor,
3436
+ fontSize: node.data.props.fontSize,
3437
+ iconSize: node.data.props.iconSize,
3438
+ gap: node.data.props.gap,
3439
+ padding: node.data.props.padding
3440
+ }));
3441
+ const currentItems = items || [];
3442
+ const updateItem = (index, field, value) => {
3443
+ setProp((props) => {
3444
+ props.items = currentItems.map(
3445
+ (item, i) => i === index ? { ...item, [field]: value } : item
3446
+ );
3447
+ });
3448
+ };
3449
+ const addItem = () => {
3450
+ setProp((props) => {
3451
+ props.items = [...currentItems, { icon: "check", text: "New item" }];
3452
+ });
3453
+ };
3454
+ const removeItem = (index) => {
3455
+ setProp((props) => {
3456
+ props.items = currentItems.filter((_, i) => i !== index);
3457
+ });
3458
+ };
3459
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
3460
+ /* @__PURE__ */ jsxs("div", { children: [
3461
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-2", children: "List Items" }),
3462
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: currentItems.map((item, index) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-start", children: [
3463
+ /* @__PURE__ */ jsx(
3464
+ "select",
3465
+ {
3466
+ value: item.icon,
3467
+ onChange: (e) => updateItem(index, "icon", e.target.value),
3468
+ className: "w-16 px-2 py-2 border rounded-md text-sm",
3469
+ children: Object.entries(ICONS).map(([key, icon]) => /* @__PURE__ */ jsx("option", { value: key, children: icon }, key))
3470
+ }
3471
+ ),
3472
+ /* @__PURE__ */ jsx(
3473
+ "input",
3474
+ {
3475
+ type: "text",
3476
+ value: item.text,
3477
+ onChange: (e) => updateItem(index, "text", e.target.value),
3478
+ className: "flex-1 px-3 py-2 border rounded-md text-sm"
3479
+ }
3480
+ ),
3481
+ /* @__PURE__ */ jsx(
3482
+ "button",
3483
+ {
3484
+ onClick: () => removeItem(index),
3485
+ className: "px-2 py-2 text-destructive hover:bg-destructive/10 rounded",
3486
+ children: "\xD7"
3487
+ }
3488
+ )
3489
+ ] }, index)) }),
3490
+ /* @__PURE__ */ jsx(
3491
+ "button",
3492
+ {
3493
+ onClick: addItem,
3494
+ className: "mt-2 w-full py-2 text-sm border border-dashed rounded-md hover:bg-accent transition-colors",
3495
+ children: "+ Add Item"
3496
+ }
3497
+ )
3498
+ ] }),
3499
+ /* @__PURE__ */ jsxs("div", { children: [
3500
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Icon Color" }),
3501
+ /* @__PURE__ */ jsx(
3502
+ "input",
3503
+ {
3504
+ type: "color",
3505
+ value: iconColor || "#22c55e",
3506
+ onChange: (e) => setProp((props) => props.iconColor = e.target.value),
3507
+ className: "w-full h-10 rounded border cursor-pointer"
3508
+ }
3509
+ )
3510
+ ] }),
3511
+ /* @__PURE__ */ jsxs("div", { children: [
3512
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Text Color" }),
3513
+ /* @__PURE__ */ jsx(
3514
+ "input",
3515
+ {
3516
+ type: "color",
3517
+ value: textColor || "#333333",
3518
+ onChange: (e) => setProp((props) => props.textColor = e.target.value),
3519
+ className: "w-full h-10 rounded border cursor-pointer"
3520
+ }
3521
+ )
3522
+ ] }),
3523
+ /* @__PURE__ */ jsxs("div", { children: [
3524
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Font Size" }),
3525
+ /* @__PURE__ */ jsx(
3526
+ "input",
3527
+ {
3528
+ type: "range",
3529
+ min: 12,
3530
+ max: 20,
3531
+ value: fontSize || 14,
3532
+ onChange: (e) => setProp((props) => props.fontSize = parseInt(e.target.value)),
3533
+ className: "w-full"
3534
+ }
3535
+ ),
3536
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3537
+ fontSize,
3538
+ "px"
3539
+ ] })
3540
+ ] }),
3541
+ /* @__PURE__ */ jsxs("div", { children: [
3542
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Icon Size" }),
3543
+ /* @__PURE__ */ jsx(
3544
+ "input",
3545
+ {
3546
+ type: "range",
3547
+ min: 14,
3548
+ max: 28,
3549
+ value: iconSize || 18,
3550
+ onChange: (e) => setProp((props) => props.iconSize = parseInt(e.target.value)),
3551
+ className: "w-full"
3552
+ }
3553
+ ),
3554
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3555
+ iconSize,
3556
+ "px"
3557
+ ] })
3558
+ ] }),
3559
+ /* @__PURE__ */ jsxs("div", { children: [
3560
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Gap" }),
3561
+ /* @__PURE__ */ jsx(
3562
+ "input",
3563
+ {
3564
+ type: "range",
3565
+ min: 4,
3566
+ max: 24,
3567
+ value: gap || 12,
3568
+ onChange: (e) => setProp((props) => props.gap = parseInt(e.target.value)),
3569
+ className: "w-full"
3570
+ }
3571
+ ),
3572
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3573
+ gap,
3574
+ "px"
3575
+ ] })
3576
+ ] }),
3577
+ /* @__PURE__ */ jsxs("div", { children: [
3578
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Padding" }),
3579
+ /* @__PURE__ */ jsx(
3580
+ "input",
3581
+ {
3582
+ type: "range",
3583
+ min: 0,
3584
+ max: 40,
3585
+ value: padding || 16,
3586
+ onChange: (e) => setProp((props) => props.padding = parseInt(e.target.value)),
3587
+ className: "w-full"
3588
+ }
3589
+ ),
3590
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
3591
+ padding,
3592
+ "px"
3593
+ ] })
3594
+ ] })
3595
+ ] });
3596
+ };
3597
+ IconList.craft = {
3598
+ props: {
3599
+ items: [
3600
+ { icon: "check", text: "Fast and reliable delivery" },
3601
+ { icon: "check", text: "Premium quality products" },
3602
+ { icon: "check", text: "24/7 customer support" },
3603
+ { icon: "check", text: "30-day money back guarantee" }
3604
+ ],
3605
+ iconColor: "#22c55e",
3606
+ textColor: "#333333",
3607
+ backgroundColor: "transparent",
3608
+ fontSize: 14,
3609
+ iconSize: 18,
3610
+ gap: 12,
3611
+ padding: 16
3612
+ },
3613
+ related: {
3614
+ settings: IconListSettings
3615
+ }
3616
+ };
3617
+ var DEFAULT_COMPONENTS = {
3618
+ EmailHeader: {
3619
+ component: EmailHeader,
3620
+ label: "Header",
3621
+ description: "Email header with logo",
3622
+ icon: PanelTop,
3623
+ category: "Layout"
3624
+ },
3625
+ EmailFooter: {
3626
+ component: EmailFooter,
3627
+ label: "Footer",
3628
+ description: "Contact info & copyright",
3629
+ icon: PanelBottom,
3630
+ category: "Layout"
3631
+ },
3632
+ Container: {
3633
+ component: Container,
3634
+ label: "Container",
3635
+ description: "Group elements together",
3636
+ icon: LayoutTemplate,
3637
+ category: "Layout",
3638
+ createElement: () => /* @__PURE__ */ jsx(Element, { is: Container, canvas: true })
3639
+ },
3640
+ TwoColumn: {
3641
+ component: TwoColumn,
3642
+ label: "Two Columns",
3643
+ description: "Side-by-side layout",
3644
+ icon: Columns,
3645
+ category: "Layout"
3646
+ },
3647
+ Spacer: {
3648
+ component: Spacer,
3649
+ label: "Spacer",
3650
+ description: "Add vertical space",
3651
+ icon: ArrowUpDown,
3652
+ category: "Layout"
3653
+ },
3654
+ Divider: {
3655
+ component: Divider,
3656
+ label: "Divider",
3657
+ description: "Horizontal line separator",
3658
+ icon: Minus,
3659
+ category: "Layout"
3660
+ },
3661
+ TextBlock: {
3662
+ component: TextBlock,
3663
+ label: "Text Block",
3664
+ description: "Paragraph or heading",
3665
+ icon: Type,
3666
+ category: "Content"
3667
+ },
3668
+ ImageBlock: {
3669
+ component: ImageBlock,
3670
+ label: "Image",
3671
+ description: "Add photos or graphics",
3672
+ icon: Image,
3673
+ category: "Content"
3674
+ },
3675
+ EmailButton: {
3676
+ component: EmailButton,
3677
+ label: "Button",
3678
+ description: "Call-to-action button",
3679
+ icon: MousePointer2,
3680
+ category: "Content"
3681
+ },
3682
+ VideoPlaceholder: {
3683
+ component: VideoPlaceholder,
3684
+ label: "Video",
3685
+ description: "Video thumbnail with play",
3686
+ icon: PlayCircle,
3687
+ category: "Content"
3688
+ },
3689
+ IconList: {
3690
+ component: IconList,
3691
+ label: "Icon List",
3692
+ description: "List with icons",
3693
+ icon: List,
3694
+ category: "Content"
3695
+ },
3696
+ SocialLinks: {
3697
+ component: SocialLinks,
3698
+ label: "Social Links",
3699
+ description: "Social media icons",
3700
+ icon: Share2,
3701
+ category: "Content"
3702
+ },
3703
+ Countdown: {
3704
+ component: Countdown,
3705
+ label: "Countdown",
3706
+ description: "Urgency timer display",
3707
+ icon: Timer,
3708
+ category: "Marketing"
3709
+ },
3710
+ PromoCode: {
3711
+ component: PromoCode,
3712
+ label: "Promo Code",
3713
+ description: "Discount code box",
3714
+ icon: Tag,
3715
+ category: "Marketing"
3716
+ },
3717
+ Testimonial: {
3718
+ component: Testimonial,
3719
+ label: "Testimonial",
3720
+ description: "Customer review quote",
3721
+ icon: Quote,
3722
+ category: "Marketing"
3723
+ },
3724
+ VariableText: {
3725
+ component: VariableText,
3726
+ label: "Variable Text",
3727
+ description: "Personalized content",
3728
+ icon: Variable,
3729
+ category: "Dynamic"
3730
+ },
3731
+ InvoiceTable: {
3732
+ component: InvoiceTable,
3733
+ label: "Invoice Table",
3734
+ description: "Itemized billing table",
3735
+ icon: Table,
3736
+ category: "Invoice"
3737
+ }
3738
+ };
3739
+ var buildResolver = (registry) => {
3740
+ const resolver = {};
3741
+ for (const [name, config] of Object.entries(registry)) {
3742
+ resolver[name] = config.component;
3743
+ }
3744
+ return resolver;
3745
+ };
3746
+ var getCategories = (registry) => {
3747
+ const cats = /* @__PURE__ */ new Set();
3748
+ for (const config of Object.values(registry)) {
3749
+ if (config.category) cats.add(config.category);
3750
+ }
3751
+ return Array.from(cats);
3752
+ };
3753
+
3754
+ // src/lib/htmlExporter.ts
3755
+ var generateEmailHtml = (nodes, customRenderers) => {
3756
+ const renderNode = (nodeId) => {
3757
+ const node = nodes[nodeId];
3758
+ if (!node) return "";
3759
+ const { type, props, nodes: childNodes, linkedNodes } = node;
3760
+ const typeName = type.resolvedName;
3761
+ let childrenHtml = "";
3762
+ if (childNodes && childNodes.length > 0) {
3763
+ childrenHtml = childNodes.map((childId) => renderNode(childId)).join("");
3764
+ }
3765
+ if (linkedNodes) {
3766
+ Object.values(linkedNodes).forEach((linkedId) => {
3767
+ childrenHtml += renderNode(linkedId);
3768
+ });
3769
+ }
3770
+ if (customRenderers == null ? void 0 : customRenderers[typeName]) {
3771
+ const result = customRenderers[typeName](typeName, props, childrenHtml, linkedNodes);
3772
+ if (result !== null) return result;
3773
+ }
3774
+ switch (typeName) {
3775
+ case "Paper":
3776
+ return `
3777
+ <!DOCTYPE html>
3778
+ <html lang="en">
3779
+ <head>
3780
+ <meta charset="UTF-8">
3781
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
3782
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
3783
+ <title>Email Template</title>
3784
+ <!--[if mso]>
3785
+ <noscript>
3786
+ <xml>
3787
+ <o:OfficeDocumentSettings>
3788
+ <o:PixelsPerInch>96</o:PixelsPerInch>
3789
+ </o:OfficeDocumentSettings>
3790
+ </xml>
3791
+ </noscript>
3792
+ <![endif]-->
3793
+ </head>
3794
+ <body style="margin: 0; padding: 0; background-color: #f4f4f4; font-family: Arial, sans-serif;">
3795
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background-color: #f4f4f4;">
3796
+ <tr>
3797
+ <td align="center" style="padding: 20px 0;">
3798
+ <table role="presentation" cellpadding="0" cellspacing="0" width="600" style="background-color: ${props.background || "#ffffff"}; max-width: 600px;">
3799
+ <tr>
3800
+ <td>
3801
+ ${childrenHtml}
3802
+ </td>
3803
+ </tr>
3804
+ </table>
3805
+ </td>
3806
+ </tr>
3807
+ </table>
3808
+ </body>
3809
+ </html>`;
3810
+ case "Container":
3811
+ return `
3812
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3813
+ <tr>
3814
+ <td style="background-color: ${props.background || "#ffffff"}; padding: ${props.padding || 20}px;">
3815
+ ${childrenHtml}
3816
+ </td>
3817
+ </tr>
3818
+ </table>`;
3819
+ case "TwoColumn": {
3820
+ const leftWidth = props.leftWidth || 50;
3821
+ const rightWidth = 100 - leftWidth;
3822
+ const leftHtml = (linkedNodes == null ? void 0 : linkedNodes["left-column"]) ? renderNode(linkedNodes["left-column"]) : "";
3823
+ const rightHtml = (linkedNodes == null ? void 0 : linkedNodes["right-column"]) ? renderNode(linkedNodes["right-column"]) : "";
3824
+ return `
3825
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background-color: ${props.backgroundColor || "#ffffff"}; padding: ${props.padding || 10}px;">
3826
+ <tr>
3827
+ <td width="${leftWidth}%" valign="top" style="padding-right: ${props.gap / 2 || 10}px;">
3828
+ ${leftHtml}
3829
+ </td>
3830
+ <td width="${rightWidth}%" valign="top" style="padding-left: ${props.gap / 2 || 10}px;">
3831
+ ${rightHtml}
3832
+ </td>
3833
+ </tr>
3834
+ </table>`;
3835
+ }
3836
+ case "EmailHeader":
3837
+ return `
3838
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3839
+ <tr>
3840
+ <td style="background-color: ${props.backgroundColor || "#1a1a2e"}; padding: ${props.padding || 24}px; text-align: center;">
3841
+ ${props.logoUrl ? `<img src="${props.logoUrl}" alt="Logo" style="max-height: 60px; margin-bottom: 12px;">` : ""}
3842
+ <h1 style="color: ${props.textColor || "#ffffff"}; font-size: 24px; font-weight: bold; margin: 0; font-family: Arial, sans-serif;">${props.companyName || "Your Company"}</h1>
3843
+ </td>
3844
+ </tr>
3845
+ </table>`;
3846
+ case "EmailFooter":
3847
+ return `
3848
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3849
+ <tr>
3850
+ <td style="background-color: ${props.backgroundColor || "#f5f5f5"}; padding: ${props.padding || 24}px; text-align: center; font-family: Arial, sans-serif;">
3851
+ <p style="color: ${props.textColor || "#666666"}; font-size: 14px; margin: 0 0 8px 0; font-weight: bold;">${props.companyName || "Your Company"}</p>
3852
+ <p style="color: ${props.textColor || "#666666"}; font-size: 12px; margin: 0 0 4px 0;">${props.address || "123 Business St, City, Country"}</p>
3853
+ <p style="color: ${props.textColor || "#666666"}; font-size: 12px; margin: 0 0 4px 0;">Email: ${props.email || "info@company.com"} | Phone: ${props.phone || "+1 234 567 890"}</p>
3854
+ <p style="color: ${props.textColor || "#666666"}; font-size: 11px; margin: 12px 0 0 0; opacity: 0.7;">\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${props.companyName || "Your Company"}. All rights reserved.</p>
3855
+ </td>
3856
+ </tr>
3857
+ </table>`;
3858
+ case "EmailButton":
3859
+ return `
3860
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3861
+ <tr>
3862
+ <td style="text-align: ${props.align || "center"}; padding: 10px 0;">
3863
+ <a href="${props.href || "#"}" style="display: inline-block; background-color: ${props.backgroundColor || "#0066cc"}; color: ${props.textColor || "#ffffff"}; padding: ${props.paddingY || 12}px ${props.paddingX || 24}px; border-radius: ${props.borderRadius || 6}px; text-decoration: none; font-size: ${props.fontSize || 16}px; font-weight: bold; font-family: Arial, sans-serif;">${props.text || "Click Here"}</a>
3864
+ </td>
3865
+ </tr>
3866
+ </table>`;
3867
+ case "TextBlock":
3868
+ return `
3869
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3870
+ <tr>
3871
+ <td style="padding: ${props.padding || 10}px;">
3872
+ <p style="font-size: ${props.fontSize || 14}px; font-weight: ${props.fontWeight || "normal"}; color: ${props.color || "#333333"}; text-align: ${props.align || "left"}; line-height: ${props.lineHeight || 1.6}; margin: 0; font-family: Arial, sans-serif;">${props.text || "Enter your text here..."}</p>
3873
+ </td>
3874
+ </tr>
3875
+ </table>`;
3876
+ case "VariableText":
3877
+ return `
3878
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3879
+ <tr>
3880
+ <td style="padding: ${props.padding || 10}px;">
3881
+ <p style="font-size: ${props.fontSize || 14}px; font-weight: ${props.fontWeight || "normal"}; color: ${props.color || "#333333"}; text-align: ${props.align || "left"}; line-height: ${props.lineHeight || 1.6}; margin: 0; font-family: Arial, sans-serif;">${props.text || ""}</p>
3882
+ </td>
3883
+ </tr>
3884
+ </table>`;
3885
+ case "ImageBlock":
3886
+ return `
3887
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3888
+ <tr>
3889
+ <td style="text-align: ${props.align || "center"}; padding: ${props.padding || 10}px;">
3890
+ <img src="${props.src || "https://via.placeholder.com/400x200"}" alt="${props.alt || "Image"}" style="width: ${props.width || "100%"}; max-width: 100%; border-radius: ${props.borderRadius || 0}px; display: inline-block;">
3891
+ </td>
3892
+ </tr>
3893
+ </table>`;
3894
+ case "VideoPlaceholder":
3895
+ return `
3896
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3897
+ <tr>
3898
+ <td style="text-align: ${props.align || "center"}; padding: ${props.padding || 10}px;">
3899
+ <a href="${props.videoUrl || "#"}" style="display: inline-block; position: relative; text-decoration: none;">
3900
+ <img src="${props.thumbnailUrl || "https://via.placeholder.com/600x338"}" alt="Video thumbnail" style="width: ${props.width || "100%"}; max-width: 100%; border-radius: ${props.borderRadius || 8}px; display: block;">
3901
+ <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 64px; height: 64px; background: rgba(0,0,0,0.6); border-radius: 50%; border: 3px solid ${props.playButtonColor || "#ffffff"};">
3902
+ <div style="position: absolute; top: 50%; left: 50%; transform: translate(-40%, -50%); width: 0; height: 0; border-top: 12px solid transparent; border-bottom: 12px solid transparent; border-left: 20px solid ${props.playButtonColor || "#ffffff"};"></div>
3903
+ </div>
3904
+ </a>
3905
+ </td>
3906
+ </tr>
3907
+ </table>`;
3908
+ case "Divider":
3909
+ return `
3910
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3911
+ <tr>
3912
+ <td style="padding: ${props.margin || 20}px 0; text-align: center;">
3913
+ <hr style="border: none; border-top: ${props.thickness || 1}px solid ${props.color || "#e0e0e0"}; width: ${props.width || "100%"}; margin: 0 auto;">
3914
+ </td>
3915
+ </tr>
3916
+ </table>`;
3917
+ case "Spacer":
3918
+ return `
3919
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3920
+ <tr>
3921
+ <td style="height: ${props.height || 20}px; line-height: ${props.height || 20}px; font-size: 1px;">&nbsp;</td>
3922
+ </tr>
3923
+ </table>`;
3924
+ case "SocialLinks": {
3925
+ const links = props.links || [];
3926
+ const iconSize = props.iconSize || 32;
3927
+ const gap = props.gap || 16;
3928
+ const socialIcons2 = {
3929
+ facebook: "https://cdn-icons-png.flaticon.com/128/733/733547.png",
3930
+ twitter: "https://cdn-icons-png.flaticon.com/128/733/733579.png",
3931
+ instagram: "https://cdn-icons-png.flaticon.com/128/2111/2111463.png",
3932
+ linkedin: "https://cdn-icons-png.flaticon.com/128/3536/3536505.png",
3933
+ youtube: "https://cdn-icons-png.flaticon.com/128/1384/1384060.png",
3934
+ tiktok: "https://cdn-icons-png.flaticon.com/128/3046/3046121.png"
3935
+ };
3936
+ const iconsHtml = links.map((link) => `
3937
+ <a href="${link.url}" style="display: inline-block; margin: 0 ${gap / 2}px;">
3938
+ <img src="${socialIcons2[link.platform] || ""}" alt="${link.platform}" style="width: ${iconSize}px; height: ${iconSize}px;">
3939
+ </a>
3940
+ `).join("");
3941
+ return `
3942
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3943
+ <tr>
3944
+ <td style="text-align: ${props.align || "center"}; padding: ${props.padding || 16}px; background-color: ${props.backgroundColor || "transparent"};">
3945
+ ${iconsHtml}
3946
+ </td>
3947
+ </tr>
3948
+ </table>`;
3949
+ }
3950
+ case "Countdown": {
3951
+ const boxStyle = `background: ${props.boxBackground || "rgba(0,0,0,0.2)"}; padding: 12px 16px; border-radius: 8px; text-align: center; display: inline-block; margin: 0 6px;`;
3952
+ const numberStyle = `font-size: 28px; font-weight: bold; color: ${props.numberColor || "#ffffff"}; font-family: Arial, sans-serif;`;
3953
+ const labelStyle = `font-size: 11px; color: ${props.labelColor || "#ffffff"}; text-transform: uppercase; letter-spacing: 1px;`;
3954
+ return `
3955
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3956
+ <tr>
3957
+ <td style="background-color: ${props.backgroundColor || "#ff6b6b"}; padding: ${props.padding || 24}px; text-align: center;">
3958
+ ${props.title ? `<h3 style="color: ${props.titleColor || "#ffffff"}; font-size: 18px; font-weight: bold; margin: 0 0 16px 0; font-family: Arial, sans-serif;">${props.title}</h3>` : ""}
3959
+ <table role="presentation" cellpadding="0" cellspacing="0" align="center">
3960
+ <tr>
3961
+ <td style="${boxStyle}">
3962
+ <div style="${numberStyle}">${String(props.days || 0).padStart(2, "0")}</div>
3963
+ <div style="${labelStyle}">Days</div>
3964
+ </td>
3965
+ <td style="${boxStyle}">
3966
+ <div style="${numberStyle}">${String(props.hours || 0).padStart(2, "0")}</div>
3967
+ <div style="${labelStyle}">Hours</div>
3968
+ </td>
3969
+ <td style="${boxStyle}">
3970
+ <div style="${numberStyle}">${String(props.minutes || 0).padStart(2, "0")}</div>
3971
+ <div style="${labelStyle}">Mins</div>
3972
+ </td>
3973
+ <td style="${boxStyle}">
3974
+ <div style="${numberStyle}">${String(props.seconds || 0).padStart(2, "0")}</div>
3975
+ <div style="${labelStyle}">Secs</div>
3976
+ </td>
3977
+ </tr>
3978
+ </table>
3979
+ </td>
3980
+ </tr>
3981
+ </table>`;
3982
+ }
3983
+ case "PromoCode":
3984
+ return `
3985
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
3986
+ <tr>
3987
+ <td style="padding: 10px;">
3988
+ <div style="background-color: ${props.backgroundColor || "#fff8e1"}; border: 2px ${props.borderStyle || "dashed"} ${props.borderColor || "#ffc107"}; border-radius: 8px; padding: ${props.padding || 24}px; text-align: center;">
3989
+ ${props.title ? `<div style="font-size: 18px; font-weight: bold; color: ${props.textColor || "#333333"}; margin-bottom: 12px; font-family: Arial, sans-serif;">${props.title}</div>` : ""}
3990
+ <div style="display: inline-block; background-color: ${props.codeBackground || "#ffffff"}; border: 1px solid ${props.borderColor || "#ffc107"}; border-radius: 6px; padding: 12px 24px; margin-bottom: 12px;">
3991
+ <span style="font-size: 24px; font-weight: bold; font-family: monospace; letter-spacing: 3px; color: ${props.codeColor || "#e65100"};">${props.code || "SAVE20"}</span>
3992
+ </div>
3993
+ ${props.description ? `<div style="font-size: 14px; color: ${props.textColor || "#333333"}; font-family: Arial, sans-serif; opacity: 0.8;">${props.description}</div>` : ""}
3994
+ </div>
3995
+ </td>
3996
+ </tr>
3997
+ </table>`;
3998
+ case "Testimonial":
3999
+ return `
4000
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
4001
+ <tr>
4002
+ <td style="padding: 10px;">
4003
+ <div style="background-color: ${props.backgroundColor || "#f8f9fa"}; padding: ${props.padding || 24}px; border-left: 4px solid ${props.accentColor || "#0066cc"};">
4004
+ ${props.showQuoteIcon !== false ? `<div style="font-size: 48px; color: ${props.accentColor || "#0066cc"}; opacity: 0.3; line-height: 1; margin-bottom: -20px; font-family: Georgia, serif;">"</div>` : ""}
4005
+ <p style="font-size: 16px; font-style: italic; color: ${props.quoteColor || "#333333"}; line-height: 1.7; margin: 0 0 16px 0; font-family: Georgia, serif;">${props.quote || ""}</p>
4006
+ <table role="presentation" cellpadding="0" cellspacing="0">
4007
+ <tr>
4008
+ ${props.authorImage ? `<td style="vertical-align: middle; padding-right: 12px;"><img src="${props.authorImage}" alt="${props.authorName}" style="width: 48px; height: 48px; border-radius: 50%;"></td>` : ""}
4009
+ <td style="vertical-align: middle;">
4010
+ <div style="font-size: 14px; font-weight: bold; color: ${props.quoteColor || "#333333"}; font-family: Arial, sans-serif;">${props.authorName || ""}</div>
4011
+ ${props.authorTitle ? `<div style="font-size: 12px; color: ${props.authorColor || "#666666"}; font-family: Arial, sans-serif;">${props.authorTitle}</div>` : ""}
4012
+ </td>
4013
+ </tr>
4014
+ </table>
4015
+ </div>
4016
+ </td>
4017
+ </tr>
4018
+ </table>`;
4019
+ case "IconList": {
4020
+ const items = props.items || [];
4021
+ const icons = {
4022
+ check: "\u2713",
4023
+ star: "\u2605",
4024
+ arrow: "\u2192",
4025
+ bullet: "\u2022",
4026
+ heart: "\u2764",
4027
+ fire: "\u{1F525}",
4028
+ rocket: "\u{1F680}",
4029
+ sparkle: "\u2728",
4030
+ gift: "\u{1F381}",
4031
+ clock: "\u23F0"
4032
+ };
4033
+ const listHtml = items.map((item) => `
4034
+ <tr>
4035
+ <td style="vertical-align: top; padding-right: 10px; color: ${props.iconColor || "#22c55e"}; font-size: ${props.iconSize || 18}px; line-height: 1.5;">${icons[item.icon] || item.icon}</td>
4036
+ <td style="vertical-align: top; color: ${props.textColor || "#333333"}; font-size: ${props.fontSize || 14}px; line-height: 1.5; padding-bottom: ${props.gap || 12}px; font-family: Arial, sans-serif;">${item.text}</td>
4037
+ </tr>
4038
+ `).join("");
4039
+ return `
4040
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
4041
+ <tr>
4042
+ <td style="padding: ${props.padding || 16}px; background-color: ${props.backgroundColor || "transparent"};">
4043
+ <table role="presentation" cellpadding="0" cellspacing="0">
4044
+ ${listHtml}
4045
+ </table>
4046
+ </td>
4047
+ </tr>
4048
+ </table>`;
4049
+ }
4050
+ case "InvoiceTable": {
4051
+ const items = props.items || [];
4052
+ const currency = props.currency || "$";
4053
+ const total = items.reduce((sum, item) => sum + item.quantity * item.unitPrice, 0);
4054
+ const headerStyle = `background-color: ${props.headerBg || "#1a1a2e"}; color: ${props.headerColor || "#ffffff"}; padding: 12px 16px; font-weight: bold; text-align: left; border-bottom: 1px solid ${props.borderColor || "#e0e0e0"};`;
4055
+ const cellStyle = `padding: 12px 16px; border-bottom: 1px solid ${props.borderColor || "#e0e0e0"}; font-family: Arial, sans-serif; font-size: 14px;`;
4056
+ return `
4057
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%">
4058
+ <tr>
4059
+ <td style="padding: 10px;">
4060
+ <table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse; border: 1px solid ${props.borderColor || "#e0e0e0"};">
4061
+ <tr>
4062
+ <th style="${headerStyle}">Description</th>
4063
+ <th style="${headerStyle} text-align: center; width: 80px;">Qty</th>
4064
+ <th style="${headerStyle} text-align: right; width: 100px;">Unit Price</th>
4065
+ <th style="${headerStyle} text-align: right; width: 100px;">Amount</th>
4066
+ </tr>
4067
+ ${items.map((item) => `
4068
+ <tr>
4069
+ <td style="${cellStyle}">${item.description}</td>
4070
+ <td style="${cellStyle} text-align: center;">${item.quantity}</td>
4071
+ <td style="${cellStyle} text-align: right;">${currency}${item.unitPrice.toFixed(2)}</td>
4072
+ <td style="${cellStyle} text-align: right;">${currency}${(item.quantity * item.unitPrice).toFixed(2)}</td>
4073
+ </tr>`).join("")}
4074
+ ${props.showTotal !== false ? `
4075
+ <tr>
4076
+ <td colspan="3" style="${cellStyle} text-align: right; font-weight: bold;">Total:</td>
4077
+ <td style="${cellStyle} text-align: right; font-weight: bold; background-color: #f5f5f5;">${currency}${total.toFixed(2)}</td>
4078
+ </tr>` : ""}
4079
+ </table>
4080
+ </td>
4081
+ </tr>
4082
+ </table>`;
4083
+ }
4084
+ default:
4085
+ return childrenHtml;
4086
+ }
4087
+ };
4088
+ return renderNode("ROOT");
4089
+ };
4090
+ var Dialog = DialogPrimitive.Root;
4091
+ var DialogPortal = DialogPrimitive.Portal;
4092
+ var DialogOverlay = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4093
+ DialogPrimitive.Overlay,
4094
+ {
4095
+ ref,
4096
+ className: cn(
4097
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
4098
+ className
4099
+ ),
4100
+ ...props
4101
+ }
4102
+ ));
4103
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
4104
+ var DialogContent = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
4105
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
4106
+ /* @__PURE__ */ jsxs(
4107
+ DialogPrimitive.Content,
4108
+ {
4109
+ ref,
4110
+ className: cn(
4111
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
4112
+ className
4113
+ ),
4114
+ ...props,
4115
+ children: [
4116
+ children,
4117
+ /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [
4118
+ /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
4119
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
4120
+ ] })
4121
+ ]
4122
+ }
4123
+ )
4124
+ ] }));
4125
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
4126
+ var DialogHeader = ({
4127
+ className,
4128
+ ...props
4129
+ }) => /* @__PURE__ */ jsx(
4130
+ "div",
4131
+ {
4132
+ className: cn(
4133
+ "flex flex-col space-y-1.5 text-center sm:text-left",
4134
+ className
4135
+ ),
4136
+ ...props
4137
+ }
4138
+ );
4139
+ DialogHeader.displayName = "DialogHeader";
4140
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4141
+ DialogPrimitive.Title,
4142
+ {
4143
+ ref,
4144
+ className: cn(
4145
+ "text-lg font-semibold leading-none tracking-tight",
4146
+ className
4147
+ ),
4148
+ ...props
4149
+ }
4150
+ ));
4151
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
4152
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4153
+ DialogPrimitive.Description,
4154
+ {
4155
+ ref,
4156
+ className: cn("text-sm text-muted-foreground", className),
4157
+ ...props
4158
+ }
4159
+ ));
4160
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
4161
+ var DropdownMenu = DropdownMenuPrimitive.Root;
4162
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
4163
+ var DropdownMenuSubTrigger = React9.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(
4164
+ DropdownMenuPrimitive.SubTrigger,
4165
+ {
4166
+ ref,
4167
+ className: cn(
4168
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-accent focus:bg-accent",
4169
+ inset && "pl-8",
4170
+ className
4171
+ ),
4172
+ ...props,
4173
+ children: [
4174
+ children,
4175
+ /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto h-4 w-4" })
4176
+ ]
4177
+ }
4178
+ ));
4179
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
4180
+ var DropdownMenuSubContent = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4181
+ DropdownMenuPrimitive.SubContent,
4182
+ {
4183
+ ref,
4184
+ className: cn(
4185
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4186
+ className
4187
+ ),
4188
+ ...props
4189
+ }
4190
+ ));
4191
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
4192
+ var DropdownMenuContent = React9.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
4193
+ DropdownMenuPrimitive.Content,
4194
+ {
4195
+ ref,
4196
+ sideOffset,
4197
+ className: cn(
4198
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4199
+ className
4200
+ ),
4201
+ ...props
4202
+ }
4203
+ ) }));
4204
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
4205
+ var DropdownMenuItem = React9.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
4206
+ DropdownMenuPrimitive.Item,
4207
+ {
4208
+ ref,
4209
+ className: cn(
4210
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
4211
+ inset && "pl-8",
4212
+ className
4213
+ ),
4214
+ ...props
4215
+ }
4216
+ ));
4217
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
4218
+ var DropdownMenuCheckboxItem = React9.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(
4219
+ DropdownMenuPrimitive.CheckboxItem,
4220
+ {
4221
+ ref,
4222
+ className: cn(
4223
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
4224
+ className
4225
+ ),
4226
+ checked,
4227
+ ...props,
4228
+ children: [
4229
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
4230
+ children
4231
+ ]
4232
+ }
4233
+ ));
4234
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
4235
+ var DropdownMenuRadioItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
4236
+ DropdownMenuPrimitive.RadioItem,
4237
+ {
4238
+ ref,
4239
+ className: cn(
4240
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
4241
+ className
4242
+ ),
4243
+ ...props,
4244
+ children: [
4245
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Circle, { className: "h-2 w-2 fill-current" }) }) }),
4246
+ children
4247
+ ]
4248
+ }
4249
+ ));
4250
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
4251
+ var DropdownMenuLabel = React9.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
4252
+ DropdownMenuPrimitive.Label,
4253
+ {
4254
+ ref,
4255
+ className: cn(
4256
+ "px-2 py-1.5 text-sm font-semibold",
4257
+ inset && "pl-8",
4258
+ className
4259
+ ),
4260
+ ...props
4261
+ }
4262
+ ));
4263
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
4264
+ var DropdownMenuSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4265
+ DropdownMenuPrimitive.Separator,
4266
+ {
4267
+ ref,
4268
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
4269
+ ...props
4270
+ }
4271
+ ));
4272
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
4273
+ var TopBar = () => {
4274
+ const { actions, query, canUndo, canRedo } = useEditor((state, query2) => ({
4275
+ canUndo: state.options.enabled && query2.history.canUndo(),
4276
+ canRedo: state.options.enabled && query2.history.canRedo()
4277
+ }));
4278
+ const { title, logo, templates, callbacks, slots, htmlRenderers } = useEditorConfig();
4279
+ const [showCode, setShowCode] = useState(false);
4280
+ const [showPreview, setShowPreview] = useState(false);
4281
+ const [copied, setCopied] = useState(false);
4282
+ const [htmlCode, setHtmlCode] = useState("");
4283
+ const [previewDevice, setPreviewDevice] = useState(
4284
+ "desktop"
4285
+ );
4286
+ const getHtml = useCallback(() => {
4287
+ const json = query.serialize();
4288
+ const nodes = JSON.parse(json);
4289
+ return generateEmailHtml(nodes, htmlRenderers);
4290
+ }, [query, htmlRenderers]);
4291
+ const handleExport = () => {
4292
+ var _a;
4293
+ const html = getHtml();
4294
+ setHtmlCode(html);
4295
+ setShowCode(true);
4296
+ (_a = callbacks.onExport) == null ? void 0 : _a.call(callbacks, html);
4297
+ };
4298
+ const handlePreview = () => {
4299
+ const html = getHtml();
4300
+ setHtmlCode(html);
4301
+ setShowPreview(true);
4302
+ };
4303
+ const handleCopy = async () => {
4304
+ await navigator.clipboard.writeText(htmlCode);
4305
+ setCopied(true);
4306
+ setTimeout(() => setCopied(false), 2e3);
4307
+ };
4308
+ const handleDownload = () => {
4309
+ const blob = new Blob([htmlCode], { type: "text/html" });
4310
+ const url = URL.createObjectURL(blob);
4311
+ const a = document.createElement("a");
4312
+ a.href = url;
4313
+ a.download = "email-template.html";
4314
+ document.body.appendChild(a);
4315
+ a.click();
4316
+ document.body.removeChild(a);
4317
+ URL.revokeObjectURL(url);
4318
+ };
4319
+ const handleClearCanvas = () => {
4320
+ var _a;
4321
+ actions.clearEvents();
4322
+ actions.deserialize(`{
4323
+ "ROOT": {
4324
+ "type": {"resolvedName": "Paper"},
4325
+ "isCanvas": true,
4326
+ "props": {"background": "#ffffff"},
4327
+ "displayName": "Paper",
4328
+ "custom": {},
4329
+ "hidden": false,
4330
+ "nodes": [],
4331
+ "linkedNodes": {}
4332
+ }
4333
+ }`);
4334
+ (_a = callbacks.onClear) == null ? void 0 : _a.call(callbacks);
4335
+ };
4336
+ const handleLoadTemplate = (template) => {
4337
+ var _a;
4338
+ try {
4339
+ actions.deserialize(template.data);
4340
+ (_a = callbacks.onTemplateLoad) == null ? void 0 : _a.call(callbacks, template.id);
4341
+ } catch (e) {
4342
+ console.error("Failed to load template:", e);
4343
+ }
4344
+ };
4345
+ if (slots.toolbar) {
4346
+ return React9__default.createElement(slots.toolbar, {
4347
+ onExport: getHtml,
4348
+ onPreview: getHtml,
4349
+ onClear: handleClearCanvas,
4350
+ title,
4351
+ logo
4352
+ });
4353
+ }
4354
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4355
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b bg-background", children: [
4356
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
4357
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4358
+ logo || /* @__PURE__ */ jsx("div", { className: "w-8 h-8 rounded-lg bg-gradient-to-br from-primary to-primary/60 flex items-center justify-center", children: /* @__PURE__ */ jsx(Palette, { className: "h-4 w-4 text-primary-foreground" }) }),
4359
+ /* @__PURE__ */ jsxs("div", { children: [
4360
+ /* @__PURE__ */ jsx("h1", { className: "text-sm font-bold leading-tight", children: title }),
4361
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Drag & Drop Builder" })
4362
+ ] })
4363
+ ] }),
4364
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-border" }),
4365
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
4366
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "gap-2", children: [
4367
+ /* @__PURE__ */ jsx(LayoutTemplate, { className: "h-4 w-4" }),
4368
+ "Templates"
4369
+ ] }) }),
4370
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-56", children: [
4371
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Quick Start Templates" }),
4372
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
4373
+ templates.map((template) => /* @__PURE__ */ jsxs(
4374
+ DropdownMenuItem,
4375
+ {
4376
+ className: "gap-2",
4377
+ onClick: () => handleLoadTemplate(template),
4378
+ children: [
4379
+ template.icon && React9__default.createElement(template.icon, {
4380
+ className: "h-4 w-4 text-muted-foreground"
4381
+ }),
4382
+ /* @__PURE__ */ jsxs("div", { children: [
4383
+ /* @__PURE__ */ jsx("div", { className: "font-medium", children: template.name }),
4384
+ template.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: template.description })
4385
+ ] })
4386
+ ]
4387
+ },
4388
+ template.id
4389
+ )),
4390
+ templates.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
4391
+ /* @__PURE__ */ jsx(
4392
+ DropdownMenuItem,
4393
+ {
4394
+ onClick: handleClearCanvas,
4395
+ className: "text-destructive",
4396
+ children: "Clear Canvas"
4397
+ }
4398
+ )
4399
+ ] })
4400
+ ] })
4401
+ ] }),
4402
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4403
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 bg-muted rounded-md p-0.5", children: [
4404
+ /* @__PURE__ */ jsx(
4405
+ Button,
4406
+ {
4407
+ variant: "ghost",
4408
+ size: "sm",
4409
+ disabled: !canUndo,
4410
+ onClick: () => actions.history.undo(),
4411
+ className: "h-8 w-8 p-0",
4412
+ title: "Undo",
4413
+ children: /* @__PURE__ */ jsx(Undo2, { className: "h-4 w-4" })
4414
+ }
4415
+ ),
4416
+ /* @__PURE__ */ jsx(
4417
+ Button,
4418
+ {
4419
+ variant: "ghost",
4420
+ size: "sm",
4421
+ disabled: !canRedo,
4422
+ onClick: () => actions.history.redo(),
4423
+ className: "h-8 w-8 p-0",
4424
+ title: "Redo",
4425
+ children: /* @__PURE__ */ jsx(Redo2, { className: "h-4 w-4" })
4426
+ }
4427
+ )
4428
+ ] }),
4429
+ /* @__PURE__ */ jsx("div", { className: "w-px h-6 bg-border" }),
4430
+ /* @__PURE__ */ jsxs(
4431
+ Button,
4432
+ {
4433
+ variant: "outline",
4434
+ size: "sm",
4435
+ onClick: handlePreview,
4436
+ className: "gap-2",
4437
+ children: [
4438
+ /* @__PURE__ */ jsx(Eye, { className: "h-4 w-4" }),
4439
+ " Preview"
4440
+ ]
4441
+ }
4442
+ ),
4443
+ /* @__PURE__ */ jsxs(
4444
+ Button,
4445
+ {
4446
+ variant: "default",
4447
+ size: "sm",
4448
+ onClick: handleExport,
4449
+ className: "gap-2",
4450
+ children: [
4451
+ /* @__PURE__ */ jsx(Code, { className: "h-4 w-4" }),
4452
+ " Export HTML"
4453
+ ]
4454
+ }
4455
+ )
4456
+ ] })
4457
+ ] }),
4458
+ /* @__PURE__ */ jsx(Dialog, { open: showCode, onOpenChange: setShowCode, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-4xl max-h-[80vh]", children: [
4459
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
4460
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Export HTML" }),
4461
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Copy this HTML code to use in your email client or system." })
4462
+ ] }),
4463
+ slots.exportDialog ? React9__default.createElement(slots.exportDialog, {
4464
+ html: htmlCode,
4465
+ onClose: () => setShowCode(false)
4466
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4467
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 mb-2", children: [
4468
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handleCopy, children: [
4469
+ copied ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 mr-2" }) : /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4 mr-2" }),
4470
+ copied ? "Copied!" : "Copy"
4471
+ ] }),
4472
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handleDownload, children: [
4473
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 mr-2" }),
4474
+ " Download"
4475
+ ] })
4476
+ ] }),
4477
+ /* @__PURE__ */ jsx(ScrollArea, { className: "h-[400px] border rounded-md", children: /* @__PURE__ */ jsx("pre", { className: "p-4 text-xs font-mono whitespace-pre-wrap", children: htmlCode }) })
4478
+ ] })
4479
+ ] }) }),
4480
+ /* @__PURE__ */ jsx(Dialog, { open: showPreview, onOpenChange: setShowPreview, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-5xl max-h-[90vh]", children: [
4481
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
4482
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center justify-between", children: [
4483
+ /* @__PURE__ */ jsx("span", { children: "Email Preview" }),
4484
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1 bg-muted rounded-lg p-1" })
4485
+ ] }),
4486
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Preview how your email will look in email clients." })
4487
+ ] }),
4488
+ slots.previewDialog ? React9__default.createElement(slots.previewDialog, {
4489
+ html: htmlCode,
4490
+ onClose: () => setShowPreview(false)
4491
+ }) : /* @__PURE__ */ jsx(ScrollArea, { className: "h-[600px]", children: /* @__PURE__ */ jsx(
4492
+ "div",
4493
+ {
4494
+ className: `mx-auto transition-all duration-300 ${previewDevice === "mobile" ? "max-w-[375px]" : "max-w-full"}`,
4495
+ children: /* @__PURE__ */ jsx("div", { className: "border rounded-lg bg-muted/30 overflow-hidden", children: /* @__PURE__ */ jsx(
4496
+ "iframe",
4497
+ {
4498
+ srcDoc: htmlCode,
4499
+ className: "w-full min-h-[500px] bg-white",
4500
+ title: "Email Preview",
4501
+ style: {
4502
+ height: previewDevice === "mobile" ? "667px" : "600px"
4503
+ }
4504
+ }
4505
+ ) })
4506
+ }
4507
+ ) })
4508
+ ] }) })
4509
+ ] });
4510
+ };
4511
+ var defaultEmailContent = /* @__PURE__ */ jsxs(Element, { is: Paper, canvas: true, children: [
4512
+ /* @__PURE__ */ jsx(EmailHeader, {}),
4513
+ /* @__PURE__ */ jsxs(Element, { is: Container, canvas: true, children: [
4514
+ /* @__PURE__ */ jsx(
4515
+ TextBlock,
4516
+ {
4517
+ text: "Thank you for your business! Please find your invoice details below.",
4518
+ fontSize: 16,
4519
+ align: "center"
4520
+ }
4521
+ ),
4522
+ /* @__PURE__ */ jsx(Spacer, { height: 10 }),
4523
+ /* @__PURE__ */ jsx(InvoiceTable, {}),
4524
+ /* @__PURE__ */ jsx(Spacer, { height: 20 }),
4525
+ /* @__PURE__ */ jsx(EmailButton, { text: "Pay Now", href: "#" })
4526
+ ] }),
4527
+ /* @__PURE__ */ jsx(EmailFooter, {})
4528
+ ] });
4529
+ var EmailEditor = ({
4530
+ components: userComponents,
4531
+ replaceBuiltins = false,
4532
+ theme = {},
4533
+ slots = {},
4534
+ templates = [],
4535
+ callbacks = {},
4536
+ initialState,
4537
+ defaultContent,
4538
+ title = "Email Editor",
4539
+ logo,
4540
+ htmlRenderers = {},
4541
+ showToolbar = true,
4542
+ showToolbox = true,
4543
+ showSettingsPanel = true,
4544
+ className,
4545
+ style
4546
+ }) => {
4547
+ const mergedComponents = useMemo(() => {
4548
+ if (replaceBuiltins) return userComponents || {};
4549
+ return { ...DEFAULT_COMPONENTS, ...userComponents || {} };
4550
+ }, [userComponents, replaceBuiltins]);
4551
+ const resolver = useMemo(() => {
4552
+ const res = buildResolver(mergedComponents);
4553
+ res.Paper = Paper;
4554
+ return res;
4555
+ }, [mergedComponents]);
4556
+ const renderNodeFn = slots.renderNode || RenderNode;
4557
+ return /* @__PURE__ */ jsx(
4558
+ EditorProvider,
4559
+ {
4560
+ value: {
4561
+ components: mergedComponents,
4562
+ theme,
4563
+ slots,
4564
+ templates,
4565
+ callbacks,
4566
+ htmlRenderers,
4567
+ title,
4568
+ logo,
4569
+ showToolbar,
4570
+ showToolbox,
4571
+ showSettingsPanel
4572
+ },
4573
+ children: /* @__PURE__ */ jsx(
4574
+ "div",
4575
+ {
4576
+ className: `h-screen flex flex-col bg-muted/30 ${className || ""}`,
4577
+ style,
4578
+ children: /* @__PURE__ */ jsxs(Editor, { resolver, onRender: renderNodeFn, children: [
4579
+ showToolbar && /* @__PURE__ */ jsx(TopBar, {}),
4580
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex overflow-hidden", children: [
4581
+ showToolbox && /* @__PURE__ */ jsxs("div", { className: "w-72 border-r bg-background flex flex-col", children: [
4582
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border-b", children: [
4583
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4584
+ /* @__PURE__ */ jsx(Palette, { className: "h-4 w-4 text-primary" }),
4585
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm", children: "Components" })
4586
+ ] }),
4587
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "Drag components to canvas" })
4588
+ ] }),
4589
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: slots.toolbox ? React9__default.createElement(slots.toolbox, {
4590
+ components: mergedComponents,
4591
+ categories: Object.keys(mergedComponents).reduce((acc, k) => {
4592
+ const cat = mergedComponents[k].category || "Other";
4593
+ if (!acc.includes(cat)) acc.push(cat);
4594
+ return acc;
4595
+ }, [])
4596
+ }) : /* @__PURE__ */ jsx(Toolbox, {}) })
4597
+ ] }),
4598
+ /* @__PURE__ */ jsx(
4599
+ "div",
4600
+ {
4601
+ className: "flex-1 overflow-auto p-8 craftjs-renderer",
4602
+ style: { backgroundColor: "#e5e5e5" },
4603
+ children: initialState ? /* @__PURE__ */ jsx(Frame, { data: initialState, children: defaultEmailContent }) : /* @__PURE__ */ jsx(Frame, { children: defaultContent || defaultEmailContent })
4604
+ }
4605
+ ),
4606
+ showSettingsPanel && /* @__PURE__ */ jsxs("div", { className: "w-80 border-l bg-background flex flex-col", children: [
4607
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border-b", children: [
4608
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4609
+ /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4 text-primary" }),
4610
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm", children: "Properties" })
4611
+ ] }),
4612
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "Edit selected component" })
4613
+ ] }),
4614
+ /* @__PURE__ */ jsx(SettingsPanel, {})
4615
+ ] })
4616
+ ] })
4617
+ ] })
4618
+ }
4619
+ )
4620
+ }
4621
+ );
4622
+ };
4623
+
4624
+ export { AVAILABLE_VARIABLES, Container, Countdown, DEFAULT_COMPONENTS, Divider, EditorProvider, EmailButton, EmailEditor, EmailFooter, EmailHeader, IconList, ImageBlock, InvoiceTable, Paper, PromoCode, RenderNode, SettingsPanel, SocialLinks, Spacer, Testimonial, TextBlock, Toolbox, TwoColumn, VariableText, VideoPlaceholder, buildResolver, generateEmailHtml, getCategories, useEditorConfig };
4625
+ //# sourceMappingURL=index.mjs.map
4626
+ //# sourceMappingURL=index.mjs.map