102 lines
3.3 KiB
Typst
102 lines
3.3 KiB
Typst
#import "@preview/minicise:0.1.0": sheet
|
|
#import "@preview/mitex:0.2.7": mitex
|
|
#import "@preview/cmarker:0.1.10"
|
|
|
|
// --------------------------------------------------------- configuration ----
|
|
|
|
#show: sheet.with(
|
|
title: [Exercices de cours -- Corrigés],
|
|
course: [Objets connectés et robotique],
|
|
semester: [L3 IFA, S5],
|
|
date: [2026],
|
|
author: [Vincent Lannurien],
|
|
)
|
|
|
|
// the markdown source rendered as the body of this sheet
|
|
#let md-source = "td-corrige.md"
|
|
|
|
// set to `false` to drop the first page with the table of contents
|
|
#let show-toc = false
|
|
|
|
// ---------------------------------------------------------------- styles ----
|
|
|
|
#show figure.caption: set text(size: 0.9em, fill: luma(70))
|
|
|
|
// the outline picks up the headings cmarker emits further down
|
|
#show outline.entry.where(level: 2): set text(weight: "semibold")
|
|
|
|
// each `##` heading starts on a fresh page, except the first one, which stays
|
|
// on the title page — `weak` avoids a blank page when we are already at the top
|
|
#let md-section = counter("md-section")
|
|
#show heading.where(level: 2, outlined: true): it => {
|
|
context if md-section.get().first() > 0 {
|
|
pagebreak(weak: true)
|
|
}
|
|
md-section.step()
|
|
it
|
|
}
|
|
|
|
// ------------------------------------------------------------------ math ----
|
|
|
|
// hugo goldmark delimits math with `\(...\)` and `\[...\]`, while cmarker
|
|
// expects the typst/markdown `$...$` and `$$...$$` forms
|
|
#let goldmark-math(markdown) = {
|
|
markdown
|
|
.replace("\\[", "$$")
|
|
.replace("\\]", "$$")
|
|
.replace("\\(", "$")
|
|
.replace("\\)", "$")
|
|
}
|
|
|
|
// ---------------------------------------------------------------- images ----
|
|
|
|
// maximum footprint of an image coming from the markdown source
|
|
#let img-max-height = 7cm
|
|
// set to `none` to drop the frame around screenshots
|
|
#let img-stroke = 0.5pt + luma(180)
|
|
|
|
// scale an image down so it fits both the available width and `img-max-height`,
|
|
// without ever blowing it up past its natural size
|
|
#let fitted-image(source, ..args) = layout(available => {
|
|
let natural = measure(image(source, ..args))
|
|
let factor = calc.min(
|
|
1.0,
|
|
available.width / natural.width,
|
|
img-max-height / natural.height,
|
|
)
|
|
image(source, width: natural.width * factor, ..args)
|
|
})
|
|
|
|
// handle `` and `<img src=... width=... height=...>`
|
|
#let md-image(source, alt: none, width: auto, height: auto, ..args) = {
|
|
// an explicit width/height in the markdown wins over the automatic fitting
|
|
let body = if width == auto and height == auto {
|
|
fitted-image(source, alt: alt, ..args)
|
|
} else {
|
|
image(source, alt: alt, width: width, height: height, ..args)
|
|
}
|
|
|
|
let framed = block(stroke: img-stroke, radius: 3pt, clip: true, body)
|
|
|
|
// alt text, when there is one, becomes a numbered caption
|
|
if alt == none or alt == "" {
|
|
align(center, framed)
|
|
} else {
|
|
figure(framed, caption: alt)
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------- toc ----
|
|
|
|
// outline's own title is a level-1 heading, which would outrank every heading in
|
|
// the source (they start at `##`), so we emit it ourselves at the right level
|
|
#if show-toc {
|
|
heading(level: 2, outlined: false)[Sommaire]
|
|
outline(title: none, depth: 3, indent: 1em)
|
|
pagebreak()
|
|
}
|
|
|
|
// ------------------------------------------------------------- exercices ----
|
|
|
|
#cmarker.render(goldmark-math(read(md-source)), math: mitex, scope: (image: md-image))
|