410 lines
7.7 KiB
Typst
410 lines
7.7 KiB
Typst
/// An *opinionated* template for a longer report or thesis.
|
|
#let tasteful-thesis(
|
|
/// The main title of the document.
|
|
/// -> string
|
|
title: "",
|
|
/// An optional subtitle for the document.
|
|
/// -> string
|
|
subtitle: "",
|
|
/// The authors of the document.
|
|
/// -> array(string)
|
|
authors: (),
|
|
supervisors: (),
|
|
affiliation: none,
|
|
other: none,
|
|
abstract: none,
|
|
|
|
background-image: none,
|
|
date: datetime.today().display(),
|
|
background-color: color.blue,
|
|
logos: (),
|
|
font: "New Computer Modern",
|
|
alpha: 50%,
|
|
pre_content: none,
|
|
body,
|
|
|
|
) = {
|
|
//
|
|
// Global settings and style customization.
|
|
//
|
|
set document(author: authors, title: title, description: subtitle)
|
|
|
|
let font-color = color;
|
|
// Check if the background color is closer to black or white
|
|
let components = background-color.components()
|
|
// show the components for debugging
|
|
let luminance = float(0.299 * components.at(0) + 0.587 * components.at(1) + 0.114 * components.at(2))
|
|
if luminance > 0.5 {
|
|
font-color = color.black
|
|
} else {
|
|
font-color = color.white
|
|
}
|
|
|
|
|
|
//customize look of figure
|
|
// set figure.caption(separator: [ --- ], position: top)
|
|
|
|
//customize inline raw code
|
|
show raw.where(block: false) : it => h(0.5em) + box(fill: color.lighten(90%), outset: 0.2em, it) + h(0.5em)
|
|
|
|
// Set body font family.
|
|
set text(font: font, 12pt)
|
|
show heading: set text(font: font, fill: background-color)
|
|
|
|
// add space for heading
|
|
show heading.where(level:1): it => it + v(0.5em)
|
|
|
|
// Set link style
|
|
show link: it => underline(text(fill: background-color, it))
|
|
|
|
show ref: it => text(fill: background-color, it)
|
|
|
|
show ref.where(): it => text(fill: background-color, it)
|
|
|
|
//numbered list colored
|
|
set enum(indent: 1em, numbering: n => [#text(fill: background-color, numbering("1.", n))])
|
|
|
|
//unordered list colored
|
|
set list(indent: 1em, marker: n => [#text(fill: background-color, "•")])
|
|
|
|
|
|
|
|
set cite(
|
|
form: "prose"
|
|
)
|
|
|
|
|
|
// display of outline entries
|
|
show outline.entry: it => text(size: 12pt, weight: "regular",it)
|
|
|
|
//
|
|
// Title page
|
|
//
|
|
|
|
// Title page background
|
|
set page(
|
|
// the title page should not have any margin, this will be reset in the next page
|
|
margin: 0pt,
|
|
)
|
|
|
|
// set the image first so that it is the lowest layer
|
|
place(
|
|
bottom,
|
|
background-image
|
|
)
|
|
|
|
// Add a tiling of white squares over the background to simulate a grid
|
|
for i in range(0, 14) {
|
|
for j in range(0, 14) {
|
|
place(
|
|
bottom + right,
|
|
dx: -i * 3.55em + 0.1em,
|
|
dy: -j * 3.55em,
|
|
)[
|
|
#square(
|
|
size: 3.55em,
|
|
// fill: gradient.linear(
|
|
// color.white,
|
|
// color.black.transparentize(0%),
|
|
// color.black.transparentize(0%),
|
|
// color.black.transparentize(0%),
|
|
// color.black.transparentize(0%),
|
|
// angle: 45deg,
|
|
// ),
|
|
fill: none,
|
|
stroke: (
|
|
paint: color.white,
|
|
thickness: 0.02em,
|
|
)
|
|
)
|
|
]
|
|
}
|
|
}
|
|
|
|
|
|
|
|
place(
|
|
top + left,
|
|
dx: -20em,
|
|
line(
|
|
angle: -10deg,
|
|
length: 200%,
|
|
stroke: (
|
|
paint: background-color.lighten(alpha),
|
|
thickness: 900pt,
|
|
),
|
|
),
|
|
)
|
|
|
|
place(
|
|
top + left,
|
|
dx: -20em,
|
|
line(
|
|
angle: -10deg,
|
|
length: 200%,
|
|
stroke: (
|
|
paint: background-color,
|
|
thickness: 800pt,
|
|
)
|
|
),
|
|
)
|
|
|
|
place(
|
|
bottom + right,
|
|
dx: 20em,
|
|
dy: 20em,
|
|
line(
|
|
angle: -10deg,
|
|
length: 200%,
|
|
stroke: (
|
|
paint: background-color.lighten(alpha),
|
|
thickness: 400pt,
|
|
)
|
|
),
|
|
)
|
|
|
|
place(
|
|
bottom + right,
|
|
dx: 20em,
|
|
dy: 20em,
|
|
line(
|
|
angle: -10deg,
|
|
length: 200%,
|
|
stroke: (
|
|
paint: background-color,
|
|
thickness: 300pt,
|
|
)
|
|
),
|
|
)
|
|
|
|
|
|
// add a few more tiles *above* the background image to simulate a grid structure
|
|
let draw_pairs = (
|
|
(0, 10),
|
|
// (1, 10),
|
|
// (2, 10),
|
|
(3, 10),
|
|
// (4, 10),
|
|
(5, 10),
|
|
(6, 10),
|
|
// (7, 10),
|
|
(8, 10),
|
|
// (9, 10),
|
|
(10, 10),
|
|
(11, 10),
|
|
// (12, 10),
|
|
(13, 10),
|
|
|
|
(0, 11),
|
|
(1, 11),
|
|
// (2, 11),
|
|
(3, 11),
|
|
// (4, 11),
|
|
(5, 11),
|
|
// (6, 11),
|
|
// (7, 11),
|
|
(8, 11),
|
|
// (9, 11),
|
|
(10, 11),
|
|
(11, 11),
|
|
// (12, 11),
|
|
(13, 11),
|
|
|
|
(0, 12),
|
|
// (1, 12),
|
|
// (2, 12),
|
|
(3, 12),
|
|
// (4, 12),
|
|
(5, 12),
|
|
// (6, 12),
|
|
// (7, 12),
|
|
// (8, 12),
|
|
(9, 12),
|
|
// (10, 12),
|
|
// (11, 12),
|
|
// (12, 12),
|
|
// (13, 12),
|
|
|
|
|
|
// (0, 13),
|
|
(1, 13),
|
|
// (2, 13),
|
|
(3, 13),
|
|
// (4, 13),
|
|
// (5, 13),
|
|
// (6, 13),
|
|
(7, 13),
|
|
// (8, 13),
|
|
// (9, 13),
|
|
// (10, 13),
|
|
// (11, 13),
|
|
(12, 13),
|
|
// (13, 13),
|
|
|
|
|
|
// (0, 14),
|
|
// (1, 14),
|
|
// (2, 14),
|
|
// (3, 14),
|
|
(4, 14),
|
|
// (5, 14),
|
|
// (6, 14),
|
|
// (7, 14),
|
|
// (8, 14),
|
|
// (9, 14),
|
|
(10, 14),
|
|
// (11, 14),
|
|
// (12, 14),
|
|
(13, 14),
|
|
)
|
|
|
|
for (i, j) in draw_pairs {
|
|
place(
|
|
bottom + right,
|
|
dx: -i * 3.55em + 0.1em,
|
|
dy: -j * 3.55em,
|
|
)[
|
|
#square(
|
|
size: 3.55em,
|
|
// fill: gradient.linear(
|
|
// color.white,
|
|
// color.black.transparentize(0%),
|
|
// color.black.transparentize(0%),
|
|
// color.black.transparentize(0%),
|
|
// color.black.transparentize(0%),
|
|
// angle: 45deg,
|
|
// ),
|
|
fill: none,
|
|
stroke: (
|
|
paint: color.white,
|
|
thickness: 0.02em,
|
|
)
|
|
)
|
|
]
|
|
|
|
}
|
|
|
|
|
|
// Title page content
|
|
pad(
|
|
x: 4em,
|
|
y: 4em,
|
|
)[
|
|
#align(center, text(font: font, 3em, weight: 700, title, fill: font-color))
|
|
#v(2em, weak: true)
|
|
#if subtitle != none {
|
|
align(center, text(font: font, 2em, weight: 600, subtitle, fill: font-color))
|
|
}
|
|
#v(2em, weak: true)
|
|
#align(
|
|
center,
|
|
text(font: font, 1em, authors.join(", "), fill: font-color)
|
|
)
|
|
]
|
|
|
|
|
|
let padded_logos = logos.map(logo => pad(x: 0.2cm, logo))
|
|
|
|
place(bottom + right, dy: -2em, dx: -2em)[
|
|
#set text(font: font, fill: font-color, size: 1.2em)
|
|
#set image(height: 0.8cm, width: auto)
|
|
|
|
#date
|
|
|
|
#stack(
|
|
dir: ltr,
|
|
// text(font: font, 1em, affiliation, fill: font-color),
|
|
..padded_logos
|
|
)
|
|
]
|
|
|
|
|
|
|
|
if pre_content != none {
|
|
pagebreak()
|
|
place(
|
|
top + left,
|
|
// dx: 2em,
|
|
// dy: 2em,
|
|
)[
|
|
#pre_content
|
|
]
|
|
}
|
|
|
|
|
|
pagebreak()
|
|
|
|
let footer = grid(
|
|
rows: auto,
|
|
v(0mm),
|
|
line(length: 100%, stroke: (paint: background-color, thickness: 1pt)),
|
|
v(2.5mm),
|
|
text(
|
|
)[
|
|
#title
|
|
#h(1fr)
|
|
#context [
|
|
#text(counter(page).display())
|
|
]
|
|
// context needed for page counter for typst >= 0.11.0
|
|
]
|
|
)
|
|
|
|
set page(
|
|
// no header
|
|
footer: footer,
|
|
margin: 4em,
|
|
)
|
|
|
|
//
|
|
// Table of contents.
|
|
//
|
|
|
|
|
|
|
|
|
|
abstract
|
|
v(2em)
|
|
outline()
|
|
|
|
pagebreak()
|
|
|
|
|
|
//
|
|
// Main body.
|
|
//
|
|
set heading(numbering: "1.")
|
|
|
|
set par(justify: true)
|
|
|
|
body
|
|
}
|
|
|
|
|
|
// let footer = grid(
|
|
// rows: auto,
|
|
// v(0mm),
|
|
// line(length: 100%, stroke: 0.6pt), // should be 1.6pt according to guidelines
|
|
// v(2.5mm),
|
|
// text(
|
|
// font: "Roboto",
|
|
// stretch: 100%,
|
|
// fallback: false,
|
|
// weight: "regular",
|
|
// size: 10pt
|
|
// )[
|
|
// #set align(right)
|
|
// // context needed for page counter for typst >= 0.11.0
|
|
// #context [
|
|
// #let counter_disp = counter(page).display()
|
|
// //#hide(counter_disp)
|
|
// //#counter_disp
|
|
// #context {
|
|
// let after_table_of_contents = query(selector(<__after_table_of_contents>).before(here())).len() >= 1
|
|
// if after_table_of_contents {counter_disp}
|
|
// else {hide(counter_disp)}
|
|
// }
|
|
// ]
|
|
// ]
|
|
// )
|