#let path = sys.inputs.at("path", default: "menus.json") #let categories = sys.inputs.at("categories", default: "E,D,C,V").split(",") #let days = json(path) #let nbsp = sym.space.nobreak #let width = if days.len() > 1 {20cm} else {10cm} #set page(margin: 0cm, height: auto, width: width) #let parse-date(date-txt) = { let (year, month, day) = date-txt.split("-") return datetime(year: int(year), month: int(month), day: int(day)) } #let fmt-number( number, decimals: 2, decimal-sep: ".", thousands-sep: "'" ) = { let integer = calc.trunc(number) let decimal = calc.fract(number) let res = str(integer).clusters() .rev() .chunks(3) .map(c => c.join("")) .join(thousands-sep) .rev() if decimals != 0 { res += decimal-sep decimal = decimal * calc.pow(10, decimals) decimal = calc.round(decimal) decimal = str(decimal) + ("0" * decimals) res += decimal.slice(0, decimals) } return res } #let day-names = ( "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" ) #let display-menus( days, categories, day-sep-stroke: rgb("#82BC00") + 1pt, title-underline-stroke: rgb("#e34243") + 2pt, menu-sep-stroke: rgb("#ababab") + 1pt, price-categ-color: rgb("#577F25") ) = { set text(font: "Liberation Sans", hyphenate: true) let cols = calc.min(2, days.len()) let cells = () for day in days { let weekday = parse-date(day.date).weekday() - 1 let day-name = day-names.at(weekday) let menus = () for menu in day.menus { let price-cell = grid.cell(rowspan: 2)[] let prices = menu.at( "prices", default: (:) ) if menu.keys().contains("price") { prices = ("": menu.price) } let pairs = prices.pairs() .filter(p => p.first() in categories) .sorted(key: p => p.last()) let prices = pairs.map(p => { let categ = emph( text( fill: price-categ-color, p.first() ) ) let price = fmt-number(p.last()) categ + ":" + nbsp + "CHF" + nbsp + price }) price-cell = grid.cell( rowspan: menu.extra.len() + 1, stack(dir: ttb, spacing: .4em, ..prices) ) //let price = "CHF" + sym.space.nobreak + str(menu.price) menus.push( grid( columns: (1fr, auto), column-gutter: .4em, row-gutter: .4em, [*#menu.name*], price-cell, ..menu.extra.map(l => text(10pt, l)) ) ) } let title = align( center, text(size: 14pt, weight: "bold", day-name) ) let title-box = box( width: 50%, inset: .6em, stroke: (bottom: title-underline-stroke), title ) let title-cell = grid.cell(align: center, title-box) cells.push(box(width: 100%, grid( columns: (100%), inset: (x, y) => ( top: if y == 0 {0pt} else {.8em}, bottom: if y == 0 {0pt} else {2em} ), stroke: (_, y) => (top: if y < 2 {none} else {menu-sep-stroke}), title-cell, ..menus ))) } if calc.rem(cells.len(), 2) == 1 { cells.last() = grid.cell(colspan: calc.min(2, cols), cells.last()) } grid( columns: (100% / cols,) * cols, inset: (x: 1.5em, y: .8em), stroke: (x, y) => { let borders = (:) if x != 0 { borders.insert("left", day-sep-stroke) } if y != 0 { borders.insert("top", day-sep-stroke) } return borders }, ..cells ) } #display-menus(days, categories)