#let lixus-report( title: "", subtitle: "", date: none, author: "Lixus DevOps", logo: "lixusLogo.1012x362.png", summary: none, summaryTitle: "Summary", toc: false, body ) = { set page( paper: "a4", margin: (x: 2cm, y: 2.5cm), header: context { if counter(page).get().first() > 1 { set text(8pt, fill: gray) grid( columns: (1fr, 1fr), align(left)[#title], align(right)[#subtitle] ) } }, footer: [ #set text(8pt, fill: gray) #line(length: 100%, stroke: 0.5pt + gray) #grid( columns: (1fr, 1fr), [Generated on #date], align(right)[Page #context counter(page).display()] ) ] ) set text(font: "Inter", size: 11pt, weight: "regular") // Title Page if title != "" { align(center + horizon)[ #if logo != none { image(logo, width: 40%) v(2cm) } #text(28pt, weight: "bold", fill: rgb("#1a237e"))[#title] #v(0.5cm) #text(16pt, fill: gray)[#subtitle] #v(1cm) #text(12pt, fill: gray)[#date] #v(2cm) ] // Summary on Title Page if summary != none { v(1fr) align(left)[ #text(14pt, weight: "bold", fill: rgb("#1a237e"))[#summaryTitle] #v(0.2cm) #set text(size: 10pt) #summary ] } pagebreak() } // Content styling show heading: set text(fill: rgb("#1a237e")) show heading.where(level: 1): set text(size: 18pt) show heading: it => { it v(0.3cm) } show outline.entry.where(level: 1): it => { v(12pt, weak: true) strong(it) } if toc { outline(indent: auto) pagebreak() } body } #let report-table(columns, header, ..rows) = { table( columns: columns, inset: (x: 5pt, y: 7.5pt), align: horizon, stroke: (x, y) => if y == 0 { none } else { 0.5pt + gray.lighten(50%) }, fill: (x, y) => if y == 0 { rgb("#1a237e") } else if calc.even(y) { gray.lighten(95%) } else { none }, table.header( ..header.map(it => text(fill: white, weight: "semibold")[#it]) ), ..rows ) }