email-builder-pro 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1386 @@
1
+ 'use client';
2
+
3
+ import { useEmailBuilder } from '@/lib/store';
4
+ import { Trash2 } from 'lucide-react';
5
+ import NumberInput from './NumberInput';
6
+ import ImageUpload from './ImageUpload';
7
+
8
+ export default function PropertiesPanel() {
9
+ const {
10
+ components,
11
+ selectedComponent,
12
+ updateComponent,
13
+ removeComponent,
14
+ selectComponent,
15
+ } = useEmailBuilder();
16
+
17
+ const component = components.find((c) => c.id === selectedComponent);
18
+
19
+ if (!component) {
20
+ return (
21
+ <div className="p-4">
22
+ <h2 className="text-sm font-semibold text-gray-700 mb-4">Properties</h2>
23
+ <p className="text-sm text-gray-400">Select a component to edit its properties</p>
24
+ </div>
25
+ );
26
+ }
27
+
28
+ const handlePropChange = (key: string, value: any) => {
29
+ updateComponent(component.id, {
30
+ props: {
31
+ ...component.props,
32
+ [key]: value,
33
+ },
34
+ });
35
+ };
36
+
37
+ // Common styling properties component
38
+ const CommonStyles = () => (
39
+ <>
40
+ <div className="mb-4 pt-4 border-t border-gray-200">
41
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Spacing</h3>
42
+ <div className="grid grid-cols-2 gap-2">
43
+ <NumberInput
44
+ label="Margin Top"
45
+ value={component.props.marginTop || 0}
46
+ onChange={(val) => handlePropChange('marginTop', val)}
47
+ min={0}
48
+ max={100}
49
+ unit="px"
50
+ />
51
+ <NumberInput
52
+ label="Margin Bottom"
53
+ value={component.props.marginBottom || 0}
54
+ onChange={(val) => handlePropChange('marginBottom', val)}
55
+ min={0}
56
+ max={100}
57
+ unit="px"
58
+ />
59
+ <NumberInput
60
+ label="Margin Left"
61
+ value={component.props.marginLeft || 0}
62
+ onChange={(val) => handlePropChange('marginLeft', val)}
63
+ min={0}
64
+ max={100}
65
+ unit="px"
66
+ />
67
+ <NumberInput
68
+ label="Margin Right"
69
+ value={component.props.marginRight || 0}
70
+ onChange={(val) => handlePropChange('marginRight', val)}
71
+ min={0}
72
+ max={100}
73
+ unit="px"
74
+ />
75
+ </div>
76
+ <NumberInput
77
+ label="Margin (All)"
78
+ value={component.props.margin || 0}
79
+ onChange={(val) => handlePropChange('margin', val)}
80
+ min={0}
81
+ max={100}
82
+ unit="px"
83
+ />
84
+ </div>
85
+ </>
86
+ );
87
+
88
+ const renderPropertyEditor = () => {
89
+ switch (component.type) {
90
+ case 'text':
91
+ return (
92
+ <>
93
+ <div className="mb-4">
94
+ <label className="block text-xs font-medium text-gray-700 mb-1">
95
+ Text Content
96
+ </label>
97
+ <textarea
98
+ value={component.props.text || ''}
99
+ onChange={(e) => handlePropChange('text', e.target.value)}
100
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
101
+ rows={4}
102
+ />
103
+ </div>
104
+
105
+ <div className="mb-4 pt-4 border-t border-gray-200">
106
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Typography</h3>
107
+ <NumberInput
108
+ label="Font Size"
109
+ value={component.props.fontSize || 16}
110
+ onChange={(val) => handlePropChange('fontSize', val)}
111
+ min={8}
112
+ max={72}
113
+ unit="px"
114
+ />
115
+ <div className="mb-4">
116
+ <label className="block text-xs font-medium text-gray-700 mb-1">
117
+ Font Weight
118
+ </label>
119
+ <select
120
+ value={component.props.fontWeight || 'normal'}
121
+ onChange={(e) => handlePropChange('fontWeight', e.target.value)}
122
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
123
+ >
124
+ <option value="normal">Normal</option>
125
+ <option value="bold">Bold</option>
126
+ <option value="300">Light</option>
127
+ <option value="400">Regular</option>
128
+ <option value="500">Medium</option>
129
+ <option value="600">Semi Bold</option>
130
+ <option value="700">Bold</option>
131
+ </select>
132
+ </div>
133
+ <div className="mb-4">
134
+ <label className="block text-xs font-medium text-gray-700 mb-1">
135
+ Font Family
136
+ </label>
137
+ <select
138
+ value={component.props.fontFamily || 'Arial'}
139
+ onChange={(e) => handlePropChange('fontFamily', e.target.value)}
140
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
141
+ >
142
+ <option value="Arial">Arial</option>
143
+ <option value="Helvetica">Helvetica</option>
144
+ <option value="Georgia">Georgia</option>
145
+ <option value="Times New Roman">Times New Roman</option>
146
+ <option value="Courier New">Courier New</option>
147
+ <option value="Verdana">Verdana</option>
148
+ </select>
149
+ </div>
150
+ <div className="mb-4">
151
+ <label className="block text-xs font-medium text-gray-700 mb-1">
152
+ Line Height
153
+ </label>
154
+ <input
155
+ type="number"
156
+ step="0.1"
157
+ value={component.props.lineHeight || 1.5}
158
+ onChange={(e) => handlePropChange('lineHeight', parseFloat(e.target.value))}
159
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
160
+ />
161
+ </div>
162
+ </div>
163
+
164
+ <div className="mb-4 pt-4 border-t border-gray-200">
165
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Colors</h3>
166
+ <div className="mb-4">
167
+ <label className="block text-xs font-medium text-gray-700 mb-1">
168
+ Text Color
169
+ </label>
170
+ <input
171
+ type="color"
172
+ value={component.props.color || '#000000'}
173
+ onChange={(e) => handlePropChange('color', e.target.value)}
174
+ className="w-full h-10 border border-gray-300 rounded-md"
175
+ />
176
+ </div>
177
+ <div className="mb-4">
178
+ <label className="block text-xs font-medium text-gray-700 mb-1">
179
+ Background Color
180
+ </label>
181
+ <input
182
+ type="color"
183
+ value={component.props.backgroundColor || 'transparent'}
184
+ onChange={(e) => handlePropChange('backgroundColor', e.target.value)}
185
+ className="w-full h-10 border border-gray-300 rounded-md"
186
+ />
187
+ </div>
188
+ </div>
189
+
190
+ <div className="mb-4 pt-4 border-t border-gray-200">
191
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Alignment</h3>
192
+ <div className="mb-4">
193
+ <label className="block text-xs font-medium text-gray-700 mb-1">
194
+ Text Align
195
+ </label>
196
+ <select
197
+ value={component.props.textAlign || 'left'}
198
+ onChange={(e) => handlePropChange('textAlign', e.target.value)}
199
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
200
+ >
201
+ <option value="left">Left</option>
202
+ <option value="center">Center</option>
203
+ <option value="right">Right</option>
204
+ <option value="justify">Justify</option>
205
+ </select>
206
+ </div>
207
+ </div>
208
+
209
+ <CommonStyles />
210
+ </>
211
+ );
212
+
213
+ case 'heading':
214
+ return (
215
+ <>
216
+ <div className="mb-4">
217
+ <label className="block text-xs font-medium text-gray-700 mb-1">
218
+ Heading Text
219
+ </label>
220
+ <input
221
+ type="text"
222
+ value={component.props.text || ''}
223
+ onChange={(e) => handlePropChange('text', e.target.value)}
224
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
225
+ />
226
+ </div>
227
+ <div className="mb-4">
228
+ <label className="block text-xs font-medium text-gray-700 mb-1">
229
+ Heading Level
230
+ </label>
231
+ <select
232
+ value={component.props.level || 1}
233
+ onChange={(e) => handlePropChange('level', parseInt(e.target.value))}
234
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
235
+ >
236
+ <option value={1}>H1</option>
237
+ <option value={2}>H2</option>
238
+ <option value={3}>H3</option>
239
+ <option value={4}>H4</option>
240
+ <option value={5}>H5</option>
241
+ <option value={6}>H6</option>
242
+ </select>
243
+ </div>
244
+
245
+ <div className="mb-4 pt-4 border-t border-gray-200">
246
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Typography</h3>
247
+ <NumberInput
248
+ label="Font Size"
249
+ value={component.props.fontSize || 24}
250
+ onChange={(val) => handlePropChange('fontSize', val)}
251
+ min={12}
252
+ max={72}
253
+ unit="px"
254
+ />
255
+ <div className="mb-4">
256
+ <label className="block text-xs font-medium text-gray-700 mb-1">
257
+ Font Weight
258
+ </label>
259
+ <select
260
+ value={component.props.fontWeight || 'bold'}
261
+ onChange={(e) => handlePropChange('fontWeight', e.target.value)}
262
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
263
+ >
264
+ <option value="normal">Normal</option>
265
+ <option value="bold">Bold</option>
266
+ <option value="600">Semi Bold</option>
267
+ <option value="700">Bold</option>
268
+ <option value="800">Extra Bold</option>
269
+ </select>
270
+ </div>
271
+ </div>
272
+
273
+ <div className="mb-4 pt-4 border-t border-gray-200">
274
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Colors</h3>
275
+ <div className="mb-4">
276
+ <label className="block text-xs font-medium text-gray-700 mb-1">
277
+ Text Color
278
+ </label>
279
+ <input
280
+ type="color"
281
+ value={component.props.color || '#000000'}
282
+ onChange={(e) => handlePropChange('color', e.target.value)}
283
+ className="w-full h-10 border border-gray-300 rounded-md"
284
+ />
285
+ </div>
286
+ </div>
287
+
288
+ <div className="mb-4 pt-4 border-t border-gray-200">
289
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Alignment</h3>
290
+ <div className="mb-4">
291
+ <label className="block text-xs font-medium text-gray-700 mb-1">
292
+ Text Align
293
+ </label>
294
+ <select
295
+ value={component.props.textAlign || 'left'}
296
+ onChange={(e) => handlePropChange('textAlign', e.target.value)}
297
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
298
+ >
299
+ <option value="left">Left</option>
300
+ <option value="center">Center</option>
301
+ <option value="right">Right</option>
302
+ </select>
303
+ </div>
304
+ </div>
305
+
306
+ <CommonStyles />
307
+ </>
308
+ );
309
+
310
+ case 'button':
311
+ return (
312
+ <>
313
+ <div className="mb-4">
314
+ <label className="block text-xs font-medium text-gray-700 mb-1">
315
+ Button Text
316
+ </label>
317
+ <input
318
+ type="text"
319
+ value={component.props.text || ''}
320
+ onChange={(e) => handlePropChange('text', e.target.value)}
321
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
322
+ />
323
+ </div>
324
+ <div className="mb-4">
325
+ <label className="block text-xs font-medium text-gray-700 mb-1">
326
+ Link URL (href)
327
+ </label>
328
+ <input
329
+ type="text"
330
+ value={component.props.href || '#'}
331
+ onChange={(e) => handlePropChange('href', e.target.value)}
332
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
333
+ placeholder="https://example.com"
334
+ />
335
+ </div>
336
+
337
+ <div className="mb-4 pt-4 border-t border-gray-200">
338
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Colors</h3>
339
+ <div className="mb-4">
340
+ <label className="block text-xs font-medium text-gray-700 mb-1">
341
+ Background Color
342
+ </label>
343
+ <input
344
+ type="color"
345
+ value={component.props.backgroundColor || '#007bff'}
346
+ onChange={(e) => handlePropChange('backgroundColor', e.target.value)}
347
+ className="w-full h-10 border border-gray-300 rounded-md"
348
+ />
349
+ </div>
350
+ <div className="mb-4">
351
+ <label className="block text-xs font-medium text-gray-700 mb-1">
352
+ Text Color
353
+ </label>
354
+ <input
355
+ type="color"
356
+ value={component.props.color || '#ffffff'}
357
+ onChange={(e) => handlePropChange('color', e.target.value)}
358
+ className="w-full h-10 border border-gray-300 rounded-md"
359
+ />
360
+ </div>
361
+ </div>
362
+
363
+ <div className="mb-4 pt-4 border-t border-gray-200">
364
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Typography</h3>
365
+ <NumberInput
366
+ label="Font Size"
367
+ value={component.props.fontSize || 14}
368
+ onChange={(val) => handlePropChange('fontSize', val)}
369
+ min={10}
370
+ max={24}
371
+ unit="px"
372
+ />
373
+ <div className="mb-4">
374
+ <label className="block text-xs font-medium text-gray-700 mb-1">
375
+ Font Weight
376
+ </label>
377
+ <select
378
+ value={component.props.fontWeight || '600'}
379
+ onChange={(e) => handlePropChange('fontWeight', e.target.value)}
380
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
381
+ >
382
+ <option value="normal">Normal</option>
383
+ <option value="500">Medium</option>
384
+ <option value="600">Semi Bold</option>
385
+ <option value="700">Bold</option>
386
+ </select>
387
+ </div>
388
+ </div>
389
+
390
+ <div className="mb-4 pt-4 border-t border-gray-200">
391
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Spacing & Size</h3>
392
+ <div className="grid grid-cols-2 gap-2 mb-4">
393
+ <NumberInput
394
+ label="Padding X"
395
+ value={component.props.paddingX || component.props.padding || 12}
396
+ onChange={(val) => handlePropChange('paddingX', val)}
397
+ min={0}
398
+ max={50}
399
+ unit="px"
400
+ />
401
+ <NumberInput
402
+ label="Padding Y"
403
+ value={component.props.paddingY || component.props.padding || 12}
404
+ onChange={(val) => handlePropChange('paddingY', val)}
405
+ min={0}
406
+ max={50}
407
+ unit="px"
408
+ />
409
+ </div>
410
+ <NumberInput
411
+ label="Border Radius"
412
+ value={component.props.borderRadius || 4}
413
+ onChange={(val) => handlePropChange('borderRadius', val)}
414
+ min={0}
415
+ max={50}
416
+ unit="px"
417
+ />
418
+ </div>
419
+
420
+ <div className="mb-4 pt-4 border-t border-gray-200">
421
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Border</h3>
422
+ <NumberInput
423
+ label="Border Width"
424
+ value={component.props.borderWidth || 0}
425
+ onChange={(val) => handlePropChange('borderWidth', val)}
426
+ min={0}
427
+ max={10}
428
+ unit="px"
429
+ />
430
+ <div className="mb-4">
431
+ <label className="block text-xs font-medium text-gray-700 mb-1">
432
+ Border Color
433
+ </label>
434
+ <input
435
+ type="color"
436
+ value={component.props.borderColor || '#000000'}
437
+ onChange={(e) => handlePropChange('borderColor', e.target.value)}
438
+ className="w-full h-10 border border-gray-300 rounded-md"
439
+ />
440
+ </div>
441
+ </div>
442
+
443
+ <CommonStyles />
444
+ </>
445
+ );
446
+
447
+ case 'image':
448
+ return (
449
+ <>
450
+ <ImageUpload
451
+ value={component.props.src || ''}
452
+ onChange={(url) => handlePropChange('src', url)}
453
+ onResize={(width, height) => {
454
+ handlePropChange('width', `${width}px`);
455
+ handlePropChange('height', `${height}px`);
456
+ }}
457
+ />
458
+ <div className="mb-4">
459
+ <label className="block text-xs font-medium text-gray-700 mb-1">
460
+ Alt Text
461
+ </label>
462
+ <input
463
+ type="text"
464
+ value={component.props.alt || ''}
465
+ onChange={(e) => handlePropChange('alt', e.target.value)}
466
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
467
+ placeholder="Image description"
468
+ />
469
+ </div>
470
+
471
+ <div className="mb-4 pt-4 border-t border-gray-200">
472
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Size</h3>
473
+ <div className="mb-4">
474
+ <label className="block text-xs font-medium text-gray-700 mb-1">
475
+ Width
476
+ </label>
477
+ <input
478
+ type="text"
479
+ value={component.props.width || '100%'}
480
+ onChange={(e) => handlePropChange('width', e.target.value)}
481
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
482
+ placeholder="100% or 400px"
483
+ />
484
+ </div>
485
+ <div className="mb-4">
486
+ <label className="block text-xs font-medium text-gray-700 mb-1">
487
+ Height
488
+ </label>
489
+ <input
490
+ type="text"
491
+ value={component.props.height || 'auto'}
492
+ onChange={(e) => handlePropChange('height', e.target.value)}
493
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
494
+ placeholder="auto or 300px"
495
+ />
496
+ </div>
497
+ </div>
498
+
499
+ <div className="mb-4 pt-4 border-t border-gray-200">
500
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Alignment</h3>
501
+ <div className="mb-4">
502
+ <label className="block text-xs font-medium text-gray-700 mb-1">
503
+ Align
504
+ </label>
505
+ <select
506
+ value={component.props.align || 'left'}
507
+ onChange={(e) => handlePropChange('align', e.target.value)}
508
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
509
+ >
510
+ <option value="left">Left</option>
511
+ <option value="center">Center</option>
512
+ <option value="right">Right</option>
513
+ </select>
514
+ </div>
515
+ </div>
516
+
517
+ <CommonStyles />
518
+ </>
519
+ );
520
+
521
+ case 'container':
522
+ return (
523
+ <>
524
+ <div className="mb-4 pt-4 border-t border-gray-200">
525
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Background</h3>
526
+ <div className="mb-4">
527
+ <label className="block text-xs font-medium text-gray-700 mb-1">
528
+ Background Color
529
+ </label>
530
+ <input
531
+ type="color"
532
+ value={component.props.backgroundColor || '#ffffff'}
533
+ onChange={(e) => handlePropChange('backgroundColor', e.target.value)}
534
+ className="w-full h-10 border border-gray-300 rounded-md"
535
+ />
536
+ </div>
537
+ </div>
538
+
539
+ <div className="mb-4 pt-4 border-t border-gray-200">
540
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Spacing</h3>
541
+ <div className="grid grid-cols-2 gap-2 mb-4">
542
+ <NumberInput
543
+ label="Padding Top"
544
+ value={component.props.paddingTop || component.props.padding || 20}
545
+ onChange={(val) => handlePropChange('paddingTop', val)}
546
+ min={0}
547
+ max={100}
548
+ unit="px"
549
+ />
550
+ <NumberInput
551
+ label="Padding Bottom"
552
+ value={component.props.paddingBottom || component.props.padding || 20}
553
+ onChange={(val) => handlePropChange('paddingBottom', val)}
554
+ min={0}
555
+ max={100}
556
+ unit="px"
557
+ />
558
+ <NumberInput
559
+ label="Padding Left"
560
+ value={component.props.paddingLeft || component.props.padding || 20}
561
+ onChange={(val) => handlePropChange('paddingLeft', val)}
562
+ min={0}
563
+ max={100}
564
+ unit="px"
565
+ />
566
+ <NumberInput
567
+ label="Padding Right"
568
+ value={component.props.paddingRight || component.props.padding || 20}
569
+ onChange={(val) => handlePropChange('paddingRight', val)}
570
+ min={0}
571
+ max={100}
572
+ unit="px"
573
+ />
574
+ </div>
575
+ <NumberInput
576
+ label="Padding (All)"
577
+ value={component.props.padding || 20}
578
+ onChange={(val) => handlePropChange('padding', val)}
579
+ min={0}
580
+ max={100}
581
+ unit="px"
582
+ />
583
+ </div>
584
+
585
+ <div className="mb-4 pt-4 border-t border-gray-200">
586
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Border</h3>
587
+ <NumberInput
588
+ label="Border Width"
589
+ value={component.props.borderWidth || 0}
590
+ onChange={(val) => handlePropChange('borderWidth', val)}
591
+ min={0}
592
+ max={10}
593
+ unit="px"
594
+ />
595
+ <div className="mb-4">
596
+ <label className="block text-xs font-medium text-gray-700 mb-1">
597
+ Border Color
598
+ </label>
599
+ <input
600
+ type="color"
601
+ value={component.props.borderColor || '#e0e0e0'}
602
+ onChange={(e) => handlePropChange('borderColor', e.target.value)}
603
+ className="w-full h-10 border border-gray-300 rounded-md"
604
+ />
605
+ </div>
606
+ <NumberInput
607
+ label="Border Radius"
608
+ value={component.props.borderRadius || 0}
609
+ onChange={(val) => handlePropChange('borderRadius', val)}
610
+ min={0}
611
+ max={50}
612
+ unit="px"
613
+ />
614
+ </div>
615
+
616
+ <CommonStyles />
617
+ </>
618
+ );
619
+
620
+ case 'divider':
621
+ return (
622
+ <>
623
+ <div className="mb-4 pt-4 border-t border-gray-200">
624
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Style</h3>
625
+ <div className="mb-4">
626
+ <label className="block text-xs font-medium text-gray-700 mb-1">
627
+ Color
628
+ </label>
629
+ <input
630
+ type="color"
631
+ value={component.props.color || '#e0e0e0'}
632
+ onChange={(e) => handlePropChange('color', e.target.value)}
633
+ className="w-full h-10 border border-gray-300 rounded-md"
634
+ />
635
+ </div>
636
+ <NumberInput
637
+ label="Height/Thickness"
638
+ value={component.props.height || 1}
639
+ onChange={(val) => handlePropChange('height', val)}
640
+ min={1}
641
+ max={20}
642
+ unit="px"
643
+ />
644
+ </div>
645
+
646
+ <CommonStyles />
647
+ </>
648
+ );
649
+
650
+ case 'spacer':
651
+ return (
652
+ <>
653
+ <NumberInput
654
+ label="Height"
655
+ value={component.props.height || 20}
656
+ onChange={(val) => handlePropChange('height', val)}
657
+ min={0}
658
+ max={200}
659
+ unit="px"
660
+ />
661
+ </>
662
+ );
663
+
664
+ case 'row':
665
+ return (
666
+ <>
667
+ <div className="mb-4 pt-4 border-t border-gray-200">
668
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Layout</h3>
669
+ <NumberInput
670
+ label="Gap"
671
+ value={component.props.gap || 10}
672
+ onChange={(val) => handlePropChange('gap', val)}
673
+ min={0}
674
+ max={50}
675
+ unit="px"
676
+ />
677
+ <div className="mb-4">
678
+ <label className="block text-xs font-medium text-gray-700 mb-1">
679
+ Justify Content
680
+ </label>
681
+ <select
682
+ value={component.props.justifyContent || 'flex-start'}
683
+ onChange={(e) => handlePropChange('justifyContent', e.target.value)}
684
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
685
+ >
686
+ <option value="flex-start">Start</option>
687
+ <option value="center">Center</option>
688
+ <option value="flex-end">End</option>
689
+ <option value="space-between">Space Between</option>
690
+ <option value="space-around">Space Around</option>
691
+ </select>
692
+ </div>
693
+ </div>
694
+
695
+ <CommonStyles />
696
+ </>
697
+ );
698
+
699
+ case 'column':
700
+ return (
701
+ <>
702
+ <div className="mb-4 pt-4 border-t border-gray-200">
703
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Size</h3>
704
+ <div className="mb-4">
705
+ <label className="block text-xs font-medium text-gray-700 mb-1">
706
+ Width
707
+ </label>
708
+ <input
709
+ type="text"
710
+ value={component.props.width || '50%'}
711
+ onChange={(e) => handlePropChange('width', e.target.value)}
712
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
713
+ placeholder="50% or 300px"
714
+ />
715
+ </div>
716
+ </div>
717
+
718
+ <CommonStyles />
719
+ </>
720
+ );
721
+
722
+ case 'header':
723
+ return (
724
+ <>
725
+ <div className="mb-4 pt-4 border-t border-gray-200">
726
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Logo</h3>
727
+ <div className="mb-4">
728
+ <label className="block text-xs font-medium text-gray-700 mb-1">
729
+ Show Logo
730
+ </label>
731
+ <input
732
+ type="checkbox"
733
+ checked={component.props.showLogo !== false}
734
+ onChange={(e) => handlePropChange('showLogo', e.target.checked)}
735
+ className="w-4 h-4"
736
+ />
737
+ </div>
738
+ {component.props.showLogo !== false && (
739
+ <>
740
+ <div className="mb-4">
741
+ <label className="block text-xs font-medium text-gray-700 mb-1">
742
+ Logo URL
743
+ </label>
744
+ <input
745
+ type="text"
746
+ value={component.props.logoUrl || ''}
747
+ onChange={(e) => handlePropChange('logoUrl', e.target.value)}
748
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
749
+ placeholder="https://example.com/logo.png"
750
+ />
751
+ </div>
752
+ <div className="mb-4">
753
+ <label className="block text-xs font-medium text-gray-700 mb-1">
754
+ Logo Alt Text
755
+ </label>
756
+ <input
757
+ type="text"
758
+ value={component.props.logoAlt || ''}
759
+ onChange={(e) => handlePropChange('logoAlt', e.target.value)}
760
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
761
+ />
762
+ </div>
763
+ <NumberInput
764
+ label="Logo Height"
765
+ value={component.props.logoHeight || 40}
766
+ onChange={(val) => handlePropChange('logoHeight', val)}
767
+ min={20}
768
+ max={100}
769
+ unit="px"
770
+ />
771
+ </>
772
+ )}
773
+ </div>
774
+
775
+ <div className="mb-4 pt-4 border-t border-gray-200">
776
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Background</h3>
777
+ <div className="mb-4">
778
+ <label className="block text-xs font-medium text-gray-700 mb-1">
779
+ Background Color
780
+ </label>
781
+ <input
782
+ type="color"
783
+ value={component.props.backgroundColor || '#ffffff'}
784
+ onChange={(e) => handlePropChange('backgroundColor', e.target.value)}
785
+ className="w-full h-10 border border-gray-300 rounded-md"
786
+ />
787
+ </div>
788
+ </div>
789
+
790
+ <div className="mb-4 pt-4 border-t border-gray-200">
791
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Border</h3>
792
+ <div className="mb-4">
793
+ <label className="block text-xs font-medium text-gray-700 mb-1">
794
+ Show Bottom Border
795
+ </label>
796
+ <input
797
+ type="checkbox"
798
+ checked={component.props.borderBottom || false}
799
+ onChange={(e) => handlePropChange('borderBottom', e.target.checked)}
800
+ className="w-4 h-4"
801
+ />
802
+ </div>
803
+ {component.props.borderBottom && (
804
+ <div className="mb-4">
805
+ <label className="block text-xs font-medium text-gray-700 mb-1">
806
+ Border Color
807
+ </label>
808
+ <input
809
+ type="color"
810
+ value={component.props.borderColor || '#e0e0e0'}
811
+ onChange={(e) => handlePropChange('borderColor', e.target.value)}
812
+ className="w-full h-10 border border-gray-300 rounded-md"
813
+ />
814
+ </div>
815
+ )}
816
+ </div>
817
+
818
+ <div className="mb-4 pt-4 border-t border-gray-200">
819
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Spacing</h3>
820
+ <NumberInput
821
+ label="Padding"
822
+ value={component.props.padding || 20}
823
+ onChange={(val) => handlePropChange('padding', val)}
824
+ min={0}
825
+ max={100}
826
+ unit="px"
827
+ />
828
+ </div>
829
+
830
+ <CommonStyles />
831
+ </>
832
+ );
833
+
834
+ case 'footer':
835
+ return (
836
+ <>
837
+ <div className="mb-4 pt-4 border-t border-gray-200">
838
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Content</h3>
839
+ <div className="mb-4">
840
+ <label className="block text-xs font-medium text-gray-700 mb-1">
841
+ Copyright Text
842
+ </label>
843
+ <input
844
+ type="text"
845
+ value={component.props.copyright || ''}
846
+ onChange={(e) => handlePropChange('copyright', e.target.value)}
847
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
848
+ placeholder="© 2024 Company Name. All rights reserved."
849
+ />
850
+ </div>
851
+ <div className="mb-4">
852
+ <label className="block text-xs font-medium text-gray-700 mb-1">
853
+ Show Social Links
854
+ </label>
855
+ <input
856
+ type="checkbox"
857
+ checked={component.props.showSocialLinks !== false}
858
+ onChange={(e) => handlePropChange('showSocialLinks', e.target.checked)}
859
+ className="w-4 h-4"
860
+ />
861
+ </div>
862
+ </div>
863
+
864
+ <div className="mb-4 pt-4 border-t border-gray-200">
865
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Background</h3>
866
+ <div className="mb-4">
867
+ <label className="block text-xs font-medium text-gray-700 mb-1">
868
+ Background Color
869
+ </label>
870
+ <input
871
+ type="color"
872
+ value={component.props.backgroundColor || '#f5f5f5'}
873
+ onChange={(e) => handlePropChange('backgroundColor', e.target.value)}
874
+ className="w-full h-10 border border-gray-300 rounded-md"
875
+ />
876
+ </div>
877
+ </div>
878
+
879
+ <div className="mb-4 pt-4 border-t border-gray-200">
880
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Typography</h3>
881
+ <NumberInput
882
+ label="Font Size"
883
+ value={component.props.fontSize || 12}
884
+ onChange={(val) => handlePropChange('fontSize', val)}
885
+ min={8}
886
+ max={24}
887
+ unit="px"
888
+ />
889
+ <div className="mb-4">
890
+ <label className="block text-xs font-medium text-gray-700 mb-1">
891
+ Text Color
892
+ </label>
893
+ <input
894
+ type="color"
895
+ value={component.props.color || '#666666'}
896
+ onChange={(e) => handlePropChange('color', e.target.value)}
897
+ className="w-full h-10 border border-gray-300 rounded-md"
898
+ />
899
+ </div>
900
+ <div className="mb-4">
901
+ <label className="block text-xs font-medium text-gray-700 mb-1">
902
+ Text Align
903
+ </label>
904
+ <select
905
+ value={component.props.textAlign || 'center'}
906
+ onChange={(e) => handlePropChange('textAlign', e.target.value)}
907
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
908
+ >
909
+ <option value="left">Left</option>
910
+ <option value="center">Center</option>
911
+ <option value="right">Right</option>
912
+ </select>
913
+ </div>
914
+ </div>
915
+
916
+ <div className="mb-4 pt-4 border-t border-gray-200">
917
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Border</h3>
918
+ <div className="mb-4">
919
+ <label className="block text-xs font-medium text-gray-700 mb-1">
920
+ Show Top Border
921
+ </label>
922
+ <input
923
+ type="checkbox"
924
+ checked={component.props.borderTop || false}
925
+ onChange={(e) => handlePropChange('borderTop', e.target.checked)}
926
+ className="w-4 h-4"
927
+ />
928
+ </div>
929
+ </div>
930
+
931
+ <CommonStyles />
932
+ </>
933
+ );
934
+
935
+ case 'section':
936
+ return (
937
+ <>
938
+ <div className="mb-4 pt-4 border-t border-gray-200">
939
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Background</h3>
940
+ <div className="mb-4">
941
+ <label className="block text-xs font-medium text-gray-700 mb-1">
942
+ Background Color
943
+ </label>
944
+ <input
945
+ type="color"
946
+ value={component.props.backgroundColor || '#ffffff'}
947
+ onChange={(e) => handlePropChange('backgroundColor', e.target.value)}
948
+ className="w-full h-10 border border-gray-300 rounded-md"
949
+ />
950
+ </div>
951
+ </div>
952
+
953
+ <div className="mb-4 pt-4 border-t border-gray-200">
954
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Spacing</h3>
955
+ <NumberInput
956
+ label="Padding"
957
+ value={component.props.padding || 20}
958
+ onChange={(val) => handlePropChange('padding', val)}
959
+ min={0}
960
+ max={100}
961
+ unit="px"
962
+ />
963
+ </div>
964
+
965
+ <CommonStyles />
966
+ </>
967
+ );
968
+
969
+ case 'link':
970
+ return (
971
+ <>
972
+ <div className="mb-4">
973
+ <label className="block text-xs font-medium text-gray-700 mb-1">
974
+ Link Text
975
+ </label>
976
+ <input
977
+ type="text"
978
+ value={component.props.text || ''}
979
+ onChange={(e) => handlePropChange('text', e.target.value)}
980
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
981
+ />
982
+ </div>
983
+ <div className="mb-4">
984
+ <label className="block text-xs font-medium text-gray-700 mb-1">
985
+ URL (href)
986
+ </label>
987
+ <input
988
+ type="text"
989
+ value={component.props.href || '#'}
990
+ onChange={(e) => handlePropChange('href', e.target.value)}
991
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
992
+ placeholder="https://example.com"
993
+ />
994
+ </div>
995
+ <div className="mb-4 pt-4 border-t border-gray-200">
996
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Style</h3>
997
+ <NumberInput
998
+ label="Font Size"
999
+ value={component.props.fontSize || 16}
1000
+ onChange={(val) => handlePropChange('fontSize', val)}
1001
+ min={10}
1002
+ max={24}
1003
+ unit="px"
1004
+ />
1005
+ <div className="mb-4">
1006
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1007
+ Color
1008
+ </label>
1009
+ <input
1010
+ type="color"
1011
+ value={component.props.color || '#007bff'}
1012
+ onChange={(e) => handlePropChange('color', e.target.value)}
1013
+ className="w-full h-10 border border-gray-300 rounded-md"
1014
+ />
1015
+ </div>
1016
+ <div className="mb-4">
1017
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1018
+ Underline
1019
+ </label>
1020
+ <input
1021
+ type="checkbox"
1022
+ checked={component.props.underline !== false}
1023
+ onChange={(e) => handlePropChange('underline', e.target.checked)}
1024
+ className="w-4 h-4"
1025
+ />
1026
+ </div>
1027
+ </div>
1028
+
1029
+ <CommonStyles />
1030
+ </>
1031
+ );
1032
+
1033
+ case 'list':
1034
+ return (
1035
+ <>
1036
+ <div className="mb-4">
1037
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1038
+ List Type
1039
+ </label>
1040
+ <select
1041
+ value={component.props.listType || 'unordered'}
1042
+ onChange={(e) => handlePropChange('listType', e.target.value)}
1043
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1044
+ >
1045
+ <option value="unordered">Unordered (Bullets)</option>
1046
+ <option value="ordered">Ordered (Numbers)</option>
1047
+ </select>
1048
+ </div>
1049
+ <div className="mb-4">
1050
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1051
+ List Items (one per line)
1052
+ </label>
1053
+ <textarea
1054
+ value={(component.props.items || []).join('\n')}
1055
+ onChange={(e) => {
1056
+ const items = e.target.value.split('\n').filter(item => item.trim());
1057
+ handlePropChange('items', items);
1058
+ }}
1059
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1060
+ rows={5}
1061
+ placeholder="Item 1&#10;Item 2&#10;Item 3"
1062
+ />
1063
+ </div>
1064
+ <div className="mb-4 pt-4 border-t border-gray-200">
1065
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Typography</h3>
1066
+ <NumberInput
1067
+ label="Font Size"
1068
+ value={component.props.fontSize || 16}
1069
+ onChange={(val) => handlePropChange('fontSize', val)}
1070
+ min={10}
1071
+ max={24}
1072
+ unit="px"
1073
+ />
1074
+ <div className="mb-4">
1075
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1076
+ Color
1077
+ </label>
1078
+ <input
1079
+ type="color"
1080
+ value={component.props.color || '#000000'}
1081
+ onChange={(e) => handlePropChange('color', e.target.value)}
1082
+ className="w-full h-10 border border-gray-300 rounded-md"
1083
+ />
1084
+ </div>
1085
+ </div>
1086
+
1087
+ <CommonStyles />
1088
+ </>
1089
+ );
1090
+
1091
+ case 'table':
1092
+ return (
1093
+ <>
1094
+ <div className="mb-4">
1095
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1096
+ Headers (comma separated)
1097
+ </label>
1098
+ <input
1099
+ type="text"
1100
+ value={(component.props.headers || []).join(', ')}
1101
+ onChange={(e) => {
1102
+ const headers = e.target.value.split(',').map(h => h.trim()).filter(h => h);
1103
+ handlePropChange('headers', headers);
1104
+ }}
1105
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1106
+ placeholder="Header 1, Header 2, Header 3"
1107
+ />
1108
+ </div>
1109
+ <div className="mb-4">
1110
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1111
+ Rows (comma separated, one row per line)
1112
+ </label>
1113
+ <textarea
1114
+ value={(component.props.rows || []).map((row: string[]) => row.join(', ')).join('\n')}
1115
+ onChange={(e) => {
1116
+ const rows = e.target.value.split('\n')
1117
+ .filter(row => row.trim())
1118
+ .map(row => row.split(',').map(cell => cell.trim()).filter(cell => cell));
1119
+ handlePropChange('rows', rows);
1120
+ }}
1121
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1122
+ rows={5}
1123
+ placeholder="Cell 1, Cell 2, Cell 3&#10;Cell 4, Cell 5, Cell 6"
1124
+ />
1125
+ </div>
1126
+ <div className="mb-4 pt-4 border-t border-gray-200">
1127
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Style</h3>
1128
+ <NumberInput
1129
+ label="Border Width"
1130
+ value={component.props.borderWidth || 1}
1131
+ onChange={(val) => handlePropChange('borderWidth', val)}
1132
+ min={0}
1133
+ max={5}
1134
+ unit="px"
1135
+ />
1136
+ <div className="mb-4">
1137
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1138
+ Border Color
1139
+ </label>
1140
+ <input
1141
+ type="color"
1142
+ value={component.props.borderColor || '#e0e0e0'}
1143
+ onChange={(e) => handlePropChange('borderColor', e.target.value)}
1144
+ className="w-full h-10 border border-gray-300 rounded-md"
1145
+ />
1146
+ </div>
1147
+ <NumberInput
1148
+ label="Cell Padding"
1149
+ value={component.props.cellPadding || 10}
1150
+ onChange={(val) => handlePropChange('cellPadding', val)}
1151
+ min={0}
1152
+ max={30}
1153
+ unit="px"
1154
+ />
1155
+ <div className="mb-4">
1156
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1157
+ Header Background Color
1158
+ </label>
1159
+ <input
1160
+ type="color"
1161
+ value={component.props.headerBackgroundColor || '#f5f5f5'}
1162
+ onChange={(e) => handlePropChange('headerBackgroundColor', e.target.value)}
1163
+ className="w-full h-10 border border-gray-300 rounded-md"
1164
+ />
1165
+ </div>
1166
+ </div>
1167
+
1168
+ <CommonStyles />
1169
+ </>
1170
+ );
1171
+
1172
+ case 'social-links':
1173
+ return (
1174
+ <>
1175
+ <div className="mb-4 pt-4 border-t border-gray-200">
1176
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Social Media Links</h3>
1177
+ <div className="mb-4">
1178
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1179
+ Facebook URL
1180
+ </label>
1181
+ <input
1182
+ type="text"
1183
+ value={component.props.facebook || ''}
1184
+ onChange={(e) => handlePropChange('facebook', e.target.value)}
1185
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1186
+ placeholder="https://facebook.com/yourpage"
1187
+ />
1188
+ </div>
1189
+ <div className="mb-4">
1190
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1191
+ Twitter URL
1192
+ </label>
1193
+ <input
1194
+ type="text"
1195
+ value={component.props.twitter || ''}
1196
+ onChange={(e) => handlePropChange('twitter', e.target.value)}
1197
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1198
+ placeholder="https://twitter.com/yourhandle"
1199
+ />
1200
+ </div>
1201
+ <div className="mb-4">
1202
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1203
+ Instagram URL
1204
+ </label>
1205
+ <input
1206
+ type="text"
1207
+ value={component.props.instagram || ''}
1208
+ onChange={(e) => handlePropChange('instagram', e.target.value)}
1209
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1210
+ placeholder="https://instagram.com/yourhandle"
1211
+ />
1212
+ </div>
1213
+ <div className="mb-4">
1214
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1215
+ LinkedIn URL
1216
+ </label>
1217
+ <input
1218
+ type="text"
1219
+ value={component.props.linkedin || ''}
1220
+ onChange={(e) => handlePropChange('linkedin', e.target.value)}
1221
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1222
+ placeholder="https://linkedin.com/company/yourcompany"
1223
+ />
1224
+ </div>
1225
+ <div className="mb-4">
1226
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1227
+ YouTube URL
1228
+ </label>
1229
+ <input
1230
+ type="text"
1231
+ value={component.props.youtube || ''}
1232
+ onChange={(e) => handlePropChange('youtube', e.target.value)}
1233
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1234
+ placeholder="https://youtube.com/yourchannel"
1235
+ />
1236
+ </div>
1237
+ </div>
1238
+ <div className="mb-4 pt-4 border-t border-gray-200">
1239
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Style</h3>
1240
+ <NumberInput
1241
+ label="Icon Size"
1242
+ value={component.props.iconSize || 24}
1243
+ onChange={(val) => handlePropChange('iconSize', val)}
1244
+ min={16}
1245
+ max={48}
1246
+ unit="px"
1247
+ />
1248
+ <NumberInput
1249
+ label="Gap"
1250
+ value={component.props.gap || 10}
1251
+ onChange={(val) => handlePropChange('gap', val)}
1252
+ min={0}
1253
+ max={30}
1254
+ unit="px"
1255
+ />
1256
+ <div className="mb-4">
1257
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1258
+ Alignment
1259
+ </label>
1260
+ <select
1261
+ value={component.props.align || 'center'}
1262
+ onChange={(e) => handlePropChange('align', e.target.value)}
1263
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1264
+ >
1265
+ <option value="flex-start">Left</option>
1266
+ <option value="center">Center</option>
1267
+ <option value="flex-end">Right</option>
1268
+ </select>
1269
+ </div>
1270
+ </div>
1271
+
1272
+ <CommonStyles />
1273
+ </>
1274
+ );
1275
+
1276
+ case 'quote':
1277
+ return (
1278
+ <>
1279
+ <div className="mb-4">
1280
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1281
+ Quote Text
1282
+ </label>
1283
+ <textarea
1284
+ value={component.props.text || ''}
1285
+ onChange={(e) => handlePropChange('text', e.target.value)}
1286
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1287
+ rows={3}
1288
+ />
1289
+ </div>
1290
+ <div className="mb-4">
1291
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1292
+ Author (optional)
1293
+ </label>
1294
+ <input
1295
+ type="text"
1296
+ value={component.props.author || ''}
1297
+ onChange={(e) => handlePropChange('author', e.target.value)}
1298
+ className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm"
1299
+ placeholder="Author Name"
1300
+ />
1301
+ </div>
1302
+ <div className="mb-4 pt-4 border-t border-gray-200">
1303
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Typography</h3>
1304
+ <NumberInput
1305
+ label="Font Size"
1306
+ value={component.props.fontSize || 18}
1307
+ onChange={(val) => handlePropChange('fontSize', val)}
1308
+ min={12}
1309
+ max={32}
1310
+ unit="px"
1311
+ />
1312
+ <div className="mb-4">
1313
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1314
+ Color
1315
+ </label>
1316
+ <input
1317
+ type="color"
1318
+ value={component.props.color || '#666666'}
1319
+ onChange={(e) => handlePropChange('color', e.target.value)}
1320
+ className="w-full h-10 border border-gray-300 rounded-md"
1321
+ />
1322
+ </div>
1323
+ </div>
1324
+ <div className="mb-4 pt-4 border-t border-gray-200">
1325
+ <h3 className="text-xs font-semibold text-gray-600 mb-3 uppercase">Border</h3>
1326
+ <div className="mb-4">
1327
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1328
+ Show Left Border
1329
+ </label>
1330
+ <input
1331
+ type="checkbox"
1332
+ checked={component.props.borderLeft !== false}
1333
+ onChange={(e) => handlePropChange('borderLeft', e.target.checked)}
1334
+ className="w-4 h-4"
1335
+ />
1336
+ </div>
1337
+ {component.props.borderLeft !== false && (
1338
+ <div className="mb-4">
1339
+ <label className="block text-xs font-medium text-gray-700 mb-1">
1340
+ Border Color
1341
+ </label>
1342
+ <input
1343
+ type="color"
1344
+ value={component.props.borderColor || '#007bff'}
1345
+ onChange={(e) => handlePropChange('borderColor', e.target.value)}
1346
+ className="w-full h-10 border border-gray-300 rounded-md"
1347
+ />
1348
+ </div>
1349
+ )}
1350
+ </div>
1351
+
1352
+ <CommonStyles />
1353
+ </>
1354
+ );
1355
+
1356
+ default:
1357
+ return <p className="text-sm text-gray-400">No properties available</p>;
1358
+ }
1359
+ };
1360
+
1361
+ return (
1362
+ <div className="p-4 h-full overflow-y-auto">
1363
+ <div className="flex items-center justify-between mb-4 sticky top-0 bg-white pb-2 border-b border-gray-200">
1364
+ <h2 className="text-sm font-semibold text-gray-700">Properties</h2>
1365
+ <button
1366
+ onClick={() => {
1367
+ removeComponent(component.id);
1368
+ selectComponent(null);
1369
+ }}
1370
+ className="p-1.5 text-red-600 hover:bg-red-50 rounded-md transition-colors"
1371
+ >
1372
+ <Trash2 size={16} />
1373
+ </button>
1374
+ </div>
1375
+
1376
+ <div className="mb-4 pb-4 border-b border-gray-200">
1377
+ <p className="text-xs text-gray-500 mb-1">Component Type</p>
1378
+ <p className="text-sm font-medium text-gray-700 capitalize">
1379
+ {component.type}
1380
+ </p>
1381
+ </div>
1382
+
1383
+ <div>{renderPropertyEditor()}</div>
1384
+ </div>
1385
+ );
1386
+ }