@lowdefy/docs 3.22.0 → 3.23.2

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 (54) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/actions/JsAction.yaml +2 -2
  3. package/blocks/display/DangerousHtml.yaml +11 -12
  4. package/blocks/display/DangerousMarkdown.yaml +8 -8
  5. package/blocks/input/MultipleSelector.yaml +80 -0
  6. package/blocks/input/Selector.yaml +62 -0
  7. package/concepts/custom-blocks.yaml +2 -2
  8. package/concepts/custom-code.yaml +3 -3
  9. package/concepts/lowdefy-schema.yaml +16 -0
  10. package/connections/AxiosHttp.yaml +1 -1
  11. package/deployment/aws-lambda.yaml +2 -2
  12. package/deployment/docker.yaml +2 -2
  13. package/head.html +2 -0
  14. package/howto/generate-csv.yaml.njk +251 -0
  15. package/howto/generate-pdf.yaml.njk +651 -0
  16. package/howto/generateCsv/lowdefy.yaml +63 -0
  17. package/howto/generateCsv/public/csvMake.js +27 -0
  18. package/howto/generatePdf/inv_template.yaml +200 -0
  19. package/howto/generatePdf/lowdefy.yaml +116 -0
  20. package/howto/generatePdf/my_header.html +1 -0
  21. package/howto/generatePdf/public/logo_example.png +0 -0
  22. package/howto/generatePdf/public/modules/importUmd.js +7 -0
  23. package/howto/generatePdf/public/modules/pdfMake.js +7 -0
  24. package/howto/generatePdf/public/modules/vfs_fonts.js +12 -0
  25. package/lowdefy.yaml +1 -1
  26. package/menus.yaml +25 -1
  27. package/operators/_actions.yaml +1 -1
  28. package/operators/_change_case.yaml +4 -4
  29. package/operators/_js.yaml +2 -2
  30. package/operators/_ref.yaml +16 -8
  31. package/operators/_switch.yaml +51 -0
  32. package/package.json +2 -2
  33. package/pages.yaml +12 -0
  34. package/public/images/authors/gervwyk.jpeg +0 -0
  35. package/public/images/authors/sandile.jpeg +0 -0
  36. package/public/images/howto/header_generate_csv.jpg +0 -0
  37. package/public/images/howto/header_generate_pdf.jpg +0 -0
  38. package/public/logo_example.png +0 -0
  39. package/public/modules/csvMake.js +27 -0
  40. package/public/modules/importUmd.js +7 -0
  41. package/public/modules/pdfMake.js +7 -0
  42. package/public/modules/vfs_fonts.js +12 -0
  43. package/public/sitemap.xml +216 -201
  44. package/templates/blocks/exampleTransformer.js +1 -1
  45. package/templates/blog.yaml.njk +221 -0
  46. package/templates/footer.yaml.njk +2 -2
  47. package/tutorial/tutorial-create-page.yaml +1 -1
  48. package/tutorial/tutorial-start.yaml +1 -1
  49. package/users/login-and-logout.yaml +2 -2
  50. package/users/openid-connect.yaml +1 -0
  51. package/users/protected-pages.yaml +2 -2
  52. package/users/roles.yaml +2 -2
  53. package/users/users-introduction.yaml +1 -1
  54. package/version.yaml +1 -1
@@ -0,0 +1,651 @@
1
+ # Copyright 2020-2021 Lowdefy, Inc
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ _ref:
16
+ path: templates/blog.yaml.njk
17
+ vars:
18
+ pageId: generate-pdf-document-from-data
19
+ pageTitle: How to generate PDFs using Lowdefy
20
+ section: How To
21
+ filePath: howto/generate-pdf.yaml
22
+ pageImage: /public/images/howto/header_generate_pdf.jpg
23
+ discussionsLink: https://github.com/lowdefy/lowdefy/discussions/889
24
+ authorProfile: /public/images/authors/gervwyk.jpeg
25
+ authorName: |
26
+ <div>Gerrie van Wyk</div>
27
+ <a href="https://twitter.com/gervwyk">Follow @gervwyk on Twitter</a>
28
+ articleLinks:
29
+ - title: Generate CSV in Lowdefy
30
+ pageId: generate-csv-files-from-data
31
+ content:
32
+ - id: md1
33
+ type: MarkdownWithCode
34
+ properties:
35
+ content: |
36
+ It is possible to extend the functionality of Lowdefy beyond the framework's current capabilities by creating custom blocks, actions or operators. In this how-to example we will create a custom action to generate PDF documents client side or in the browser.
37
+
38
+ The full project folder for this how-to is available at:
39
+ https://github.com/lowdefy/lowdefy/tree/main/packages/docs/howto/generatePdf
40
+
41
+ To see how this works, click this button to generate a PDF of an example invoice that will be discussed in this how-to.
42
+
43
+ - id: pdf_generate_button
44
+ type: Button
45
+ style:
46
+ textAlign: center
47
+ properties:
48
+ title: Generate & Download PDF
49
+ icon: DownloadOutlined
50
+ color: '#6293F8'
51
+ events:
52
+ onMount:
53
+ - id: init_data
54
+ type: SetState
55
+ params:
56
+ invoice:
57
+ id: '0030135'
58
+ account_id: 'A-11344'
59
+ inv_date:
60
+ _date: now
61
+ subtotal: 397.034
62
+ discount: -19.8517
63
+ vat: 59.5551
64
+ total: 436.7374
65
+ balance: 413.2330
66
+ customer:
67
+ name: Service Center
68
+ phone: +123-456-7890
69
+ vat_nmr: 12-333-4567
70
+ address: |
71
+ 123 Main St.
72
+ Anytown
73
+ CA
74
+ US
75
+ 9999
76
+ services:
77
+ - name: Hosting and Maintannce
78
+ qty: 1
79
+ price: 235.90
80
+ code: X12-33C
81
+ - name: Developer Hours
82
+ qty: 16
83
+ price: 60.345
84
+ code: X12-39A
85
+ - name: Designer Hours
86
+ qty: 4
87
+ price: 40.122
88
+ code: X12-21A
89
+ - name: Project Management
90
+ qty: 2
91
+ price: 60.667
92
+ code: X12-49A
93
+ onClick:
94
+ - id: generate_pdf
95
+ type: JsAction
96
+ params:
97
+ name: pdfMake
98
+ args:
99
+ _ref: howto/generatePdf/inv_template.yaml
100
+
101
+ - id: md2
102
+ type: MarkdownWithCode
103
+ properties:
104
+ content: |
105
+ Now click this button to share this article on Twitter 😉
106
+ - id: twitter_button
107
+ type: Button
108
+ style:
109
+ textAlign: center
110
+ properties:
111
+ title: Share this post
112
+ icon: UploadOutlined
113
+ color: '#6293F8'
114
+ events:
115
+ onClick:
116
+ - id: share_twitter
117
+ type: Link
118
+ params:
119
+ newTab: true
120
+ url: https://twitter.com/intent/tweet?url=https%3A%2F%2Fdocs.lowdefy.com%2Fgenerate-pdf-document-from-data&text=Learn%20to%20generate%20pdf%20documents%20from%20data%20using%20@lowdefy%20-%20an%20open-source%2C%20self-hosted%2C%20low-code%20from%20work%20to%20build%20web%20apps%20and%20internal%20tools%20with%20ease.%20&hashtags=opensource%20%23selfhosted%20%23lowcode%20%23internaltools
121
+ - id: md3
122
+ type: MarkdownWithCode
123
+ properties:
124
+ content: |
125
+ ## Generate PDF TLDR;
126
+
127
+ 1. Select a client side PDF library and add the JavaScript to your Lowdefy app, we'll be using [pdfMake](https://github.com/bpampuch/pdfmake).
128
+ 2. Register a [JsAction](/JsAction) method to generate the PDF document.
129
+ 3. Load the custom JavaScript using a script tag.
130
+ 4. Add a button with a onClick action to call the generate PDF method.
131
+ 5. Define the content of your PDF and add data variables as needed.
132
+ - id: md_vid
133
+ type: DangerousMarkdown
134
+ properties:
135
+ DOMPurifyOptions:
136
+ ADD_TAGS:
137
+ - iframe
138
+ content: |
139
+ <div style="position: relative; padding-bottom: 62.5%; height: 0;"><iframe src="https://www.loom.com/embed/771948a63b0240238d7edb0d0a9a59e7" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>
140
+ - id: md2_1
141
+ type: MarkdownWithCode
142
+ properties:
143
+ content: |
144
+ ## Background
145
+
146
+ Generating PDFs are often required in workflow applications where data needs to be parsed into a document. These type of documents can be anything from quotes or invoices to contracts or even recipes. Making these documents represent the latest data, or exactly match the desired formatting can be tricky and time consuming. Auto generated PDFs are a great solution.
147
+
148
+ > This how-to assumes that you are already running a Lowdefy app locally in dev mode. If not:
149
+ > 1) Create a empty folder.
150
+ > 2) Open your terminal or cmd and `cd` to your empty folder.
151
+ > 3) Run `npx lowdefy@latest init && npx lowdefy@latest dev` to initialize and start your Lowdefy app development server.
152
+
153
+ ## 1. Choosing a open-source PDF library
154
+
155
+ The power of open-source is mind blowing. There are a number of well tested, popular, easy to use and free PDF generating libraries that we can possibly use. We'll be using pdfMake since it is well documented, and simple configuration settings. Some of the popular ones are:
156
+ - [pdfMake](https://github.com/bpampuch/pdfmake)
157
+ - [JsPDF](https://github.com/MrRio/jsPDF)
158
+ - [PDFKit](https://github.com/foliojs/pdfkit)
159
+ - [Puppeteer](https://github.com/puppeteer/puppeteer)
160
+ - [PDF-lib](https://github.com/Hopding/pdf-lib)
161
+
162
+ > If you use open-source libraries to automate your business and save you time, please try to thank the maintainers by contributing where possible or simply providing sponsorship. Look for the sponsorship links usually found in the project readme files.
163
+
164
+ ## 2. Register a custom JavaScript Action
165
+
166
+ Lowdefy actions are triggered by page events, like `onClick` when a user clicks a button, or `onEnter` when the page loads. Lowdefy comes with a list of predefined actions, however, sometimes custom code is the best awnser. Let's create a custom action which will generate a PDF based on pdfMake config.
167
+
168
+ 1) Create a `public` folder inside your Lowdefy working directory.
169
+ 2) Since all content in the `public` folder is served by the Lowdefy server, simply create a `pdfMake.js` file inside the `public` folder.
170
+ 3) Add this script to the file and save.
171
+
172
+ ###### /public/modules/pdfMake.js
173
+ ```js
174
+ import importUmd from './importUmd.js';
175
+ import vfs from './vfs_fonts.js';
176
+ const pdfMake = await importUmd(
177
+ `https://cdn.jsdelivr.net/npm/pdfmake@0.2.2/build/pdfmake.min.js`
178
+ );
179
+ const pdfMakeFn = async (
180
+ context,
181
+ filename,
182
+ docDefinition,
183
+ tableLayouts,
184
+ fonts
185
+ ) => {
186
+ await pdfMake
187
+ .createPdf(docDefinition, tableLayouts, fonts, vfs)
188
+ .download(filename);
189
+ };
190
+ window.lowdefy.registerJsAction('pdfMake', pdfMakeFn);
191
+ ```
192
+
193
+ This script does a few things, first, it imports [importUmd.js](/public/modules/importUmd.js) and the [vfs_fonts.js](/public/modules/vfs_fonts.js) file also from our `public` folder. Then it loads [pdfMake](https://cdn.jsdelivr.net/npm/pdfmake@0.2.2/build/pdfmake.min.js) from [jsdelivr](https://www.jsdelivr.com/). Then we create an async function `pdfMakeFn` which takes some parameters like the `filename` and `docDefinition` and passes it to pdfMake as it is being called.
194
+
195
+ Finally, it registers the `pdfMakeFn` function as a custom [JsAction](/JsAction) using `window.lowdefy.registerJsAction`. This gives our new method to the Lowdefy logic engine to use.
196
+
197
+ > IMPORTANT: We mentioned two additional files here. [`importUmd.js`](/public/modules/importUmd.js) is a helper function to load umd modules from a source, and [`vfs_fonts.js`](/public/modules/vfs_fonts.js) is a virtualized font which we provide to pdfMake. Download these files and copy them into your `public` folder.
198
+
199
+ ## 3. Load the custom JavaScript using a script tag
200
+
201
+ With our JavaScript ready, we need to load the JavaScript onto our page in order for it to be evaluated by the browser.
202
+
203
+ Create a `my_header.html` file inside your project route and add the following HTML:
204
+
205
+ ###### /my_header.html
206
+ ```html
207
+ <script defer type="module" src="/public/modules/pdfMake.js"></script>
208
+ ```
209
+
210
+ This loads the `pdfMake.js` module file into HTML.
211
+
212
+ Also, add the HTML file to your Lowdefy application header. To do this, use the `app.html.appendHead` Lowdefy config property. Your `lowdefy.yaml` file should look something like this:
213
+
214
+ ###### /lowdefy.yaml
215
+ ```yaml
216
+ name: Generate a PDF
217
+ lowdefy: {{ version }}
218
+
219
+ app:
220
+ html:
221
+ appendHead:
222
+ _ref: my_header.html
223
+ ```
224
+
225
+ Congratulations 🎉 your custom JSAction is now available in you Lowdefy app and ready to use.
226
+
227
+ Up until this part, this how-to has been very generic and will likely be the same for most apps using pdfMake to generate PDFs.
228
+
229
+ In the next part we'll configure our example app to generate a PDF.
230
+
231
+ ## 4. Generate a PDF when a button is clicked
232
+
233
+ Next, we want to add a button to the page, and when the button is clicked, our PDF will be generated and downloaded, client side.
234
+
235
+ Let's make this quick and simple, we'll change our Lowdefy config to:
236
+
237
+ ###### /lowdefy.yaml
238
+ ```yaml
239
+ name: Generate a PDF
240
+ lowdefy: 3.23.2
241
+
242
+ app:
243
+ html:
244
+ appendHead:
245
+ _ref: my_header.html
246
+
247
+ pages:
248
+ - id: generate-a-pdf
249
+ type: PageHeaderMenu
250
+ blocks:
251
+ - id: generate_pdf_button
252
+ type: Button
253
+ properties:
254
+ title: Download PDF
255
+ icon: DownloadOutlined
256
+ events:
257
+ onClick:
258
+ - id: make_pdf
259
+ type: JsAction
260
+ params:
261
+ name: pdfMake
262
+ args:
263
+ - my_file_name.pdf
264
+ - pageMargins: 50
265
+ defaultStyle:
266
+ fontSize: 10
267
+ content:
268
+ - text: This pdf has been generated with Lowdefy and pdfMake.
269
+ bold: true
270
+ ```
271
+
272
+ When you run this app, you'll have a 'Download PDF' button, and when clicked, a pdf will be generated and downloaded. This example should work like the button below.
273
+
274
+ - id: make_pdf_button
275
+ type: Button
276
+ style:
277
+ textAlign: center
278
+ properties:
279
+ title: Download PDF
280
+ icon: DownloadOutlined
281
+ events:
282
+ onClick:
283
+ - id: make_pdf
284
+ type: JsAction
285
+ params:
286
+ name: pdfMake
287
+ args:
288
+ - my_file_name.pdf
289
+ - pageMargins: 50
290
+ defaultStyle:
291
+ fontSize: 10
292
+ content:
293
+ - text: This pdf has been generated with Lowdefy and pdfMake.
294
+ bold: true
295
+ - id: md4
296
+ type: MarkdownWithCode
297
+ properties:
298
+ content: |
299
+ ## 4. Define the content of the PDF
300
+
301
+ Finally to demonstrate how powerful this can be, we'll build out our pdfMake config to generate an invoice. In practice we would request the account data from our database and then pass the data to pdfMake when the button is clicked. For this example, we'll just hard code the invoice data and set it to the page state. The full project folder for this example is available at: https://github.com/lowdefy/lowdefy/tree/main/packages/docs/howto/generatePdf
302
+
303
+ ###### /lowdefy.yaml
304
+ ```yaml
305
+ lowdefy: 3.23.2
306
+ name: Generate PDF from data with Lowdefy
307
+
308
+ app:
309
+ html:
310
+ appendHead:
311
+ _ref: my_header.html
312
+
313
+ pages:
314
+ - id: example
315
+ type: PageHeaderMenu
316
+ properties:
317
+ title: Example
318
+ events:
319
+ onEnter:
320
+ - id: init_data
321
+ type: SetState
322
+ params:
323
+ invoice:
324
+ id: '0030135'
325
+ account_id: 'A-11344'
326
+ inv_date:
327
+ _date: now
328
+ subtotal: 397.034
329
+ discount: -19.8517
330
+ vat: 59.5551
331
+ total: 436.7374
332
+ balance: 413.2330
333
+ customer:
334
+ name: Service Center
335
+ phone: +123-456-7890
336
+ vat_nmr: 12-333-4567
337
+ address: |
338
+ 123 Main St.
339
+ Anytown
340
+ CA
341
+ US
342
+ 9999
343
+ services:
344
+ - name: Hosting and Maintannce
345
+ qty: 1
346
+ price: 235.90
347
+ code: X12-33C
348
+ - name: Developer Hours
349
+ qty: 16
350
+ price: 60.345
351
+ code: X12-39A
352
+ - name: Designer Hours
353
+ qty: 4
354
+ price: 40.122
355
+ code: X12-21A
356
+ - name: Project Management
357
+ qty: 2
358
+ price: 60.667
359
+ code: X12-49A
360
+ areas:
361
+ content:
362
+ justify: center
363
+ blocks:
364
+ - id: docs_button
365
+ type: Button
366
+ properties:
367
+ size: large
368
+ title: Generate Invoice
369
+ color: '#1890ff'
370
+ events:
371
+ onClick:
372
+ - id: make_pdf
373
+ type: JsAction
374
+ params:
375
+ name: pdfMake
376
+ args:
377
+ _ref: inv_template.yaml
378
+ ```
379
+
380
+ Note that we have split out the pdfMake config into a seperate file `inv_template.yaml`. This makes it more readible and the same template used in various parts of our app config. This is implemented using the [`_ref`](/_ref) operator.
381
+
382
+ ###### `/inv_template.yaml`
383
+ ```yaml
384
+ - _nunjucks:
385
+ on:
386
+ _state: invoice
387
+ template: 'INV-{{ id }}-{{ inv_date | date("DD-MM-YYYY") }}.pdf'
388
+ - pageMargins: [50, 25, 50, 70]
389
+ defaultStyle:
390
+ fontSize: 10
391
+ images:
392
+ logo:
393
+ _string.concat:
394
+ - _location: origin
395
+ - /public/logo_example.png
396
+ footer:
397
+ _function:
398
+ - columns:
399
+ - qr:
400
+ _string.concat:
401
+ - _location: origin
402
+ - /invoice?id="
403
+ - _state: invoice.id
404
+ - '"'
405
+ margin: [50, 0, 0, 0]
406
+ fit: '64'
407
+ - alignment: 'right'
408
+ fontSize: 7
409
+ margin: [0, 0, 50, 0]
410
+ text:
411
+ __nunjucks:
412
+ template: 'Page {{ page }} of {{ total }}'
413
+ on:
414
+ page:
415
+ __args: 0
416
+ total:
417
+ __args: 1
418
+ content:
419
+ - columns:
420
+ - width: 'auto'
421
+ margin: [0, 20, 0, 0]
422
+ stack:
423
+ - fontSize: 9
424
+ text: |
425
+
426
+ - fontSize: 7
427
+ text: |
428
+ Example Services Ltd.
429
+ 112 Street Name
430
+ City, State 12345
431
+ Country
432
+ 001-AB
433
+
434
+ +00-1234-5566
435
+ info@example.com
436
+
437
+ Vat Number: 444 5555 0000
438
+
439
+ - width: '*'
440
+ text: ' '
441
+ - width: 110
442
+ stack:
443
+ - width: 110
444
+ image: logo
445
+ - margin: [0, 5, 0, 0]
446
+ alignment: right
447
+ fontSize: 7
448
+ text: |
449
+ Example Services Ltd.
450
+ Reg Number: 2001/22224/09
451
+
452
+ - margin: [0, 20, 0, 20]
453
+ text: Customer Invoice
454
+ bold: true
455
+ alignment: center
456
+ fontSize: 14
457
+ - columns:
458
+ - width: 150
459
+ bold: true
460
+ text: |
461
+ INVOICE NUMBER:
462
+ DATE ISSUED:
463
+ ACCOUNT NUMBER:
464
+ - width: '*'
465
+ text:
466
+ _nunjucks:
467
+ template: |
468
+ {{ id }}
469
+ {{ inv_date | date("YYYY/MM/DD") }}
470
+ {{ account_id }}
471
+ on:
472
+ _state: invoice
473
+ - width: 150
474
+ bold: true
475
+ text: |
476
+ CUSTOMER:
477
+ ADDRESS:
478
+ - width: '*'
479
+ text:
480
+ _nunjucks:
481
+ template: |
482
+ {{ customer.name }}
483
+ {{ customer.address }}
484
+ on:
485
+ _state: invoice
486
+
487
+ - layout: 'lightHorizontalLines'
488
+ margin: [0, 10, 0, 0]
489
+ table:
490
+ widths: [70, '*', 70, 70, 70]
491
+ headerRows: 1
492
+ body:
493
+ _json.parse:
494
+ _nunjucks:
495
+ on:
496
+ services:
497
+ _state: invoice.services
498
+ template: |
499
+ [
500
+ [
501
+ { "text": "ITEM CODE", "bold": true },
502
+ { "text": "SERVICE", "bold": true },
503
+ { "text": "UNIT PRICE", "bold": true, "alignment": "right" },
504
+ { "text": "QTY", "bold": true, "alignment": "right" },
505
+ { "text": "COST", "bold": true, "alignment": "right" }
506
+ ],
507
+ {% for item in services %}
508
+ [
509
+ "{{ loop.index }}: {{ item.code }}",
510
+ "{{ item.name | safe }}",
511
+ { "text": "{{ ( item.price / item.qty ).toFixed(2) }}", "alignment": "right"},
512
+ { "text": "{{ item.qty }}", "alignment": "right"},
513
+ { "text": "{{ item.price.toFixed(2) }}", "alignment": "right"}
514
+ {% if loop.last %} ] {% else %} ], {% endif %}
515
+ {% endfor %}
516
+ ]
517
+ - layout: 'headerLineOnly'
518
+ margin: [0, -5, 0, 0]
519
+ table:
520
+ widths: ['*', 70, 70, 70]
521
+ headerRows: 1
522
+ body:
523
+ - - ''
524
+ - ''
525
+ - ''
526
+ - ''
527
+ - - ''
528
+ - alignment: right
529
+ text: 'Subtotal:'
530
+ - ''
531
+ - alignment: right
532
+ text:
533
+ _number.toFixed:
534
+ - _state: invoice.subtotal
535
+ - 2
536
+ - - ''
537
+ - alignment: right
538
+ text: 'Discount (5%):'
539
+ - ''
540
+ - alignment: right
541
+ text:
542
+ _number.toFixed:
543
+ - _state: invoice.discount
544
+ - 2
545
+ - - ''
546
+ - alignment: right
547
+ text: 'VAT (15%):'
548
+ - ''
549
+ - alignment: right
550
+ text:
551
+ _number.toFixed:
552
+ - _state: invoice.vat
553
+ - 2
554
+ - - ''
555
+ - alignment: right
556
+ text: 'Total:'
557
+ - ''
558
+ - alignment: right
559
+ text:
560
+ _number.toFixed:
561
+ - _state: invoice.total
562
+ - 2
563
+ - layout: 'headerLineOnly'
564
+ margin: [0, -5, 0, 0]
565
+ table:
566
+ widths: ['*', 70, 70, 70]
567
+ headerRows: 1
568
+ body:
569
+ - - ''
570
+ - ''
571
+ - ''
572
+ - ''
573
+ - - ''
574
+ - alignment: right
575
+ bold: true
576
+ text: 'BALANCE DUE:'
577
+ - ''
578
+ - alignment: right
579
+ bold: true
580
+ text:
581
+ _number.toFixed:
582
+ - _state: invoice.balance
583
+ - 2
584
+ ```
585
+
586
+ The above example will generate a PDF invoice with a logo, a QR code, a footer, a header, a table with the invoice details, and a table with the invoice items. Click the button to see this in action.
587
+
588
+ - id: generate_invoice
589
+ type: Button
590
+ style:
591
+ textAlign: center
592
+ properties:
593
+ title: Generate Invoice
594
+ icon: DownloadOutlined
595
+ color: '#6293F8'
596
+ events:
597
+ onMount:
598
+ - id: init_data
599
+ type: SetState
600
+ params:
601
+ invoice:
602
+ id: '0030135'
603
+ account_id: 'A-11344'
604
+ inv_date:
605
+ _date: now
606
+ subtotal: 397.034
607
+ discount: -19.8517
608
+ vat: 59.5551
609
+ total: 436.7374
610
+ balance: 413.2330
611
+ customer:
612
+ name: Service Center
613
+ phone: +123-456-7890
614
+ vat_nmr: 12-333-4567
615
+ address: |
616
+ 123 Main St.
617
+ Anytown
618
+ CA
619
+ US
620
+ 9999
621
+ services:
622
+ - name: Hosting and Maintannce
623
+ qty: 1
624
+ price: 235.90
625
+ code: X12-33C
626
+ - name: Developer Hours
627
+ qty: 16
628
+ price: 60.345
629
+ code: X12-39A
630
+ - name: Designer Hours
631
+ qty: 4
632
+ price: 40.122
633
+ code: X12-21A
634
+ - name: Project Management
635
+ qty: 2
636
+ price: 60.667
637
+ code: X12-49A
638
+ onClick:
639
+ - id: generate_pdf
640
+ type: JsAction
641
+ params:
642
+ name: pdfMake
643
+ args:
644
+ _ref: howto/generatePdf/inv_template.yaml
645
+ - id: md5
646
+ type: MarkdownWithCode
647
+ properties:
648
+ content: |
649
+ ## Conclusion
650
+
651
+ This how-to aims to demonstrate how easy custom JsActions in Lowdefy can be. With Lowdefy's ability to reference data and use JavaScript libraries like [pdfMake](https://github.com/bpampuch/pdfmake), Lowdefy becomes a superpower capable of even generating advanced PDFs with ease. Check out the project folder for this how-to and why not give it a try: https://github.com/lowdefy/lowdefy/tree/main/packages/docs/howto/generatePdf