We'll assume knowledge of HTML/CSS, as documenting that here as well wouldn't scale.
The templating language is Handlebars (the {{ }}
bits), go read their guide for a complete picture. We'll cover the basics:
PrintGrid was designed to print many objects at once, so you will always receive an array of data, even if you only asked for one.
Suppose you need a simple contact print:
from the following data:
[
{
"id": "some-sku",
"name": "Elite C:68X SLT"
"metadata": {
"pictures": {
"name": "Pictures",
"value": [
{
"id": "674f0a775eb4b5481aabce9a",
"name": "48.jpg",
"fileType": "JPG",
"mimeType": "image/jpeg",
"links": {
"large": "https://some.image/large.jpg",
"small": "https://some.image/small.jpg"
}
},
{
"id": "674f0a78cfd9f9475ca42d1d",
"name": "22.jpg",
"fileType": "JPG",
"mimeType": "image/jpeg",
"links": {
"large": "https://some.image/large.jpg",
"small": "https://some.image/small.jpg"
}
}
/* ... snip ...*/
]
}
/* ... snip ...*/
}
}
]
{{#each this}}
and {{/each}}
{{name}}
of the object{{#each metadata.pictures.value}}
to display its {{links.small}}
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="https://brix.printgrid.brix.ch/public/grid/">
<link href="./style.css" rel="stylesheet" type="text/css">
</head>
<body>
{{#each this}}
<h2>{{name}}</h2>
<div id="gallery">
{{#each metadata.pictures.value}}
<figure>
<img src="{{links.small}}">
<figcaption>{{name}}</figcaption>
</figure>
{{/each}}
</div>
{{/each}}
</body>
</html>
Basically we're just shimmying down the structure of the JSON data. Note that the overall structure will always be the same, but certain metadata formats may depend on the $PIM
you're using.
When copying templates around, ensure that the
<base href="">
is still pointing at the correct back-end, otherwise all relative paths will break (e.g../style.css
)
@media print {
@page {
size: A4; /* important for the PDF */
margin: 5mm;
@top-right { /* page counter */
padding-top: 7mm;
content: counter(page) "/" counter(pages);
color: #005282;
}
}
}
html {
font-family: 'Arial', sans-serif;
}
h2 {
color: #005282;
break-before: always; /* to get a new page per object */
}
#gallery {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 5mm;
}
figure {
margin: 0;
width: 60mm;
height: 60mm;
break-inside: avoid;
}
figure img {
object-fit: contain;
width: 60mm;
height: 50mm;
background-color: #f5f5f5;
}
... and that's it.
Note that your mileage may vary depending on the PDF rendering engine that is used, so something that looks good in the preview window might not work well in the PDF.
The Handlebars core is very thin on logic, basically you can only check for existence via {{#if some.field}}
(truthy).
However, you may also want to test if a metadata field belongs to a certain group, which is why helpers were added.
<h2>Technical Data</h2>
<table>
{{#each metadata}}
{{#eq group "technical"}}<!-- only values from the group "technical" -->
{{#neq @key "battery-type"}<!-- but not if the key is "battery-type" -->
<tr>
<td>{{name}}</td>
<td>{{value}}{{#if measurement}} {{measurement.symbol}}{{/if}}</td>
</tr>
{{/neq}
{{/eq}}
{{/each}}
</table>
... this yields a table containing only the technical data by filtering on {{#eq group "technical"}}
, as seen in the first screenshot.
Additionally, the helper {{now}}
allows you to get the current time, and it takes a pattern such as {{now "MMMM yyyy"}}
to get April 2025 (useful to show how old the PDF is).
The PDF engine usually offers a way to count pages, which is handy for adding a "page x of y" type display. Suppose you have a
Page <span class="currentPage"></span> of <span class="totalPages"></span>
... then you can use the counter
feature in CSS via the content
property:
.currentPage:after {
content: counter(page);
}
.totalPages:after {
content: counter(pages);
}
© brix Solutions AG