From 40bf0af544d4adb4f8c9e734ec98815cc3dfdc77 Mon Sep 17 00:00:00 2001 From: teridax Date: Tue, 2 Jul 2024 10:57:38 +0200 Subject: [PATCH] feat: added default configuration and configuration validation --- src/conf.typ | 80 +++++++++++++++++++++++++ src/lib.typ | 41 +++++-------- src/pages/abstract.typ | 2 + src/pages/confidentiality-statement.typ | 2 + src/pages/declaration-of-authorship.typ | 2 + src/pages/outline.typ | 4 +- src/pages/prerelease-note.typ | 2 + src/requirements.typ | 1 + src/style.typ | 75 +++++++++++------------ 9 files changed, 146 insertions(+), 63 deletions(-) create mode 100644 src/requirements.typ diff --git a/src/conf.typ b/src/conf.typ index 728de8c..e0aede3 100644 --- a/src/conf.typ +++ b/src/conf.typ @@ -6,3 +6,83 @@ // Author: Sven Vogel // Edited: 27.06.2024 // License: MIT + +// default configuration +#let default-config = ( + lang: "en", + region: "en", + author: ( + name: "Sven Vogel", + semester: 4, + program: "Informationtechnology", + course: "TINF19IT1", + faculty: "Technik", + university: "DHBW Mannheim", + company: "ABB AG", + supervisor: "Benny Goodman", + matriculation-number: 123456789), + thesis: ( + title: "Unofficial ABB/DHBW Typst template", + subtitle: "for reports and thesises", + submission-date: "23rd march 2020", + timeframe: "1st january 2020 - 20th march 2020", + kind: "T2000", + summary: none, + abstract: none, + keywords: ( "IT", "other stuff" ), + bibliography: none /* bibliography("refs.bib") */, + glossary: none, + appendices: none), + style: ( + header: ( + bottom-padding: 1.5em, + underline-top-padding: 0pt, + logo-height: 3em), + page: ( + format: "a4", + margin: ( + left: 3cm, + right: 2.5cm, + top: 2.5cm, + bottom: 2.5cm)), + text: ( + size: 12pt, + font: "Open Sans"), + heading: ( + font: "Montserrat"), + link: ( + color: red.darken(15%)))) + +// Insert a dictionary `update` into `base` but only the entries of update that also exist in base +// Runs recursively on all sub dictionaries +#let deep-insert-checked(base, update) = { + if base == none { + panic("target dictionary is none") + } + + if update == none { + return base + } + + for (key, val) in base { + if key in update { + let update_val = update.at(key) + + if type(val) == dictionary and type(update_val) == dictionary { + base.insert(key, deep-insert-checked(val, update_val)) + } else if val == none or type(val) == type(update_val) { + base.insert(key, update_val) + } else { + panic("missmatched dictionary entry `" + key + "` type: expected `" + type(val) + "` got `" + type(update_val) + "`") + } + } else { + base.insert(key, val) + } + } + + return base +} + +#let validate-config(config) = { + return deep-insert-checked(default-config, config) +} diff --git a/src/lib.typ b/src/lib.typ index e038171..0ec9777 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -10,7 +10,17 @@ // start of template pages and styles #let dhbw-template(config: dictionary, body) = [ + #import "conf.typ": validate-config #import "style.typ": global_styled_doc, content_styled, end_styled + #import "pages/titlepage.typ": new_title_page + #import "pages/declaration-of-authorship.typ": new_declaration_of_authorship + #import "pages/confidentiality-statement.typ": new_confidentiality_statement_page + #import "pages/prerelease-note.typ": new_prerelease_note + #import "pages/outline.typ": new_outline + #import "pages/abstract.typ": new_abstract + #import "pages/appendix.typ": show-appendix + + #let config = validate-config(config) #let doc = body @@ -23,41 +33,25 @@ // apply global style to every element in the argument content #global_styled_doc(config: config, body: [ - #import "pages/titlepage.typ": new_title_page - #import "pages/declaration-of-authorship.typ": new_declaration_of_authorship - #import "pages/confidentiality-statement.typ": new_confidentiality_statement_page - #import "pages/prerelease-note.typ": new_prerelease_note - #import "pages/outline.typ": new_outline - #import "pages/abstract.typ": new_abstract - #import "pages/appendix.typ": show-appendix - // configure text locale - #set text(lang: config.lang, region: config.region) + #set text( + lang: config.lang, + region: config.region) // preppend title page #new_title_page(config) // prelude includes: title, declaration of authorship, confidentiality statement, outline and abstract // these will have roman page numbers - - #pagebreak(weak: true) #new_declaration_of_authorship(config) - - #pagebreak(weak: true) #new_confidentiality_statement_page(config) - - #pagebreak(weak: true) #new_prerelease_note(config) - - #pagebreak(weak: true) #new_abstract(config) - - #pagebreak(weak: true) #new_outline() // glossary is built inline here because the links must be // exposed to the entire document - #import "@preview/glossarium:0.4.1": make-glossary, print-glossary, gls, glspl + #import "@preview/glossarium:0.4.1": make-glossary, print-glossary #show: make-glossary #pagebreak(weak: true) @@ -74,16 +68,13 @@ // mark end of prelude #metadata("prelude terminate") - #content_styled(config: config, body: [ - // code of document follows here - #doc - ]) + #content_styled(config: config, body: doc) #metadata("content terminate") #end_styled(config: config, body: [ // add bibliography if set - #if config.thesis.bibliography != none { + #if "bibliography" in config.thesis and config.thesis.bibliography != none { pagebreak(weak: true) set bibliography(style: "ieee") config.thesis.bibliography diff --git a/src/pages/abstract.typ b/src/pages/abstract.typ index 291561a..654f6b9 100644 --- a/src/pages/abstract.typ +++ b/src/pages/abstract.typ @@ -8,6 +8,8 @@ #let new_abstract(config) = context [ + #pagebreak(weak: true) + #let thesis = config.thesis #pagebreak(weak: true) diff --git a/src/pages/confidentiality-statement.typ b/src/pages/confidentiality-statement.typ index 4c508e3..2ee1d2b 100644 --- a/src/pages/confidentiality-statement.typ +++ b/src/pages/confidentiality-statement.typ @@ -1,6 +1,8 @@ #let new_confidentiality_statement_page(config) = context [ + #pagebreak(weak: true) + #let thesis = config.thesis #let author = config.author diff --git a/src/pages/declaration-of-authorship.typ b/src/pages/declaration-of-authorship.typ index 8b73a45..81fb1ed 100644 --- a/src/pages/declaration-of-authorship.typ +++ b/src/pages/declaration-of-authorship.typ @@ -1,6 +1,8 @@ #let new_declaration_of_authorship(config) = context [ + #pagebreak(weak: true) + #let thesis = config.thesis #let author = config.author diff --git a/src/pages/outline.typ b/src/pages/outline.typ index cb84f8b..1bde5f3 100644 --- a/src/pages/outline.typ +++ b/src/pages/outline.typ @@ -4,6 +4,7 @@ // can optionally insert a pagebreak after the outline // NOTE: will not render in case the listing is empty #let render_filtered_outline(title: str, kind: selector) = context { + let elems = query(figure.where(kind: kind), here()) let count = elems.len() @@ -82,8 +83,9 @@ } } - #let new_outline() = { + pagebreak(weak: true) + show outline.entry.where( level: 1, ): it => { diff --git a/src/pages/prerelease-note.typ b/src/pages/prerelease-note.typ index 967b062..3475346 100644 --- a/src/pages/prerelease-note.typ +++ b/src/pages/prerelease-note.typ @@ -1,6 +1,8 @@ #let new_prerelease_note(config) = context [ + #pagebreak(weak: true) + #let thesis = config.thesis #let author = config.author diff --git a/src/requirements.typ b/src/requirements.typ new file mode 100644 index 0000000..4b9b2b3 --- /dev/null +++ b/src/requirements.typ @@ -0,0 +1 @@ +#import "@preview/glossarium:0.4.1": * \ No newline at end of file diff --git a/src/style.typ b/src/style.typ index 19258ac..59eb04f 100644 --- a/src/style.typ +++ b/src/style.typ @@ -7,40 +7,38 @@ // Edited: 27.06.2024 // License: MIT -#let HeaderPaddingBottom = 1.5em -#let LogoHeight = 3em -#let HeaderUnderlinePaddingTop = 0pt - // global style of document -#let global_styled_doc(config: dictionary, body: content) = context [ - #let thesis = config.thesis +#let global_styled_doc(config: dictionary, body: content) = context { + let thesis = config.thesis + let style = config.style // set page geometry - // paper format of A4 - #set page( - paper: "a4", - margin: (left: 3cm, right: 2.5cm, top: 2.5cm, bottom: 2.5cm)) + // and paper format + set page( + paper: style.page.format, + margin: style.page.margin) - #set text( - size: 12pt, + set text( + size: style.text.size, ligatures: true, hyphenate: true, dir: ltr, - font: "Open Sans") + font: style.text.font) - #show heading: set text( - font: "Montserrat", + show heading: set text( + font: style.heading.font, weight: "semibold") - #set heading(supplement: [chapter]) + set heading(supplement: [chapter]) // Set header spacing - #show heading.where(level: 1): it => v(2em) + it + v(1em) - #show heading.where(level: 2): it => v(1em) + it + v(0.5em) - #show heading.where(level: 3): it => v(0.5em) + it + v(0.25em) + show heading.where(level: 1): it => v(2em) + it + v(1em) + show heading.where(level: 2): it => v(1em) + it + v(0.5em) + show heading.where(level: 3): it => v(0.5em) + it + v(0.25em) - #set raw(tab-size: 4, theme: "res/github.tmTheme") - #show raw.where(block: true): code => { + // set theme for code blocks + set raw(tab-size: 4, theme: "res/github.tmTheme") + show raw.where(block: true): code => { show raw.line: line => { text(fill: gray)[#line.number] h(1em) @@ -49,20 +47,23 @@ code } - #set block(spacing: 2em) - #set par( + set block(spacing: 2em) + set par( justify: true, first-line-indent: 1em, leading: 1em) - #show link: set text(fill: red.darken(15%)) - #show ref: set text(fill: red.darken(15%)) + // give links a color + show link: set text(fill: style.link.color) + show ref: set text(fill: style.link.color) - #set heading(numbering: none) - #set page( - header-ascent: HeaderUnderlinePaddingTop + HeaderPaddingBottom, + set heading(numbering: none) + set page( + header-ascent: style.header.underline-top-padding + style.header.bottom-padding, footer-descent: 1em, - margin: (top: 2.5cm + LogoHeight + HeaderUnderlinePaddingTop + HeaderPaddingBottom, bottom: 2.5cm + 1em), + margin: ( + top: style.page.margin.top + style.header.logo-height + style.header.underline-top-padding + style.header.bottom-padding, + bottom: style.page.margin.bottom + 1em), numbering: (..nums) => { let current-page = here().page() if current-page == 1{ @@ -84,9 +85,9 @@ // we need two, so make both half the page width columns: (50%, 50%), // left align logo of ABB - align(left, image("res/ABB.svg", height: LogoHeight)), + align(left, image("res/ABB.svg", height: style.header.logo-height)), // right align logo of DHBW - align(right, image("res/DHBW.svg", height: LogoHeight))) + align(right, image("res/DHBW.svg", height: style.header.logo-height))) } else if query().first().location().page() <= here().page() { let headers-before = query(selector(heading.where(numbering: "1.", level: 1)).before(here())) @@ -107,24 +108,24 @@ columns: (1fr, auto), align: (horizon, bottom), context [ _ #header-title _ ], - image("res/DHBW.svg", height: LogoHeight)) + image("res/DHBW.svg", height: style.header.logo-height)) - v(HeaderUnderlinePaddingTop - 1em) + v(style.header.underline-top-padding - 1em) line(length: 100%) } else { grid( columns: (1fr, auto), align: (horizon, bottom), context [ _ #config.thesis.title _ ], - image("res/DHBW.svg", height: LogoHeight) + image("res/DHBW.svg", height: style.header.logo-height) ) - v(HeaderUnderlinePaddingTop - 1em) + v(style.header.underline-top-padding - 1em) line(length: 100%) } }) - #body -] + body +} #let content_styled(config: dictionary, body: content) = [ #set heading(numbering: "1.")