typst-chemex/main.typ

291 lines
6.8 KiB
Typst
Raw Permalink Normal View History

2025-11-09 21:46:12 +01:00
#import "@preview/typsium-ghs:0.1.0": *
#import "@preview/one-liner:0.2.0": fit-to-width
#import "@preview/subpar:0.2.2"
#import "@preview/typsium:0.3.0":*
#import "@preview/typsium-iso-7010:0.1.0": *
2025-11-09 21:46:12 +01:00
#let chemscript(
language: ("en"),
title: ("Die Methan-Mamba"),
title_fontsize: (25pt),
signs_gridlength: 9,
2025-11-11 23:36:35 +01:00
ghs_signs: (1,2,2),
fire_signs: (1,2,3,4,1,1,2,2,2,2,23,4,5,1,),
warning_signs: (1,6,2),
mandatory_actions_signs: (),
tablebreak_bias: (6),
step_descriptions: ("adwa", "asdwa"),
step_image_paths: (),
step_image_size: (5cm),
image_paths: (),
image_radius: 2pt,
material_names: ("asdaw", "asda"),
materials: ((amount: "20", name: "fischascwd"),(amount: "20", name: "fischascwd")),
chemicals: ((amount: "20", name: "fischascwd"),(amount: "20", name: "fischascwd")),
safety_notices: ("asdw",),
2025-11-11 23:36:35 +01:00
observation: ["Hier gibt es etwas zu sehen",],
interpretation: ["Hier sind die Gründe dafür"],
doc
2025-11-09 21:46:12 +01:00
) = {
//tranforms dictionaries to array
let material_names = materials.map(material => text(material.name))
let material_amounts = materials.map(material => text(material.amount))
let chemical_names = chemicals.map(chemical => text(chemical.name))
let chemical_amounts = materials.map(chemical => text(chemical.amount))
2025-11-09 21:46:12 +01:00
let tablecolumns = calc.ceil(material_names.len() / tablebreak_bias)
2025-11-09 21:46:12 +01:00
let has_images = step_image_paths.any(path => path != "" and path != "none")
set text(lang:language)
2025-11-09 21:46:12 +01:00
//Create a breakable Table
2025-11-09 21:46:12 +01:00
let repeated-table(num-repeats: 2, ..args) = {
let options = args.named()
let data = args.pos()
let columns = options.at("columns", default: ())
let (column-count, columns) = if type(columns) == int {
2025-11-09 21:46:12 +01:00
(columns, columns * num-repeats)
} else if type(columns) == array and columns != () {
2025-11-09 21:46:12 +01:00
(columns.len(), columns * num-repeats)
} else {
(1, (auto,) * num-repeats)
}
let header = if data.len() > 0 and type(data.first()) == content and data.first().func() == table.header {
let (children, ..args) = data.remove(0).fields()
table.header(..args, ..children * num-repeats)
}
let footer = if data.len() > 0 and type(data.last()) == content and data.last().func() == table.footer {
let (children, ..args) = data.pop().fields()
table.footer(..args, ..children * num-repeats)
}
let rows = data.chunks(column-count)
let num-rows = calc.ceil(rows.len() / num-repeats)
let repeats = rows.chunks(num-rows)
let empty-row = (none,) * column-count
repeats.last() += (empty-row,) * (num-rows - repeats.last().len())
let rows = array.zip(..repeats)
data = rows.flatten()
if header != none {
data.insert(0, header)
}
if footer != none {
data.push(footer)
}
table(..options, ..data)
}
// Style changes to Subpar
2025-11-09 21:46:12 +01:00
let my-subfig(..args) = subpar.grid(
show-sub-caption: (num, it) => {
set text(size: 7pt)
text(weight: "bold", num)
it.body
},
..args
)
let steps = step_descriptions.enumerate().map(((i, desc)) => {
let img = if i < step_image_paths.len() { step_image_paths.at(i) } else { "none" }
grid(
columns: if has_images { (1fr, step_image_size) } else { (1fr, auto) },
align: (horizon+left, horizon+center),
inset: (top: 5pt, bottom: 5pt, left: 5pt, right: 0pt),
stroke: (
top: (paint: black, thickness: 0.1pt, dash: "dashed"),
bottom: (paint: black, thickness: 0.1pt, dash: "dashed"),
left: none,
right: none,
),
pad(top: 0.2cm, bottom: 0.2cm, text("Schritt " + str(i+1) + ":\n" + desc)),
if img != "none" {
pad(right: 10pt, block(
clip: true,
radius: image_radius,
image(img)
))
} else {
none
},
)
})
let figures = image_paths.map(path => block(
clip: true,
radius: image_radius,
image(path)
))
let signgrid = (range(0, signs_gridlength).map(_ => 1fr))
2025-11-11 23:36:35 +01:00
//Convert signs to images
let ghs_signs = ghs_signs.map(x => ghs(x))
let other_signs = (fire_signs.map(x => fire-sign(x)) +
warning_signs.map(x => warning-sign(x)) +
mandatory_actions_signs.map(x => mandatory-actions-sign(x)))
//Calculate rows needed
let num_ghsrows = calc.ceil(ghs_signs.len() / signs_gridlength)
let num_othersigns = calc.ceil(other_signs.len() / signs_gridlength)
// fill with emptys to fill from right to left
for x in range(0, signs_gridlength * num_ghsrows - ghs_signs.len() ) {
ghs_signs.insert(signs_gridlength * (num_ghsrows - 1), [])
}
for x in range(0, signs_gridlength * num_othersigns - other_signs.len() ) {
other_signs.insert(signs_gridlength * (num_othersigns - 1), [])
}
2025-11-09 21:46:12 +01:00
grid(
columns: (1fr, 1fr),
align: (horizon, right),
2025-11-09 21:46:12 +01:00
stroke: (bottom:0.5pt + black),
inset: (5pt),
2025-11-11 16:32:09 +01:00
text(title, size: title_fontsize),
2025-11-09 21:46:12 +01:00
grid(
columns: 1,
rows: 2,
align: right,
grid(
columns: signgrid,
rows: auto,
2025-11-11 23:36:35 +01:00
..(ghs_signs)
),
grid(
2025-11-11 16:32:09 +01:00
inset: (left: 1.5pt,right: 1.5pt,top: 1.5pt,bottom: 0pt),
columns: signgrid,
rows: auto,
2025-11-11 23:36:35 +01:00
..(other_signs)
)
))
2025-11-09 21:46:12 +01:00
//safety
v(-0.3cm)
show table.cell: set text(size: 6pt)
box( stroke: 0.5pt + red, inset: -1pt, radius: 1pt,
table(
stroke: none,
columns: ( 1fr, 1fr, 1fr, 1fr),
..safety_notices,
)
)
// Materials and Overview
show table.cell: set text(size: 9pt)
grid(
columns: (auto, 1fr),
stroke: (bottom:0.5pt + black),
inset: (top: 0pt, bottom: 5pt, left: 5pt, right: 5pt),
grid(
rows: (auto),
text("Material", weight: "bold"),
v(0.4cm),
repeated-table(
num-repeats: tablecolumns,
stroke: (x, y) =>
(if y > 0 { (top: (paint: black, thickness: 0.1pt, dash: "dashed")) } else { none }) +
(if calc.rem(x, 2) == 0 and x > 0 { (left: (paint: black, thickness: 0.1pt, dash: "dashed")) } else { none }),
columns: (auto, auto),
align: (right, left),
..for x in material_amounts.zip(material_names) {(
2025-11-09 21:46:12 +01:00
..for y in x {(
[#y],
)}
)}
)
),
grid(
2025-11-11 23:36:35 +01:00
rows: (auto,),
2025-11-09 21:46:12 +01:00
text("Übersicht", weight: "bold"),
v(0.4cm),
2025-11-11 23:36:35 +01:00
2025-11-09 21:46:12 +01:00
my-subfig(
..figures,
columns: (auto, auto),
),
),
)
// Durchführung
grid(
columns: (1fr),
stroke: (bottom:0.5pt + black),
inset: (top: 0pt, bottom: 5pt, left: 5pt, right: 5pt),
grid(
rows: (auto),
text("Durchführung", weight: "bold"),
v(0.4cm),
..steps
),
)
//Interpretation
//observation
2025-11-09 21:46:12 +01:00
grid(
columns: (1fr),
stroke: (bottom:0.5pt + black),
inset: (top: 0pt, bottom: 5pt, left: 5pt, right: 5pt),
grid(
rows: (auto),
text("Observation", weight: "bold"),
2025-11-09 21:46:12 +01:00
v(0.4cm),
observation,
2025-11-11 23:36:35 +01:00
v(0.2cm),
2025-11-09 21:46:12 +01:00
),
)
grid(
columns: (1fr),
stroke: (bottom:0.5pt + black),
inset: (top: 0pt, bottom: 5pt, left: 5pt, right: 5pt),
grid(
rows: (auto),
text("Interpretation", weight: "bold"),
2025-11-09 21:46:12 +01:00
v(0.4cm),
2025-11-11 23:36:35 +01:00
interpretation,
v(0.2cm),
),
)
grid(
columns: (1fr),
stroke: (bottom:0.5pt + black),
inset: (top: 0pt, bottom: 5pt, left: 5pt, right: 5pt),
grid(
rows: (auto),
text("Entsorgung", weight: "bold"),
v(0.4cm),
str(num_ghsrows),
v(0.2cm),
2025-11-09 21:46:12 +01:00
),
)
// Safety Notices
doc
2025-11-09 21:46:12 +01:00
}
// Interpretation