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.
- package/README.md +40 -0
- package/fn/aggAlias.js +21 -0
- package/fn/moveComponents.js +129 -0
- package/fn/postinstall.js +66 -0
- package/fn/upVersion.js +12 -0
- package/fn/updateTsconfig.js +10 -0
- package/next.config.mjs +6 -0
- package/package.json +39 -0
- package/public/bg-login.jpg +0 -0
- package/public/codigo_guardado.js +1 -0
- package/public/css/style.css +751 -0
- package/public/dboard/logo.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/fonts/TimesNewerRoman-Bold.otf +0 -0
- package/public/fonts/TimesNewerRoman-BoldItalic.otf +0 -0
- package/public/fonts/TimesNewerRoman-Italic.otf +0 -0
- package/public/fonts/TimesNewerRoman-Regular.otf +0 -0
- package/public/header-pdf.jpg +0 -0
- package/public/home/bgHome.jpg +0 -0
- package/public/home/bgHome2.jpg +0 -0
- package/public/home/download.jpg +0 -0
- package/public/home/undraw_elements_re_25t9.svg +1 -0
- package/public/home/undraw_project_completed_re_jr7u.svg +1 -0
- package/public/home/undraw_shared_goals_re_jvqd.svg +1 -0
- package/public/home/undraw_spread_love_re_v3cl.svg +1 -0
- package/public/home/undraw_target_re_fi8j.svg +1 -0
- package/public/home/undraw_visionary_technology_re_jfp7.svg +1 -0
- package/public/logo.png +0 -0
- package/public/marca/logo.svg +1 -0
- package/src/components/PDF/components/DocumentoTemplate.tsx +140 -0
- package/src/components/PDF/components/PDFContent.tsx +192 -0
- package/src/components/PDF/core/Etiquetas.tsx +152 -0
- package/src/components/PDF/core/Grid.tsx +101 -0
- package/src/components/PDF/core/Img.tsx +22 -0
- package/src/components/PDF/core/LayoutPDF.tsx +186 -0
- package/src/components/PDF/core/Listas.tsx +10 -0
- package/src/components/PDF/core/MakePDF.tsx +50 -0
- package/src/components/PDF/core/PageElements.tsx +50 -0
- package/src/components/PDF/core/Position.tsx +33 -0
- package/src/components/PDF/core/Tablet.tsx +121 -0
- package/src/components/PDF/core/index.tsx +56 -0
- package/src/components/PDF/lib/pdfParser.ts +620 -0
- package/src/components/PDF/services/apiService.ts +17 -0
- package/src/components/PDF/templates/AllTemplate.tsx +134 -0
- package/src/components/PDF/templates/BusinessCardTemplate.tsx +139 -0
- package/src/components/PDF/templates/CertificateTemplate.tsx +31 -0
- package/src/components/PDF/templates/HeaderFooterTemplate.tsx +61 -0
- package/src/components/PDF/templates/InvoiceTemplate.tsx +53 -0
- package/src/components/PDF/templates/ProposalTemplate.tsx +246 -0
- package/src/components/PDF/templates/ReportTemplate.tsx +57 -0
- package/src/components/PDF/templates/ResumeTemplate.tsx +170 -0
- package/src/components/PDF/templates/TablasTemplate.tsx +307 -0
- package/src/components/PDF/templates/index.ts +9 -0
- package/src/components/PDF/view/ColorPicker.tsx +147 -0
- package/src/components/PDF/view/Header.tsx +102 -0
- package/src/components/PDF/view/HomePDF.tsx +177 -0
- package/src/components/PDF/view/SettingsPanel.tsx +703 -0
- package/src/pages/AllTemplate.tsx +53 -0
- package/src/pages/Documento2.tsx +45 -0
- package/src/pages/_app.tsx +6 -0
- package/src/pages/_document.tsx +13 -0
- package/src/pages/api/generatePDF.ts +74 -0
- package/src/pages/api/hello.ts +13 -0
- package/src/pages/api/readFile.ts +18 -0
- package/src/pages/api/readTemplateFile.ts +26 -0
- package/src/pages/api/save.ts +22 -0
- package/src/pages/api/saveFile.ts +20 -0
- package/src/pages/index.tsx +13 -0
- package/src/pages/template/[template].tsx +250 -0
- 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
|
+
|