282 lines
11 KiB
Typst
282 lines
11 KiB
Typst
// This theme is adapted from https://github.com/touying-typ/touying/blob/main/themes/simple.typ by OrangeX4
|
|
|
|
#import "@preview/touying:0.6.1": *
|
|
|
|
/// Default slide function for the presentation.
|
|
///
|
|
/// - config (dictionary): The configuration of the slide. You can use `config-xxx` to set the configuration of the slide. For more several configurations, you can use `utils.merge-dicts` to merge them.
|
|
///
|
|
/// - repeat (int, auto): The number of subslides. Default is `auto`, which means touying will automatically calculate the number of subslides.
|
|
///
|
|
//// The `repeat` argument is necessary when you use `#slide(repeat: 3, self => [ .. ])` style code to create a slide. The callback-style `uncover` and `only` cannot be detected by touying automatically.
|
|
///
|
|
/// - setting (function): The setting of the slide. You can use it to add some set/show rules for the slide.
|
|
///
|
|
/// - composer (function): The composer of the slide. You can use it to set the layout of the slide.
|
|
///
|
|
/// For example, `#slide(composer: (1fr, 2fr, 1fr))[A][B][C]` to split the slide into three parts. The first and the last parts will take 1/4 of the slide, and the second part will take 1/2 of the slide.
|
|
///
|
|
/// If you pass a non-function value like `(1fr, 2fr, 1fr)`, it will be assumed to be the first argument of the `components.side-by-side` function.
|
|
///
|
|
/// The `components.side-by-side` function is a simple wrapper of the `grid` function. It means you can use the `grid.cell(colspan: 2, ..)` to make the cell take 2 columns.
|
|
///
|
|
/// For example, `#slide(composer: 2)[A][B][#grid.cell(colspan: 2)[Footer]]` will make the `Footer` cell take 2 columns.
|
|
///
|
|
/// If you want to customize the composer, you can pass a function to the `composer` argument. The function should receive the contents of the slide and return the content of the slide, like `#slide(composer: grid.with(columns: 2))[A][B]`.
|
|
///
|
|
/// - bodies (array): The contents of the slide. You can call the `slide` function with syntax like `#slide[A][B][C]` to create a slide.
|
|
#let slide(
|
|
config: (:),
|
|
repeat: auto,
|
|
setting: body => body,
|
|
composer: auto,
|
|
..bodies,
|
|
) = touying-slide-wrapper(self => {
|
|
let header(self) = utils.call-or-display(self, self.store.header)
|
|
let footer(self) = {
|
|
text(size: 0.5em, fill: self.colors.neutral-lightest, grid(
|
|
align: (left + horizon, center + horizon, right + horizon),
|
|
fill: self.colors.secondary,
|
|
columns: (1fr, 4.5fr, 1fr),
|
|
// gutter: 0em,
|
|
// stroke: (x: self.colors.secondary + 0.5em),
|
|
rows: 100%,
|
|
box(inset: (left: self.page.margin.x / 2), utils.call-or-display(self, self.store.footer-left)),
|
|
utils.call-or-display(self, self.store.footer),
|
|
box(fill: self.colors.primary, height: 100%, inset: (x: self.page.margin.x / 2), align(center, utils.call-or-display(self, self.store.footer-right))),
|
|
)
|
|
)
|
|
}
|
|
let self = utils.merge-dicts(
|
|
self,
|
|
config-page(
|
|
header: header,
|
|
footer: footer,
|
|
),
|
|
config-common(subslide-preamble: self.store.subslide-preamble),
|
|
)
|
|
touying-slide(self: self, config: config, repeat: repeat, setting: setting, composer: composer, ..bodies)
|
|
})
|
|
|
|
|
|
/// Centered slide for the presentation.
|
|
///
|
|
/// - config (dictionary): The configuration of the slide. You can use `config-xxx` to set the configuration of the slide. For several configurations, you can use `utils.merge-dicts` to merge them.
|
|
#let centered-slide(config: (:), ..args) = touying-slide-wrapper(self => {
|
|
touying-slide(self: self, ..args.named(), config: config, align(center + horizon, args.pos().sum(default: none)))
|
|
})
|
|
|
|
|
|
/// Title slide for the presentation.
|
|
///
|
|
/// Example: `#title-slide(title-image: "assets/title-image.png")`
|
|
///
|
|
/// - content (content | none): The content of the title slide, typically an image. The content will be displayed centered above the title and subtitle.
|
|
///
|
|
/// - config (dictionary): The configuration of the slide. You can use `config-xxx` to set the configuration of the slide. For several configurations, you can use `utils.merge-dicts` to merge them.
|
|
#let title-slide(content, config: (:), ..args) = touying-slide-wrapper(self => {
|
|
let body = {
|
|
set block(spacing: 0em)
|
|
// show text: it => align(right + horizon, it)
|
|
set text(fill: self.colors.neutral-lightest)
|
|
|
|
block(
|
|
inset: (x: self.page.margin.x * 2/3, y: 0.5cm),
|
|
width: 100%,
|
|
height: 1fr,
|
|
content
|
|
)
|
|
block(
|
|
fill: self.colors.primary,
|
|
width: 100%,
|
|
height: 2.2cm,
|
|
inset: (x: self.page.margin.x * 2/3),
|
|
align(right + horizon, text(size: 1.4em, weight: "bold", self.info.title))
|
|
)
|
|
let secondary-info = (self.info.subtitle, self.info.author, self.info.date.display("[month repr:long] [day], [year]")).filter(it => it != none).join(" | ")
|
|
block(
|
|
fill: self.colors.secondary,
|
|
width: 100%,
|
|
height: 1.1cm,
|
|
inset: (x: self.page.margin.x * 2/3),
|
|
align(right + horizon, text(size: 0.9em, secondary-info))
|
|
)
|
|
block(
|
|
width: 100%,
|
|
height: 2.2cm,
|
|
inset: (x: self.page.margin.x * 2/3, y: 0.35cm),
|
|
box(image(self.info.institute-logo, height: 1fr)) + h(1fr) + box(image(self.info.university-logo, height: 1fr))
|
|
)
|
|
}
|
|
let self = utils.merge-dicts(
|
|
self,
|
|
config-common(freeze-slide-counter: true),
|
|
config-page(margin: 0em)
|
|
)
|
|
touying-slide(self: self, ..args.named(), config: config, body)
|
|
})
|
|
|
|
|
|
/// New section slide for the presentation. You can update it by updating the `new-section-slide-fn` argument for `config-common` function.
|
|
///
|
|
/// - config (dictionary): The configuration of the slide. You can use `config-xxx` to set the configuration of the slide. For more several configurations, you can use `utils.merge-dicts` to merge them.
|
|
#let new-section-slide(config: (:), body) = centered-slide(config: config, [
|
|
#text(1.2em, weight: "bold", utils.display-current-heading(level: 1))
|
|
|
|
#body
|
|
])
|
|
|
|
|
|
/// Focus on some content.
|
|
///
|
|
/// Example: `#focus-slide[Wake up!]`
|
|
///
|
|
/// - config (dictionary): The configuration of the slide. You can use `config-xxx` to set the configuration of the slide. For more several configurations, you can use `utils.merge-dicts` to merge them.
|
|
///
|
|
/// - background (color, auto): The background color of the slide. Default is `auto`, which means the primary color of the slides.
|
|
///
|
|
/// - foreground (color): The foreground color of the slide. Default is `white`.
|
|
#let focus-slide(config: (:), background: auto, foreground: white, body) = touying-slide-wrapper(self => {
|
|
self = utils.merge-dicts(
|
|
self,
|
|
config-common(freeze-slide-counter: true),
|
|
config-page(fill: if background == auto {
|
|
self.colors.primary
|
|
} else {
|
|
background
|
|
}),
|
|
)
|
|
set text(fill: foreground, size: 1.5em)
|
|
touying-slide(self: self, config: config, align(center + horizon, body))
|
|
})
|
|
|
|
/// Fancy Ulm University theme (Institute of Software Engineering and Programming Languages).
|
|
///
|
|
/// Example:
|
|
///
|
|
/// ```typst
|
|
/// #show: fancyuulm.with(aspect-ratio: "16-9", config-colors(primary: blue))`
|
|
/// ```
|
|
///
|
|
/// The default colors:
|
|
///
|
|
/// ```typst
|
|
/// config-colors(
|
|
/// neutral-light: gray,
|
|
/// neutral-lightest: rgb("#ffffff"),
|
|
/// neutral-darkest: rgb("#000000"),
|
|
/// primary: rgb("#A32638"),
|
|
/// secondary: rgb("#A9A28D"),
|
|
/// )
|
|
/// ```
|
|
///
|
|
/// - aspect-ratio (string): The aspect ratio of the slides. Default is `16-9`.
|
|
///
|
|
/// - header (function): The header of the slides. Default is `self => utils.display-current-heading(setting: utils.fit-to-width.with(grow: false, 100%), depth: self.slide-level)`.
|
|
///
|
|
/// - footer-left (function): The left part of the footer. Default is `self => self.info.author`.
|
|
///
|
|
/// - footer (function): The footer of the slides. Default is `self => self.info.title`.
|
|
///
|
|
/// - footer-right (content): The right part of the footer. Default is `context utils.slide-counter.display()`.
|
|
///
|
|
/// - primary (color): The primary color of the slides. Default is `rgb("#A32638")`.
|
|
///
|
|
/// - secondary (color): The secondary color of the slides. Default is `rgb("#A9A28D")`.
|
|
///
|
|
/// - subslide-preamble (content): The preamble of the subslides. Default is `block(below: 1.5em, text(1.2em, weight: "bold", utils.display-current-heading(level: 2)))`.
|
|
///
|
|
/// - include-new-section-slides (bool): Whether to include slides for introducing new sections. Default is `false`.
|
|
#let fancyuulm(
|
|
aspect-ratio: "16-9",
|
|
header: self => [],//utils.display-current-heading(
|
|
// setting: utils.fit-to-width.with(grow: false, 100%),
|
|
// level: 1,
|
|
// depth: self.slide-level,
|
|
// ),
|
|
footer-left: self => self.info.author,
|
|
footer: self => [#self.info.title -- #self.info.subtitle -- #utils.display-current-heading(level: 1)],
|
|
footer-right: context utils.slide-counter.display(),
|
|
primary: rgb("#A32638"),
|
|
secondary: rgb("#A9A28D"),
|
|
subslide-preamble: block(
|
|
below: 1.3cm,
|
|
text(1.5em, weight: "bold", utils.display-current-heading(level: 2)),
|
|
),
|
|
include-new-section-slides: false,
|
|
..args,
|
|
body,
|
|
) = {
|
|
show: touying-slides.with(
|
|
config-page(
|
|
paper: "presentation-" + aspect-ratio,
|
|
margin: (x: 2cm, top: 1.5cm, bottom: 2cm),
|
|
footer-descent: 1.2cm,
|
|
),
|
|
config-common(
|
|
slide-fn: slide,
|
|
new-section-slide-fn: if include-new-section-slides { new-section-slide },
|
|
zero-margin-header: false,
|
|
zero-margin-footer: true,
|
|
),
|
|
config-methods(
|
|
init: (self: none, body) => {
|
|
set text(size: 18pt, number-width: "tabular", font: "Fira Sans")
|
|
show raw: set text(font: "Fira Code")
|
|
show math.equation: set text(font: "Noto Sans Math")
|
|
set par(spacing: 1cm)
|
|
|
|
set footnote.entry(indent: 0cm, clearance: 0.3cm)
|
|
show footnote.entry: set text(size: 8pt)
|
|
show footnote.entry: set cite(form: "full")
|
|
show footnote.entry: box.with(width: 62.5%)
|
|
|
|
// set list(spacing: 1cm)
|
|
// show list: it => {
|
|
// show list: set list(spacing: 0.75cm)
|
|
// it
|
|
// }
|
|
|
|
// show raw.where(block: false): box
|
|
// show raw.where(block: false): set box(
|
|
// fill: self.colors.neutral-lighter,
|
|
// inset: (x: 5pt, y: 0pt),
|
|
// outset: (y: 5pt),
|
|
// radius: 3pt,
|
|
// )
|
|
|
|
// set table(inset: 9pt, stroke: (0.5pt + self.colors.neutral-light))
|
|
// show table: table => {
|
|
// show raw.where(block: false): set box(
|
|
// fill: none,
|
|
// inset: (x: 1pt),
|
|
// outset: 0pt
|
|
// )
|
|
// table
|
|
// }
|
|
|
|
body
|
|
},
|
|
alert: utils.alert-with-primary-color,
|
|
),
|
|
config-colors(
|
|
neutral-light: luma(200),
|
|
neutral-lighter: luma(250),
|
|
neutral-lightest: rgb("#ffffff"),
|
|
neutral-darkest: rgb("#000000"),
|
|
primary: primary,
|
|
secondary: secondary,
|
|
),
|
|
// Save the variables for later use
|
|
config-store(
|
|
header: header,
|
|
footer-left: footer-left,
|
|
footer: footer,
|
|
footer-right: footer-right,
|
|
subslide-preamble: subslide-preamble,
|
|
),
|
|
..args,
|
|
)
|
|
|
|
body
|
|
} |