Skip to content

Instantly share code, notes, and snippets.

@MultisampledNight
Created April 9, 2024 20:39
Show Gist options
  • Save MultisampledNight/4745722857fce67e93e27de2953dfe3d to your computer and use it in GitHub Desktop.
Save MultisampledNight/4745722857fce67e93e27de2953dfe3d to your computer and use it in GitHub Desktop.
heading → slide converter for typst
#import "@preview/polylux:0.3.1": *
#set text(font: "IBM Plex Sans")
#import themes.simple: *
#show: simple-theme
#enable-handout-mode(true)
// Splits the array `it`
// on each item where `check` returns `true`.
// These items are called "edge items".
// What is done with these edge items depends on `edge-action`:
//
// - `"discard"`: It is completely removed and not present anywhere.
// - `"isolate"`: It receives its whole own array to have fun in.
// - `"left"`: It becomes the end of the array before it.
// - `"right"`: It becomes the start of the next array.
//
// If it's none of these, the function panics.
// If it's unspecified, the default is `"discard"`.
#let split-by(it, check, edge-action: "discard") = {
if not ("discard", "isolate", "left", "right").contains(edge-action) {
panic("unknown edge action `" + edge-action + "`")
}
let result = ((),)
// edge action discard is handled by being not handled
// in which case the edge item is done nothing with, and just forgotten
for item in it {
let is-edge = check(item)
if is-edge {
if edge-action == "left" {
result.push(item)
}
result.push(())
if edge-action == "isolate" {
result.last().push(item)
result.push(())
}
}
if edge-action == "right" or not is-edge {
result.last().push(item)
}
}
if result.last().len() == 0 {
let _ = result.pop()
}
result
}
#let split-onto-slides(it) = {
// isolate the top-level headings
let sections = split-by(
it.children,
part => part.func() == heading and part.depth == 1,
edge-action: "isolate"
)
// then care about the rest and get each heading with its body
let slide-contents = sections
.map(section => split-by(
section,
// checking for != 1 as we don't want to further split the toplevel ones
part => part.func() == heading and part.depth != 1,
edge-action: "right",
))
.join()
.map(slide => slide.join())
// recombine them into proper slides
let front-slide = title-slide(slide-contents.first())
let main-slides = slide-contents
.slice(1, -2)
.map(body => {
let kind = if body.func() == heading {
// most likely a toplevel heading -> 1st-level one
// those should be prominently centered
centered-slide
} else {
slide
}
kind(body)
})
let final-slide = centered-slide(
slide-contents.slice(-2).join()
)
// .flatten() causes a repr() display for some reason
(
(front-slide,),
main-slides,
(final-slide,),
).join().join()
}
// this show rule should be after any other `show` and `set` rules
// since it transform the document quite drastically
// if it is styled via `set` afterwards,
// it can't get the `.children` array out of the `sequence`
#show: split-onto-slides
#text(size: 1.5em)[cursed `sequence` hacks]
by: a cat \
(the content before the first heading is the title/first slide)
= why
== less repetition
#line-by-line[
- i was bored by having an extra indent all the time
- i noticed that i structure my presentations very similar
- toplevel headings with depth 1
- are the ones with just 1 `=` (equal sign)
- get their own full slide which allows me to transition nicely
- all other headings
- are the titles of slides
- usually a summary of what the slide wants to say
- also helps with rembering what to say when presenting
]
== the #strike[false]true reason
#line-by-line[
- i was bored
- needed something to procastinate
- sowwy
]
= how
== failed: `query`ing `text`
#line-by-line[
- "hmm i want to have an array of each heading and its text"
- "hmm lol i can put `text` into a `show` rule??"
- "but i can't `query` for `text`"
- "well i can, by labeling each text, but that'd mean"
- "i'd need to label + `show` rule every content type manually"
- "this would have a scary quadratic or worse runtime"
- "i'm bored with this problem let's do something else"
]
== this try: top-level `show`
#line-by-line[
- "...unsatisfying. i started to do this. i want to see this working"
- "...how does a document look like from a show: ... perspective"
- "oh it's just a sequence"
- "i've hacked around with those"
- "behind `.children` they're just `array`"
- "guess i can split on the `array` + use functional programming?"
- "oh here we go, it works perfectly"
]
= where do we go from here
== absolutely nowhere
#line-by-line[
- this thing is under the MIT license to be compatible with polylux
- i'd love to contribute this to polylux
- but i'm not sure if polylux needs this highly opinionated thing tbh
- maybe as part of a theme?
- feel free to use this in whatever project you want to tho uwu
- for looking at the internals, do this to above
```diff
-kind(body)
+kind(repr(body))
```
]
== how do i not type `#line-by-line` all the time
#line-by-line[
- one could check if the toplevel is a sequence consisting only of
- `item`
- whitespace `content`
- if that's true, wrap the whole slide in `#line-by-line`
- i'm too lazy to actually impl that though
- and this document is far too long already,
i accidentally overwrote it and needed to rewrite it,
i should get back to my actual presentation lol
]
= thank you for listening
or not because you're most likely reading this \
or you convinced me to actually hold a talk about this
the last 1st-level heading and its content will be the final slide
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment