Merge pull request #98 from EETagent/frontend_svg2pdf

WIP: Frontend PDF creation
This commit is contained in:
Vojtěch Jungmann 2023-02-06 00:54:16 +01:00 committed by GitHub
commit fbcd2edd8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 279 additions and 1 deletions

View file

@ -50,6 +50,8 @@
"swiper": "^8.4.6",
"tippy.js": "^6.3.7",
"typesafe-i18n": "^5.20.0",
"jspdf": "^2.5.1",
"svg2pdf.js": "^2.2.1",
"yup": "^0.32.11"
}
}

View file

@ -19,6 +19,9 @@ dependencies:
isomorphic-dompurify:
specifier: ^0.26.0
version: 0.26.0
jspdf:
specifier: ^2.5.1
version: 2.5.1
just-debounce-it:
specifier: ^3.2.0
version: 3.2.0
@ -34,6 +37,9 @@ dependencies:
svelte-tippy:
specifier: ^1.3.2
version: 1.3.2
svg2pdf.js:
specifier: ^2.2.1
version: 2.2.1(jspdf@2.5.1)
swiper:
specifier: ^8.4.6
version: 8.4.6
@ -572,6 +578,11 @@ packages:
resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==}
dev: true
/@types/raf@3.4.0:
resolution: {integrity: sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==}
dev: false
optional: true
/@types/resolve@1.20.2:
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
dev: true
@ -807,6 +818,12 @@ packages:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/atob@2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
engines: {node: '>= 4.5.0'}
hasBin: true
dev: false
/axios@1.2.5:
resolution: {integrity: sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==}
dependencies:
@ -821,6 +838,12 @@ packages:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-arraybuffer@1.0.2:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
dev: false
optional: true
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@ -846,6 +869,12 @@ packages:
fill-range: 7.0.1
dev: true
/btoa@1.2.1:
resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==}
engines: {node: '>= 0.4.0'}
hasBin: true
dev: false
/buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: true
@ -867,6 +896,22 @@ packages:
engines: {node: '>=6'}
dev: true
/canvg@3.0.10:
resolution: {integrity: sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==}
engines: {node: '>=10.0.0'}
requiresBuild: true
dependencies:
'@babel/runtime': 7.20.13
'@types/raf': 3.4.0
core-js: 3.27.2
raf: 3.4.1
regenerator-runtime: 0.13.11
rgbcolor: 1.0.1
stackblur-canvas: 2.5.0
svg-pathdata: 6.0.3
dev: false
optional: true
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
@ -921,6 +966,12 @@ packages:
engines: {node: '>= 0.6'}
dev: true
/core-js@3.27.2:
resolution: {integrity: sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w==}
requiresBuild: true
dev: false
optional: true
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -930,6 +981,19 @@ packages:
which: 2.0.2
dev: true
/css-line-break@2.1.0:
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
dependencies:
utrie: 1.0.2
dev: false
optional: true
/cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
dev: false
/cssom@0.3.8:
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
dev: false
@ -1285,6 +1349,10 @@ packages:
reusify: 1.0.4
dev: true
/fflate@0.4.8:
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
dev: false
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -1343,6 +1411,10 @@ packages:
optional: true
dev: false
/font-family-papandreou@0.2.0-patch2:
resolution: {integrity: sha512-l/YiRdBSH/eWv6OF3sLGkwErL+n0MqCICi9mppTZBOCL5vixWGDqCYvRcuxB2h7RGCTzaTKOHT2caHvCXQPRlw==}
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@ -1463,6 +1535,16 @@ packages:
whatwg-encoding: 2.0.0
dev: false
/html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
requiresBuild: true
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
dev: false
optional: true
/http-proxy-agent@5.0.0:
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
engines: {node: '>= 6'}
@ -1658,6 +1740,20 @@ packages:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
dev: true
/jspdf@2.5.1:
resolution: {integrity: sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==}
dependencies:
'@babel/runtime': 7.20.13
atob: 2.1.2
btoa: 1.2.1
fflate: 0.4.8
optionalDependencies:
canvg: 3.0.10
core-js: 3.27.2
dompurify: 2.4.3
html2canvas: 1.4.1
dev: false
/just-debounce-it@3.2.0:
resolution: {integrity: sha512-WXzwLL0745uNuedrCsCs3rpmfD6DBaf7uuVwaq98/8dafURfgQaBsSpjiPp5+CW6Vjltwy9cOGI6qE71b3T8iQ==}
dev: false
@ -1901,6 +1997,11 @@ packages:
engines: {node: '>=8'}
dev: true
/performance-now@2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
dev: false
optional: true
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: true
@ -2033,6 +2134,13 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/raf@3.4.1:
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
dependencies:
performance-now: 2.1.0
dev: false
optional: true
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@ -2072,6 +2180,12 @@ packages:
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/rgbcolor@1.0.1:
resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==}
engines: {node: '>= 0.8.15'}
dev: false
optional: true
/rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
hasBin: true
@ -2187,10 +2301,21 @@ packages:
dev: false
optional: true
/specificity@0.4.1:
resolution: {integrity: sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==}
hasBin: true
dev: false
/ssr-window@4.0.2:
resolution: {integrity: sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==}
dev: false
/stackblur-canvas@2.5.0:
resolution: {integrity: sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==}
engines: {node: '>=0.1.14'}
dev: false
optional: true
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
@ -2345,6 +2470,28 @@ packages:
resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==}
engines: {node: '>= 8'}
/svg-pathdata@6.0.3:
resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==}
engines: {node: '>=12.0.0'}
dev: false
optional: true
/svg2pdf.js@2.2.1(jspdf@2.5.1):
resolution: {integrity: sha512-gJsFT42tb+pYTuFudkKgpMws54DvsJW7wmzGRUY1b9CUJpRMoBU5B4HrCMUTlK2lpcdPL5cOyr84hy2BEj1/Ag==}
peerDependencies:
jspdf: ^2.0.0
dependencies:
cssesc: 3.0.0
font-family-papandreou: 0.2.0-patch2
jspdf: 2.5.1
specificity: 0.4.1
svgpath: 2.6.0
dev: false
/svgpath@2.6.0:
resolution: {integrity: sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==}
dev: false
/swiper@8.4.6:
resolution: {integrity: sha512-HACW035vBz2T6Kfut23EAzXhcDpgR8doX+wjq0ZUvJgS5SQApGrV885DAPLBFnmPUISsAhNSVxPKDxqroFvXvQ==}
engines: {node: '>= 4.7.0'}
@ -2358,6 +2505,13 @@ packages:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: false
/text-segmentation@1.0.3:
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
dependencies:
utrie: 1.0.2
dev: false
optional: true
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
@ -2491,6 +2645,13 @@ packages:
requires-port: 1.0.0
dev: false
/utrie@1.0.2:
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
dependencies:
base64-arraybuffer: 1.0.2
dev: false
optional: true
/vite@4.0.4:
resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==}
engines: {node: ^14.18.0 || >=16.0.0}

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="drawing.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.54488788"
inkscape:cx="376.22419"
inkscape:cy="548.73675"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#0000ff;stroke-width:0.264583"
id="rect788"
width="65.580345"
height="76.91098"
x="41.545662"
y="78.284393" />
<text
xml:space="preserve"
style="font-size:9.87777px;fill:#0000ff;stroke-width:0.264583"
x="33.648552"
y="187.12717"
id="text844"><tspan
sodipodi:role="line"
id="tspan842"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'JetBrains Mono';-inkscape-font-specification:'JetBrains Mono';stroke-width:0.264583"
x="33.648552"
y="187.12717">${APPLICATION}</tspan></text>
<text
xml:space="preserve"
style="font-size:9.87777px;fill:#0000ff;stroke-width:0.264583"
x="35.021965"
y="202.23468"
id="text898"><tspan
sodipodi:role="line"
id="tspan896"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'JetBrains Mono';-inkscape-font-specification:'JetBrains Mono';stroke-width:0.264583"
x="35.021965"
y="202.23468">${CODE}</tspan></text>
<rect
style="fill:#00ff00;stroke-width:0.264583"
id="rect6059"
width="82.061272"
height="65.236992"
x="97.168785"
y="39.48555" />
<ellipse
style="fill:#ff0000;stroke-width:0.264583"
id="path6327"
cx="129.95895"
cy="136.1393"
rx="58.884972"
ry="44.464161" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -10,6 +10,8 @@
import IdField from '../../textfield/IdField.svelte';
import NumberField from '../../textfield/NumberField.svelte';
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
import jsPDF from 'jspdf';
import 'svg2pdf.js';
let isOpened = true;
@ -84,6 +86,25 @@
}
};
const generatePdf = async () => {
const template = (await import('$lib/assets/pdf/drawing.svg?raw')).default;
const svg = template
.replace('${APPLICATION}', login.applicationId.toString())
.replace('${CODE}', login.password);
const element = document.getElementById('svg-element')!;
element.innerHTML = svg;
const doc = new jsPDF('p', 'mm', [210, 297]);
await doc.svg(element);
doc.save('PRIHLASOVACI_UDAJE_' + login.applicationId.toString());
element.innerHTML = '';
};
const close = () => {
isOpened = false;
dispatch('close');
@ -95,6 +116,8 @@
<Modal on:close={close}>
<div class="p-20">
{#if login}
<svg width="210mm" height="297mm" class="hidden h-[297mm] w-[210mm]" id="svg-element" />
<h1 class="text-sspsBlue text-3xl font-semibold">Ev. č.: {applicationId}</h1>
<h1 class="text-sspsBlue text-3xl font-semibold">R. č.: {login.personalIdNumber}</h1>
<h1 class="text-sspsBlue text-3xl font-semibold">Heslo: {login.password}</h1>
@ -103,6 +126,11 @@
Slinkovaný s {login.applications.filter((a) => a != applicationId)}
</h1>
{/if}
<div class="mt-2">
<button class="rounded-lg bg-red-800 p-2 text-white" on:click={generatePdf}
>Stáhnout PDF</button
>
</div>
{:else}
<h1 class="text-sspsBlue text-3xl font-semibold">Registrace nového uchazeče</h1>
{#if error}
@ -114,7 +142,8 @@
</div>
{/if}
<div>
<h3 class="my-4">Evidenční číslo přihlášky (
<h3 class="my-4">
Evidenční číslo přihlášky (
<span class="font-bold">{`Obor: ${field}`}</span>)
</h3>
<NumberField bind:value={applicationId} />