mirror of
https://github.com/C0ffeeCode/typst-dhbw-technik-template.git
synced 2025-12-28 15:22:18 +01:00
579 lines
14 KiB
Text
Executable file
579 lines
14 KiB
Text
Executable file
|
|
#let acronyms = yaml("acronyms.yml");
|
|
#let acroStates = state("acronymStates", ());
|
|
|
|
#let english_pack = (
|
|
degree_1: "for the",
|
|
degree_2: "from the Course of Studies Computer Science",
|
|
by: "by",
|
|
time_period: "Time Period",
|
|
student_id_course: "Student ID, Course",
|
|
company: "Company",
|
|
supervisor: "Supervisor in the Company",
|
|
decleration: (type, title) => [
|
|
= Author's Declaration
|
|
|
|
Hereby I solemnly declare:
|
|
|
|
+ that this #type, titled #text(style: "italic")[#title] is entirely the product of my own scholarly work, unless otherwise indicated in the text or references, or acknowledged below;
|
|
|
|
+ I have indicated the thoughts adopted directly or indirectly from other sources at the appropriate places within the document;
|
|
|
|
+ this #type has not been submitted either in whole or part, for a degree at this or any other university or institution;
|
|
|
|
+ I have not published this #type in the past;
|
|
|
|
// + the printed version is equivalent to the submitted one.
|
|
|
|
I am aware that a dishonest declaration will entail legal consequences.
|
|
],
|
|
abstract: "Abstract",
|
|
contents: "Contents",
|
|
list_of_figures: "List of Figures",
|
|
acronyms: "Acronyms",
|
|
bibliography: "Bibliography",
|
|
appendix: "Appendix",
|
|
chapter: "Chapter",
|
|
section: "Section",
|
|
confidentiality_clause: [
|
|
= Confidentiality Clause
|
|
|
|
The content of this work may not be made accessible to people outside of the
|
|
testing process and the evaluation process neither as a whole nor as excerpts,
|
|
unless an authorization stating otherwise is presented by the training facility.
|
|
]
|
|
)
|
|
|
|
// TODO: Check alignment to LaTeX template
|
|
#let german_pack = (
|
|
degree_1: "für den",
|
|
degree_2: "im Studiengang Informatik an der Dualen Hochschule Baden-Württemberg Stuttgart",
|
|
by: "von",
|
|
time_period: "Bearbeitungszeitraum",
|
|
student_id_course: "Matrikelnummer, Kurs",
|
|
company: "Ausbildungsfirma",
|
|
supervisor: "Betreuer",
|
|
decleration: (type, title) => [
|
|
== Erklärung
|
|
|
|
Ich erkläre hiermit ehrenwörtlich:
|
|
+ dass ich meine #type mit dem Thema #title ohne fremde Hilfe
|
|
angefertigt habe;
|
|
+ dass ich die Übernahme wörtlicher Zitate aus der Literatur sowie die Verwendung
|
|
der Gedanken anderer Autoren an den entsprechenden Stellen innerhalb der
|
|
Arbeit gekennzeichnet habe;
|
|
+ dass ich meine T1000 bei keiner anderen Prüfung vorgelegt habe;
|
|
|
|
Ich bin mir bewusst, dass eine falsche Erklärung rechtliche Folgen haben wird.
|
|
|
|
#title
|
|
*a big & fat _TODO_!*
|
|
],
|
|
abstract: "Abstract",
|
|
contents: "Inhaltsverzeichnis",
|
|
list_of_figures: "Abbildungsverzeichnis",
|
|
acronyms: "Abkürzungsverzeichnis",
|
|
bibliography: "Literaturverzeichnis",
|
|
appendix: "Anhang",
|
|
chapter: "Kapitel",
|
|
section: "Abschnitt",
|
|
confidentiality_clause: [
|
|
= Sperrvermerk
|
|
|
|
Der Inhalt dieser Arbeit darf weder als Ganzes noch in Auszügen Personen außerhalb des
|
|
Prüfungs- und des Evaluationsverfahrens zugänglich gemacht werden, sofern keine anders
|
|
lautende Genehmigung des Dualen Partners vorliegt.
|
|
]
|
|
)
|
|
|
|
#let thesis(
|
|
// the title of your thesis
|
|
title: none,
|
|
// your name
|
|
author: none,
|
|
// your student id / matriculation number
|
|
student_id: none,
|
|
// the name of your course, such as "TINF21A"
|
|
course: none,
|
|
signature: none,
|
|
|
|
// the name of your supervisor
|
|
supervisor: none,
|
|
|
|
// the due date of your thesis
|
|
date: none,
|
|
// the time period that the work described in your thesis took place in
|
|
time_period: none,
|
|
|
|
// the type of your thesis, such as T1000, T2000, etc.
|
|
type: none,
|
|
// your degree, such as "Bachelor of Science"
|
|
degree: "Bachelor of Science",
|
|
// your major, such as "Computer Science"
|
|
major: "Computer Science",
|
|
// Change the language to `de` if desired
|
|
language: "en",
|
|
|
|
// Details on your university
|
|
university: (
|
|
name: "Cooperative State University Baden-Württemberg",
|
|
location: "Stuttgart",
|
|
image: "assets/dhbw.svg",
|
|
),
|
|
|
|
// Details on your company
|
|
company: (
|
|
name: "Hewlett Packard Enterprise",
|
|
image: "assets/hpe.svg",
|
|
),
|
|
|
|
// Does the document require a Confidentiality Clause?
|
|
confidentiality_clause: false,
|
|
|
|
// Path to your bibliography file
|
|
// You may use `.yml` for Hayagriva format
|
|
// or `.bib` for BibLaTeX format
|
|
bibliography_path: "literature.yml",
|
|
|
|
// The contents of your abstract
|
|
abstract: include "./abstract.typ",
|
|
// To be append after the bibliography
|
|
appendix: none,
|
|
|
|
// First chapter of your thesis
|
|
// This is required to generate the content section correctly
|
|
first_chapter_title: "Introduction",
|
|
|
|
// Factor of page location when to pagebreak headings
|
|
// to avoid a heading without content on the same page.
|
|
// Can be disabled by setting it to none
|
|
// WARNING: can result in "layout did not converge within 5 attempts" issue
|
|
heading_pagebreak_percentage: none,
|
|
|
|
// set automatically by using the template via `#show: thesis.with(...)
|
|
body,
|
|
) = [
|
|
// Assert all parameters are set
|
|
#assert.ne(title, none)
|
|
#assert.ne(author, none)
|
|
#assert.ne(student_id, none)
|
|
#assert.ne(type, none)
|
|
#assert.ne(course, none)
|
|
#assert.ne(date, none)
|
|
#assert.ne(time_period, none)
|
|
#assert.ne(supervisor, none)
|
|
|
|
// Use english by default
|
|
#let selected_lang = if language == "de" {german_pack} else {english_pack}
|
|
|
|
#set document(
|
|
title: title,
|
|
author: author,
|
|
date: date,
|
|
)
|
|
|
|
#set page(
|
|
paper: "a4",
|
|
margin: 2.5cm,
|
|
numbering: none, // don't number the first pages, i.e. titlepage and abstract
|
|
)
|
|
|
|
// suggested font and font size by the DHBW style guide
|
|
#set text(
|
|
font: "Linux Libertine", // Linux Biolinum O
|
|
// font: "Linux Biolinum O",
|
|
size: 12pt,
|
|
hyphenate: false,
|
|
lang: language,
|
|
ligatures: true,
|
|
)
|
|
|
|
#set par(
|
|
leading: 8pt, // 1.5x line spacing
|
|
justify: true,
|
|
linebreaks: "optimized",
|
|
)
|
|
|
|
#set figure(
|
|
numbering: "I"
|
|
)
|
|
|
|
// don't outline or number the first headings
|
|
#set heading(
|
|
numbering: none,
|
|
outlined: false,
|
|
)
|
|
|
|
// modify the spacing between various headings and the content below them
|
|
#show heading: it => {
|
|
let sizes = if it.level == 1 {
|
|
(64pt, 24pt, 24pt)
|
|
} else if it.level == 2 {
|
|
(32pt, 20pt, 18pt)
|
|
} else {
|
|
(24pt, 16pt, 14pt)
|
|
}
|
|
|
|
// On top-level headers, do a weak pagebreak
|
|
// (weak = no pagebreak on already blank pages)
|
|
if it.level == 1 {
|
|
pagebreak(weak: true)
|
|
} else if heading_pagebreak_percentage != none {
|
|
// If a heading would start at the very end of a page,
|
|
// it would not look right => pagebreak
|
|
context {
|
|
let here_abs = here().position().y
|
|
let here_rel = here_abs.abs / page.height
|
|
|
|
if here_rel > heading_pagebreak_percentage {
|
|
// Write but hide to assess location correctly
|
|
// Hidden will not have any influence
|
|
// on the output besides correct calculation
|
|
hide[#here_abs.abs #page.height rel: #here_rel%]
|
|
pagebreak(weak: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
[
|
|
#set text(size: sizes.at(2))
|
|
#v(sizes.at(0))
|
|
#if it.numbering != none [
|
|
#counter(heading).display(it.numbering) #h(4pt) #it.body
|
|
] else [#it.body]
|
|
#v(sizes.at(1))
|
|
]
|
|
}
|
|
// Alternative formating for headdings
|
|
// #show heading: it => {
|
|
// v(1em)
|
|
// if it.numbering != none {
|
|
// grid(
|
|
// columns: (auto, auto),
|
|
// {
|
|
// numbering(it.numbering, ..counter(heading).at(it.location()))
|
|
// h(24pt / it.level)
|
|
// },
|
|
// it.body,
|
|
// )
|
|
// } else {
|
|
// it.body
|
|
// }
|
|
// v(0.5em)
|
|
// }
|
|
// #show heading.where(level: 1): set text(size: 24pt)
|
|
// #show heading.where(level: 2): set text(size: 20pt)
|
|
// #show heading.where(level: 3): set text(size: 16pt)
|
|
|
|
// Style figure captions
|
|
// TODO: consider reenabling, broken
|
|
// #show figure : it => block(breakable: false)[
|
|
// #v(15pt, weak: true)
|
|
// #it.body
|
|
// #align(center)[
|
|
// // #v(.5em)
|
|
// #block(width: 80%, text(size: .9em)[
|
|
// #it.supplement #it.counter.display(it.numbering):
|
|
// #emph(it.caption.text)
|
|
// ])
|
|
// #v(15pt)
|
|
// ]
|
|
// ]
|
|
|
|
// rename level 1 headings to "Chapter", otherwise "Section"
|
|
#set ref(supplement: it => {
|
|
if it.func() == heading {
|
|
if it.level == 1 {
|
|
selected_lang.chapter
|
|
} else {
|
|
selected_lang.section
|
|
}
|
|
} else {
|
|
it.supplement
|
|
}
|
|
})
|
|
|
|
// beginning of the document, render the title page
|
|
|
|
#set align(center)
|
|
|
|
// nice
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
align(center)[
|
|
#image(company.image, width: 69%)
|
|
],
|
|
align(center)[
|
|
#image(university.image, width: 69%)
|
|
],
|
|
)
|
|
#v(64pt)
|
|
|
|
#set par(justify: false)
|
|
#text(20pt)[*#title*]
|
|
#v(32pt)
|
|
#set par(justify: true)
|
|
|
|
#text(16pt)[*#type*]
|
|
#v(16pt)
|
|
|
|
#text(14pt, selected_lang.degree_1)
|
|
|
|
#text(14pt)[*#degree*]
|
|
|
|
#text(14pt)[#selected_lang.degree_2 #major]
|
|
#v(32pt)
|
|
|
|
#text(14pt, selected_lang.by)
|
|
|
|
#text(16pt)[*#author*]
|
|
#v(16pt)
|
|
|
|
#text(14pt)[#date.display("[day].[month].[year]")]
|
|
|
|
#set align(bottom)
|
|
|
|
#grid(
|
|
columns: (1fr, 0.5fr, 1fr),
|
|
align(left)[
|
|
*#selected_lang.time_period* \
|
|
*#selected_lang.student_id_course* \
|
|
*#selected_lang.company* \
|
|
*#selected_lang.supervisor*
|
|
],
|
|
none,
|
|
align(left)[
|
|
#time_period \
|
|
#student_id, #course \
|
|
#company.name \
|
|
#supervisor
|
|
],
|
|
)
|
|
|
|
#pagebreak()
|
|
#set align(top)
|
|
#set align(left)
|
|
|
|
// initially set the page numbering to roman
|
|
#set page(numbering: "I")
|
|
#counter(page).update(1)
|
|
|
|
// https://www.dhbw.de/fileadmin/user_upload/Dokumente/Broschueren_Handbuch_Betriebe/Infoblatt_Vertraulichkeit.pdf
|
|
// English by default
|
|
#if confidentiality_clause {
|
|
selected_lang.confidentiality_clause
|
|
pagebreak(weak: true)
|
|
}
|
|
|
|
// render the abstract aligned to the center of the page
|
|
#set align(horizon)
|
|
#set align(center)
|
|
|
|
#heading(outlined: true, selected_lang.abstract)
|
|
|
|
#block(width: 70%)[#abstract]
|
|
|
|
#pagebreak()
|
|
|
|
#set align(top)
|
|
#set align(start)
|
|
|
|
#(selected_lang.decleration)(type, title)
|
|
|
|
#v(48pt)
|
|
|
|
#university.location, #date.display("[day].[month].[year]")
|
|
// #v(48pt)
|
|
|
|
#box(width: 196pt, height: 40pt)[
|
|
#if signature == "hide" {
|
|
box(height: 50pt)
|
|
} else if signature == none {
|
|
[
|
|
Set your signature by setting the `signature` argument
|
|
to an image or set it to `hide`, to leave place for signing otherwise
|
|
#v(2pt)
|
|
]
|
|
} else {
|
|
image(signature)
|
|
}
|
|
#v(0pt, weak: true)
|
|
#line(length: 100%)
|
|
#author
|
|
]
|
|
|
|
#pagebreak()
|
|
|
|
= #selected_lang.contents
|
|
|
|
#locate(loc => {
|
|
let headings = query(heading, loc)
|
|
let before_content = true
|
|
let after_content = false
|
|
|
|
for elem in headings {
|
|
// kind of hacky, we track whether the main document has started by looking for a chapter by name
|
|
if elem.body == [#first_chapter_title] {
|
|
before_content = false
|
|
}
|
|
|
|
// similarly, track the end of the main content by the position of the "Bibliography" chapter
|
|
if elem.body == [#selected_lang.bibliography] {
|
|
after_content = true
|
|
}
|
|
|
|
// page numbers of the main document are arabic, the first pages are roman
|
|
let index_fmt = if before_content {
|
|
"I"
|
|
} else {
|
|
"1"
|
|
}
|
|
|
|
let location = elem.location()
|
|
let page_index = counter(page).at(location).at(0)
|
|
|
|
let formatted_index = numbering(index_fmt, page_index)
|
|
|
|
// only the main content should be numbered
|
|
let formatted_name = if before_content or after_content {
|
|
elem.body
|
|
} else [
|
|
#numbering("1.1", ..counter(heading).at(location))
|
|
#h(4pt)
|
|
#elem.body
|
|
]
|
|
|
|
let is_chapter = elem.level == 1
|
|
|
|
// indent headings in the table of contents based on their level
|
|
let indent = if is_chapter {
|
|
0pt
|
|
} else if elem.level == 2 {
|
|
2em
|
|
} else {
|
|
4em
|
|
}
|
|
|
|
// non-chapter headings have their line filled with dots
|
|
let spacer = if is_chapter { " " } else { " . " }
|
|
|
|
// if elem.body != [#selected_lang.abstract] and elem.outlined != false {
|
|
if elem.outlined != false {
|
|
link(
|
|
location,
|
|
[
|
|
#h(indent)
|
|
// add extra spacing between chapters
|
|
#if is_chapter {v(1pt)}
|
|
// chapters are bold, sections are not
|
|
#if is_chapter [*#formatted_name*] else [#formatted_name]
|
|
#box(width: 1fr, repeat(spacer))
|
|
#h(8pt)
|
|
#if is_chapter [*#formatted_index*] else [#formatted_index] \
|
|
],
|
|
)
|
|
}
|
|
}
|
|
})
|
|
|
|
// #outline(target: heading.)
|
|
|
|
// #show outline.entry.where(
|
|
// level: 1
|
|
// ): it => {
|
|
// v(12pt, weak: true)
|
|
// strong(it)
|
|
// }
|
|
|
|
// #outline(target: heading, depth: 3, indent: 2em, fill: repeat(" . "))
|
|
|
|
#pagebreak()
|
|
|
|
// start adding headings to the outline after the table of contents
|
|
#set heading(outlined: true)
|
|
|
|
#show outline.entry: it => [
|
|
#v(12pt, weak: true) #it
|
|
]
|
|
|
|
// List of figures
|
|
= #selected_lang.list_of_figures
|
|
#outline(target: figure, title: none, fill: repeat(" . "))
|
|
|
|
#pagebreak()
|
|
|
|
= #selected_lang.acronyms
|
|
|
|
#let acroArr = ();
|
|
#for (k, v) in acronyms.pairs().sorted(key: s => lower(s.at(0))) {
|
|
acroArr.push([*#k* #label(k)]);
|
|
acroArr.push([#v]);
|
|
}
|
|
|
|
#table(
|
|
columns: (1fr, 6fr),
|
|
align: horizon,
|
|
stroke: none,
|
|
..acroArr,
|
|
)
|
|
|
|
#pagebreak(weak: true)
|
|
|
|
// update heading and page numberings to begin the main part of the document
|
|
#set heading(numbering: "1.1")
|
|
#set page(numbering: "1 / 1")
|
|
#counter(page).update(1)
|
|
|
|
// the actual chapters
|
|
#body
|
|
|
|
// finally, include the bibliography chapter at the end of the document
|
|
#pagebreak()
|
|
#if appendix != none [
|
|
#pagebreak(weak: true)
|
|
#heading(numbering: none, selected_lang.appendix)
|
|
#set heading(
|
|
outlined: true,
|
|
bookmarked: true,
|
|
numbering: (..nums) => {
|
|
let n = nums.pos()
|
|
n.remove(0)
|
|
return numbering("A.1", ..n)
|
|
}
|
|
)
|
|
#appendix
|
|
]
|
|
]
|
|
|
|
// `pref` if to prefer the long form
|
|
// may be normal, short or long
|
|
#let acro(short, pref: "normal", append: "") = {
|
|
let item = acronyms.at(short)
|
|
|
|
locate(loc => {
|
|
let entries = acroStates.at(loc).filter(e => e == short);
|
|
|
|
// Already used once
|
|
if entries.len() > 0 {
|
|
if pref == "long" {
|
|
link(label(short))[#item#append]
|
|
} else {
|
|
link(label(short))[#short#append]
|
|
}
|
|
// First usage
|
|
} else {
|
|
acroStates.update(e => {e.push(short); e;});
|
|
if pref == "short" {
|
|
link(label(short))[#short#append (#item)]
|
|
} else {
|
|
link(label(short))[#item#append (#short)]
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
#let acroOnce(main, inside) = [#main (#inside)]
|
|
|
|
#let todo(content) = par(emph([
|
|
#h(5pt) #text(weight: "bold")[To-do/WIP:] #content
|
|
]))
|