@gov-cy/govcy-frontend-renderer 1.26.9 → 1.27.0

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 CHANGED
@@ -1,731 +1,772 @@
1
- [![npm (scoped)](https://img.shields.io/npm/v/@gov-cy/govcy-frontend-renderer)](https://www.npmjs.com/package/@gov-cy/govcy-frontend-renderer)
2
- ![License](https://img.shields.io/github/license/gov-cy/govcy-frontend-renderer)
3
- [![Unit test](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/unit-test.yml/badge.svg)](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/unit-test.yml)
4
- [![tag-and-publish-on-version-change](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/tag-and-publish-on-version-change.yml/badge.svg)](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/tag-and-publish-on-version-change.yml)
5
-
6
- Use this package to render HTML for gov.cy elements, as they are defined in the [Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/), using njk or json templates.
7
-
8
- ![govcy-frontend-renderer](DSF-govcy-frontend-renderer.png)
9
-
10
- The project was developed to support the [gov.cy Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/), so that the rendered HTML:
11
- - is as close of a representation as possible of the design elements as they are defined in the [Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/)
12
- - includes the gov.cy branding
13
- - uses the [govcy design system](https://gov-cy.github.io/govcy-design-system-docs/) css classes and javascript functions
14
- - uses HTML best practices and be valid HTML
15
- - uses accessibility best practices
16
- - allows multiple languages
17
- - is tested
18
-
19
- Though the project is not intended to be used for production purposes and does provide any guaranties, your welcome to try it.
20
-
21
- The project uses [nunjucks](https://mozilla.github.io/nunjucks/) templates to built the html.
22
-
23
- The package currently works with the **version 3.2.0** of the design system.
24
-
25
- ## Features
26
-
27
- The package can:
28
- can:
29
-
30
- - Generate HTML programmatically from [input nunjucks template](#nunjucks-template-example), using the project's base template and macros.
31
- - Generate HTML programmatically from [input JSON](#json-template-example) data
32
- - Generate complete pages as well as [individual components](#render-individual-components-example)
33
-
34
- ## Pre-requisites
35
- - You need to have [Node.js](https://nodejs.org/en/) installed. The package has been tested on node version 20.
36
-
37
- ## Install
38
-
39
- First, install the package using npm:
40
-
41
- ```shell
42
- npm install @gov-cy/govcy-frontend-renderer
43
- ```
44
-
45
- ## Usage
46
- First, you need to import the package as shown in the example below.
47
-
48
- ```js
49
- import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
50
- ```
51
-
52
- The package's main functions accept an input:
53
- - a **JSON object** with the [site and page meta data](#site-and-page-meta-data-explained)
54
- - and a **template** which can either be a [nunjucks template](#nunjucks-template-example) or a [JSON object](#json-template-example), that define the design elements to be rendered.
55
-
56
- Whether you are using a nunjucks template or a JSON object, the result is identical as they are both rendered using the same nunjucks macros.
57
-
58
- The output returned is a string with the rendered HTML.
59
-
60
- ### Nunjucks template example
61
- Use a [string with a nunjucks template](#nunjucks-input-template) and the `renderFromString` function to render HTML from a nunjucks template. See the example below.
62
-
63
- ```js
64
- import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
65
- const renderer = new govcyFrontendRenderer();
66
-
67
- // Define the input data
68
- const inputData =
69
- {
70
- "site" : {
71
- "lang" : "en",
72
- "languages": [
73
- {"code": "el", "label": "EL", "alt": "Ελληνική γλώσσα", "href": "?lang=el"},
74
- {"code": "en", "label": "EN", "alt": "English language", "href": "?lang=en"}
75
- ],
76
- "footerLinks": [
77
- {"label": {"en":"Privacy statement", "el":"Δήλωση απορρήτου"}, "href": "#"},
78
- {"label": {"en":"Cookies", "el":"Cookies"}, "href": "#"},
79
- {"label": {"en":"Accessibility", "el":"Προσβασιμότητα"}, "href": "#"},
80
- {"label": {"en":"Help us improve this service", "el":"Βοηθήστε μας να βελτιώσουμε αυτή την υπηρεσία"}, "href": "#"}
81
- ],
82
- "footerIcons": [
83
- {
84
- "src": {
85
- "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg",
86
- "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg"
87
- },
88
- "alt": {
89
- "en": "Service Standard Verified seal",
90
- "el": "Σφραγίδα Πιστοποίησης Υπηρεσίας"
91
- },
92
- "href": {
93
- "en": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/",
94
- "el": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/"
95
- },
96
- "style": {
97
- "en": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;",
98
- "el": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;"
99
- },
100
- "target": "_blank",
101
- "classes": "govcy-mr-3"
102
- },
103
- {
104
- "src": {
105
- "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png",
106
- "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EL.png"
107
- },
108
- "alt": {
109
- "en": "Funded by the EU Next Generation EU",
110
- "el": "Χρηματοδοτείται από την ΕΕ Next Generation EU"
111
- },
112
- "href": {
113
- "en": "https://europa.eu/",
114
- "el": "https://europa.eu/"
115
- },
116
- "title": {
117
- "en": "Go to EU website",
118
- "el": "Μετάβαση στην ιστοσελίδα της ΕΕ"
119
- },
120
- "target": "_blank"
121
- },
122
- {
123
- "src": {
124
- "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png",
125
- "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EL.png"
126
- },
127
- "alt": {
128
- "en": "Cyprus tomorrow, recovery and resilience plan",
129
- "el": "Κύπρος το Αύριο, σχέδιο ανάκαμψης και ανθεντικότητας"
130
- },
131
- "href": {
132
- "en": "http://www.cyprus-tomorrow.gov.cy/",
133
- "el": "http://www.cyprus-tomorrow.gov.cy/"
134
- },
135
- "title": {
136
- "en": "Go to Cyprus Tomorrow website",
137
- "el": "Μετάβαση στην ιστοσελίδα Κύπρος το Αύριο"
138
- },
139
- "target": "_blank"
140
- }
141
- ],
142
- "copyrightText" : {"en":"Republic of Cyprus, 2025", "el":"Κυπριακή Δημοκρατία, 2025"},
143
- "menu" : {"en":"Menu", "el":"Μενου"},
144
- "title" : {"en":"Service title", "el":"Τιτλός υπηρεσίας"},
145
- "headerTitle" :
146
- {
147
- "title": {
148
- "en":"Header title",
149
- "el":"Τιτλός επικεφαλιδας"
150
- },
151
- "href": {
152
- "en":"/service-id",
153
- "el":"/service-id"
154
- }
155
- },
156
- "description" : {"en":"Service description", "el":"Περιγραφή υπηρεσίας"},
157
- "url" : "https://gov.cy",
158
- "manifest": "/manifest.json",
159
- "matomo": {
160
- "url": "//wp.matomo.dits.dmrid.gov.cy/",
161
- "siteId": "1234"
162
- },
163
- "cdn" : {
164
- "dist" : "https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@3.0.0/dist",
165
- "cssIntegrity" : "sha384-1zLHWOtnS0hOIz5mVEPZp0UH5gUE6eo0CQcCGA3sF2TyYhHyKOd3Ni8Iy/NjEASU",
166
- "jsIntegrity" : "sha384-zOuDuogVaaTveh/Ou2iYwCk14zFiSmMk7Ax8yRnXDtOJMyKZH5+ZNibNVwZSKtw+"
167
- }
168
- },
169
- "pageData": {
170
- "title": {"en": "Page title", "el": "Τιτλός σελιδας"},
171
- "layout": "layouts/govcyBase.njk",
172
- "mainLayout": "max-width"
173
- }
174
- };
175
-
176
- // Define the template (njk)
177
- let inputString =
178
- `
179
- {% if pageData.layout %} {% extends pageData.layout %} {% endif %}
180
- {% from "govcyElement.njk" import govcyElement %}
181
- {% from "utilities/govcyUtilities.njk" import govcyLocalizeContent %}
182
- {% block main %}
183
- {% call govcyElement("form",
184
- {
185
- elements:
186
- [
187
- {
188
- element: "textInput",
189
- params:
190
- {
191
- label:{en:"What is your name?",el:"Ποιο είναι το όνομα σας;"}
192
- ,id:"name"
193
- ,name:"name"
194
- ,isPageHeading: true
195
- ,autocomplete:"tel"
196
- }
197
- },
198
- {
199
- element: "button",
200
- params: {
201
- text:{en:"Continue",el:"Συνέχεια"}
202
- , type:"submit"
203
- }
204
- }
205
- ]
206
- }) %}{% endcall %}
207
-
208
- {% endblock %}
209
- `
210
-
211
- // Render
212
- let rtn = renderer.renderFromString(inputString, inputData)
213
- console.log(rtn);
214
-
215
- ```
216
- In the example above, a sting will be written in the console containing the rendered HTML of a complete page.
217
-
218
- It is important to start your template string with the following:
219
- - `{% if pageData.layout %} {% extends pageData.layout %} {% endif %}`: Will extend the gov.cy page template as defined in the `pageData.layout` property.
220
- - `{% from "govcyElement.njk" import govcyElement %}`: Will import the `govcyElement` macro which is responsible for rendering all the [design elements](#included-design-elements).
221
- - `{% from "utilities/govcyUtilities.njk" import govcyLocalizeContent %}`: (Optional) Will import the `govcyUtilities` macro which includes [localization](#localization) and other utilities.
222
-
223
- To render design elements, the packages uses the `govcyElement` macro. See more details in the [design elements](DESIGN_ELEMENTS.md) section.
224
-
225
- ### JSON template example
226
- Use a [JSON object as the template](#json-input-template) and the `renderFromJSON` function to render HTML from a nunjucks template. See the example below.
227
-
228
- ```js
229
- import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
230
- const renderer = new govcyFrontendRenderer();
231
-
232
- // Define the input data
233
- const inputData =
234
- {
235
- "site" : {
236
- "lang" : "en",
237
- "languages": [
238
- {"code": "el", "label": "EL", "alt": "Ελληνική γλώσσα", "href": "?lang=el"},
239
- {"code": "en", "label": "EN", "alt": "English language", "href": "?lang=en"}
240
- ],
241
- "footerLinks": [
242
- {"label": {"en":"Privacy statement", "el":"Δήλωση απορρήτου"}, "href": "#"},
243
- {"label": {"en":"Cookies", "el":"Cookies"}, "href": "#"},
244
- {"label": {"en":"Accessibility", "el":"Προσβασιμότητα"}, "href": "#"},
245
- {"label": {"en":"Help us improve this service", "el":"Βοηθήστε μας να βελτιώσουμε αυτή την υπηρεσία"}, "href": "#"}
246
- ],
247
- "footerIcons": [
248
- {
249
- "src": {
250
- "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg",
251
- "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg"
252
- },
253
- "alt": {
254
- "en": "Service Standard Verified seal",
255
- "el": "Σφραγίδα Πιστοποίησης Υπηρεσίας"
256
- },
257
- "href": {
258
- "en": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/",
259
- "el": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/"
260
- },
261
- "style": {
262
- "en": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;",
263
- "el": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;"
264
- },
265
- "target": "_blank",
266
- "classes": "govcy-mr-3"
267
- },
268
- {
269
- "src": {
270
- "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png",
271
- "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EL.png"
272
- },
273
- "alt": {
274
- "en": "Funded by the EU Next Generation EU",
275
- "el": "Χρηματοδοτείται από την ΕΕ Next Generation EU"
276
- },
277
- "href": {
278
- "en": "https://europa.eu/",
279
- "el": "https://europa.eu/"
280
- },
281
- "title": {
282
- "en": "Go to EU website",
283
- "el": "Μετάβαση στην ιστοσελίδα της ΕΕ"
284
- },
285
- "target": "_blank"
286
- },
287
- {
288
- "src": {
289
- "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png",
290
- "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EL.png"
291
- },
292
- "alt": {
293
- "en": "Cyprus tomorrow, recovery and resilience plan",
294
- "el": "Κύπρος το Αύριο, σχέδιο ανάκαμψης και ανθεντικότητας"
295
- },
296
- "href": {
297
- "en": "http://www.cyprus-tomorrow.gov.cy/",
298
- "el": "http://www.cyprus-tomorrow.gov.cy/"
299
- },
300
- "title": {
301
- "en": "Go to Cyprus Tomorrow website",
302
- "el": "Μετάβαση στην ιστοσελίδα Κύπρος το Αύριο"
303
- },
304
- "target": "_blank"
305
- }
306
- ],
307
- "copyrightText" : {"en":"Republic of Cyprus, 2025", "el":"Κυπριακή Δημοκρατία, 2025"},
308
- "menu" : {"en":"Menu", "el":"Μενου"},
309
- "title" : {"en":"Service title", "el":"Τιτλός υπηρεσίας"},
310
- "headerTitle" :
311
- {
312
- "title": {
313
- "en":"Header title",
314
- "el":"Τιτλός επικεφαλιδας"
315
- },
316
- "href": {
317
- "en":"/service-id",
318
- "el":"/service-id"
319
- }
320
- },
321
- "description" : {"en":"Service description", "el":"Περιγραφή υπηρεσίας"},
322
- "url" : "https://gov.cy",
323
- "manifest": "manifest.json",
324
- "matomo": {
325
- "url": "//wp.matomo.dits.dmrid.gov.cy/",
326
- "siteId": "1234"
327
- },
328
- "cdn" : {
329
- "dist" : "https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@3.0.0/dist",
330
- "cssIntegrity" : "sha384-1zLHWOtnS0hOIz5mVEPZp0UH5gUE6eo0CQcCGA3sF2TyYhHyKOd3Ni8Iy/NjEASU",
331
- "jsIntegrity" : "sha384-zOuDuogVaaTveh/Ou2iYwCk14zFiSmMk7Ax8yRnXDtOJMyKZH5+ZNibNVwZSKtw+"
332
- }
333
- },
334
- "pageData": {
335
- "title": {"en": "Page title", "el": "Τιτλός σελιδας"},
336
- "layout": "layouts/govcyBase.njk",
337
- "mainLayout": "max-width"
338
- }
339
- };
340
-
341
- // Define the JSON template
342
- let inputJson =
343
- {
344
- "sections": [
345
- {
346
- "name": "main",
347
- "elements": [
348
- {
349
- "element": "form",
350
- "params": {
351
- "elements": [
352
- {
353
- "element": "textInput",
354
- "params":
355
- {
356
- "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
357
- ,"id":"name"
358
- ,"name":"name"
359
- ,"isPageHeading": true
360
- ,"autocomplete":"tel"
361
- }
362
- },
363
- {
364
- "element": "button",
365
- "params":
366
- {
367
- "text":{"en":"Continue","el":"Συνέχεια"}
368
- , "type":"submit"
369
- }
370
- }
371
- ]
372
- }
373
- }
374
- ]
375
- }
376
- ]
377
- }
378
- ;
379
-
380
- // Render
381
- let rtn = renderer.renderFromJSON(inputJson, inputData)
382
- console.log(rtn);
383
- ```
384
- In the example above, a sting will be written in the console containing the rendered HTML of a complete page.
385
-
386
- More details in defining design elements see in the [design elements](DESIGN_ELEMENTS.md) section.
387
-
388
- ### Render individual components example
389
-
390
- To render individual components, use the same functions as above, but leave the `pageData.layout` empty, as shown in the example below (the example uses a JSON template). Everything except the `site.lang`in the *siteData* and *pageData* will be ignored.
391
-
392
- ```js
393
- import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
394
- const renderer = new govcyFrontendRenderer();
395
-
396
- // Define the input data
397
- const inputData =
398
- {
399
- "site" : {
400
- "lang" : "en"
401
- },
402
- "pageData": {
403
- "layout": "",
404
- }
405
- };
406
-
407
- // Define the JSON template
408
- let inputJson =
409
- {
410
- "sections": [
411
- {
412
- "name": "main",
413
- "elements": [
414
- {
415
- "element": "form",
416
- "params": {
417
- "elements": [
418
- {
419
- "element": "textInput",
420
- "params":
421
- {
422
- "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
423
- ,"id":"name"
424
- ,"name":"name"
425
- ,"isPageHeading": true
426
- ,"autocomplete":"tel"
427
- }
428
- },
429
- {
430
- "element": "button",
431
- "params":
432
- {
433
- "text":{"en":"Continue","el":"Συνέχεια"}
434
- , "type":"submit"
435
- }
436
- }
437
- ]
438
- }
439
- }
440
- ]
441
- }
442
- ]
443
- }
444
- ;
445
-
446
- // Render
447
- let rtn = renderer.renderFromJSON(inputJson, inputData)
448
- console.log(rtn);
449
- ```
450
- All the `inputData` except the `site.lang` and the empty `pageData.layout` will be ignored.
451
-
452
- ### Site and page meta data explained
453
- In the examples above an `inputData` object is defined and it is used to pass the site and page's meta data. They are used by the `layouts/govcyBase.njk` template to add the necessary HTML tags and attributes.
454
-
455
- The `inputData` object has the following structure:
456
-
457
- - **site.lang**: the language of the site. It is used both in the `<html lang` attribute and to define the default language to be used by the individual design elements defined in the template.
458
- - **site.languages**: the languages in the language menu.
459
- - **site.footerLinks**: the links of the footer.
460
- - **site.footerIcons**: the icons with links of the footer.
461
- - **site.copyrightText**: the text of the copyright in the footer, including the year.
462
- - **site.menu**: the menu label.
463
- - **site.title**: the title of the site. It is used in the `<title>`, `<meta property="og:title"` and `<meta property="twitter:title"` tags of the head.
464
- - **site.description**: the description of the site. It is used in the `<meta name="description"`, `<meta property="og:description"` and `<meta property="twitter:description"` tags of the head.
465
- - **site.url**: the URL of the site. It is used in the `<meta property="og:url"` and `<meta property="twitter:url"` tags of the head.
466
- - **site.manifest**: the manifest of the site. It is used to add the manifest location to the page.
467
- - **site.matomo**: the matomo data. It is used to add the Matomo code to the page. If you don't want to use Matomo tracking, you can remove this value. Use `site.matomo.url` to define the URL of the Matomo server and `site.matomo.siteId` to define the site ID to be tracked.
468
- - **site.cdn.dist**: the CDN of the site. It is used to define the URL of the CDN used for the CSS and JS files. If you need to change the version of the CDN, you can do it by changing this value (in this case you will need to change the `site.cdn.cssIntegrity` and `site.cdn.jsIntegrity` values as well)
469
- - **site.cdn.cssIntegrity**: the integrity of the CSS file. It is used to define the integrity of the CSS file. If you need to change the version of the CDN, you will need to change this value. https://www.srihash.org/ can help you generate the integrity value.
470
- - **site.cdn.jsIntegrity**: the integrity of the JS file. It is used to define the integrity of the JS file. If you need to change the version of the CDN, you will need to change this value. https://www.srihash.org/ can help you generate the integrity value.
471
- - **site.customCSSFile**: the custom CSS file. It is used to add a custom CSS file to the page. This comes after the default CSS file so it will override the default CDN CSS file.
472
- - **pageData.title**: the title of the page. It is used in the `<title>`, `<meta property="og:title"` and `<meta property="twitter:title"` tags of the head.
473
- - **pageData.layout**: the layout of the page. It is used to define the layout (or page template) of the page, which is defined in the `layouts/govcyBase.njk` template.
474
- - **pageData.mainLayout**: the main layout of the page. It can be either `two-thirds` or `max-width`.
475
-
476
- ### Input Template explained
477
- The input template can either be a JSON template or a nunjucks template string. It is used to define the design elements to be rendered.
478
-
479
- #### Nunjucks input template
480
- To use the pre-defined design elements, you need to import the `govcyElement` macro by including the`{% from "govcyElement.njk" import govcyElement %}` as shown in the coded examples.
481
-
482
- ```js
483
- // Define the template (njk)
484
- let inputString =
485
- `
486
- {% if pageData.layout %} {% extends pageData.layout %} {% endif %}
487
- {% from "govcyElement.njk" import govcyElement %}
488
- {% from "utilities/govcyUtilities.njk" import govcyLocalizeContent %}
489
- {% block main %}
490
- {% call govcyElement("form",
491
- {
492
- elements:
493
- [
494
- {
495
- element: "textInput",
496
- params:
497
- {
498
- label:{en:"What is your name?",el:"Ποιο είναι το όνομα σας;"}
499
- ,id:"name"
500
- ,name:"name"
501
- ,isPageHeading: true
502
- ,autocomplete:"tel"
503
- }
504
- },
505
- {
506
- element: "button",
507
- params: {
508
- text:{en:"Continue",el:"Συνέχεια"}
509
- , type:"submit"
510
- }
511
- }
512
- ]
513
- }) %}{% endcall %}
514
-
515
- {% endblock %}
516
- `;
517
- ```
518
-
519
- If your using the `pageData.layout`, you can render html in each of the following [gov.cy page template](https://gov-cy.github.io/govcy-design-system-docs/getting-started/page-template/) blocks:
520
- - **bodyStart**: the start of the body
521
- - **userName**: the section where the username and logout links are rendered
522
- - **header**: the header section (where the gov.cy logo and service name are rendered)
523
- - **beforeMain**: the section before the main content
524
- - **main**: the main content
525
- - **footer**: the footer section
526
- - **bodyEnd**: the end of the body
527
- - **afterBody**: the section after the body. Usually reserved for overlay elements
528
- - **afterJS**: the section after the JS. Usually reserved for JS scripts
529
-
530
- Use the `govcyElement` macro inside the blocks to render the design elements defined in the `govcyElement.njk` template. More details in defining design elements see in the [design elements](DESIGN_ELEMENTS.md) section.
531
-
532
- #### JSON input template
533
- When using a JSON input template, there is no need to import or extend anything.
534
-
535
- ```js
536
- // Define the JSON template
537
- let inputJson =
538
- {
539
- "sections": [
540
- {
541
- "name": "main",
542
- "elements": [
543
- {
544
- "element": "form",
545
- "params": {
546
- "elements": [
547
- {
548
- "element": "textInput",
549
- "params":
550
- {
551
- "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
552
- ,"id":"name"
553
- ,"name":"name"
554
- ,"isPageHeading": true
555
- ,"autocomplete":"tel"
556
- }
557
- },
558
- {
559
- "element": "button",
560
- "params":
561
- {
562
- "text":{"en":"Continue","el":"Συνέχεια"}
563
- , "type":"submit"
564
- }
565
- }
566
- ]
567
- }
568
- }
569
- ]
570
- }
571
- ]
572
- }
573
- ;
574
-
575
- ```
576
-
577
- If your using the `pageData.layout`, you can render html in each of the following [gov.cy page template](https://gov-cy.github.io/govcy-design-system-docs/getting-started/page-template/) blocks, by using the `sections` array (in a similar way `blocks` is use ) :
578
- - **bodyStart**: the start of the body
579
- - **userName**: the section where the username and logout links are rendered
580
- - **header**: the header section (where the gov.cy logo and service name are rendered)
581
- - **beforeMain**: the section before the main content
582
- - **main**: the main content
583
- - **footer**: the footer section
584
- - **bodyEnd**: the end of the body
585
- - **afterBody**: the section after the body. Usually reserved for overlay elements
586
- - **afterJS**: the section after the JS. Usually reserved for JS scripts
587
-
588
- Define your design elements for each `sections` under the `elements` array. These elements use the same `govcyElement` macro to render the design elements. Do that by defining the `element` and `params` objects. For example:
589
-
590
- ```json
591
- {
592
- "element": "textInput",
593
- "params":
594
- {
595
- "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
596
- }
597
- }
598
- ```
599
-
600
- will use the `govcyElement` macro to render the `textInput` design element as follows:
601
-
602
- ```Nunjucks
603
- {{
604
- govcyElement({
605
- "textInput",
606
- {
607
- "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
608
- }
609
- })
610
- }}
611
- ```
612
-
613
- More details in defining design elements see in the [design elements](DESIGN_ELEMENTS.md) section.
614
-
615
- #### Included design elements
616
- More details on the elements that are supported by the package and how to include them in your templates, can be found on the [design elements](DESIGN_ELEMENTS.md) document.
617
-
618
- ### Localization
619
- All content in design elements are defined with an object defining the available languages and their content. For example `label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}`. When rendering the package will determin which language to use with the following logic and order:
620
-
621
- 1. if `params.lang` is defined in the design element, use that
622
- 2. else if `site.lang` is defined in the `siteData`, use that
623
- 3. else use `el`
624
-
625
- If the `params.lang` is defined in the design element, the package will also render element with a `lang` attribute.
626
-
627
- ## Browser usage (client-side)
628
- > [!WARNING]
629
- > Browser classes are not thoroughly tested, so use with care.
630
-
631
- The package offers compiled templates in `govcyCompiledTemplates.browser.js` and a helper class `govcyFrontendRenderer.browser.js` to render the same components on the browser. Unlike the note.js methods, you will need to provide the HTML shell.
632
-
633
- The easiest way to use these is to include the libraries via CDN in your HTML and use the `renderFromJSON` and `updateDOMAndInitialize` functions.
634
-
635
- Here's an example:
636
-
637
- ```html
638
-
639
- <!DOCTYPE html>
640
- <html lang="en">
641
-
642
- <head>
643
- <!-- Required meta tags -->
644
- <meta charset="utf-8">
645
- <meta name="viewport" content="width=device-width, initial-scale=1">
646
- <!-- CSS -->
647
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@v3/dist/css/govcy.uds.min.css">
648
- <title>Page title - Service Name - gov.cy</title>
649
- <meta name="description" content="Description of what the service does">
650
-
651
- </head>
652
-
653
- <body>
654
- <!--bodyStart-->
655
- <section class="govcy-container-fluid" id="bodyStartContainer">
656
- <a href="#mainContainer" class="govcy-skip-link">Skip to main content</a>
657
- </section>
658
- <!--main-->
659
- <main class="govcy-container" id="mainContainer">
660
- <div class="govcy-row">
661
- <article class="govcy-col-8">
662
- <div id="output" class="govcy-form"></div>
663
- </article>
664
- </div>
665
- </main>
666
- <script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@v3/dist/js/govcy.uds.min.js"></script>
667
- <script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyCompiledTemplates.browser.js"></script>
668
- <script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyFrontendRenderer.browser.js"></script>
669
- <script>
670
-
671
- document.addEventListener("DOMContentLoaded", async function () {
672
-
673
- // Create an instance of GovcyFrontendRendererBrowser
674
- const renderer = new GovcyFrontendRendererBrowser();
675
-
676
- // Define the input data
677
- const inputData =
678
- {
679
- "site": {
680
- "lang": "en"
681
- }
682
- };
683
-
684
- // Construct the JSONTemplate
685
- const JSONTemplate = {
686
- "elements": [
687
- {
688
- "element": "backLink",
689
- "params": {}
690
- },
691
- {
692
- "element": "tag",
693
- "params": {
694
- "text": {
695
- "en": "SIMPLE TAG",
696
- "el": "ΑΠΛΟ TAG"
697
- }
698
- }
699
- }
700
- ]
701
- };
702
-
703
- //render HTML into string
704
- let renderedHtml = renderer.renderFromJSON(JSONTemplate,inputData);
705
- //update DOM and initialize the JS components
706
- renderer.updateDOMAndInitialize('output', renderedHtml);
707
- });
708
- </script>
709
- </body>
710
-
711
- </html>
712
- ```
713
-
714
- ### Things you should know about browser usage
715
- Using the example above as reference:
716
- 1. `renderer.renderFromJSON(JSONTemplate,inputData);` generates the HTML based on the JSON input template.
717
- 2. `renderer.updateDOMAndInitialize('output', renderedHtml);` updates the DOM and initializes the JS components. It finds the element with id `output` and :
718
- - used the `innerHTML` to update it's contents
719
- - initializes all GOVCY design system's JS components within that elements (so it will not re-initialize other elements such as `header` in different sections of the page)
720
-
721
- ## Change the package
722
-
723
- Details on how to build, test and update the project can be found in the [project notes](NOTES.md) document.
724
-
725
- ## License
726
-
727
- The package is released under the [MIT License](https://opensource.org/licenses/MIT).
728
-
729
- ## Contact
730
-
1
+ [![npm (scoped)](https://img.shields.io/npm/v/@gov-cy/govcy-frontend-renderer)](https://www.npmjs.com/package/@gov-cy/govcy-frontend-renderer)
2
+ ![License](https://img.shields.io/github/license/gov-cy/govcy-frontend-renderer)
3
+ [![Unit test](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/unit-test.yml/badge.svg)](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/unit-test.yml)
4
+ [![tag-and-publish-on-version-change](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/tag-and-publish-on-version-change.yml/badge.svg)](https://github.com/gov-cy/govcy-frontend-renderer/actions/workflows/tag-and-publish-on-version-change.yml)
5
+
6
+ Use this package to render HTML for gov.cy elements, as they are defined in the [Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/), using njk or json templates.
7
+
8
+ ![govcy-frontend-renderer](DSF-govcy-frontend-renderer.png)
9
+
10
+ The project was developed to support the [gov.cy Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/), so that the rendered HTML:
11
+ - is as close of a representation as possible of the design elements as they are defined in the [Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/)
12
+ - includes the gov.cy branding
13
+ - uses the [govcy design system](https://gov-cy.github.io/govcy-design-system-docs/) css classes and javascript functions
14
+ - uses HTML best practices and be valid HTML
15
+ - uses accessibility best practices
16
+ - allows multiple languages
17
+ - is tested
18
+
19
+ Though the project is not intended to be used for production purposes and does provide any guaranties, your welcome to try it.
20
+
21
+ The project uses [nunjucks](https://mozilla.github.io/nunjucks/) templates to built the html.
22
+
23
+ The package currently works with the **version 3.2.0** of the design system.
24
+
25
+ ## Features
26
+
27
+ The package can:
28
+ can:
29
+
30
+ - Generate HTML programmatically from [input nunjucks template](#nunjucks-template-example), using the project's base template and macros.
31
+ - Generate HTML programmatically from [input JSON](#json-template-example) data
32
+ - Generate complete pages as well as [individual components](#render-individual-components-example)
33
+
34
+ ## Pre-requisites
35
+ - You need to have [Node.js](https://nodejs.org/en/) installed. The package has been tested on node version 20.
36
+
37
+ ## Install
38
+
39
+ First, install the package using npm:
40
+
41
+ ```shell
42
+ npm install @gov-cy/govcy-frontend-renderer
43
+ ```
44
+
45
+ ## Usage
46
+ First, you need to import the package as shown in the example below.
47
+
48
+ ```js
49
+ import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
50
+ ```
51
+
52
+ The package's main functions accept an input:
53
+ - a **JSON object** with the [site and page meta data](#site-and-page-meta-data-explained)
54
+ - and a **template** which can either be a [nunjucks template](#nunjucks-template-example) or a [JSON object](#json-template-example), that define the design elements to be rendered.
55
+
56
+ Whether you are using a nunjucks template or a JSON object, the result is identical as they are both rendered using the same nunjucks macros.
57
+
58
+ The output returned is a string with the rendered HTML.
59
+
60
+ ### Nunjucks template example
61
+ Use a [string with a nunjucks template](#nunjucks-input-template) and the `renderFromString` function to render HTML from a nunjucks template. See the example below.
62
+
63
+ ```js
64
+ import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
65
+ const renderer = new govcyFrontendRenderer();
66
+
67
+ // Define the input data
68
+ const inputData =
69
+ {
70
+ "site" : {
71
+ "lang" : "en",
72
+ "languages": [
73
+ {"code": "el", "label": "EL", "alt": "Ελληνική γλώσσα", "href": "?lang=el"},
74
+ {"code": "en", "label": "EN", "alt": "English language", "href": "?lang=en"}
75
+ ],
76
+ "footerLinks": [
77
+ {"label": {"en":"Privacy statement", "el":"Δήλωση απορρήτου"}, "href": "#"},
78
+ {"label": {"en":"Cookies", "el":"Cookies"}, "href": "#"},
79
+ {"label": {"en":"Accessibility", "el":"Προσβασιμότητα"}, "href": "#"},
80
+ {"label": {"en":"Help us improve this service", "el":"Βοηθήστε μας να βελτιώσουμε αυτή την υπηρεσία"}, "href": "#"}
81
+ ],
82
+ "footerIcons": [
83
+ {
84
+ "src": {
85
+ "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg",
86
+ "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg"
87
+ },
88
+ "alt": {
89
+ "en": "Service Standard Verified seal",
90
+ "el": "Σφραγίδα Πιστοποίησης Υπηρεσίας"
91
+ },
92
+ "href": {
93
+ "en": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/",
94
+ "el": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/"
95
+ },
96
+ "style": {
97
+ "en": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;",
98
+ "el": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;"
99
+ },
100
+ "target": "_blank",
101
+ "classes": "govcy-mr-3"
102
+ },
103
+ {
104
+ "src": {
105
+ "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png",
106
+ "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EL.png"
107
+ },
108
+ "alt": {
109
+ "en": "Funded by the EU Next Generation EU",
110
+ "el": "Χρηματοδοτείται από την ΕΕ Next Generation EU"
111
+ },
112
+ "href": {
113
+ "en": "https://europa.eu/",
114
+ "el": "https://europa.eu/"
115
+ },
116
+ "title": {
117
+ "en": "Go to EU website",
118
+ "el": "Μετάβαση στην ιστοσελίδα της ΕΕ"
119
+ },
120
+ "target": "_blank"
121
+ },
122
+ {
123
+ "src": {
124
+ "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png",
125
+ "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EL.png"
126
+ },
127
+ "alt": {
128
+ "en": "Cyprus tomorrow, recovery and resilience plan",
129
+ "el": "Κύπρος το Αύριο, σχέδιο ανάκαμψης και ανθεντικότητας"
130
+ },
131
+ "href": {
132
+ "en": "http://www.cyprus-tomorrow.gov.cy/",
133
+ "el": "http://www.cyprus-tomorrow.gov.cy/"
134
+ },
135
+ "title": {
136
+ "en": "Go to Cyprus Tomorrow website",
137
+ "el": "Μετάβαση στην ιστοσελίδα Κύπρος το Αύριο"
138
+ },
139
+ "target": "_blank"
140
+ }
141
+ ],
142
+ "copyrightText" : {"en":"Republic of Cyprus, 2025", "el":"Κυπριακή Δημοκρατία, 2025"},
143
+ "menu" : {"en":"Menu", "el":"Μενου"},
144
+ "navigation": {
145
+ "items": [
146
+ {
147
+ "label": {"en":"Home", "el":"Home"},
148
+ "href": {"en":"/en", "el":"/el"},
149
+ "current": true
150
+ },
151
+ {
152
+ "label": {"en":"Contact", "el":"Contact"},
153
+ "href": {"en":"/en/contact", "el":"/el/contact"}
154
+ }
155
+ ]
156
+ },
157
+ "title" : {"en":"Service title", "el":"Τιτλός υπηρεσίας"},
158
+ "headerTitle" :
159
+ {
160
+ "title": {
161
+ "en":"Header title",
162
+ "el":"Τιτλός επικεφαλιδας"
163
+ },
164
+ "href": {
165
+ "en":"/service-id",
166
+ "el":"/service-id"
167
+ }
168
+ },
169
+ "description" : {"en":"Service description", "el":"Περιγραφή υπηρεσίας"},
170
+ "url" : "https://gov.cy",
171
+ "manifest": "/manifest.json",
172
+ "matomo": {
173
+ "url": "//wp.matomo.dits.dmrid.gov.cy/",
174
+ "siteId": "1234"
175
+ },
176
+ "cdn" : {
177
+ "dist" : "https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@3.0.0/dist",
178
+ "cssIntegrity" : "sha384-1zLHWOtnS0hOIz5mVEPZp0UH5gUE6eo0CQcCGA3sF2TyYhHyKOd3Ni8Iy/NjEASU",
179
+ "jsIntegrity" : "sha384-zOuDuogVaaTveh/Ou2iYwCk14zFiSmMk7Ax8yRnXDtOJMyKZH5+ZNibNVwZSKtw+"
180
+ }
181
+ },
182
+ "pageData": {
183
+ "title": {"en": "Page title", "el": "Τιτλός σελιδας"},
184
+ "layout": "layouts/govcyBase.njk",
185
+ "mainLayout": "max-width"
186
+ }
187
+ };
188
+
189
+ // Define the template (njk)
190
+ let inputString =
191
+ `
192
+ {% if pageData.layout %} {% extends pageData.layout %} {% endif %}
193
+ {% from "govcyElement.njk" import govcyElement %}
194
+ {% from "utilities/govcyUtilities.njk" import govcyLocalizeContent %}
195
+ {% block main %}
196
+ {% call govcyElement("form",
197
+ {
198
+ elements:
199
+ [
200
+ {
201
+ element: "textInput",
202
+ params:
203
+ {
204
+ label:{en:"What is your name?",el:"Ποιο είναι το όνομα σας;"}
205
+ ,id:"name"
206
+ ,name:"name"
207
+ ,isPageHeading: true
208
+ ,autocomplete:"tel"
209
+ }
210
+ },
211
+ {
212
+ element: "button",
213
+ params: {
214
+ text:{en:"Continue",el:"Συνέχεια"}
215
+ , type:"submit"
216
+ }
217
+ }
218
+ ]
219
+ }) %}{% endcall %}
220
+
221
+ {% endblock %}
222
+ `
223
+
224
+ // Render
225
+ let rtn = renderer.renderFromString(inputString, inputData)
226
+ console.log(rtn);
227
+
228
+ ```
229
+ In the example above, a sting will be written in the console containing the rendered HTML of a complete page.
230
+
231
+ It is important to start your template string with the following:
232
+ - `{% if pageData.layout %} {% extends pageData.layout %} {% endif %}`: Will extend the gov.cy page template as defined in the `pageData.layout` property.
233
+ - `{% from "govcyElement.njk" import govcyElement %}`: Will import the `govcyElement` macro which is responsible for rendering all the [design elements](#included-design-elements).
234
+ - `{% from "utilities/govcyUtilities.njk" import govcyLocalizeContent %}`: (Optional) Will import the `govcyUtilities` macro which includes [localization](#localization) and other utilities.
235
+
236
+ To render design elements, the packages uses the `govcyElement` macro. See more details in the [design elements](DESIGN_ELEMENTS.md) section.
237
+
238
+ ### JSON template example
239
+ Use a [JSON object as the template](#json-input-template) and the `renderFromJSON` function to render HTML from a nunjucks template. See the example below.
240
+
241
+ ```js
242
+ import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
243
+ const renderer = new govcyFrontendRenderer();
244
+
245
+ // Define the input data
246
+ const inputData =
247
+ {
248
+ "site" : {
249
+ "lang" : "en",
250
+ "languages": [
251
+ {"code": "el", "label": "EL", "alt": "Ελληνική γλώσσα", "href": "?lang=el"},
252
+ {"code": "en", "label": "EN", "alt": "English language", "href": "?lang=en"}
253
+ ],
254
+ "footerLinks": [
255
+ {"label": {"en":"Privacy statement", "el":"Δήλωση απορρήτου"}, "href": "#"},
256
+ {"label": {"en":"Cookies", "el":"Cookies"}, "href": "#"},
257
+ {"label": {"en":"Accessibility", "el":"Προσβασιμότητα"}, "href": "#"},
258
+ {"label": {"en":"Help us improve this service", "el":"Βοηθήστε μας να βελτιώσουμε αυτή την υπηρεσία"}, "href": "#"}
259
+ ],
260
+ "footerIcons": [
261
+ {
262
+ "src": {
263
+ "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg",
264
+ "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg"
265
+ },
266
+ "alt": {
267
+ "en": "Service Standard Verified seal",
268
+ "el": "Σφραγίδα Πιστοποίησης Υπηρεσίας"
269
+ },
270
+ "href": {
271
+ "en": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/",
272
+ "el": "https://dsf.dmrid.gov.cy/2022/11/15/update-my-details/"
273
+ },
274
+ "style": {
275
+ "en": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;",
276
+ "el": "content: url(https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/seals/ssv-certificate-verification-info.svg) !important;aspect-ratio: auto;height: 53px !important;"
277
+ },
278
+ "target": "_blank",
279
+ "classes": "govcy-mr-3"
280
+ },
281
+ {
282
+ "src": {
283
+ "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png",
284
+ "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EL.png"
285
+ },
286
+ "alt": {
287
+ "en": "Funded by the EU Next Generation EU",
288
+ "el": "Χρηματοδοτείται από την ΕΕ Next Generation EU"
289
+ },
290
+ "href": {
291
+ "en": "https://europa.eu/",
292
+ "el": "https://europa.eu/"
293
+ },
294
+ "title": {
295
+ "en": "Go to EU website",
296
+ "el": "Μετάβαση στην ιστοσελίδα της ΕΕ"
297
+ },
298
+ "target": "_blank"
299
+ },
300
+ {
301
+ "src": {
302
+ "en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png",
303
+ "el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EL.png"
304
+ },
305
+ "alt": {
306
+ "en": "Cyprus tomorrow, recovery and resilience plan",
307
+ "el": "Κύπρος το Αύριο, σχέδιο ανάκαμψης και ανθεντικότητας"
308
+ },
309
+ "href": {
310
+ "en": "http://www.cyprus-tomorrow.gov.cy/",
311
+ "el": "http://www.cyprus-tomorrow.gov.cy/"
312
+ },
313
+ "title": {
314
+ "en": "Go to Cyprus Tomorrow website",
315
+ "el": "Μετάβαση στην ιστοσελίδα Κύπρος το Αύριο"
316
+ },
317
+ "target": "_blank"
318
+ }
319
+ ],
320
+ "copyrightText" : {"en":"Republic of Cyprus, 2025", "el":"Κυπριακή Δημοκρατία, 2025"},
321
+ "menu" : {"en":"Menu", "el":"Μενου"},
322
+ "navigation": {
323
+ "items": [
324
+ {
325
+ "label": {"en":"Home", "el":"Home"},
326
+ "href": {"en":"/en", "el":"/el"},
327
+ "current": true
328
+ },
329
+ {
330
+ "label": {"en":"Contact", "el":"Contact"},
331
+ "href": {"en":"/en/contact", "el":"/el/contact"}
332
+ }
333
+ ]
334
+ },
335
+ "title" : {"en":"Service title", "el":"Τιτλός υπηρεσίας"},
336
+ "headerTitle" :
337
+ {
338
+ "title": {
339
+ "en":"Header title",
340
+ "el":"Τιτλός επικεφαλιδας"
341
+ },
342
+ "href": {
343
+ "en":"/service-id",
344
+ "el":"/service-id"
345
+ }
346
+ },
347
+ "description" : {"en":"Service description", "el":"Περιγραφή υπηρεσίας"},
348
+ "url" : "https://gov.cy",
349
+ "manifest": "manifest.json",
350
+ "matomo": {
351
+ "url": "//wp.matomo.dits.dmrid.gov.cy/",
352
+ "siteId": "1234"
353
+ },
354
+ "cdn" : {
355
+ "dist" : "https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@3.0.0/dist",
356
+ "cssIntegrity" : "sha384-1zLHWOtnS0hOIz5mVEPZp0UH5gUE6eo0CQcCGA3sF2TyYhHyKOd3Ni8Iy/NjEASU",
357
+ "jsIntegrity" : "sha384-zOuDuogVaaTveh/Ou2iYwCk14zFiSmMk7Ax8yRnXDtOJMyKZH5+ZNibNVwZSKtw+"
358
+ }
359
+ },
360
+ "pageData": {
361
+ "title": {"en": "Page title", "el": "Τιτλός σελιδας"},
362
+ "layout": "layouts/govcyBase.njk",
363
+ "mainLayout": "max-width"
364
+ }
365
+ };
366
+
367
+ // Define the JSON template
368
+ let inputJson =
369
+ {
370
+ "sections": [
371
+ {
372
+ "name": "main",
373
+ "elements": [
374
+ {
375
+ "element": "form",
376
+ "params": {
377
+ "elements": [
378
+ {
379
+ "element": "textInput",
380
+ "params":
381
+ {
382
+ "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
383
+ ,"id":"name"
384
+ ,"name":"name"
385
+ ,"isPageHeading": true
386
+ ,"autocomplete":"tel"
387
+ }
388
+ },
389
+ {
390
+ "element": "button",
391
+ "params":
392
+ {
393
+ "text":{"en":"Continue","el":"Συνέχεια"}
394
+ , "type":"submit"
395
+ }
396
+ }
397
+ ]
398
+ }
399
+ }
400
+ ]
401
+ }
402
+ ]
403
+ }
404
+ ;
405
+
406
+ // Render
407
+ let rtn = renderer.renderFromJSON(inputJson, inputData)
408
+ console.log(rtn);
409
+ ```
410
+ In the example above, a sting will be written in the console containing the rendered HTML of a complete page.
411
+
412
+ More details in defining design elements see in the [design elements](DESIGN_ELEMENTS.md) section.
413
+
414
+ ### Render individual components example
415
+
416
+ To render individual components, use the same functions as above, but leave the `pageData.layout` empty, as shown in the example below (the example uses a JSON template). Everything except the `site.lang`in the *siteData* and *pageData* will be ignored.
417
+
418
+ ```js
419
+ import { govcyFrontendRenderer } from '@gov-cy/govcy-frontend-renderer';
420
+ const renderer = new govcyFrontendRenderer();
421
+
422
+ // Define the input data
423
+ const inputData =
424
+ {
425
+ "site" : {
426
+ "lang" : "en"
427
+ },
428
+ "pageData": {
429
+ "layout": "",
430
+ }
431
+ };
432
+
433
+ // Define the JSON template
434
+ let inputJson =
435
+ {
436
+ "sections": [
437
+ {
438
+ "name": "main",
439
+ "elements": [
440
+ {
441
+ "element": "form",
442
+ "params": {
443
+ "elements": [
444
+ {
445
+ "element": "textInput",
446
+ "params":
447
+ {
448
+ "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
449
+ ,"id":"name"
450
+ ,"name":"name"
451
+ ,"isPageHeading": true
452
+ ,"autocomplete":"tel"
453
+ }
454
+ },
455
+ {
456
+ "element": "button",
457
+ "params":
458
+ {
459
+ "text":{"en":"Continue","el":"Συνέχεια"}
460
+ , "type":"submit"
461
+ }
462
+ }
463
+ ]
464
+ }
465
+ }
466
+ ]
467
+ }
468
+ ]
469
+ }
470
+ ;
471
+
472
+ // Render
473
+ let rtn = renderer.renderFromJSON(inputJson, inputData)
474
+ console.log(rtn);
475
+ ```
476
+ All the `inputData` except the `site.lang` and the empty `pageData.layout` will be ignored.
477
+
478
+ ### Site and page meta data explained
479
+ In the examples above an `inputData` object is defined and it is used to pass the site and page's meta data. They are used by the `layouts/govcyBase.njk` template to add the necessary HTML tags and attributes.
480
+
481
+ The `inputData` object has the following structure:
482
+
483
+ - **site.lang**: the language of the site. It is used both in the `<html lang` attribute and to define the default language to be used by the individual design elements defined in the template.
484
+ - **site.languages**: the languages in the language menu.
485
+ - **site.footerLinks**: the links of the footer.
486
+ - **site.footerIcons**: the icons with links of the footer.
487
+ - **site.copyrightText**: the text of the copyright in the footer, including the year.
488
+ - **site.menu**: the menu label (optional).
489
+ - **site.navigation**: the header navigation structure (optional). See [Navigation explained](#navigation-explained).
490
+ - **site.menuHideLabelVisibility**: if true, hides the visibility of the menu hide label and only shows the humburger icon on small screens (optional).
491
+ - **site.title**: the title of the site. It is used in the `<title>`, `<meta property="og:title"` and `<meta property="twitter:title"` tags of the head.
492
+ - **site.description**: the description of the site. It is used in the `<meta name="description"`, `<meta property="og:description"` and `<meta property="twitter:description"` tags of the head.
493
+ - **site.url**: the URL of the site. It is used in the `<meta property="og:url"` and `<meta property="twitter:url"` tags of the head.
494
+ - **site.manifest**: the manifest of the site. It is used to add the manifest location to the page.
495
+ - **site.matomo**: the matomo data. It is used to add the Matomo code to the page. If you don't want to use Matomo tracking, you can remove this value. Use `site.matomo.url` to define the URL of the Matomo server and `site.matomo.siteId` to define the site ID to be tracked.
496
+ - **site.cdn.dist**: the CDN of the site. It is used to define the URL of the CDN used for the CSS and JS files. If you need to change the version of the CDN, you can do it by changing this value (in this case you will need to change the `site.cdn.cssIntegrity` and `site.cdn.jsIntegrity` values as well)
497
+ - **site.cdn.cssIntegrity**: the integrity of the CSS file. It is used to define the integrity of the CSS file. If you need to change the version of the CDN, you will need to change this value. https://www.srihash.org/ can help you generate the integrity value.
498
+ - **site.cdn.jsIntegrity**: the integrity of the JS file. It is used to define the integrity of the JS file. If you need to change the version of the CDN, you will need to change this value. https://www.srihash.org/ can help you generate the integrity value.
499
+ - **site.customCSSFile**: the custom CSS file. It is used to add a custom CSS file to the page. This comes after the default CSS file so it will override the default CDN CSS file.
500
+ - **pageData.title**: the title of the page. It is used in the `<title>`, `<meta property="og:title"` and `<meta property="twitter:title"` tags of the head.
501
+ - **pageData.layout**: the layout of the page. It is used to define the layout (or page template) of the page, which is defined in the `layouts/govcyBase.njk` template.
502
+ - **pageData.mainLayout**: the main layout of the page. It can be either `two-thirds` or `max-width`.
503
+
504
+ #### Navigation explained
505
+ Use `site.navigation.items` to define header navigation links.
506
+
507
+ - Each item supports:
508
+ - `label`: localized object, for example `{ "en": "Home", "el": "Αρχική" }` (required)
509
+ - `href`: localized object, for example `{ "en": "/en", "el": "/el" }` (required for links, use `"#"` for toggle-like parent links)
510
+ - `current`: boolean for the current page item (optional)
511
+ - If an item's `label` is missing for the current language, that item is skipped.
512
+ - If an item's `href` is missing for the current language, it falls back to `"#"`.
513
+ - For accessibility:
514
+ - current item is rendered with `active` and `aria-current="true"`
515
+ - parent dropdown toggles of current descendants are rendered with `active`
516
+
517
+ ### Input Template explained
518
+ The input template can either be a JSON template or a nunjucks template string. It is used to define the design elements to be rendered.
519
+
520
+ #### Nunjucks input template
521
+ To use the pre-defined design elements, you need to import the `govcyElement` macro by including the`{% from "govcyElement.njk" import govcyElement %}` as shown in the coded examples.
522
+
523
+ ```js
524
+ // Define the template (njk)
525
+ let inputString =
526
+ `
527
+ {% if pageData.layout %} {% extends pageData.layout %} {% endif %}
528
+ {% from "govcyElement.njk" import govcyElement %}
529
+ {% from "utilities/govcyUtilities.njk" import govcyLocalizeContent %}
530
+ {% block main %}
531
+ {% call govcyElement("form",
532
+ {
533
+ elements:
534
+ [
535
+ {
536
+ element: "textInput",
537
+ params:
538
+ {
539
+ label:{en:"What is your name?",el:"Ποιο είναι το όνομα σας;"}
540
+ ,id:"name"
541
+ ,name:"name"
542
+ ,isPageHeading: true
543
+ ,autocomplete:"tel"
544
+ }
545
+ },
546
+ {
547
+ element: "button",
548
+ params: {
549
+ text:{en:"Continue",el:"Συνέχεια"}
550
+ , type:"submit"
551
+ }
552
+ }
553
+ ]
554
+ }) %}{% endcall %}
555
+
556
+ {% endblock %}
557
+ `;
558
+ ```
559
+
560
+ If your using the `pageData.layout`, you can render html in each of the following [gov.cy page template](https://gov-cy.github.io/govcy-design-system-docs/getting-started/page-template/) blocks:
561
+ - **bodyStart**: the start of the body
562
+ - **userName**: the section where the username and logout links are rendered
563
+ - **header**: the header section (where the gov.cy logo and service name are rendered)
564
+ - **beforeMain**: the section before the main content
565
+ - **main**: the main content
566
+ - **footer**: the footer section
567
+ - **bodyEnd**: the end of the body
568
+ - **afterBody**: the section after the body. Usually reserved for overlay elements
569
+ - **afterJS**: the section after the JS. Usually reserved for JS scripts
570
+
571
+ Use the `govcyElement` macro inside the blocks to render the design elements defined in the `govcyElement.njk` template. More details in defining design elements see in the [design elements](DESIGN_ELEMENTS.md) section.
572
+
573
+ #### JSON input template
574
+ When using a JSON input template, there is no need to import or extend anything.
575
+
576
+ ```js
577
+ // Define the JSON template
578
+ let inputJson =
579
+ {
580
+ "sections": [
581
+ {
582
+ "name": "main",
583
+ "elements": [
584
+ {
585
+ "element": "form",
586
+ "params": {
587
+ "elements": [
588
+ {
589
+ "element": "textInput",
590
+ "params":
591
+ {
592
+ "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
593
+ ,"id":"name"
594
+ ,"name":"name"
595
+ ,"isPageHeading": true
596
+ ,"autocomplete":"tel"
597
+ }
598
+ },
599
+ {
600
+ "element": "button",
601
+ "params":
602
+ {
603
+ "text":{"en":"Continue","el":"Συνέχεια"}
604
+ , "type":"submit"
605
+ }
606
+ }
607
+ ]
608
+ }
609
+ }
610
+ ]
611
+ }
612
+ ]
613
+ }
614
+ ;
615
+
616
+ ```
617
+
618
+ If your using the `pageData.layout`, you can render html in each of the following [gov.cy page template](https://gov-cy.github.io/govcy-design-system-docs/getting-started/page-template/) blocks, by using the `sections` array (in a similar way `blocks` is use ) :
619
+ - **bodyStart**: the start of the body
620
+ - **userName**: the section where the username and logout links are rendered
621
+ - **header**: the header section (where the gov.cy logo and service name are rendered)
622
+ - **beforeMain**: the section before the main content
623
+ - **main**: the main content
624
+ - **footer**: the footer section
625
+ - **bodyEnd**: the end of the body
626
+ - **afterBody**: the section after the body. Usually reserved for overlay elements
627
+ - **afterJS**: the section after the JS. Usually reserved for JS scripts
628
+
629
+ Define your design elements for each `sections` under the `elements` array. These elements use the same `govcyElement` macro to render the design elements. Do that by defining the `element` and `params` objects. For example:
630
+
631
+ ```json
632
+ {
633
+ "element": "textInput",
634
+ "params":
635
+ {
636
+ "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
637
+ }
638
+ }
639
+ ```
640
+
641
+ will use the `govcyElement` macro to render the `textInput` design element as follows:
642
+
643
+ ```Nunjucks
644
+ {{
645
+ govcyElement({
646
+ "textInput",
647
+ {
648
+ "label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}
649
+ }
650
+ })
651
+ }}
652
+ ```
653
+
654
+ More details in defining design elements see in the [design elements](DESIGN_ELEMENTS.md) section.
655
+
656
+ #### Included design elements
657
+ More details on the elements that are supported by the package and how to include them in your templates, can be found on the [design elements](DESIGN_ELEMENTS.md) document.
658
+
659
+ ### Localization
660
+ All content in design elements are defined with an object defining the available languages and their content. For example `label":{"en":"What is your name?","el":"Ποιο είναι το όνομα σας;"}`. When rendering the package will determin which language to use with the following logic and order:
661
+
662
+ 1. if `params.lang` is defined in the design element, use that
663
+ 2. else if `site.lang` is defined in the `siteData`, use that
664
+ 3. else use `el`
665
+
666
+ If the `params.lang` is defined in the design element, the package will also render element with a `lang` attribute.
667
+
668
+ ## Browser usage (client-side)
669
+ > [!WARNING]
670
+ > Browser classes are not thoroughly tested, so use with care.
671
+
672
+ The package offers compiled templates in `govcyCompiledTemplates.browser.js` and a helper class `govcyFrontendRenderer.browser.js` to render the same components on the browser. Unlike the note.js methods, you will need to provide the HTML shell.
673
+
674
+ The easiest way to use these is to include the libraries via CDN in your HTML and use the `renderFromJSON` and `updateDOMAndInitialize` functions.
675
+
676
+ Here's an example:
677
+
678
+ ```html
679
+
680
+ <!DOCTYPE html>
681
+ <html lang="en">
682
+
683
+ <head>
684
+ <!-- Required meta tags -->
685
+ <meta charset="utf-8">
686
+ <meta name="viewport" content="width=device-width, initial-scale=1">
687
+ <!-- CSS -->
688
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@v3/dist/css/govcy.uds.min.css">
689
+ <title>Page title - Service Name - gov.cy</title>
690
+ <meta name="description" content="Description of what the service does">
691
+
692
+ </head>
693
+
694
+ <body>
695
+ <!--bodyStart-->
696
+ <section class="govcy-container-fluid" id="bodyStartContainer">
697
+ <a href="#mainContainer" class="govcy-skip-link">Skip to main content</a>
698
+ </section>
699
+ <!--main-->
700
+ <main class="govcy-container" id="mainContainer">
701
+ <div class="govcy-row">
702
+ <article class="govcy-col-8">
703
+ <div id="output" class="govcy-form"></div>
704
+ </article>
705
+ </div>
706
+ </main>
707
+ <script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@v3/dist/js/govcy.uds.min.js"></script>
708
+ <script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyCompiledTemplates.browser.js"></script>
709
+ <script src="https://cdn.jsdelivr.net/gh/gov-cy/govcy-frontend-renderer@v1/dist/govcyFrontendRenderer.browser.js"></script>
710
+ <script>
711
+
712
+ document.addEventListener("DOMContentLoaded", async function () {
713
+
714
+ // Create an instance of GovcyFrontendRendererBrowser
715
+ const renderer = new GovcyFrontendRendererBrowser();
716
+
717
+ // Define the input data
718
+ const inputData =
719
+ {
720
+ "site": {
721
+ "lang": "en"
722
+ }
723
+ };
724
+
725
+ // Construct the JSONTemplate
726
+ const JSONTemplate = {
727
+ "elements": [
728
+ {
729
+ "element": "backLink",
730
+ "params": {}
731
+ },
732
+ {
733
+ "element": "tag",
734
+ "params": {
735
+ "text": {
736
+ "en": "SIMPLE TAG",
737
+ "el": "ΑΠΛΟ TAG"
738
+ }
739
+ }
740
+ }
741
+ ]
742
+ };
743
+
744
+ //render HTML into string
745
+ let renderedHtml = renderer.renderFromJSON(JSONTemplate,inputData);
746
+ //update DOM and initialize the JS components
747
+ renderer.updateDOMAndInitialize('output', renderedHtml);
748
+ });
749
+ </script>
750
+ </body>
751
+
752
+ </html>
753
+ ```
754
+
755
+ ### Things you should know about browser usage
756
+ Using the example above as reference:
757
+ 1. `renderer.renderFromJSON(JSONTemplate,inputData);` generates the HTML based on the JSON input template.
758
+ 2. `renderer.updateDOMAndInitialize('output', renderedHtml);` updates the DOM and initializes the JS components. It finds the element with id `output` and :
759
+ - used the `innerHTML` to update it's contents
760
+ - initializes all GOVCY design system's JS components within that elements (so it will not re-initialize other elements such as `header` in different sections of the page)
761
+
762
+ ## Change the package
763
+
764
+ Details on how to build, test and update the project can be found in the [project notes](NOTES.md) document.
765
+
766
+ ## License
767
+
768
+ The package is released under the [MIT License](https://opensource.org/licenses/MIT).
769
+
770
+ ## Contact
771
+
731
772
  If you have any questions or feedback, please feel free to reach out to us at [dsf-admin@dits.dmrid.gov.cy](mailto:dsf-admin@dits.dmrid.gov.cy)