Compare commits

..

7 Commits

Author SHA1 Message Date
4a26c6980b Improve letter typst template 2025-03-19 17:06:54 +01:00
eba88bcc4b Add typst letter template 2025-03-17 17:32:03 +01:00
481c1d69d5 Improve recipe typst 2025-01-14 10:56:38 +01:00
5a765e1112 Improve typst recipe 2024-11-21 23:06:59 +01:00
53d521e9f0 Improve recipe typst 2024-11-10 19:26:12 +01:00
14ea605b26 Add wait time to recipe 2024-07-28 13:23:57 +00:00
932af0c5c9 Update typst/recipe/example.typ 2024-05-26 11:30:22 +00:00
4 changed files with 217 additions and 24 deletions

22
typst/letter/example.typ Normal file
View File

@@ -0,0 +1,22 @@
#import "letter.typ": template
#show: template.with(
lang: "en",
name: "Joël von der Weid",
subject: "Cover letter for the Software Engineer (Backend) position",
from-address: "Route de Sézegnin 63, CH-1285 Sézegnin",
to-details: [
Adaptyv Bio \
Biopole Life Science Campus \
Route de la Corniche 5 \
1066 Epalinges
],
)
Dear Sir or Madam,
#lorem(50)
Sincerely,
Joël von der Weid

146
typst/letter/letter.typ Normal file
View File

@@ -0,0 +1,146 @@
#let line-stroke = (paint: rgb("#731010"), thickness: 1pt, cap: "round")
#let header-font = ("Nimbus Sans", "Nimbus Sans L")
#let body-font = ("Libertinus Serif")
#let months-en = ("", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")
#let months-fr = ("", "janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre")
#let template(
lang: "fr",
background: rgb("fff"),
name: "Joël von der Weid",
from-address: "Rue de la Baumettaz 7, CH-1023 Crissier",
from-email: "jvonderweid@ikmail.com",
from-phone: "+41 79 861 88 08",
to-details: none,
subject: none,
place: "Crissier",
date: datetime.today(),
margin: (top: 1.5cm, left: 2.5cm, right: 2.5cm, bottom: 2cm),
font-size: 11pt,
vertical-center-level: 2,
appendices: (),
doc
) = {
set page(fill: background, margin: margin, paper: "a4", footer: context {
if counter(page).final().first() > 1 [
#align(right, counter(page).display("1/1", both: true))
]
})
let full-date = {
let date = if date != none {
let months = if lang == "en" { months-en } else { months-fr }
str(date.day()) + " " + months.at(date.month()) + " " + str(date.year())
}
if place == none {
date
} else if date == none {
place
} else {
let sep = if lang == "en" { ", " } else { ", le " }
place + sep + date
}
}
let header = {
set text(font: header-font, style: "italic")
set par(leading: 0.8em)
grid(
inset: (x: 0cm, y: 2.5mm),
columns: (50%, 1fr),
grid.hline(start: 1, stroke: line-stroke),
[
#text(size: 22pt, weight: "bold", name) \
#text(size: 10pt, fill: rgb("444"), from-address)
],
align(bottom + end, box(
inset: (top: 1em),
[
#set par(leading: 0.7em)
#set text(size: 10pt, fill: rgb("444"))
#from-phone \
#from-email
]
)),
grid.hline(end: 1, stroke: line-stroke),
)
v(1cm)
set par(leading: 0.6em)
set text(style: "normal")
[
#h(10cm)
#box(width: 100% - 10cm, [
#text(size: 10pt, to-details)
#v(2cm)
#if full-date != none {
text(size: font-size, font: body-font, full-date)
}
])
]
v(1cm)
}
let subject = if subject != none {
let head = if lang == "en" { "Subject" } else { "Concerne " }
[
#text(weight: "bold", underline(head) + ": " + subject)
#v(0.5cm)
]
} else {
none
}
let appendices-content = {
if appendices.len() > 0 {
[
#v(0.5cm)
#if lang == "en" { "Appendices: " } else { "Annexes : " }
#context {
box(baseline: 100% - measure("Appendices").height)[
#if type(appendices) == array {
for (i, value) in appendices.enumerate() {
"- " + value + linebreak()
}
} else {
"- " + appendices + linebreak()
}
]
}
]
}
}
let body = [
#set text(font: body-font, size: font-size, weight: "regular")
#show par: set par(spacing: 1.75em, justify: true)
#subject
#doc
#appendices-content
]
layout(size => context [
#let header-sz = measure(block(width: size.width, header))
#let body-sz = measure(block(width: size.width, body))
#let ratio = (header-sz.height + body-sz.height) / size.height
#let overflowing = ratio > 1
#if overflowing or vertical-center-level == none {
header
body
} else {
// If no overflow of the first page, we do a bit of centering magic for style
grid(
rows: (auto, 1fr),
header,
box([
#v(1fr * ratio)
#body
#v(vertical-center-level * 1fr)
]),
)
}
])
}

View File

@@ -7,6 +7,9 @@
doc
)
#place(top + right, dy: 3.5cm, image("image.png", width: 5.5cm))
#v(1.5cm)
= Pâte
#step([
3 jaunes d'oeufs \

70
typst/recipe/recipe.typ Normal file → Executable file
View File

@@ -1,11 +1,16 @@
#let ovensvg = ```<?xml version="1.0" encoding="utf-8"?><!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon --><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve"><g><g transform="translate(0.000000,511.000000) scale(0.100000,-0.100000)"><path d="M797.8,4946l-72.8-64V110v-4772l72.8-64l70.6-64h4127.5h4127.5l70.6,64l72.8,64l6.6,4710.2c4.4,3293.1,0,4732.2-17.7,4789.6c-13.2,44.1-48.6,101.5-81.7,125.8l-57.4,46.4H4993.7H868.4L797.8,4946z M8814.4,3740.9v-827.7H4995.9H1177.4v827.7v827.7h3818.5h3818.5V3740.9z M8814.4-949.5v-3399.1H4995.9H1177.4v3399.1v3399.1h3818.5h3818.5V-949.5z"/><path d="M2921.1,4195.5c-198.6-64-304.6-189.8-322.3-379.6c-35.3-375.2,421.6-609.2,697.5-359.8c282.5,256,145.7,699.7-231.8,746C3016,4208.8,2952,4206.6,2921.1,4195.5z M3046.9,3760.7c-19.9-19.9-61.8,13.2-46.4,39.7c8.8,13.2,22.1,13.2,37.5-2.2C3051.3,3785,3055.8,3769.5,3046.9,3760.7z"/><path d="M4854.6,4182.3c-176.6-61.8-278.1-211.9-278.1-408.3c0-240.6,174.4-419.4,408.3-419.4c108.2,0,238.4,44.1,304.6,105.9c114.8,103.7,161.1,339.9,94.9,496.6c-55.2,136.9-249.4,260.5-399.5,258.2C4960.6,4213.2,4903.2,4200,4854.6,4182.3z M5018,3774c0-11-8.8-22.1-22.1-22.1c-11,0-22.1,11-22.1,22.1c0,13.2,11,22.1,22.1,22.1C5009.1,3796,5018,3787.2,5018,3774z"/><path d="M6849.9,4191.1c-247.2-75-379.6-368.6-267.1-589.3c86.1-165.5,214.1-247.2,388.5-247.2c178.8,0,311.2,86.1,388.4,253.8C7509.9,3930.7,7194.3,4292.7,6849.9,4191.1z M6984.6,3767.3c-28.7-28.7-57.4-6.6-35.3,26.5c6.6,13.2,24.3,17.7,37.5,11C7000,3796,7000,3782.8,6984.6,3767.3z"/><path d="M2367.1,1613.1c-315.6-101.5-554-377.4-615.8-712.9c-15.5-79.4-22.1-737.2-17.7-1840.8c6.6-1615.7,8.8-1726,48.5-1829.8c94.9-258.3,295.8-467.9,547.4-569.5l117-48.6l2491.9-6.6c2723.7-6.6,2635.4-8.8,2858.3,121.4c216.3,125.8,386.3,366.4,441.4,620.2c30.9,152.3,35.3,3388.1,2.2,3558c-64,339.9-315.6,620.2-637.9,715.1c-108.1,30.9-399.5,35.3-2615.5,33.1C2651.8,1652.8,2481.9,1650.6,2367.1,1613.1z M7468,1191.5c108.1-28.7,240.6-145.7,289.1-251.6c22.1-50.8,41.9-141.3,41.9-205.3v-117H4995.9H2192.7v117c2.2,203.1,121.4,381.9,300.2,445.9c70.6,26.5,505.4,30.9,2491.9,33.1C6481.3,1213.6,7419.4,1204.8,7468,1191.5z M7794.6-1234.2l-6.6-1410.4l-66.2-94.9c-35.3-50.8-110.4-117-163.3-145.7l-97.1-50.8H4995.9H2530.4l-97.1,50.8c-53,28.7-125.8,94.9-163.3,145.7l-66.2,94.9l-6.6,1410.4l-4.4,1410.4h2803.1H7799L7794.6-1234.2z"/></g></g></svg>```.text
#let clocksvg = ```<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M24 0C10.7 0 0 10.7 0 24S10.7 48 24 48h8V67c0 40.3 16 79 44.5 107.5L158.1 256 76.5 337.5C48 366 32 404.7 32 445v19H24c-13.3 0-24 10.7-24 24s10.7 24 24 24H360c13.3 0 24-10.7 24-24s-10.7-24-24-24h-8V445c0-40.3-16-79-44.5-107.5L225.9 256l81.5-81.5C336 146 352 107.3 352 67V48h8c13.3 0 24-10.7 24-24s-10.7-24-24-24H24zM192 289.9l81.5 81.5C293 391 304 417.4 304 445v19H80V445c0-27.6 11-54 30.5-73.5L192 289.9zm0-67.9l-81.5-81.5C91 121 80 94.6 80 67V48H304V67c0 27.6-11 54-30.5 73.5L192 222.1z"/></svg>```.text
#let hourglasssvg = ```<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M24 0C10.7 0 0 10.7 0 24S10.7 48 24 48h8V67c0 40.3 16 79 44.5 107.5L158.1 256 76.5 337.5C48 366 32 404.7 32 445v19H24c-13.3 0-24 10.7-24 24s10.7 24 24 24H360c13.3 0 24-10.7 24-24s-10.7-24-24-24h-8V445c0-40.3-16-79-44.5-107.5L225.9 256l81.5-81.5C336 146 352 107.3 352 67V48h8c13.3 0 24-10.7 24-24s-10.7-24-24-24H24zM192 289.9l81.5 81.5C293 391 304 417.4 304 445v19H80V445c0-27.6 11-54 30.5-73.5L192 289.9zm0-67.9l-81.5-81.5C91 121 80 94.6 80 67V48H304V67c0 27.6-11 54-30.5 73.5L192 222.1z"/></svg>```.text
#let timersvg = ```<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 100 100"><path fill="currentColor" d="M42 0a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h3v5.295C23.364 15.785 6.5 34.209 6.5 56.5C6.5 80.483 26.017 100 50 100s43.5-19.517 43.5-43.5a43.22 43.22 0 0 0-6.72-23.182l4.238-3.431l1.888 2.332a2 2 0 0 0 2.813.297l3.11-2.518a2 2 0 0 0 .294-2.812L89.055 14.75a2 2 0 0 0-2.813-.297l-3.11 2.518a2 2 0 0 0-.294 2.812l1.889 2.332l-4.22 3.414C73.77 18.891 64.883 14.435 55 13.297V8h3a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm8 20c20.2 0 36.5 16.3 36.5 36.5S70.2 93 50 93S13.5 76.7 13.5 56.5S29.8 20 50 20m.002 7.443L50 56.5l23.234 17.447a29.056 29.056 0 0 0 2.758-30.433a29.056 29.056 0 0 0-25.99-16.07" color="currentColor"/></svg>```.text
#let knifesvg = ```<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M18.387 8.116h.008m-3.293 8.629c2.788-3.027 4.727-5.417 5.938-7.044c.663-.89.995-1.336.957-1.943C21.92 6.49 18.725 3 17.32 3c-.643 0-1.16.537-2.195 1.612L2.55 17.672a2.003 2.003 0 0 0 0 2.757c.831.863 2.213.73 2.877-.278l2.29-3.475c.918-1.394 1.577-1.402 2.678-.259c.665.691 1.505 1.978 2.553 1.966c.653-.008 1.153-.551 2.154-1.638" color="currentColor"/></svg>```.text
#let template(
title: "",
subtitle: none,
persons: none,
quantity: none,
preptime: none,
cooktime: none,
waittime: none,
doc
) = {
@@ -15,50 +20,67 @@ set page(
)
set par(justify: true, leading: 0.6em)
set text(
font: "Linux Libertine",
font: "Libertinus Serif",
size: 12pt,
)
show heading: set text(font: "Roboto")
show heading: set text(font: "Nimbus Sans")
v(0.5cm)
align(center, text(35pt, font: "Roboto")[
#text(title, weight: "medium")
align(center, text(32pt, font: "Nimbus Sans")[
#text(title, weight: "medium") \
#if subtitle != none {
v(-0.9cm)
text(subtitle, size: 18pt)
} else {
v(-0.5cm)
}
])
v(-0.8cm)
v(-0.2cm)
align(center, {
let l = [#v(-0.25em)#line(length: 1.5em, angle: 90deg)]
let data = ()
if persons != none or persons != 0 {
if persons != none and persons != 0 {
data.push([#box([*#persons* pers], baseline: 3.5mm)])
data.push(l)
}
if preptime != none or preptime == "" {
data.push([#box(image.decode(clocksvg, format: "svg", height: 4.5mm), baseline: 1mm) *#preptime*])
if quantity != none and quantity != 0 {
data.push([#box([*#quantity* pièces], baseline: 3.5mm)])
data.push(l)
}
if cooktime != none or cooktime == "" {
data.push([#box(image.decode(ovensvg, format: "svg", height: 4.5mm), baseline: 1mm) *#cooktime*])
if preptime != none and preptime != "" {
data.push([#box(image.decode(knifesvg, format: "svg", height: 4.7mm), baseline: 1.2mm) *#preptime*])
data.push(l)
}
let _ = data.pop()
if cooktime != none and cooktime != "" {
data.push([#box(image.decode(ovensvg, format: "svg", height: 4.4mm), baseline: 0.9mm) *#cooktime*])
data.push(l)
}
if waittime != none and waittime != "" {
data.push([#box(image.decode(hourglasssvg, format: "svg", height: 4mm), baseline: 0.5mm) *#waittime*])
data.push(l)
}
if (data.len() > 0) {
let _ = data.pop() // remove last separator
grid(
columns: data.len(),
rows: 1,
gutter: 3.5mm,
..data
)
}
grid(
columns: data.len(),
rows: 1,
gutter: 3.5mm,
..data
)
})
v(1cm)
v(0.5cm)
doc
}
#let step(ingredients, procedure) = {
style(styles => {
let space = measure(par(ingredients, leading: 0.8em), styles).height - 0.75em
v(2.5mm)
context {
let space = measure(par(ingredients, leading: 0.8em)).height - 0.75em
grid(columns: (1fr, 1fr), par(ingredients, leading: 0.8em), [#v(space)#procedure])
})
v(5mm)
v(2.5mm)
}
}