For my students to takes notes besides the content of the lesson, I like to only write content on the left page of my documents and to let the right page empty except for a grid.
I managed to only put the grid on the right pages but not to write the content on one every two pages.
My code so far :
#let grid-paper(content) = {
let grid-color = rgb("#CCCCCC")
let grid-spacing = 5mm
set page(
paper: "a4",
margin: (x: 2cm, y: 2cm),
background: {
context if calc.even(here().page()) { // n'affiche la grille que sur les pages paires
// Lignes verticales
for x in range(int(page.width / grid-spacing)) {
place(
line(
start: (x * grid-spacing, 0pt),
end: (x * grid-spacing, page.height),
stroke: (paint: grid-color, thickness: 0.2pt)
)
)
}
// Lignes horizontales
for y in range(int(page.height / grid-spacing)) {
place(
line(
start: (0pt, y * grid-spacing),
end: (page.width, y * grid-spacing),
stroke: (paint: grid-color, thickness: 0.2pt)
)
)
}
}
}
)
// N'affiche le contenu que sur les pages paires
context if calc.odd(here().page()) {
content
}
}
#show: grid-paper
= Titre du document
#lorem(2000)```
Hi! I guess this is possible within Typst, but would need some work to make all the details (page numbers, cross references to other pages, etc.) right.
I suggest putting regular pages and grid pages in two separate PDFs and merging them before printing.
Alternatively, it might be more convenient to prepare a stack of grid paper in advance, and then print regular documents on them.
Thanks, but that sounds like too many operations for me, tho.
Actually, only the “lesson” part of the document has a blank page besides (not the exercises for example), so I would need to generate many documents and merge them afterwards.
I managed to automate the process with Latex so that is what is holding me from migrating to typst.
How are you going to determine which page(s) have to have a grid on the next one? Are you going to use a mix of lessons and exercises in the same document? What is going to differentiate both “sections”? The solution is quite trivial if you are using manual pagebreak(to: "odd"), which I understand you are trying to avoid…
How did you manage in LaTeX by the way? I suspect some markup was necessary, perhaps per section?
\documentclass{article}
\usepackage{lipsum}
\usepackage{etoolbox} % for \newbool to be defined
\usepackage{scrextend} % for \Ifthispageodd to be defined
\usepackage{tikz} % for the tikzpicture environment
\usepackage{paracol} % writing on one every two pages
\usepackage{eso-pic} % absolute placement on page
\newbool{notes}
\boolfalse{notes}
\AddToShipoutPictureBG{%
\ifbool{notes}{%
\Ifthispageodd{%
\begin{tikzpicture}
\foreach \x in {0,...,42} {\draw[black!10,thin] (\x*0.5,0) -- (\x*0.5,30.7);}
\foreach \y in {0,...,62} {\draw[black!10,thin] (0,\y*0.5) -- (21,\y*0.5);}
\end{tikzpicture}%
}{}%
}%
}
\title{My document}
\begin{document}
\maketitle
\clearpage \booltrue{notes}
\begin{paracol}[1]*{2}
\begin{leftcolumn}
\section{Lesson}
\lipsum[0-10]
\end{leftcolumn}
\begin{rightcolumn}
\end{rightcolumn}
\end{paracol}
\clearpage \boolfalse{notes}
\section{Exercises}
\lipsum[10-20]
\end{document}
The key point is the usage of paracol. I suppose there is no equivalent in typst ? I looked at the columns but it doesn’t seem to be as flexible as paracol.
There is not yet a convenient way to tell Meander to repeat a layout, so the most straightforward solution currently is to specify manually how many pages you’re going to need. I’ll come back to this soon.
Meander does not currently have the performance required to compile large documents. Expect long startup times.
Now, if somehow you don’t find a more efficient solution, there is a way to abuse Meander’s overflow option to avoid having to manually specify the number of pages.
#let print-every-other-page(ct) = {
import "@preview/meander:0.2.3"
let print-one-skip-one(ct) = {
meander.reflow(
// If the content overflows, recursively call the same
// function again.
// Beware of the recursion limit though...
overflow: print-one-skip-one,
{
import meander: *
container()
pagebreak()
pagebreak() // skip a whole page
ct.structured
}
)
}
print-one-skip-one((structured: meander.content(ct)))
}
At that point we’re really getting into stuff that’s only accidentally supported, and be aware that this is soooo far away from Meander’s intended use-case.
Side note: you really don’t need all of Meander’s surface machinery for this, I wonder how much more efficient this could be if you had access to some of Meander’s internals.
As of 0.2.4, Meander now exposes a new module internals.
I would say that now the best way of using Meander to do what you wanted is the following:
#let print-every-other-page(ct) = layout(size => {
// This function can now be imported.
// fill-box(dims, content) -> (content, content)
// cuts the inner content into what fits in a box
// of size dims, and the overflow.
import "@preview/meander:0.2.4": internals.fill-box
// The container must be slightly smaller than the page for it to work properly
let container = (width: size.width, height: size.height - 1pt)
// Strategy: for as long as there is text that hasn't been put
// on the page yet, we create one box the size of the page,
// put as much text in it as fits, and the overflow is kept
// for the next iteration.
let remaining = ct
while remaining != none {
let (fit, overflow) = fill-box(container, remaining, size: size)
box(..container)[#fit]
colbreak()
colbreak() // blank page
remaining = overflow
}
})
This avoids both the overhead of the higher-level machinery of Meander, and the obscure recursive overflow handler tricks.
IMO it also feels less hacky, there’s no forcing Meander into something it wasn’t designed for.
Combined with general performance improvements in 0.2.4, this can produce a 20k word document in <3 seconds on my machine, down from >12 seconds for the previously suggested solution.
Thank you so much, I’ll give it a try. The first solution didn’t play well with showybox so I abandoned it and made a Python script to insert blank pages where needed.
It’s still the same underlying algorithm, so if it didn’t work well with showybox I doubt this solution will. Do you have an example ? It sounds like an interaction between the two packages that I should try to solve.