react-pdf-levelup 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +40 -0
  2. package/fn/aggAlias.js +21 -0
  3. package/fn/moveComponents.js +129 -0
  4. package/fn/postinstall.js +66 -0
  5. package/fn/upVersion.js +12 -0
  6. package/fn/updateTsconfig.js +10 -0
  7. package/next.config.mjs +6 -0
  8. package/package.json +39 -0
  9. package/public/bg-login.jpg +0 -0
  10. package/public/codigo_guardado.js +1 -0
  11. package/public/css/style.css +751 -0
  12. package/public/dboard/logo.png +0 -0
  13. package/public/favicon.ico +0 -0
  14. package/public/fonts/TimesNewerRoman-Bold.otf +0 -0
  15. package/public/fonts/TimesNewerRoman-BoldItalic.otf +0 -0
  16. package/public/fonts/TimesNewerRoman-Italic.otf +0 -0
  17. package/public/fonts/TimesNewerRoman-Regular.otf +0 -0
  18. package/public/header-pdf.jpg +0 -0
  19. package/public/home/bgHome.jpg +0 -0
  20. package/public/home/bgHome2.jpg +0 -0
  21. package/public/home/download.jpg +0 -0
  22. package/public/home/undraw_elements_re_25t9.svg +1 -0
  23. package/public/home/undraw_project_completed_re_jr7u.svg +1 -0
  24. package/public/home/undraw_shared_goals_re_jvqd.svg +1 -0
  25. package/public/home/undraw_spread_love_re_v3cl.svg +1 -0
  26. package/public/home/undraw_target_re_fi8j.svg +1 -0
  27. package/public/home/undraw_visionary_technology_re_jfp7.svg +1 -0
  28. package/public/logo.png +0 -0
  29. package/public/marca/logo.svg +1 -0
  30. package/src/components/PDF/components/DocumentoTemplate.tsx +140 -0
  31. package/src/components/PDF/components/PDFContent.tsx +192 -0
  32. package/src/components/PDF/core/Etiquetas.tsx +152 -0
  33. package/src/components/PDF/core/Grid.tsx +101 -0
  34. package/src/components/PDF/core/Img.tsx +22 -0
  35. package/src/components/PDF/core/LayoutPDF.tsx +186 -0
  36. package/src/components/PDF/core/Listas.tsx +10 -0
  37. package/src/components/PDF/core/MakePDF.tsx +50 -0
  38. package/src/components/PDF/core/PageElements.tsx +50 -0
  39. package/src/components/PDF/core/Position.tsx +33 -0
  40. package/src/components/PDF/core/Tablet.tsx +121 -0
  41. package/src/components/PDF/core/index.tsx +56 -0
  42. package/src/components/PDF/lib/pdfParser.ts +620 -0
  43. package/src/components/PDF/services/apiService.ts +17 -0
  44. package/src/components/PDF/templates/AllTemplate.tsx +134 -0
  45. package/src/components/PDF/templates/BusinessCardTemplate.tsx +139 -0
  46. package/src/components/PDF/templates/CertificateTemplate.tsx +31 -0
  47. package/src/components/PDF/templates/HeaderFooterTemplate.tsx +61 -0
  48. package/src/components/PDF/templates/InvoiceTemplate.tsx +53 -0
  49. package/src/components/PDF/templates/ProposalTemplate.tsx +246 -0
  50. package/src/components/PDF/templates/ReportTemplate.tsx +57 -0
  51. package/src/components/PDF/templates/ResumeTemplate.tsx +170 -0
  52. package/src/components/PDF/templates/TablasTemplate.tsx +307 -0
  53. package/src/components/PDF/templates/index.ts +9 -0
  54. package/src/components/PDF/view/ColorPicker.tsx +147 -0
  55. package/src/components/PDF/view/Header.tsx +102 -0
  56. package/src/components/PDF/view/HomePDF.tsx +177 -0
  57. package/src/components/PDF/view/SettingsPanel.tsx +703 -0
  58. package/src/pages/AllTemplate.tsx +53 -0
  59. package/src/pages/Documento2.tsx +45 -0
  60. package/src/pages/_app.tsx +6 -0
  61. package/src/pages/_document.tsx +13 -0
  62. package/src/pages/api/generatePDF.ts +74 -0
  63. package/src/pages/api/hello.ts +13 -0
  64. package/src/pages/api/readFile.ts +18 -0
  65. package/src/pages/api/readTemplateFile.ts +26 -0
  66. package/src/pages/api/save.ts +22 -0
  67. package/src/pages/api/saveFile.ts +20 -0
  68. package/src/pages/index.tsx +13 -0
  69. package/src/pages/template/[template].tsx +250 -0
  70. package/tsconfig.json +63 -0
@@ -0,0 +1,703 @@
1
+ "use client"
2
+
3
+ import type React from "react"
4
+ import { useState, useEffect } from "react"
5
+ import { X } from "lucide-react"
6
+
7
+ interface SettingsPanelProps {
8
+ isOpen: boolean
9
+ onClose: () => void
10
+ onApplySettings: (settings: LayoutSettings) => void
11
+ currentCode: string
12
+ }
13
+
14
+ export interface LayoutSettings {
15
+ pageSize: string
16
+ orientation: string
17
+ padding: number
18
+ paddingTop: number
19
+ paddingRight: number
20
+ paddingBottom: number
21
+ paddingLeft: number
22
+ backgroundColor: string
23
+ fontFamily: string
24
+ fontSize: number
25
+ lineHeight: number
26
+ showPageNumbers: boolean
27
+ customPadding: boolean
28
+ }
29
+
30
+ const defaultSettings: LayoutSettings = {
31
+ pageSize: "A4",
32
+ orientation: "portrait",
33
+ padding: 72,
34
+ paddingTop: 72,
35
+ paddingRight: 72,
36
+ paddingBottom: 86,
37
+ paddingLeft: 72,
38
+ backgroundColor: "white",
39
+ fontFamily: "Times New Roman",
40
+ fontSize: 12,
41
+ lineHeight: 1.5,
42
+ showPageNumbers: true,
43
+ customPadding: false,
44
+ }
45
+
46
+ // Paper size dimensions in mm
47
+ const paperSizes = {
48
+ A0: "841 × 1189 mm",
49
+ A1: "594 × 841 mm",
50
+ A2: "420 × 594 mm",
51
+ A3: "297 × 420 mm",
52
+ A4: "210 × 297 mm",
53
+ A5: "148 × 210 mm",
54
+ A6: "105 × 148 mm",
55
+ A7: "74 × 105 mm",
56
+ A8: "52 × 74 mm",
57
+ A9: "37 × 52 mm",
58
+ A10: "26 × 37 mm",
59
+ LETTER: "216 × 279 mm",
60
+ LEGAL: "216 × 356 mm",
61
+ }
62
+
63
+ const SettingsPanel: React.FC<SettingsPanelProps> = ({ isOpen, onClose, onApplySettings, currentCode }) => {
64
+ const [settings, setSettings] = useState<LayoutSettings>(defaultSettings)
65
+ const [activeSection, setActiveSection] = useState<string>("page")
66
+ const [previewKey, setPreviewKey] = useState(0)
67
+
68
+ // Extract current settings from code
69
+ useEffect(() => {
70
+ if (currentCode && isOpen) {
71
+ try {
72
+ const pageSizeMatch = currentCode.match(/size="([^"]+)"/)
73
+ if (pageSizeMatch?.[1]) {
74
+ setSettings((prev) => ({ ...prev, pageSize: pageSizeMatch[1] }))
75
+ }
76
+
77
+ const orientationMatch = currentCode.match(/orientation="([^"]+)"/)
78
+ if (orientationMatch?.[1]) {
79
+ setSettings((prev) => ({ ...prev, orientation: orientationMatch[1] }))
80
+ }
81
+
82
+ const paddingMatch = currentCode.match(/padding:\s*(\d+)/)
83
+ if (paddingMatch?.[1]) {
84
+ setSettings((prev) => ({
85
+ ...prev,
86
+ padding: Number.parseInt(paddingMatch[1]),
87
+ customPadding: false,
88
+ }))
89
+ }
90
+
91
+ // Extract individual padding values
92
+ const paddingProps = ["paddingTop", "paddingRight", "paddingBottom", "paddingLeft"]
93
+ const hasCustomPadding = paddingProps.some((prop) => currentCode.includes(prop))
94
+
95
+ if (hasCustomPadding) {
96
+ setSettings((prev) => ({ ...prev, customPadding: true }))
97
+ paddingProps.forEach((prop) => {
98
+ const match = currentCode.match(new RegExp(`${prop}:\\s*(\\d+)`))
99
+ if (match?.[1]) {
100
+ setSettings((prev) => ({ ...prev, [prop]: Number.parseInt(match[1]) }))
101
+ }
102
+ })
103
+ }
104
+
105
+ const backgroundColorMatch = currentCode.match(/backgroundColor:\s*"([^"]+)"/)
106
+ if (backgroundColorMatch?.[1]) {
107
+ setSettings((prev) => ({ ...prev, backgroundColor: backgroundColorMatch[1] }))
108
+ }
109
+
110
+ const fontFamilyMatch = currentCode.match(/fontFamily:\s*"([^"]+)"/)
111
+ if (fontFamilyMatch?.[1]) {
112
+ setSettings((prev) => ({ ...prev, fontFamily: fontFamilyMatch[1] }))
113
+ }
114
+
115
+ const fontSizeMatch = currentCode.match(/fontSize:\s*(\d+)/)
116
+ if (fontSizeMatch?.[1]) {
117
+ setSettings((prev) => ({ ...prev, fontSize: Number.parseInt(fontSizeMatch[1]) }))
118
+ }
119
+
120
+ const lineHeightMatch = currentCode.match(/lineHeight:\s*([\d.]+)/)
121
+ if (lineHeightMatch?.[1]) {
122
+ setSettings((prev) => ({ ...prev, lineHeight: Number.parseFloat(lineHeightMatch[1]) }))
123
+ }
124
+
125
+ const showPageNumbers = currentCode.includes("style={styles.pageNumber}")
126
+ setSettings((prev) => ({ ...prev, showPageNumbers }))
127
+ } catch (error) {
128
+ console.error("Error parsing code:", error)
129
+ }
130
+ }
131
+ }, [currentCode, isOpen])
132
+
133
+ // Actualizar la función handleChange para aplicar cambios en tiempo real
134
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
135
+ const { name, value, type } = e.target
136
+ const newValue =
137
+ type === "checkbox" ? (e.target as HTMLInputElement).checked : type === "number" ? Number(value) : value
138
+
139
+ const updatedSettings = { ...settings, [name]: newValue }
140
+ setSettings(updatedSettings)
141
+ setPreviewKey((prev) => prev + 1)
142
+
143
+ // Apply settings in real-time for all changes
144
+ onApplySettings(updatedSettings)
145
+ }
146
+
147
+ // Actualizar la función handleApply para aplicar inmediatamente los cambios
148
+ const handleApply = () => {
149
+ // Asegurarse de que los cambios se apliquen inmediatamente
150
+ onApplySettings(settings)
151
+ onClose()
152
+ }
153
+
154
+ if (!isOpen) return null
155
+
156
+ const renderPagePreview = () => {
157
+ // Proporciones aproximadas para la vista previa
158
+ const pageSizeRatios: Record<string, [number, number]> = {
159
+ A0: [841, 1189],
160
+ A1: [594, 841],
161
+ A2: [420, 594],
162
+ A3: [297, 420],
163
+ A4: [210, 297],
164
+ A5: [148, 210],
165
+ A6: [105,148],
166
+ A7: [74 , 105],
167
+ A8: [52, 74],
168
+ A9: [37, 52],
169
+ A10: [26, 37],
170
+ LETTER: [216, 279],
171
+ LEGAL: [216, 356],
172
+ }
173
+
174
+ // Obtener las proporciones para el tamaño seleccionado
175
+ const [width, height] = pageSizeRatios[settings.pageSize] || [210, 297] // A4 por defecto
176
+
177
+ // Calcular dimensiones manteniendo la proporción pero con un tamaño máximo
178
+ const maxDimension = 160
179
+ const ratio = width / height
180
+
181
+ let previewWidth, previewHeight
182
+
183
+ if (settings.orientation === "portrait") {
184
+ if (height > width) {
185
+ previewHeight = maxDimension
186
+ previewWidth = previewHeight * ratio
187
+ } else {
188
+ previewWidth = maxDimension
189
+ previewHeight = previewWidth / ratio
190
+ }
191
+ } else {
192
+ // landscape
193
+ if (width > height) {
194
+ previewWidth = maxDimension
195
+ previewHeight = previewWidth / ratio
196
+ } else {
197
+ previewHeight = maxDimension
198
+ previewWidth = previewHeight * ratio
199
+ }
200
+ }
201
+
202
+ const style: React.CSSProperties = {
203
+ width: settings.orientation === "portrait" ? `${previewWidth}px` : `${previewHeight}px`,
204
+ height: settings.orientation === "portrait" ? `${previewHeight}px` : `${previewWidth}px`,
205
+ backgroundColor: settings.backgroundColor,
206
+ border: "1px solid var(--border-color)",
207
+ borderRadius: "4px",
208
+ position: "relative",
209
+ overflow: "hidden",
210
+ transition: "all 0.3s ease",
211
+ }
212
+
213
+ // Calcular el escalado para los márgenes en la vista previa
214
+ const scale = Math.min(previewWidth, previewHeight) / 595 // 595 es aproximadamente el ancho de A4 en puntos
215
+
216
+ const contentStyle: React.CSSProperties = {
217
+ position: "absolute",
218
+ top: `${(settings.customPadding ? settings.paddingTop : settings.padding) * scale}px`,
219
+ right: `${(settings.customPadding ? settings.paddingRight : settings.padding) * scale}px`,
220
+ bottom: `${(settings.customPadding ? settings.paddingBottom : settings.padding) * scale}px`,
221
+ left: `${(settings.customPadding ? settings.paddingLeft : settings.padding) * scale}px`,
222
+ border: "1px dashed var(--border-color)",
223
+ borderRadius: "2px",
224
+ fontSize: `${settings.fontSize * scale}px`,
225
+ fontFamily: settings.fontFamily,
226
+ lineHeight: settings.lineHeight,
227
+ }
228
+
229
+ return (
230
+ <div className="preview-container" key={previewKey}>
231
+ <div style={style} className="page-preview">
232
+ <div style={contentStyle} className="content-preview">
233
+ <div className="preview-text">Lorem ipsum</div>
234
+ {settings.showPageNumbers && <div className="preview-page-number">1</div>}
235
+ </div>
236
+ </div>
237
+ <div className="preview-size-label">
238
+ {settings.pageSize} - {settings.orientation}
239
+ </div>
240
+ </div>
241
+ )
242
+ }
243
+
244
+ return (
245
+ <div className="settings-panel-overlay">
246
+ <div className="settings-panel">
247
+ <div className="settings-panel-header">
248
+ <h2>Configuración del Layout</h2>
249
+ <button className="btn-icon" onClick={onClose}>
250
+ <X size={20} />
251
+ </button>
252
+ </div>
253
+
254
+ <div className="settings-panel-nav">
255
+ <button
256
+ className={`nav-button ${activeSection === "page" ? "active" : ""}`}
257
+ onClick={() => setActiveSection("page")}
258
+ >
259
+ Página
260
+ </button>
261
+ <button
262
+ className={`nav-button ${activeSection === "margins" ? "active" : ""}`}
263
+ onClick={() => setActiveSection("margins")}
264
+ >
265
+ Márgenes
266
+ </button>
267
+ <button
268
+ className={`nav-button ${activeSection === "typography" ? "active" : ""}`}
269
+ onClick={() => setActiveSection("typography")}
270
+ >
271
+ Tipografía
272
+ </button>
273
+ <button
274
+ className={`nav-button ${activeSection === "other" ? "active" : ""}`}
275
+ onClick={() => setActiveSection("other")}
276
+ >
277
+ Otros
278
+ </button>
279
+ </div>
280
+
281
+ <div className="settings-panel-content">
282
+ <div className="settings-layout">
283
+ <div className="settings-controls">
284
+ {activeSection === "page" && (
285
+ <div className="settings-section">
286
+ <h3>Configuración de página</h3>
287
+ <div className="form-group with-preview">
288
+ <label htmlFor="pageSize">Tamaño de página</label>
289
+ <select
290
+ id="pageSize"
291
+ name="pageSize"
292
+ className="form-control"
293
+ value={settings.pageSize}
294
+ onChange={handleChange}
295
+ >
296
+ {Object.entries(paperSizes).map(([size, dimensions]) => (
297
+ <option key={size} value={size}>
298
+ {size} ({dimensions})
299
+ </option>
300
+ ))}
301
+ </select>
302
+ </div>
303
+
304
+ <div className="form-group with-preview">
305
+ <label htmlFor="orientation">Orientación</label>
306
+ <div className="orientation-buttons">
307
+ <button
308
+ type="button"
309
+ className={`orientation-button ${settings.orientation === "portrait" ? "active" : ""}`}
310
+ onClick={() => handleChange({ target: { name: "orientation", value: "portrait" } } as any)}
311
+ >
312
+ Vertical
313
+ </button>
314
+ <button
315
+ type="button"
316
+ className={`orientation-button ${settings.orientation === "landscape" ? "active" : ""}`}
317
+ onClick={() => handleChange({ target: { name: "orientation", value: "landscape" } } as any)}
318
+ >
319
+ Horizontal
320
+ </button>
321
+ </div>
322
+ </div>
323
+
324
+ <div className="form-group">
325
+ <label htmlFor="backgroundColor">Color de fondo</label>
326
+ <div className="color-input-group">
327
+ <input
328
+ type="color"
329
+ id="backgroundColor"
330
+ name="backgroundColor"
331
+ value={settings.backgroundColor === "white" ? "#ffffff" : settings.backgroundColor}
332
+ onChange={handleChange}
333
+ className="form-control color-input"
334
+ />
335
+ <input
336
+ type="text"
337
+ value={settings.backgroundColor === "white" ? "#ffffff" : settings.backgroundColor}
338
+ onChange={(e) =>
339
+ handleChange({ target: { name: "backgroundColor", value: e.target.value } } as any)
340
+ }
341
+ className="form-control color-text"
342
+ />
343
+ </div>
344
+ </div>
345
+ </div>
346
+ )}
347
+
348
+ {activeSection === "margins" && (
349
+ <div className="settings-section">
350
+ <h3>Márgenes</h3>
351
+ <div className="form-group">
352
+ <div className="checkbox-group">
353
+ <input
354
+ type="checkbox"
355
+ id="customPadding"
356
+ name="customPadding"
357
+ checked={settings.customPadding}
358
+ onChange={handleChange}
359
+ />
360
+ <label htmlFor="customPadding">Personalizar márgenes individuales</label>
361
+ </div>
362
+ </div>
363
+
364
+ {!settings.customPadding ? (
365
+ <div className="form-group with-preview">
366
+ <label htmlFor="padding">Margen uniforme (puntos)</label>
367
+ <input
368
+ type="range"
369
+ id="padding"
370
+ name="padding"
371
+ value={settings.padding}
372
+ onChange={handleChange}
373
+ className="form-control range-input"
374
+ min="0"
375
+ max="200"
376
+ />
377
+ <div className="range-value">{settings.padding}pt</div>
378
+ </div>
379
+ ) : (
380
+ <div className="padding-grid">
381
+ <div className="form-group">
382
+ <label htmlFor="paddingTop">Superior</label>
383
+ <input
384
+ type="range"
385
+ id="paddingTop"
386
+ name="paddingTop"
387
+ value={settings.paddingTop}
388
+ onChange={handleChange}
389
+ className="form-control range-input"
390
+ min="0"
391
+ max="200"
392
+ />
393
+ <div className="range-value">{settings.paddingTop}pt</div>
394
+ </div>
395
+ <div className="form-group">
396
+ <label htmlFor="paddingRight">Derecho</label>
397
+ <input
398
+ type="range"
399
+ id="paddingRight"
400
+ name="paddingRight"
401
+ value={settings.paddingRight}
402
+ onChange={handleChange}
403
+ className="form-control range-input"
404
+ min="0"
405
+ max="200"
406
+ />
407
+ <div className="range-value">{settings.paddingRight}pt</div>
408
+ </div>
409
+ <div className="form-group">
410
+ <label htmlFor="paddingBottom">Inferior</label>
411
+ <input
412
+ type="range"
413
+ id="paddingBottom"
414
+ name="paddingBottom"
415
+ value={settings.paddingBottom}
416
+ onChange={handleChange}
417
+ className="form-control range-input"
418
+ min="0"
419
+ max="200"
420
+ />
421
+ <div className="range-value">{settings.paddingBottom}pt</div>
422
+ </div>
423
+ <div className="form-group">
424
+ <label htmlFor="paddingLeft">Izquierdo</label>
425
+ <input
426
+ type="range"
427
+ id="paddingLeft"
428
+ name="paddingLeft"
429
+ value={settings.paddingLeft}
430
+ onChange={handleChange}
431
+ className="form-control range-input"
432
+ min="0"
433
+ max="200"
434
+ />
435
+ <div className="range-value">{settings.paddingLeft}pt</div>
436
+ </div>
437
+ </div>
438
+ )}
439
+ </div>
440
+ )}
441
+
442
+ {activeSection === "typography" && (
443
+ <div className="settings-section">
444
+ <h3>Tipografía</h3>
445
+ <div className="form-group">
446
+ <label htmlFor="fontFamily">Familia de fuente</label>
447
+ <select
448
+ id="fontFamily"
449
+ name="fontFamily"
450
+ className="form-control"
451
+ value={settings.fontFamily}
452
+ onChange={handleChange}
453
+ >
454
+ <option value="Times New Roman">Times New Roman</option>
455
+ <option value="Helvetica">Helvetica</option>
456
+ <option value="Courier">Courier</option>
457
+ <option value="Arial">Arial</option>
458
+ </select>
459
+ </div>
460
+
461
+ <div className="form-group">
462
+ <label htmlFor="fontSize">Tamaño de fuente (puntos)</label>
463
+ <input
464
+ type="range"
465
+ id="fontSize"
466
+ name="fontSize"
467
+ value={settings.fontSize}
468
+ onChange={handleChange}
469
+ className="form-control range-input"
470
+ min="8"
471
+ max="24"
472
+ />
473
+ <div className="range-value">{settings.fontSize}pt</div>
474
+ </div>
475
+
476
+ <div className="form-group">
477
+ <label htmlFor="lineHeight">Interlineado</label>
478
+ <input
479
+ type="range"
480
+ id="lineHeight"
481
+ name="lineHeight"
482
+ value={settings.lineHeight}
483
+ onChange={handleChange}
484
+ className="form-control range-input"
485
+ min="1"
486
+ max="3"
487
+ step="0.1"
488
+ />
489
+ <div className="range-value">{settings.lineHeight}</div>
490
+ </div>
491
+ </div>
492
+ )}
493
+
494
+ {activeSection === "other" && (
495
+ <div className="settings-section">
496
+ <h3>Otras opciones</h3>
497
+ <div className="form-group">
498
+ <div className="checkbox-group">
499
+ <input
500
+ type="checkbox"
501
+ id="showPageNumbers"
502
+ name="showPageNumbers"
503
+ checked={settings.showPageNumbers}
504
+ onChange={handleChange}
505
+ />
506
+ <label htmlFor="showPageNumbers">Mostrar números de página</label>
507
+ </div>
508
+ </div>
509
+ </div>
510
+ )}
511
+ </div>
512
+
513
+ <div className="settings-preview">
514
+ <div className="preview-label">Vista previa</div>
515
+ {renderPagePreview()}
516
+ </div>
517
+ </div>
518
+ </div>
519
+
520
+ <div className="settings-panel-footer">
521
+ <button className="btn btn-outline" onClick={onClose}>
522
+ Cancelar
523
+ </button>
524
+ <button className="btn btn-primary" onClick={handleApply}>
525
+ Aplicar cambios
526
+ </button>
527
+ </div>
528
+ </div>
529
+
530
+ <style>{`
531
+ .settings-panel-nav {
532
+ display: flex;
533
+ gap: 1px;
534
+ background: var(--border-color);
535
+ padding: 1px;
536
+ margin: 0 1.5rem;
537
+ border-radius: var(--radius);
538
+ }
539
+
540
+ .nav-button {
541
+ flex: 1;
542
+ padding: 0.5rem;
543
+ background: var(--surface-color);
544
+ border: none;
545
+ cursor: pointer;
546
+ font-size: 0.875rem;
547
+ color: var(--text-light);
548
+ transition: var(--transition);
549
+ }
550
+
551
+ .nav-button:first-child {
552
+ border-top-left-radius: calc(var(--radius) - 1px);
553
+ border-bottom-left-radius: calc(var(--radius) - 1px);
554
+ }
555
+
556
+ .nav-button:last-child {
557
+ border-top-right-radius: calc(var(--radius) - 1px);
558
+ border-bottom-right-radius: calc(var(--radius) - 1px);
559
+ }
560
+
561
+ .nav-button.active {
562
+ background: var(--primary-color);
563
+ color: white;
564
+ }
565
+
566
+ .settings-layout {
567
+ display: grid;
568
+ grid-template-columns: 1fr 200px;
569
+ gap: 2rem;
570
+ height: 100%;
571
+ }
572
+
573
+ .settings-preview {
574
+ position: sticky;
575
+ top: 1.5rem;
576
+ background: var(--background-color);
577
+ padding: 1.5rem;
578
+ border-radius: var(--radius);
579
+ display: flex;
580
+ flex-direction: column;
581
+ align-items: center;
582
+ gap: 1rem;
583
+ }
584
+
585
+ .preview-label {
586
+ font-size: 0.875rem;
587
+ color: var(--text-light);
588
+ }
589
+
590
+ .preview-container {
591
+ display: flex;
592
+ justify-content: center;
593
+ align-items: center;
594
+ }
595
+
596
+ .page-preview {
597
+ box-shadow: var(--shadow-md);
598
+ transition: var(--transition);
599
+ }
600
+
601
+ .content-preview {
602
+ display: flex;
603
+ flex-direction: column;
604
+ justify-content: space-between;
605
+ }
606
+
607
+ .preview-text {
608
+ font-size: inherit;
609
+ color: var(--text-color);
610
+ }
611
+
612
+ .preview-page-number {
613
+ font-size: 0.75em;
614
+ color: var(--text-light);
615
+ text-align: center;
616
+ }
617
+
618
+ .orientation-buttons {
619
+ display: flex;
620
+ gap: 1px;
621
+ background: var(--border-color);
622
+ padding: 1px;
623
+ border-radius: var(--radius);
624
+ }
625
+
626
+ .orientation-button {
627
+ flex: 1;
628
+ padding: 0.5rem;
629
+ background: var(--surface-color);
630
+ border: none;
631
+ cursor: pointer;
632
+ font-size: 0.875rem;
633
+ color: var(--text-light);
634
+ transition: var(--transition);
635
+ }
636
+
637
+ .orientation-button:first-child {
638
+ border-top-left-radius: calc(var(--radius) - 1px);
639
+ border-bottom-left-radius: calc(var(--radius) - 1px);
640
+ }
641
+
642
+ .orientation-button:last-child {
643
+ border-top-right-radius: calc(var(--radius) - 1px);
644
+ border-bottom-right-radius: calc(var(--radius) - 1px);
645
+ }
646
+
647
+ .orientation-button.active {
648
+ background: var(--primary-color);
649
+ color: white;
650
+ }
651
+
652
+ .color-input-group {
653
+ display: flex;
654
+ gap: 0.5rem;
655
+ }
656
+
657
+ .color-input {
658
+ width: 50px !important;
659
+ padding: 0 !important;
660
+ height: 38px;
661
+ }
662
+
663
+ .color-text {
664
+ flex: 1;
665
+ }
666
+
667
+ .range-input {
668
+ margin-bottom: 0.5rem;
669
+ }
670
+
671
+ .range-value {
672
+ font-size: 0.875rem;
673
+ color: var(--text-light);
674
+ text-align: right;
675
+ }
676
+
677
+ .form-group.with-preview {
678
+ margin-bottom: 2rem;
679
+ }
680
+
681
+ @media (max-width: 768px) {
682
+ .settings-layout {
683
+ grid-template-columns: 1fr;
684
+ }
685
+
686
+ .settings-preview {
687
+ display: none;
688
+ }
689
+ }
690
+
691
+ .preview-size-label {
692
+ font-size: 0.75rem;
693
+ color: var(--text-light);
694
+ text-align: center;
695
+ margin-top: 0.5rem;
696
+ }
697
+ `}</style>
698
+ </div>
699
+ )
700
+ }
701
+
702
+ export default SettingsPanel
703
+