335 lines
10 KiB
Typst
335 lines
10 KiB
Typst
// University theme
|
|
|
|
// Originally contributed by Pol Dellaiera - https://github.com/drupol
|
|
#import "@preview/touying:0.4.2": *
|
|
|
|
#let slide(
|
|
self: none,
|
|
title: auto,
|
|
subtitle: auto,
|
|
header: auto,
|
|
footer: auto,
|
|
display-current-section: auto,
|
|
..args,
|
|
) = {
|
|
if title != auto {
|
|
self.uni-title = title
|
|
}
|
|
if subtitle != auto {
|
|
self.uni-subtitle = subtitle
|
|
}
|
|
if header != auto {
|
|
self.uni-header = header
|
|
}
|
|
if footer != auto {
|
|
self.uni-footer = footer
|
|
}
|
|
if display-current-section != auto {
|
|
self.uni-display-current-section = display-current-section
|
|
}
|
|
(self.methods.touying-slide)(
|
|
..args.named(),
|
|
self: self,
|
|
title: title,
|
|
setting: body => {
|
|
show: args.named().at("setting", default: body => body)
|
|
body
|
|
},
|
|
..args.pos(),
|
|
)
|
|
}
|
|
|
|
#let title-slide(self: none, ..args) = {
|
|
self = utils.empty-page(self)
|
|
let info = self.info + args.named()
|
|
info.authors = {
|
|
let authors = if "authors" in info { info.authors } else { info.author }
|
|
if type(authors) == array { authors } else { (authors,) }
|
|
}
|
|
let content = {
|
|
if info.logo != none {
|
|
align(center, pad(1em, info.logo))
|
|
}
|
|
align(center + horizon, {
|
|
block(
|
|
inset: 0em,
|
|
breakable: false,
|
|
{
|
|
text(size: 2em, fill: self.colors.primary, strong(info.title))
|
|
if info.subtitle != none {
|
|
parbreak()
|
|
text(size: 1.2em, fill: self.colors.primary, info.subtitle)
|
|
}
|
|
}
|
|
)
|
|
set text(size: .8em)
|
|
grid(
|
|
columns: (1fr,) * calc.min(info.authors.len(), 3),
|
|
column-gutter: 1em,
|
|
row-gutter: 1em,
|
|
..info.authors.map(author => text(fill: black, author))
|
|
)
|
|
v(1em)
|
|
if info.institution != none {
|
|
parbreak()
|
|
text(size: .9em, info.institution)
|
|
}
|
|
if info.date != none {
|
|
parbreak()
|
|
text(size: .8em, utils.info-date(self))
|
|
}
|
|
})
|
|
}
|
|
(self.methods.touying-slide)(self: self, repeat: none, content)
|
|
}
|
|
|
|
|
|
|
|
#let matrix-slide(self: none, columns: none, rows: none, ..bodies) = {
|
|
self = utils.empty-page(self)
|
|
(self.methods.touying-slide)(self: self, composer: (..bodies) => {
|
|
let bodies = bodies.pos()
|
|
let columns = if type(columns) == int {
|
|
(1fr,) * columns
|
|
} else if columns == none {
|
|
(1fr,) * bodies.len()
|
|
} else {
|
|
columns
|
|
}
|
|
let num-cols = columns.len()
|
|
let rows = if type(rows) == int {
|
|
(1fr,) * rows
|
|
} else if rows == none {
|
|
let quotient = calc.quo(bodies.len(), num-cols)
|
|
let correction = if calc.rem(bodies.len(), num-cols) == 0 { 0 } else { 1 }
|
|
(1fr,) * (quotient + correction)
|
|
} else {
|
|
rows
|
|
}
|
|
let num-rows = rows.len()
|
|
if num-rows * num-cols < bodies.len() {
|
|
panic("number of rows (" + str(num-rows) + ") * number of columns (" + str(num-cols) + ") must at least be number of content arguments (" + str(bodies.len()) + ")")
|
|
}
|
|
let cart-idx(i) = (calc.quo(i, num-cols), calc.rem(i, num-cols))
|
|
let color-body(idx-body) = {
|
|
let (idx, body) = idx-body
|
|
let (row, col) = cart-idx(idx)
|
|
let color = if calc.even(row + col) { white } else { silver }
|
|
set align(center + horizon)
|
|
rect(inset: .5em, width: 100%, height: 100%, fill: color, body)
|
|
}
|
|
let content = grid(
|
|
columns: columns, rows: rows,
|
|
gutter: 0pt,
|
|
..bodies.enumerate().map(color-body)
|
|
)
|
|
content
|
|
}, ..bodies)
|
|
}
|
|
|
|
|
|
#let focus-slide(self: none, background-color: none, background-img: none, body) = {
|
|
let background-color = if background-img == none and background-color == none {
|
|
rgb(self.colors.primary)
|
|
} else {
|
|
background-color
|
|
}
|
|
self = utils.empty-page(self)
|
|
self.page-args += (
|
|
fill: self.colors.primary-dark,
|
|
margin: 1em,
|
|
..(if background-color != none { (fill: background-color) }),
|
|
..(if background-img != none { (background: {
|
|
set image(fit: "stretch", width: 100%, height: 100%)
|
|
background-img
|
|
})
|
|
}),
|
|
)
|
|
set text(fill: white, weight: "bold", size: 2em)
|
|
(self.methods.touying-slide)(self: self, repeat: none, align(horizon, body))
|
|
}
|
|
|
|
#let outline-slide(self: none, ..args) = {
|
|
(self.methods.slide)(self: self, heading(level: 2, self.outline-title) + parbreak() + (self.methods.touying-outline)(self: self, cover: false))
|
|
}
|
|
|
|
#let new-section-slide(self: none, short-title: auto, title) = {
|
|
self = utils.empty-page(self)
|
|
let content(self) = {
|
|
set align(horizon)
|
|
show: pad.with(20%)
|
|
set text(size: 1.5em, fill: self.colors.primary, weight: "bold")
|
|
states.current-section-with-numbering(self)
|
|
v(-.5em)
|
|
block(height: 2pt, width: 100%, spacing: 0pt, utils.call-or-display(self, self.uni-progress-bar))
|
|
}
|
|
(self.methods.touying-slide)(self: self, repeat: none, section: (title: title, short-title: short-title), content)
|
|
}
|
|
|
|
#let new-section-slide(self: none, short-title: auto, title) = {
|
|
(self.methods.slide)(self: self, section: (title: title, short-title: short-title), heading(level: 2, self.outline-title) + parbreak() + (self.methods.touying-outline)(self: self))
|
|
}
|
|
|
|
#let d-outline(self: none, enum-args: (:), list-args: (:), cover: true) = states.touying-progress-with-sections(dict => {
|
|
let (current-sections, final-sections) = dict
|
|
current-sections = current-sections.filter(section => section.loc != none)
|
|
final-sections = final-sections.filter(section => section.loc != none)
|
|
let current-index = current-sections.len() - 1
|
|
let d-cover(i, body) = if i != current-index and cover {
|
|
(self.methods.d-cover)(self: self, body)
|
|
} else {
|
|
body
|
|
}
|
|
set enum(..enum-args)
|
|
set list(..enum-args)
|
|
set text(fill: self.colors.primary)
|
|
for (i, section) in final-sections.enumerate() {
|
|
d-cover(i, {
|
|
enum.item(i + 1, [#link(section.loc, section.title)<touying-link>] + if section.children.filter(it => it.kind != "slide").len() > 0 {
|
|
let subsections = section.children.filter(it => it.kind != "slide")
|
|
set text(fill: self.colors.tertiary, size: 0.9em)
|
|
list(
|
|
..subsections.map(subsection => [#link(subsection.loc, subsection.title)<touying-link>])
|
|
)
|
|
})
|
|
})
|
|
parbreak()
|
|
}
|
|
})
|
|
|
|
#let slides(self: none, title-slide: true, slide-level: 1, ..args) = {
|
|
if title-slide {
|
|
(self.methods.title-slide)(self: self)
|
|
}
|
|
(self.methods.touying-slides)(self: self, slide-level: slide-level, ..args)
|
|
}
|
|
|
|
#let register(
|
|
self: themes.default.register(),
|
|
aspect-ratio: "16-9",
|
|
progress-bar: true,
|
|
display-current-section: true,
|
|
footer-columns: (25%, 1fr, 25%),
|
|
footer-a: self => self.info.author,
|
|
footer-b: self => if self.info.short-title == auto { self.info.title } else { self.info.short-title },
|
|
footer-c: self => {
|
|
h(1fr)
|
|
utils.info-date(self)
|
|
h(1fr)
|
|
states.slide-counter.display() + " / " + states.last-slide-number
|
|
h(1fr)
|
|
},
|
|
..args,
|
|
) = {
|
|
// color theme
|
|
self = (self.methods.colors)(
|
|
self: self,
|
|
primary: rgb("#2D373C"),
|
|
secondary: rgb("#A5D7D2"),
|
|
tertiary: rgb("#46505A"),
|
|
minthell: rgb("#D2EBE9"),
|
|
unibasred: rgb("#D20537")
|
|
)
|
|
// save the variables for later use
|
|
self.outline-title = [Outline]
|
|
self.uni-enable-progress-bar = progress-bar
|
|
self.uni-progress-bar = self => states.touying-progress(ratio => {
|
|
grid(
|
|
columns: (ratio * 100%, 1fr),
|
|
rows: 5pt,
|
|
components.cell(fill: self.colors.primary),
|
|
components.cell(fill: self.colors.secondary)
|
|
)
|
|
})
|
|
self.uni-display-current-section = display-current-section
|
|
self.uni-title = none
|
|
self.uni-subtitle = none
|
|
self.uni-footer = self => {
|
|
let cell(fill: none, it) = rect(
|
|
width: 100%, height: 100%, inset: 1mm, outset: 0mm, fill: fill, stroke: none,
|
|
align(horizon, text(fill: white, it))
|
|
)
|
|
show: block.with(width: 100%, height: auto, fill: self.colors.secondary)
|
|
grid(
|
|
columns: footer-columns,
|
|
rows: (1.5em, auto),
|
|
cell(fill: self.colors.primary, utils.call-or-display(self, footer-a)),
|
|
cell(fill: self.colors.secondary, utils.call-or-display(self, footer-b)),
|
|
cell(fill: self.colors.tertiary, utils.call-or-display(self, footer-c)),
|
|
)
|
|
}
|
|
self.uni-header = self => {
|
|
if self.uni-title != none {
|
|
block(inset: (x: .5em),
|
|
grid(
|
|
columns: 1,
|
|
gutter: .1em,
|
|
grid(
|
|
columns: (2fr, 2fr, 2fr),
|
|
align: (left+horizon, center+horizon, right+horizon),
|
|
align(horizon + left, text(fill: self.colors.primary, weight: "bold", size: 1.1em, self.uni-title)),
|
|
image(height: 1em,"logo-en.svg"),
|
|
if self.uni-display-current-section {
|
|
align(horizon + right, text(fill: self.colors.primary.lighten(30%), states.current-section-with-numbering(self)))
|
|
}
|
|
),
|
|
text(fill: self.colors.secondary, size: .8em, self.uni-subtitle)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
// set page
|
|
let header(self) = {
|
|
set align(top)
|
|
grid(
|
|
fill: self.colors.minthell,
|
|
rows: (auto, auto),
|
|
row-gutter:.0mm,
|
|
if self.uni-enable-progress-bar {
|
|
utils.call-or-display(self, self.uni-progress-bar)
|
|
},
|
|
utils.call-or-display(self, self.uni-header)
|
|
)
|
|
}
|
|
let footer(self) = {
|
|
set text(size: .5em)
|
|
set align(center + bottom)
|
|
utils.call-or-display(self, self.uni-footer)
|
|
}
|
|
|
|
self.page-args += (
|
|
paper: "presentation-" + aspect-ratio,
|
|
header: header,
|
|
footer: footer,
|
|
header-ascent: 0em,
|
|
footer-descent: 0em,
|
|
margin: (top: 2.5em, bottom: 1.25em, x: 2em),
|
|
)
|
|
// register methods
|
|
self.methods.slide = slide
|
|
self.methods.title-slide = title-slide
|
|
self.methods.new-section-slide = new-section-slide
|
|
self.methods.touying-new-section-slide = new-section-slide
|
|
self.methods.focus-slide = focus-slide
|
|
self.methods.matrix-slide = matrix-slide
|
|
self.methods.slides = slides
|
|
self.methods.outline-slide = outline-slide
|
|
self.methods.touying-outline = (self: none, enum-args: (:), ..args) => {
|
|
states.touying-outline(self: self, enum-args: (tight: false,) + enum-args, ..args)
|
|
}
|
|
self.methods.touying-outline = d-outline
|
|
self.methods.d-outline = d-outline
|
|
self.methods.d-cover = (self: none, body) => {
|
|
utils.cover-with-rect(fill: utils.update-alpha(
|
|
constructor: rgb, self.page-args.fill, 50%), body)
|
|
}
|
|
//self.methods.alert = (self: none, it) => text(fill: self.colors.unibasred, it)
|
|
self.methods.init = (self: none, body) => {
|
|
set text(size: 20pt)
|
|
set heading(outlined: true)
|
|
show footnote.entry: set text(size: .6em)
|
|
body
|
|
}
|
|
self
|
|
}
|