This is a simple example of what the future Modulhandbuch will look like. It’s hosted using Github pages:
https://vindaar.github.io/MHB_test
There is one “Modulhandbuch” for each degree and for each “Prüfungsordnung”. The list of current hand books is:
BSPHYSIK: B.Sc. of Physics (Prüfungsordngung of 2006)BSPHYSIK2: B.Sc. of Physics (Prüfungsordngung of 2014)MSPHYSIK: M.Sc. of Physics (Prüfungsordngung of 2006)MSPHYSIK: M.Sc. of Physics (Prüfungsordngung of 2014)MSASTRO: M.Sc. of Astrophysics (Prüfungsordngung of 2006)MSASTRO2: M.Sc. of Astrophysics (Prüfungsordngung of 2014)LVANDERE: Lehrveranstaltungen anderer Fächer- contains physics modules that may be taken by students as the first elective module (TODO: what’s the term for those modules?)
- contains physics modules people from other degrees might take
For each degree there is one subdirectory in the content directory
starting with mhb_<degree> where <degree> is the notation given above.
The structure of each Modulhandbuch is represented in a tree of directories
containing containing _index.md markdown files. For all courses there is
another subdirectory, which then again contains such a markdown file.
In Hugo these _index.md files are called list files, i.e. their goal normally
would be to list all posts found in a given directory. In our use case we
(ab-)use them to map our module / course structure directly to a Hugo structure.
TODO: an alternative / possibly an improvement would be to use a regular “post”
file (i.e. a named markdown file within a directory e.g. physik110, which
contains physik111.md).
An example tree as such looks like:
basti at void in ~/src/tinyIap/staticExample/content/docs/mhb_bsphysik ツ tree
.
├── _index.md
├── math140
│ ├── _index.md
│ └── math141
│ └── _index.md
├── math240
│ ├── _index.md
│ └── math241
│ └── _index.md
├── math340
│ ├── _index.md
│ └── math341
│ └── _index.md
├── physik110
│ ├── _index.md
│ ├── ph110.pdf
│ ├── physik111
│ │ └── _index.md
│ └── physik112
│ └── _index.md
...Each of these _index.md files itself is essentially empty, aside from a few
pieces of information about the name of the module/course and some optional
tags.
Consider the list file of the physik110 module:
+++
weight = 10
title = "physik110"
degree = "bsphysik"
tags = ["bsphysik", "physik110"]
categories = ["module"]
+++
{{< genModulePage >}}The part within the +++ is called the “front matter” in Hugo and it may
contain metadata about each file. The fact that it starts and stops using +++
indicates that the front matter body is written in TOML (Hugo supports TOML,
YAML, JSON and Org mode).
A short explanation of the fields present:
weight: the associated weight for this module. The weights are used to determine the order of the modules in the menu TODO: assign correct weights to all modules!title: The name of the module / coursedegree: the name of the degree in the notation from above (e.g.BSPHYSIK) in lowercase letterstags:- for modules: the degree and the module name
- for courses: the degree, the course name and its parent module
categories: the kind of this file: amoduleor acourse
Here the tags and categories fields are taxonomies in Hugo terms. These
essentially just create auto generated pages, which list all pages that have the
same value (same tag or same category). These two are default taxonomies,
additional ones can be added.
Finally, the line containing {{< genModulePage >}} is a Go text template used
for string interpolation, which Hugo is essentially built on top of by using
such string interpolation code to build HTML pages from individual snippets and
template functions.
In particular a template showing up in a markdown file is a Hugo shortcode (in
this case a custom shortcode).
From a programming perspective shortcodes and in general Go templates can be considered a crude programming language. A shortcode is a function, which can take arguments and returns markdown or HTML strings.
Shortcodes however are pretty restricted. The majority of Hugo templating is done via full HTML focussed templates (a Go library to build HTML using the above mentioned Go text templates).
- finish the above:
- partial templates: what are they, where are they
- distinguish genCoursePage and genModulePage
- give brief idea about how they work
- explain the data model
PDF generation is done using pandoc from the final HTML pages generated by Hugo.
Because these pages contain all sorts of additional information that is not of
interest for the PDF of a module/course. Therefore we extract the <article> tag
from each page and hand only that to pandoc.
To perform the tag extraction we use xmllint. For a given HTML file fname:
xmllint --nowarning --html --xpath '/html/body/main/div/article' <fname> 2> /dev/nullDue to some technically invalid tags (duplicates) in the generated HTML files,
we dump stderr.
Furthermore, the default TeX template used by pandoc uses a too wide
margin. The mhb_pandoc_template.latex file is a slightly modified version of
pandoc’s default TeX template (which can be extracted using pandoc -D latex)
with a margin of 2 cm.
Conversion of a single page is thus:
xmllint --nowarning --html --xpath '/html/body/main/div/article' <fname> | \
pandoc -f html -t latex --template mhb_pandoc_template.latex -o <outfile>.pdfwhich will generate an <outfile>.pdf of the module/course.
For the full command to generate all PDFs see the Github action workflow.
Just a few features I personally like, cause I would have enjoyed them back when I was a student or things that could improve the module handbook in some ways.
- working search functionality (yay!)
- multi language support for the full website, so one could in principle even offer e.g. the B.Sc. handbooks with English headers or the M.Sc. handbooks with German headers (and theoretically content of couse)
- KaTeX (similar to MathJax) for inline LaTeX equations (well, probably not too important for the module handbook, unless something in the descriptions)
- dark theme
Generate the table of contents from the database when converting to generate something like the following table of content.
UPDATE: We do not even have to manually generate the sub trees. Only the degrees have to be manually added. The rest is done automagically.
- [**B.Sc. Physik**]({{< relref "/docs/mhb_bsphysik" >}})
- [**M.Sc. Physics**]({{< relref "/docs/mhb_msphysik" >}})
- [**Module**]({{< relref "/docs/module" >}})
- [Modul 1]({{< relref "/docs/module/modul1" >}})
- [Course 1.1]({{< relref "/docs/module/modul1/course1" >}})
- [Course 1.2]({{< relref "/docs/module/modul1/course2" >}})
- [Modul 2]({{< relref "/docs/module/modul1" >}})
- [Course 2.1]({{< relref "/docs/module/modul1/course1" >}})where the module / course pages are generated in the same way as the PDF is currently.
Module / course structure is represented by the directory structure.
Each page has the actual content that is found in the PDF then.
PDF creation can be achieved reasonably well already with a default
pandoc call:
pandoc _index.md -o <module>.pdfwill create a single PDF for a module, which looks really good. See number 14 here:
for an idea how we might generate a full handbook for all pages
(e.g. we walk the content directory and append the content of each
found markdown file to a single one and use a custom TeX header). With
that we should be able to generate a beautiful PDF, which can then be
injected with things like the page of the overview etc using
pdfunite, pdftk or similar.