Last active
October 10, 2022 20:40
-
-
Save lesleyandreza/7699603b20f2459d1fcf3b9480fb22e1 to your computer and use it in GitHub Desktop.
Generate PDF with Electron
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<link href="./styles.css" rel="stylesheet"> | |
<title>Generate PDF</title> | |
</head> | |
<body> | |
<div class="wrapper"> | |
<aside class="hide-in-print sidebar"> | |
<form method="dialog" class="form-layout"> | |
<label> | |
<span> | |
Layout: | |
</span> | |
<select name="landscape" data-type="boolean"> | |
<option value="false"> Portrait </option> | |
<option value="true"> Landscape </option> | |
</select> | |
</label> | |
<label> | |
<span> | |
Paper size: | |
</span> | |
<select name="pageSize"> | |
<option value="A0"> A0 </option> | |
<option value="A1"> A1 </option> | |
<option value="A2"> A2 </option> | |
<option value="A3"> A3 </option> | |
<option value="A4" selected> A4 </option> | |
<option value="A5"> A5 </option> | |
<option value="A6"> A6 </option> | |
<option value="Legal"> Legal </option> | |
<option value="Letter"> Letter </option> | |
<option value="Tabloid"> Tabloid </option> | |
<option value="Ledger"> Ledger </option> | |
</select> | |
</label> | |
<label> | |
<span>Scale:</span> | |
<input name="scale" value="1" type="number" min="0" max="2" step="0.25" /> | |
</label> | |
<div class="separator"> | |
<span> Options </span> | |
</div> | |
<label> | |
<span> | |
Header and footer: | |
</span> | |
<input name="displayHeaderFooter" type="checkbox" checked /> | |
</label> | |
<label> | |
<span> | |
Background graphics: | |
</span> | |
<input name="printBackground" type="checkbox" /> | |
</label> | |
<div class="separator"> | |
<span> Margins </span> | |
</div> | |
<label> | |
<span>Margin type:</span> | |
<select name="margins.marginType"> | |
<option value="default"> Default </option> | |
<option value="none"> None </option> | |
<option value="printableArea"> Printable area </option> | |
<option value="custom" selected> Custom </option> | |
</select> | |
</label> | |
<label> | |
<span>Top:</span> | |
<input name="margins.top" value="0.4" type="number" step="0.01" /> | |
</label> | |
<label> | |
<span>Bottom:</span> | |
<input name="margins.bottom" value="0.4" type="number" step="0.01" /> | |
</label> | |
<label> | |
<span>Left:</span> | |
<input name="margins.left" value="0.4" type="number" step="0.01" /> | |
</label> | |
<label> | |
<span>Right:</span> | |
<input name="margins.right" value="0.4" type="number" step="0.01" /> | |
</label> | |
<div class="separator"> | |
<span> | |
Custom header and footer | |
</span> | |
</div> | |
<label> | |
<select name="customHeaderFooter" style="width: 100%;"></select> | |
<button data-bind="show-content-header-and-footer" class="show-content-header-and-footer" title="Show content HTML of header and footer"> | |
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" | |
x="0px" y="0px" viewBox="0 0 512.011 512.011" | |
style="enable-background:new 0 0 512.011 512.011;" xml:space="preserve"> | |
<g> | |
<g> | |
<g> | |
<path d="M505.755,240.92l-89.088-89.088c-88.576-88.597-232.747-88.597-321.323,0L6.256,240.92 | |
c-8.341,8.341-8.341,21.824,0,30.165l89.088,89.088c44.288,44.288,102.464,66.453,160.661,66.453s116.373-22.165,160.661-66.453 | |
l89.088-89.088C514.096,262.744,514.096,249.261,505.755,240.92z M256.005,362.669c-58.816,0-106.667-47.851-106.667-106.667 | |
s47.851-106.667,106.667-106.667s106.667,47.851,106.667,106.667S314.821,362.669,256.005,362.669z" /> | |
<path | |
d="M256.005,192.003c-35.285,0-64,28.715-64,64s28.715,64,64,64s64-28.715,64-64S291.291,192.003,256.005,192.003z" /> | |
</g> | |
</g> | |
</g> | |
</svg> | |
</button> | |
</label> | |
<button type="submit" class="btn"> | |
Generate PDF | |
</button> | |
</form> | |
</aside> | |
<section class="printable"> | |
<h1 style="background-color: #222; color: #CCC">Hello World!</h1> | |
<p> | |
We are using Node.js <span id="node-version"></span>, | |
Chromium <span id="chrome-version"></span>, | |
and Electron <span id="electron-version"></span>. | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
<p> | |
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis deserunt voluptas saepe inventore | |
autem | |
facilis quam quia rerum ipsum illo. Quasi, hic. Praesentium voluptatum, accusamus esse illum quaerat | |
quos | |
quis, corrupti consequuntur explicabo ad nemo a dolorem quidem magnam non sapiente ipsam odit illo | |
exercitationem, facilis sunt! Iste, obcaecati debitis? | |
</p> | |
</section> | |
<dialog class="hide-in-print pdf-preview"> | |
<div class="center-inline-elements"> | |
<button data-bind="btn-close-preview" class="btn"> | |
Close Preview | |
</button> | |
</div> | |
<iframe></iframe> | |
</dialog> | |
<dialog data-bind="dialog-content-header-and-footer" class="hide-in-print"> | |
<details open> | |
<summary>Header</summary> | |
<pre data-bind="custom-header"></pre> | |
</details> | |
<details open> | |
<summary>Footer</summary> | |
<pre data-bind="custom-footer"></pre> | |
</details> | |
</dialog> | |
<div class="backdrop"></div> | |
</div> | |
<script src="./renderer.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Modules to control application life and create native browser window | |
const { app, BrowserWindow, ipcMain } = require('electron') | |
const path = require('path') | |
let mainWindow | |
function createWindow() { | |
// Create the browser window. | |
mainWindow = new BrowserWindow({ | |
width: 1300, | |
height: 700, | |
webPreferences: { | |
nodeIntegration: true, | |
contextIsolation: false, | |
preload: path.join(__dirname, 'preload.js') | |
} | |
}) | |
// and load the index.html of the app. | |
mainWindow.loadFile('index.html') | |
// Open the DevTools. | |
mainWindow.webContents.openDevTools() | |
} | |
ipcMain.on('generate-pdf', async(event, options) => { | |
console.log(options); | |
const buffer = await mainWindow.webContents.printToPDF(options) | |
const base64PDF = Buffer.from(buffer).toString('base64') | |
mainWindow.webContents.send('base64-pdf', base64PDF) | |
}) | |
// This method will be called when Electron has finished | |
// initialization and is ready to create browser windows. | |
// Some APIs can only be used after this event occurs. | |
app.whenReady().then(() => { | |
createWindow() | |
app.on('activate', function () { | |
// On macOS it's common to re-create a window in the app when the | |
// dock icon is clicked and there are no other windows open. | |
if (BrowserWindow.getAllWindows().length === 0) createWindow() | |
}) | |
}) | |
// Quit when all windows are closed, except on macOS. There, it's common | |
// for applications and their menu bar to stay active until the user quits | |
// explicitly with Cmd + Q. | |
app.on('window-all-closed', function () { | |
if (process.platform !== 'darwin') app.quit() | |
}) | |
// In this file you can include the rest of your app's specific main process | |
// code. You can also put them in separate files and require them here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "cut-alarm-jump-1cbvj", | |
"productName": "cut-alarm-jump-1cbvj", | |
"description": "My Electron application description", | |
"keywords": [], | |
"main": "./main.js", | |
"version": "1.0.0", | |
"author": "lesleyandreza", | |
"scripts": { | |
"start": "electron ." | |
}, | |
"dependencies": {}, | |
"devDependencies": { | |
"electron": "21.1.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The preload script runs before. It has access to web APIs | |
* as well as Electron's renderer process modules and some | |
* polyfilled Node.js functions. | |
* | |
* https://www.electronjs.org/docs/latest/tutorial/sandbox | |
*/ | |
window.addEventListener('DOMContentLoaded', () => { | |
const replaceText = (selector, text) => { | |
const element = document.getElementById(selector) | |
if (element) element.innerText = text | |
} | |
for (const type of ['chrome', 'node', 'electron']) { | |
replaceText(`${type}-version`, process.versions[type]) | |
} | |
}) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { ipcRenderer } = require('electron') | |
const { customHeadersFooters, getCustomHeaderFooter } = require('./customHeaderFooter') | |
const { serializeForm, base64ToUrl, pdfPreview } = require('./util') | |
const $form = document.querySelector('form') | |
const $dialogShowContentHeaderAndFooter = document.querySelector('[data-bind="dialog-content-header-and-footer"]') | |
const $backropDialogShowContentHeaderAndFooter = document.querySelector('[data-bind="dialog-content-header-and-footer"]+.backdrop') | |
const $btnShowContentHeaderAndFooter = document.querySelector('[data-bind="show-content-header-and-footer"]') | |
const $btnClosePreview = document.querySelector('[data-bind="btn-close-preview"]') | |
ipcRenderer.on('base64-pdf', (event, base64) => { | |
const $iframe = document.querySelector('iframe') | |
$iframe.src = base64ToUrl(base64) | |
}) | |
$form.onsubmit = (event) => { | |
const formData = serializeForm(event.target) | |
ipcRenderer.send('generate-pdf', formData) | |
console.log(formData) | |
pdfPreview.show() | |
} | |
$btnShowContentHeaderAndFooter.onclick = (event) => { | |
event.preventDefault() | |
const customHeaderFooter = getCustomHeaderFooter(); | |
const $customHeader = document.querySelector('[data-bind="custom-header"]') | |
const $customFooter = document.querySelector('[data-bind="custom-footer"]') | |
$customHeader.innerText = customHeaderFooter.header?.trim() || 'Not defined' | |
$customFooter.innerText = customHeaderFooter.footer?.trim() || 'Not defined' | |
$dialogShowContentHeaderAndFooter.show() | |
} | |
$backropDialogShowContentHeaderAndFooter.onclick = () => { | |
$dialogShowContentHeaderAndFooter.close() | |
} | |
$btnClosePreview.onclick = () => { | |
pdfPreview.hide() | |
} | |
document.onkeyup = (event) => { | |
if (event.key.toLowerCase() === 'escape') { | |
document.querySelector('dialog[open]')?.close?.() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
padding: 0; | |
margin: 0; | |
box-sizing: border-box; | |
font-family: sans-serif; | |
accent-color: hsl(221deg 100% 61%); | |
outline-color: hsl(221deg 100% 61%); | |
} | |
body { | |
background-color: #CBCBCB; | |
} | |
button { | |
font-family: sans-serif; | |
} | |
.wrapper { | |
display: flex; | |
} | |
.sidebar { | |
z-index: 1; | |
min-width: 290px; | |
max-width: 290px; | |
height: 100vh; | |
padding: 1rem; | |
box-shadow: 3px 0px 4px -2px rgb(0 0 0 / 40%); | |
user-select: none; | |
position: sticky; | |
top: 0; | |
overflow: auto; | |
background-color: #FFF; | |
; | |
} | |
.printable { | |
max-width: 120ch; | |
z-index: 0; | |
background-color: #CBCBCB; | |
} | |
section { | |
min-height: 100vh; | |
width: 100vw; | |
padding: 1rem; | |
} | |
h1 { | |
margin-bottom: 1.5rem; | |
} | |
p+p { | |
margin-top: 1rem; | |
} | |
iframe { | |
display: none; | |
will-change: transform, opacity; | |
} | |
iframe { | |
display: block; | |
height: calc(100% - 3rem); | |
width: 100%; | |
border: 0; | |
border-radius: 4px; | |
box-shadow: 0.7px 1px 2px 1px #000; | |
} | |
input, | |
select, | |
textarea { | |
background: #f1f3f4; | |
border: none; | |
border-radius: 5px; | |
padding: 4px 8px; | |
width: 118px; | |
} | |
.pdf-preview { | |
position: fixed; | |
top: 0; | |
left: 0; | |
height: 100vh; | |
width: 100vw; | |
padding: 1rem; | |
padding-top: 1rem; | |
background-color: #191c1c; | |
display: none; | |
will-change: opacity; | |
z-index: 2; | |
} | |
.pdf-preview iframe { | |
margin-top: 1rem; | |
border-radius: 10px; | |
opacity: 0; | |
} | |
.pdf-preview.show { | |
display: block; | |
} | |
.pdf-preview.show iframe { | |
animation: fadeIn .3s, slideUp .3s; | |
animation-fill-mode: forwards; | |
animation-delay: 0.5s; | |
} | |
.form-layout { | |
display: flex; | |
flex-direction: column; | |
gap: 0.5rem; | |
} | |
.separator { | |
padding-top: 0.5rem; | |
} | |
.separator span { | |
font-size: 0.8rem; | |
font-weight: 900; | |
color: #777; | |
} | |
label { | |
display: flex; | |
gap: 0.5rem; | |
align-items: center; | |
} | |
label span { | |
width: 50%; | |
text-align: right; | |
font-size: 0.8rem; | |
color: #444; | |
} | |
.btn { | |
height: 2rem; | |
padding: 0 1rem; | |
background: hsl(221deg 100% 61%); | |
border-radius: 5px; | |
border: none; | |
color: #FFF; | |
font-size: 0.9rem; | |
outline-offset: 2px; | |
} | |
.btn[type="submit"] { | |
margin-top: 1rem; | |
} | |
.btn:hover, | |
.btn:focus-visible { | |
background: hsl(221deg 100% 66%); | |
} | |
.btn:active { | |
background: hsl(221deg 100% 51%); | |
transform: translateY(1px); | |
} | |
[type="checkbox"] { | |
height: 1.1rem; | |
width: 1.1rem; | |
} | |
.center-inline-elements { | |
text-align: center; | |
} | |
.show-content-header-and-footer { | |
width: 1.8rem; | |
height: 1.5rem; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
padding: 2px; | |
border: none; | |
background: transparent; | |
opacity: 0.8; | |
} | |
.show-content-header-and-footer:hover, | |
.show-content-header-and-footer:focus-visible { | |
opacity: 0.6; | |
} | |
.show-content-header-and-footer:active { | |
opacity: 1; | |
transform: translateY(1px); | |
} | |
[data-bind="dialog-content-header-and-footer"] { | |
z-index: 10; | |
height: 50vh; | |
width: 50vw; | |
position: fixed; | |
margin-left: 25vw; | |
margin-top: 25vh; | |
padding: 1rem; | |
overflow: auto; | |
} | |
[data-bind="dialog-content-header-and-footer"][open]+.backdrop { | |
display: block; | |
} | |
.backdrop { | |
display: none; | |
content: ''; | |
background: rgba(0, 0, 0, .3); | |
z-index: 9; | |
position: fixed; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
} | |
pre { | |
background: #E5E5E5; | |
border: 1px solid #DDD; | |
padding: 0.5rem; | |
border-radius: 5px; | |
margin-bottom: 1rem; | |
color: #444; | |
user-select: all; | |
overflow-x: auto; | |
} | |
@media print { | |
.hide-in-print { | |
display: none !important; | |
} | |
} | |
@keyframes fadeIn { | |
0% { | |
opacity: 0; | |
} | |
100% { | |
opacity: 1; | |
} | |
} | |
@keyframes slideUp { | |
0% { | |
transform: translateY(2rem); | |
} | |
100% { | |
transform: translateY(0); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { customHeadersFooters } = require("./customHeaderFooter") | |
function base64ToUrl(base64 = '', typeOfBase64 = 'application/pdf') { | |
const binary = atob(base64.replace(/\s/g, '')) | |
const len = binary.length | |
const buffer = new ArrayBuffer(len) | |
const view = new Uint8Array(buffer) | |
for (let i = 0; i < len; i++) { | |
view[i] = binary.charCodeAt(i) | |
} | |
const blob = new Blob([view], { type: typeOfBase64 }) | |
return URL.createObjectURL(blob) | |
} | |
function serializeForm($formElement) { | |
return [...$formElement.elements].reduce((prev, curr) => { | |
const inputName = curr.name | |
let inputValue = null | |
if (curr.type === 'checkbox') { | |
inputValue = curr.checked | |
} else if (curr.type === 'number') { | |
inputValue = curr.valueAsNumber | |
} else if (curr.dataset.type === 'boolean') { | |
inputValue = curr.value.toLowerCase() === 'true' | |
} else { | |
inputValue = curr.value | |
} | |
if (inputName === 'customHeaderFooter') { | |
const customHeaderFooter = customHeadersFooters.find(e => e.id === +curr.value) | |
if (!customHeaderFooter.header && !customHeaderFooter.footer) { | |
return prev | |
} | |
return { | |
...prev, | |
headerTemplate: customHeaderFooter.header, | |
footerTemplate: customHeaderFooter.footer, | |
} | |
} | |
if (inputName.startsWith('margins')) { | |
let marginInputs = null | |
const [base, property] = inputName.split('.') | |
const value = curr.type === 'number' ? curr.valueAsNumber : curr.value | |
marginInputs = { | |
...(marginInputs || {}), | |
[property]: value | |
} | |
return { | |
...prev, | |
...{ | |
margins: { | |
...(prev.margins || {}), | |
...marginInputs | |
} | |
} | |
} | |
} | |
if (inputName === '') return prev | |
return { ...prev, ...{ [inputName]: inputValue } } | |
}, {}) | |
} | |
const pdfPreview = { | |
$pdfPreview: document.querySelector('.pdf-preview'), | |
show() { | |
this.$pdfPreview.classList.add('show') | |
document.body.style.overflow = 'hidden' | |
}, | |
hide() { | |
this.$pdfPreview.classList.remove('show') | |
document.body.style.overflow = 'unset' | |
}, | |
} | |
module.exports = { base64ToUrl, serializeForm, pdfPreview } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment