Files
master-thesis-report/template/template.typ

396 lines
7.1 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)
// Set body font family.
set text(font: font, 11pt)
show heading: set text(font: font, fill: background-color)
let font-color = color;
// Check if the background color is closer to black or white
let components = background-color.components()
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
}
// color links
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)
// colors lists
set enum(indent: 1em, numbering: n => [#text(fill: background-color, numbering("1.", n))])
set list(indent: 1em, marker: n => [#text(fill: background-color, "•")])
// citation style
set cite(
form: "prose"
)
// add space for heading
show heading.where(level:1): it => it + v(0.5em)
//
// Included content
//
// figures
// set figure.caption(separator: [ --- ], position: top)
// code blocks
show raw.where(block: true) : it => h(0.5em) + box(fill: background-color.lighten(80%), outset: 0.5em, width: 100%, it) + h(0.5em)
let authors_block(authors, denomination: "Author") = {
if authors.len() == 0 {
return
}
let prefix = denomination
if authors.len() > 2 {
prefix += "s"
}
stack(
dir: ltr,
text(prefix + ": ", weight: 600),
stack(
dir: ttb,
spacing: 0.5em,
..authors
)
)
}
//
// 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
)
// define the base widht of a tile, as a tenth of the page width
let tile_width = 1.51cm
// 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 * tile_width + 0.1em,
dy: -j * tile_width,
)[
#square(
size: tile_width,
// 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 * tile_width + 0.1em,
dy: -j * tile_width,
)[
#square(
size: tile_width,
fill: none,
stroke: (
paint: color.white,
thickness: 0.02em,
)
)
]
}
// Title page content
pad(
x: 4em,
y: 4em,
)[
#set text(font: font, fill: font-color)
#align(center, text(title, size: 2.5em, weight: 600))
#if subtitle != none {
v(1.5em, weak: true)
align(center, text(subtitle, size: 2em, weight: 500))
}
#pad(
x: 6em,
y: 0em,
)[
#stack(
dir: ltr,
authors_block(authors),
h(1fr),
authors_block(supervisors, denomination: "Supervisor")
)
]
]
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,
)
counter(page).update(1)
//
// "First" page - abstract and TOC
//
abstract
v(2em)
outline()
pagebreak()
//
// Main body.
//
set heading(numbering: "1.")
set par(justify: true)
body
}