From 39a33e327bc9748762d7cd33037cf3ed5610759f Mon Sep 17 00:00:00 2001 From: Sven Vogel Date: Mon, 8 Jul 2024 13:49:04 +0200 Subject: [PATCH] added: custom glossarium theme --- src/glossarium.typ | 220 ++++++++++++++++++++++++++++++++++++++++++ src/lib.typ | 9 +- src/pages/outline.typ | 12 +-- src/requirements.typ | 2 +- template/glossary.typ | 10 +- template/main.typ | 1 + 6 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 src/glossarium.typ diff --git a/src/glossarium.typ b/src/glossarium.typ new file mode 100644 index 0000000..5fb8bae --- /dev/null +++ b/src/glossarium.typ @@ -0,0 +1,220 @@ +// .--------------------------------------------------------------------------. +// | Glossarium@4.1.0 with custom format | +// '--------------------------------------------------------------------------' + +// Authors: ENIB-Community +// Changed: Sven Vogel +// Edited: 08.07.2024 +// License: MIT + +// Customized version of https://github.com/ENIB-Community/glossarium/tree/release-0.4.1 +// in order to conform to DHBW requirements in terms of format + +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +// glossarium figure kind +#let __glossarium_figure = "glossarium_entry" +// prefix of label for references query +#let __glossary_label_prefix = "glossary:" +// global state containing the glossary entry and their location +#let __glossary_entries = state("__glossary_entries", (:)) + +#let __glossarium_error_prefix = "glossarium error : " + +#let __query_labels_with_key(loc, key, before: false) = { + if before { + query( + selector(label(__glossary_label_prefix + key)).before(loc, inclusive: false), + loc, + ) + } else { + query(selector(label(__glossary_label_prefix + key)), loc) + } +} + +// key not found error +#let __not-found-panic-error-msg(key) = { + __glossarium_error_prefix+"key '"+key+"' not found" +} + +// Reference a term +#let gls(key, suffix: none, long: none, display: none) = { + context { + let __glossary_entries = __glossary_entries.final(here()) + if key in __glossary_entries { + let entry = __glossary_entries.at(key) + + let gloss = __query_labels_with_key(here(), key, before: true) + + let is_first = gloss == () + let entlong = entry.at("long", default: "") + let textLink = if display != none { + [#display] + } else if (is_first or long == true) and entlong != [] and entlong != "" and long != false { + [#entlong (#entry.short#suffix)] + } else { + [#entry.short#suffix] + } + + [#link(label(entry.key), textLink)#label(__glossary_label_prefix + entry.key)] + } else { + panic(__not-found-panic-error-msg(key)) + } + } +} + +// Reference to term with pluralisation +#let glspl(key, long: none) = { + let suffix = "s" + context { + let __glossary_entries = __glossary_entries.final(here()) + if key in __glossary_entries { + let entry = __glossary_entries.at(key) + + let gloss = __query_labels_with_key(here(), key, before: true) + + let is_first = gloss == () + let entlongplural = entry.at("longplural", default: ""); + let entlong = if entlongplural == [] or entlongplural == "" { + // if the entry long plural is not provided, then fallback to adding 's' suffix + let entlong = entry.at("long", default: ""); + if entlong != [] and entlong != "" { + [#entlong#suffix] + } else { + entlong + } + } else { + [#entlongplural] + } + + let entplural = entry.at("plural", default: ""); + let short = if entplural == [] or entplural == "" { + [#entry.short#suffix] + } else { + [#entplural] + } + + let textLink = if (is_first or long == true) and entlong != [] and entlong != "" and long != false { + [#entlong (#short)] + } else { + [#short] + } + + [#link(label(entry.key), textLink)#label(__glossary_label_prefix + entry.key)] + } else { + panic(__not-found-panic-error-msg(key)) + } + } +} + +// show rule to make the references for glossarium +#let make-glossary(body) = { + show ref: r => { + if r.element != none and r.element.func() == figure and r.element.kind == __glossarium_figure { + // call to the general citing function + gls(str(r.target), suffix: r.citation.supplement) + } else { + r + } + } + body +} + +#let __normalize-entry-list(entry_list) = { + let new-list = () + for entry in entry_list { + new-list.push(( + key: entry.key, + short: entry.short, + plural: entry.at("plural", default: ""), + long: entry.at("long", default: ""), + longplural: entry.at("longplural", default: ""), + desc: entry.at("desc", default: ""), + group: entry.at("group", default: ""), + )) + } + return new-list +} +#let print-glossary( + entry_list, + show-all: false, + disable-back-references: false, + enable-group-pagebreak: false, +) = { + let entries = __normalize-entry-list(entry_list) + __glossary_entries.update(x => { + for entry in entry_list { + x.insert(entry.key, entry) + } + + x + }) + + let groups = entries.map(x => x.at("group")).dedup() + + for group in groups.sorted() { + if group != "" [#heading(group, level: 1, outlined: false) ] + for entry in entries.sorted(key: x => x.key) { + if entry.group == group { + [ + #show figure.where(kind: __glossarium_figure): it => it.caption + #figure( + supplement: "", + kind: __glossarium_figure, + numbering: none, + caption: { + context { + let term_references = __query_labels_with_key(here(), entry.key) + if term_references.len() != 0 or show-all { + let desc = entry.at("desc", default: "") + let long = entry.at("long", default: "") + let hasLong = long != "" and long != [] + let hasDesc = desc != "" and desc != [] + grid( + columns: 2, + column-gutter: 1em, + text(weight: "bold", entry.short), + { + if hasLong { + text(weight: "bold", entry.long) + } + if hasLong and hasDesc [:] + if hasDesc [ #desc ] else [. ] + if disable-back-references != true { + term_references.map(x => x.location()).sorted(key: x => x.page()).fold( + (values: (), pages: ()), + ((values, pages), x) => if pages.contains(x.page()) { + (values: values, pages: pages) + } else { + values.push(x) + pages.push(x.page()) + (values: values, pages: pages) + }, + ).values.map(x => { + let page-numbering = x.page-numbering(); + if page-numbering == none { + page-numbering = "1" + } + link(x)[#numbering(page-numbering, ..counter(page).at(x))] + } + ).join(", ") + } + } + ) + } + } + }, + )[] #label(entry.key) + #parbreak() + ] + } + } + if enable-group-pagebreak { pagebreak(weak: true) } + } +}; \ No newline at end of file diff --git a/src/lib.typ b/src/lib.typ index 0f7b87b..b61dcb8 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -19,6 +19,10 @@ #import "pages/preface.typ": new-preface #import "pages/appendix.typ": show-appendix +#let group-break()= { + [#pagebreak()] +} + // start of template pages and styles #let dhbw-template(config, body) = [ #let config = validate-config(config) @@ -54,16 +58,15 @@ // 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 + #import "glossarium.typ": * #show: make-glossary #pagebreak(weak: true) #if "glossary" in config.thesis and config.thesis.glossary != none { - heading(supplement: [outline], "Glossar") - print-glossary( disable-back-references: true, + enable-group-pagebreak: true, config.thesis.glossary) pagebreak(weak: true) diff --git a/src/pages/outline.typ b/src/pages/outline.typ index 328c17f..fb98477 100644 --- a/src/pages/outline.typ +++ b/src/pages/outline.typ @@ -19,7 +19,7 @@ if count > 0 { pagebreak(weak: true) outline( - title: heading(level: 3, title), + title: title, target: figure.where(kind: kind)) } } @@ -63,8 +63,8 @@ pagebreak(weak: true) outline( - target: heading.where(supplement: [chapter]), - title: heading(level: 3, title), + target: heading, + title: title, indent: auto) } @@ -85,7 +85,7 @@ pagebreak(weak: true) outline( target: heading.where(supplement: supplement), - title: heading(level: 3, title), + title: title, indent: auto) } } @@ -100,6 +100,8 @@ strong(it) } + render_heading_outline() + render_figures_outline() render_table_outline() @@ -107,6 +109,4 @@ render_raw_outline() render_appendix_outline() - - render_heading_outline() } \ No newline at end of file diff --git a/src/requirements.typ b/src/requirements.typ index cfb5a0a..d3a8824 100644 --- a/src/requirements.typ +++ b/src/requirements.typ @@ -7,4 +7,4 @@ // Edited: 05.07.2024 // License: MIT -#import "@preview/glossarium:0.4.1": * \ No newline at end of file +#import "glossary.typ": * \ No newline at end of file diff --git a/template/glossary.typ b/template/glossary.typ index 2d4bd01..9afb9c1 100644 --- a/template/glossary.typ +++ b/template/glossary.typ @@ -4,12 +4,14 @@ key: "oidc", short: "OIDC", long: "OpenID Connect", - desc: [OpenID is an open standard and decentralized authentication protocol promoted by the non-profit #link("https://en.wikipedia.org/wiki/OpenID#OpenID_Foundation")[OpenID Foundation].] + desc: [OpenID is an open standard and decentralized authentication protocol promoted by the non-profit #link("https://en.wikipedia.org/wiki/OpenID#OpenID_Foundation")[OpenID Foundation].], + group: "Akronyme" ), ( key: "potato", - short: "potato", + short: "EDDI/EDDP", plural: "potatoes", - desc: [#lorem(10)] - ), + desc: [#lorem(10)], + group: "Akronyme" + ) ) diff --git a/template/main.typ b/template/main.typ index 6fd0c24..41ab1de 100644 --- a/template/main.typ +++ b/template/main.typ @@ -38,6 +38,7 @@ #lorem(25) @oidc +@potato #lorem(100) @Anhang-A