In desktop publishing programs, text frames can be linked to enable freely positioned images and text on a page.
Is something like this possible in Typst?
In desktop publishing programs, text frames can be linked to enable freely positioned images and text on a page.
Is something like this possible in Typst?
Hello @Thomas_Kindler , welcome to the forum.
You can try something like:
It’s not possible right now. Here is a nice blog post where Laurenz explains why, TeX and Typst: Layout Models | Laurenz's Blog and compares with Latex and hints that linking blocks like this is something that could (maybe) be done in the future.
If you just care about the output, then it’s technically possible:
#let two-boxes(size: 3cm, text) = {
let remaining = state("remaining", "")
set square(size: size)
square(layout(size => {
let parts = (text, "")
let overflowing = true
while overflowing and parts.first().split().len() > 1 {
let got = measure(width: size.width, parts.first())
overflowing = got.height > size.height
if got.height > size.height {
let (a, b) = parts
let (..a, c) = a.split()
parts = (a.join(" "), (c, b).join(" "))
}
}
parts.first()
remaining.update(parts.last())
}))
rotate(-15deg, square(context remaining.get()))
}
#two-boxes("The text contents of this block should automatically overflow into another block, when it is full.")
// #two-boxes(lorem(19))
But that’s just PoC.
Great! This almost solves the problem for me.
Only one question: How would I need to change the code to work with marked up text like
#two-boxes[This *doesn't* work! #lorem(10)]
?
I’ve made an issue about this a while ago:
And they said this is planned, but not possible yet.
(It might be a good idea to react to the issue with
or something to show that this is a wanted feature)
Expanding upon @Andrew’s workaround:
#let split(this, rest) = {
let this = this
let rest = rest
if this.has("text") {
let (..a, b) = this.text.split()
this = [#a.join(" ")]
rest = [#b #rest]
} else if this.has("body") {
let (a, b) = split(this.body, rest)
this = (this.func())(a)
rest = (this.func())(b)
} else if this.has("children") {
let (..a, b) = this.children
let (ba, brest) = split(b, rest)
this = { a.join(); ba }
rest = brest
} else {
panic("don’t know how to handle this")
}
return (this, rest)
}
#let two-boxes(size: 3cm, text) = {
let remaining = state("remaining", [])
set square(size: size)
square(layout(size => {
let this = [#text]
let rest = []
while measure(this, width: size.width).height > size.height {
(this, rest) = split(this, rest)
}
this
if par.justify { linebreak(justify: true) }
remaining.update(rest)
}))
rotate(-15deg, square(context remaining.get()))
}
emph well, as it adds the surrounding this.func() repeatedly, which in the case of emph leads to the overflown words alternating between italics like this.The split is technically possible, but not really practical with the current version. See Can blocks be linked and overflow into other blocks? - #6 by nleanba. That, for example, won’t work with context as it’s an opaque content that you literally can’t look at, let alone split. For some basic markup, you can try to do this. For plain markup, including lorem, use t4t package’s get.text to try to convert content to str.
So the general answer would be to wait until such a thing is possible. Not sure when, but maybe at some point you can make a robust 100% working solution.