How can I generate grid content?

I want to use Typst to print tickets and labels, for instance putting 10 tickets on an A4 sheet (later to be cut in pieces). My Typst source file looks like this:

#set page("a4", margin: 0mm)
#let tx = 210mm / 2; #let ty = 297mm / 5;

#let ticket(number, price: "3.00") = {
  rect(height: ty, width: tx, stroke: silver)[
    #set text(font: "Times New Roman")
    
    /* some stuff to write into the ticket
       #place(…, image(…))
       #place(…, text(…)[…])
       etc.
    */
  ]
}  
   
#grid(columns: (tx, tx), rows: (ty, ty, ty, ty, ty), gutter: 0mm,
  ticket(29980),
  ticket(29981),
  /* and so on */
)  

This works well. Up to ten tickets are placed into the grid, and the
eleventh ticket starts a new page – very good.

[Aside: I found no way to query the size of the (current) page instead of computing
my column and row sizes beforehand. Using 1fr for the grid sizes doesn’t
work, Typst then squeezes all elements into one single page.]

If I put the ticket numbers into an array and generate the grid contents
in a for loop, it doesn’t work any more. I get a single column of tickets
which are a few mm apart and run southwards off the page:

#let ticket-data = (29980, 29981, 29982, 29983, 29984, …)
…  
#grid(columns: (tx, tx), rows: (ty, ty, ty, ty, ty), gutter: 0mm,
  for nr in ticket-data {ticket(nr)}
)  

Any attempt to spread the tickets into the grid failed, the error message
telling me that I can’t spread content. (I tried a few variants but Typst remained
consistent.)

Being able to unpack the data from an array into the grid would be prerequisite
to reading it from an external file.

Any ideas?

Perhaps consider tabut – Typst Universe
Or there are lots of examples on the forum like How can I read this JSON into a (breakable) table(x) - #4 by nleanba
Note that grid and table behave the same way.

Also Table guide – Typst Documentation

2 Likes

You could simplify your template in various ways:

#set page("a4", margin: 0mm)

#let ticket(number, price: "3.00") = [
  #number
] 

#let ticket-data = (29980, 29981, 29982, 29983, 29984, 29980, 29981, 29982, 29983, 29984, 34920)

#grid(columns: 2*(100%/2,), rows: 5*(100%/5,), stroke: silver,
  ..ticket-data.map(ticket)
)
2 Likes

Just to answer the last part of the question. A for-loop inside a grid/table needs to return an array so that the elments can be spread with .. into cells:

..for nr in ticket-data {(ticket(nr),)}
4 Likes

Many thanks to all respondents! The suggested changes from @Mathemensch made it work as intended, and the pointers and explanation are helpful, too.

1 Like