CM 2026
This commit is contained in:
101
tp1.typ
Normal file
101
tp1.typ
Normal file
@@ -0,0 +1,101 @@
|
||||
#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 TP],
|
||||
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 = "tp1.md"
|
||||
|
||||
// set to `false` to drop the first page with the table of contents
|
||||
#let show-toc = true
|
||||
|
||||
// ---------------------------------------------------------------- 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 = 6cm
|
||||
// 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))
|
||||
Reference in New Issue
Block a user