From f5be12555ca4946f563046de078435d2a65d09a1 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Sat, 24 Jan 2026 21:56:33 +0100 Subject: [PATCH 1/8] fix: download pictures from include scripts --- src/build.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/build.py b/src/build.py index 4b2dc6e..ceec83e 100644 --- a/src/build.py +++ b/src/build.py @@ -1,5 +1,6 @@ import json import random +import re import shutil from jinja2 import Environment, FileSystemLoader @@ -129,8 +130,7 @@ class Build: page_template = self.env.get_template("html/page.html") return page_template.render(content=content, course_wrapper=course_wrapper, sidebar=sidebar) - def __picture_handler(self, id): - self.config.p_build_pictures.mkdir(parents=True, exist_ok=True) + def __copy_picture(self, id): file = f"{id}.svg" try: shutil.copyfile(self.config.p_data_pictures / file, self.config.p_build_pictures / file) @@ -141,6 +141,10 @@ class Build: except FileNotFoundError: tqdm.write(f"\033[31mPicture #{id} not found\033[0m") + def __picture_handler(self, id): + self.config.p_build_pictures.mkdir(parents=True, exist_ok=True) + return self.__copy_picture(id) + def __photo_handler(self, id): self.config.p_build_photos.mkdir(parents=True, exist_ok=True) file = f"{id}.jpg" @@ -177,7 +181,11 @@ class Build: def __include_handler(self, include): with (self.config.p_data / "includes.json").open() as file: includes = json.load(file) - return includes.get(include) + code = includes.get(include) + svg_list = re.findall(r"(\d+)\.svg", code or "") + for id in svg_list: + self.__copy_picture(id) + return code # cached def __build_section( From 0d89da119ea399f12b3267f8cc4b4b38237824b0 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Mon, 9 Feb 2026 20:31:23 +0100 Subject: [PATCH 2/8] feature: thousand separators and exponent to support siunitx --- assets/latex.js | 208 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 143 insertions(+), 65 deletions(-) diff --git a/assets/latex.js b/assets/latex.js index bdf64c5..536b679 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -1,69 +1,147 @@ document.addEventListener("DOMContentLoaded", function() { - var macros = { - ",": (context) => context.future()?.text === " " ? "{\\char`,}" : "\\char`,", - "\\qty": "{#1\\,\\mathrm{#2}}", - "\\qtyrange": "{#1\\text{--}#2\\,\\mathrm{#3}}", - "\\unit": "{\\mathrm{#1}}", - "\\num": "{#1}", - "\\squared": "{^{2}}", - "\\cubed": "{^{3}}", - "\\per": "/", - "\\percent": "\\%", - "\\tera": "\\text{T}", - "\\giga": "\\text{G}", - "\\mega": "\\text{M}", - "\\kilo": "\\text{k}", - "\\dezi": "\\text{d}", - "\\centi": "\\text{c}", - "\\milli": "\\text{m}", - "\\micro": "\\text{μ}", - "\\nano": "\\text{n}", - "\\pico": "\\text{p}", - "\\kilogram": "\\text{kg}", - "\\gram": "\\text{g}", - "\\meter": "\\text{m}", - "\\second": "\\text{s}", - "\\hour": "\\text{h}", - "\\ampere": "\\text{A}", - "\\kelvin": "\\text{K}", - "\\mol": "\\text{mol}", - "\\bel": "\\text{B}", - "\\dezibel": "\\text{dB}", - "\\dB": "\\text{dB}", - "\\dBm": "\\text{dBm}", - "\\dBu": "\\text{dBu}", - "\\dBW": "\\text{dBW}", - "\\dBi": "\\text{dBi}", - "\\dBd": "\\text{dBd}", - "\\candela": "\\text{cd}", - "\\newton": "\\text{N}", - "\\hertz": "\\text{Hz}", - "\\pascal": "\\text{Pa}", - "\\volt": "\\text{V}", - "\\watt": "\\text{W}", - "\\joule": "\\text{J}", - "\\henry": "\\text{H}", - "\\farad": "\\text{F}", - "\\coulomb": "\\text{C}", - "\\ohm": "\\Omega", - "\\Ohm": "\\Omega", - "\\weber": "\\text{Wb}", - "\\tesla": "\\text{T}", - "\\bit": "\\text{b}", - "\\baud": "\\text{Bd}", - "\\degree": "^\\circ", - "\\degreeCelsius": "^\\circ\\text{C}", - }; + function formatThousands(input) { + + let s = String(input).trim(); + + // Extract exponent (e or E) and convert to \cdot 10^{...} + let exponent = ""; + const expMatch = s.match(/([eE])([+-]?\d+)$/); + if (expMatch) { + let expValue = expMatch[2]; + + // Remove leading "+" + if (expValue[0] === "+") { + expValue = expValue.slice(1); + } + + // Exponent numerisch prüfen + const expNum = parseInt(expValue, 10); + + // e0 → komplett unterdrücken + if (expNum !== 0) { + exponent = "\\cdot 10^{" + expNum + "}"; + } + + s = s.slice(0, -expMatch[0].length); + } + + // Sign + let sign = ""; + if (s[0] === "+" || s[0] === "-") { + sign = s[0]; + s = s.slice(1); + } + + // Find decimal point (last . or ,) + let intPart = s; + let fracSep = ""; + let fracDigits = ""; + const decMatch = s.match(/([.,])(\d+)$/); + if (decMatch) { + intPart = s.slice(0, decMatch.index); + fracSep = decMatch[1]; + fracDigits = decMatch[2]; + } + + // Thousand grouping in integer part + if (intPart.length >= 5) { + intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, "\\,"); + } + + // Thousand grouping in fractional part (from left in 3-digit blocks) + if (fracDigits.length >= 4) { + fracDigits = fracDigits.replace(/(\d{3})(?=\d)/g, "$1\\,"); + } + + // Reassemble + return res = sign + intPart + (fracDigits ? (fracSep + fracDigits) : "") + exponent; + } + + + var macros = { + ",": (context) => context.future()?.text === " " ? "{\\char`,}" : "\\char`,", + "\\num": (context) => { + const [arg] = context.consumeArgs(1); + const raw = arg.reverse().map(t => t.text).join(""); + return formatThousands(raw); + }, + "\\qty": (context) => { + const [numTok, unitTok] = context.consumeArgs(2); + const rawNum = numTok.reverse().map(t => t.text).join(""); + const unit = unitTok.reverse().map(t => t.text).join(""); + const formattedNum = formatThousands(rawNum); + return formattedNum + "\\,\\mathrm{" + unit + "}"; + }, + "\\qtyrange": (context) => { + const [aTok, bTok, unitTok] = context.consumeArgs(3); + const aRaw = aTok.reverse().map(t => t.text).join(""); + const bRaw = bTok.reverse().map(t => t.text).join(""); + const unit = unitTok.reverse().map(t => t.text).join(""); + const aFmt = formatThousands(aRaw); + const bFmt = formatThousands(bRaw); + return aFmt + "\\,\\text{--}\\," + bFmt + "\\,\\mathrm{" + unit + "}"; + }, + "\\unit": "{\\mathrm{#1}}", + "\\squared": "{^{2}}", + "\\cubed": "{^{3}}", + "\\per": "/", + "\\percent": "\\%", + "\\tera": "\\text{T}", + "\\giga": "\\text{G}", + "\\mega": "\\text{M}", + "\\kilo": "\\text{k}", + "\\dezi": "\\text{d}", + "\\centi": "\\text{c}", + "\\milli": "\\text{m}", + "\\micro": "\\text{μ}", + "\\nano": "\\text{n}", + "\\pico": "\\text{p}", + "\\kilogram": "\\text{kg}", + "\\gram": "\\text{g}", + "\\meter": "\\text{m}", + "\\second": "\\text{s}", + "\\hour": "\\text{h}", + "\\ampere": "\\text{A}", + "\\kelvin": "\\text{K}", + "\\mol": "\\text{mol}", + "\\bel": "\\text{B}", + "\\dezibel": "\\text{dB}", + "\\dB": "\\text{dB}", + "\\dBm": "\\text{dBm}", + "\\dBu": "\\text{dBu}", + "\\dBW": "\\text{dBW}", + "\\dBi": "\\text{dBi}", + "\\dBd": "\\text{dBd}", + "\\candela": "\\text{cd}", + "\\newton": "\\text{N}", + "\\hertz": "\\text{Hz}", + "\\pascal": "\\text{Pa}", + "\\volt": "\\text{V}", + "\\watt": "\\text{W}", + "\\joule": "\\text{J}", + "\\henry": "\\text{H}", + "\\farad": "\\text{F}", + "\\coulomb": "\\text{C}", + "\\ohm": "\\Omega", + "\\Ohm": "\\Omega", + "\\weber": "\\text{Wb}", + "\\tesla": "\\text{T}", + "\\bit": "\\text{b}", + "\\baud": "\\text{Bd}", + "\\degree": "^\\circ", + "\\degreeCelsius": "^\\circ\\text{C}", + }; + + renderMathInElement(document.body, { + delimiters: [ + { left: '$$', right: '$$', display: true }, // Note: $$ has to come before $ + { left: '$', right: '$', display: false }, + { left: '\\[', right: '\\]', display: true }, + { left: "\\(", right: "\\)", display: false }, + ], + throwOnError: false, + macros: macros + }); - renderMathInElement(document.body, { - delimiters: [ - {left: '$$', right: '$$', display: true}, // Note: $$ has to come before $ - {left: '$', right: '$', display: false}, - {left: '\\[', right: '\\]', display: true}, - {left: "\\(", right: "\\)", display: false}, - ], - throwOnError : false, - macros: macros - }); }); \ No newline at end of file From 314de951cfce0a8089044de28eb42302aa8b4a5b Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Mon, 9 Feb 2026 20:44:01 +0100 Subject: [PATCH 3/8] fix: short milli solves #67 --- assets/latex.js | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/latex.js b/assets/latex.js index 536b679..25c8999 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -94,6 +94,7 @@ document.addEventListener("DOMContentLoaded", function() { "\\dezi": "\\text{d}", "\\centi": "\\text{c}", "\\milli": "\\text{m}", + "\\m": "\\text{m}", "\\micro": "\\text{μ}", "\\nano": "\\text{n}", "\\pico": "\\text{p}", From 6cc779af89720beadf5944578ee8e659480d3f48 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Mon, 9 Feb 2026 20:45:35 +0100 Subject: [PATCH 4/8] fix: undo was not the problem for #67 --- assets/latex.js | 1 - 1 file changed, 1 deletion(-) diff --git a/assets/latex.js b/assets/latex.js index 25c8999..536b679 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -94,7 +94,6 @@ document.addEventListener("DOMContentLoaded", function() { "\\dezi": "\\text{d}", "\\centi": "\\text{c}", "\\milli": "\\text{m}", - "\\m": "\\text{m}", "\\micro": "\\text{μ}", "\\nano": "\\text{n}", "\\pico": "\\text{p}", From 0af159852c63bd42615b1abdd31a2382a1d1b902 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Wed, 11 Feb 2026 13:16:04 +0100 Subject: [PATCH 5/8] Update assets/latex.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- assets/latex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/latex.js b/assets/latex.js index 25c8999..a737e1c 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -55,7 +55,7 @@ document.addEventListener("DOMContentLoaded", function() { } // Reassemble - return res = sign + intPart + (fracDigits ? (fracSep + fracDigits) : "") + exponent; + return sign + intPart + (fracDigits ? (fracSep + fracDigits) : "") + exponent; } From 1419fad3788f8b1e89bdddc6b2751ec858225cac Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Wed, 11 Feb 2026 13:18:28 +0100 Subject: [PATCH 6/8] Update assets/latex.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- assets/latex.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/latex.js b/assets/latex.js index a737e1c..52512c8 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -15,10 +15,10 @@ document.addEventListener("DOMContentLoaded", function() { expValue = expValue.slice(1); } - // Exponent numerisch prüfen + // Parse exponent as a numeric value const expNum = parseInt(expValue, 10); - // e0 → komplett unterdrücken + // Suppress exponent if it is 0 (no \cdot 10^0 shown) if (expNum !== 0) { exponent = "\\cdot 10^{" + expNum + "}"; } From 4a4f6aaa78dfe763b112498f8ed1a7b8c881b382 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Sat, 14 Feb 2026 23:21:35 +0100 Subject: [PATCH 7/8] feature: degree special handling --- assets/latex.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/assets/latex.js b/assets/latex.js index 702ffba..85fbb1c 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -71,7 +71,11 @@ document.addEventListener("DOMContentLoaded", function() { const rawNum = numTok.reverse().map(t => t.text).join(""); const unit = unitTok.reverse().map(t => t.text).join(""); const formattedNum = formatThousands(rawNum); - return formattedNum + "\\,\\mathrm{" + unit + "}"; + if (unit.startsWith("\\degree")) { + return formattedNum + "\\mathrm{" + unit + "}"; + } else { + return formattedNum + "\\,\\mathrm{" + unit + "}"; + } }, "\\qtyrange": (context) => { const [aTok, bTok, unitTok] = context.consumeArgs(3); @@ -80,7 +84,11 @@ document.addEventListener("DOMContentLoaded", function() { const unit = unitTok.reverse().map(t => t.text).join(""); const aFmt = formatThousands(aRaw); const bFmt = formatThousands(bRaw); - return aFmt + "\\,\\text{--}\\," + bFmt + "\\,\\mathrm{" + unit + "}"; + if (unit.startsWith("\\degree")) { + return aFmt + "\\text{--}\\," + bFmt + "\\mathrm{" + unit + "}"; + } else { + return aFmt + "\\,\\text{--}\\," + bFmt + "\\,\\mathrm{" + unit + "}"; + } }, "\\unit": "{\\mathrm{#1}}", "\\squared": "{^{2}}", @@ -129,8 +137,7 @@ document.addEventListener("DOMContentLoaded", function() { "\\tesla": "\\text{T}", "\\bit": "\\text{b}", "\\baud": "\\text{Bd}", - "\\degree": "^\\circ", - "\\degreeCelsius": "^\\circ\\text{C}", + "\\degreeCelsius": "\\,\\degree\\text{C}", }; renderMathInElement(document.body, { From 236bfff1f4f0c7af72f4e6f11c2629c9bd1de4b8 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Sun, 15 Feb 2026 00:03:54 +0100 Subject: [PATCH 8/8] feature: include PM --- assets/latex.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/assets/latex.js b/assets/latex.js index 85fbb1c..1181000 100644 --- a/assets/latex.js +++ b/assets/latex.js @@ -26,9 +26,13 @@ document.addEventListener("DOMContentLoaded", function() { s = s.slice(0, -expMatch[0].length); } - // Sign + // Sign (+, -, \pm). Also accept "\\pm" (double-escaped backslash) and optional whitespace. let sign = ""; - if (s[0] === "+" || s[0] === "-") { + const pmMatch = s.match(/^(?:\\\\pm|\\pm)\s*/); + if (pmMatch) { + sign = "\\pm"; + s = s.slice(pmMatch[0].length); + } else if (s[0] === "+" || s[0] === "-") { sign = s[0]; s = s.slice(1); }