MkDocs¶
Like GitBook, MkDocs is a fast and simple static site generator with template, plugin and extension support. Documentation source files are written also in Markdown, and configured with a single YAML configuration file. MkDocs brings modern and customizable style, lots of possible extensions with powerful markdown interpretation.
This site use the material theme but others are possible, too. Material theme has responsive design and fluid layout for all kinds of screens and devices, designed to serve your project documentation in a user-friendly way in 34 languages with optimal readability. Some basic customization like primary and accent color, fonts... could be configured.
Also a collection of useful extensions are included here, too. So this is not only a description of the basics but presenting you a fully usable and optimal setup of it.
Install¶
Python 3 is already installed, so nothing to do.
On Debian the following steps should be enough to get it locally running:
sudo apt install build-essential python3-dev python3-pip python3-setuptools python3-wheel python3-cffi libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev shared-mime-info
Take care that you use python 3!
$ ll -al $(which python)
lrwxrwxrwx 1 root root 18 Mär 8 10:03 /usr/bin/python -> /usr/bin/python3.6*
If this points to python 2.7 you should change that on problems first.
Now you can install the python packages:
python -m pip install --upgrade pip
python -m pip install mkdocs
python -m pip install mkdocs-material
python -m pip install pymdown-extensions
python -m pip install markdown-blockdiag
python -m pip install markdown-include
python -m pip install mkdocs-with-pdf
You should be able to directly call mkdocs
on the console, now.
To make it accessible in path, add the following to ~/.bashrc
:
PATH=$PATH:~/.local/bin
And for the epub conversion you need to have calibre installed as package or using:
curl -sL https://download.calibre-ebook.com/linux-installer.sh | sudo -E bash -
Problems¶
mkdocs could not be installed
If the above won't install mkdocs
try to install some tools first:
sudo apt-get install python-setuptools
python -m pip install wheel
After that retry to install mkdocs
and it's extensions.
Problem with cairocffi
Maybe your cairocffi version is not matching and you get some errors like Requirement.parse('cairocffi>=0.9.0'), {'weasyprint'})
, then you can check your version like:
$ python -m pip show cairocffi
Name: cairocffi
Version: 0.9.0
...
To install a specific version use:
python -m pip uninstall cairocffi
python -m pip install cairocffi==1.0.1
Update¶
To later update your installation only call the following:
python -m pip install --upgrade pip
python -m pip install --upgrade mkdocs
python -m pip install --upgrade mkdocs-material
python -m pip install --upgrade pymdown-extensions
python -m pip install --upgrade markdown-blockdiag
python -m pip install --upgrade markdown-include
python -m pip install --UPGHRADE mkdocs-with-pdf
Preview Server¶
While you are working on the documentation and create new stuff it is often necessary to immediately see how it looks like. This is possible if you start an development server of mkdocs
using:
mkdocs serve # from within the project home
This will start an development server which automatically reloads on changes.
Build Documentation¶
To create the documentation in the site
sub folder use:
mkdocs build
Configuration¶
The setup is completely done in a mkdocs.yml
file within your project's root directory.
First some descriptive information for the site:
site_name: Alinex Development Guide
site_description: A book to learn modern web technologies.
site_author: Alexander Schilling
copyright: Copyright © 2016 - 2021 <a href="https://alinex.de">Alexander Schilling</a>
While the site_name
is used as heading the site_description
and site_author
goes into the meta data. And the copyright
line will be displayed in the footer with optional HTML links as seen above.
The navigation may be auto detected or defined using a navigation structure:
nav:
- Home:
- README.md
- alinex.md
- Languages:
- Overview: lang/README.md
- Markdown: lang/markdown.m
- Handlebars: lang/handlebars.md
Chapters can not contain a direct page. A title can be given for each page. If not the title setting at the top of each page is used or the first heading.
Now the theme definition, here we use the material theme as a basis:
theme:
name: material
icon:
logo: material/book-open-variant
favicon: assets/favicon.ico
language: en
palette:
scheme: slate
primary: grey
accent: dark orange
font:
text: Lato
code: Roboto Mono
features:
- navigation.instant
The logo
can be a name from the material icons (displayed on the top left beside the page heading). The favicon
has to be set to an image within the docs
folder.
If feature/tabs
is set the first level of navigation is put at tabs on the top.
repo_name: 'alinex/alinex.gitlab.io'
repo_url: 'https://gitlab.com/alinex/alinex.gitlab.io'
edit_uri: ''
Like shown in the image the repository will be displayed on the right and if no edit_uri: "...."
is given or set an icon to edit the page source is added, too. To prevent this in the example config edit_uri
is set to an empty string.
extra:
social:
- icon: material/gitlab
link: https://gitlab.com/alinex
- icon: material/github
link: https://github.com/alinex
- icon: material/home
link: https://alinex.de
The social links use the FontAwesome names as type with a link. They will be displayed at the bottom right corner of the page.
extra_css:
- assets/extra.css
With the extra_css
section you may add more stylesheets to the generated HTML which are used to:
- optimize the theme
- to be used with attributes
Such an CSS file may look like:
@import url("https://fonts.googleapis.com/css2?family=Oswald&display=swap");
/* use image for color theme */
body,
.md-header,
.md-footer,
.md-tabs {
/* background-image: url('blue-tunnel.jpg');*/
background-image: url("default.jpg");
background-size: cover;
background-attachment: fixed;
}
.md-container,
.md-search__inner {
background-color: rgba(0, 0, 0, 0.9);
}
.md-footer-nav,
.md-footer-meta {
background: transparent;
}
/* General style */
.md-typeset h1,
.md-tabs,
.md-header-nav__topic,
.md-sidebar {
font-family: "Oswald", sans-serif;
}
.md-tabs a {
font-size: 0.9rem;
}
.md-sidebar label {
font-size: 0.85rem;
}
.md-sidebar a {
font-size: 0.75rem;
margin-top: 0.4em;
}
.md-typeset h1 {
color: white;
}
.md-typeset__table th {
border-bottom: 2px solid darkorange;
font-weight: bold;
}
.md-typeset__table tr:nth-child(even) {
background: rgb(61, 61, 76);
}
.md-typeset table:not([class]) tr:nth-child(even):hover {
background-color: rgba(61, 61, 76, 0.035);
}
/* change link colors for grey theme */
.md-header-nav__button:hover {
opacity: 1;
color: darkorange;
transition: color 0.5s;
}
[data-md-color-primary="grey"] .md-typeset a {
color: #00ade2;
}
[data-md-color-primary="grey"] .md-typeset a:hover {
color: darkorange;
}
.md-nav__item .md-nav__link--active {
color: white;
}
.md-sidebar label,
.md-nav__item--nested > .md-nav__link,
.md-sidebar a {
color: gray;
}
.md-nav__link:hover {
color: darkorange;
}
.md-nav__link[data-md-state="blur"] {
color: rgb(180, 180, 180);
}
.md-nav__item .md-nav__link--active {
color: white;
}
.md-footer-nav__link {
font-weight: bold;
}
.md-footer-nav__link:hover {
opacity: 1;
color: darkorange;
transition: color 0.5s;
}
a.headerlink {
color: gray;
}
/* display external links with icon */
div.md-content a[href^="http://"]:not([href*="alinex.gitlab.io"]):after,
div.md-content a[href^="https://"]:not([href*="alinex.gitlab.io"]):after,
div.md-content a[href^="//"]:not([href*="alinex.gitlab.io"])
{
content: "↗";
font-weight: normal;
font-style: normal;
font-size: 70%;
vertical-align: top;
display: inline-block;
text-decoration: none;
}
/* attribute classes to be used via {: .class} */
.left {
/* left align with text float on the right */
float: left;
padding-right: 20px;
}
.right {
/* right align with text float on the left */
float: right;
padding-left: 20px;
}
.icon {
/* change image size */
width: 25%;
}
.border {
/* add drop shadow */
border: 1px solid #021a40;
-webkit-box-shadow: 0px 0px 18px 5px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 0px 0px 18px 5px rgba(0, 0, 0, 0.5);
box-shadow: 0px 0px 18px 5px rgba(0, 0, 0, 0.5);
}
/* special use tags ==...== */
mark,
.md-typeset mark {
background-color: rgb(255, 253, 130);
color: black;
font-weight: bold;
}
/* blockdiag */
img[src*="%3Ctitle%3Eblockdiag%3C"] {
background-color: lightgray;
}
And at last some plugins and extensions for more markdown possibilities like described below:
plugins:
- search
markdown_extensions:
- extra
- toc:
permalink: true
- pymdownx.caret
- pymdownx.tilde
- pymdownx.mark
- admonition
- pymdownx.details
- pymdownx.superfences
- pymdownx.tabbed
- codehilite:
guess_lang: false
linenums: false
- pymdownx.inlinehilite
- pymdownx.betterem:
smart_enable: all
- pymdownx.emoji:
emoji_generator: !!python/name:pymdownx.emoji.to_svg
- pymdownx.keys
- pymdownx.smartsymbols
- pymdownx.tasklist:
custom_checkbox: true
- markdown_blockdiag:
format: svg
- markdown_include.include
See the complete setup of this book.
If VS Code with the Prettier plugin is used, set the tab width to 4 spaces for correct Markdown formatting in MkDocs.
{
"MD007": { "indent": 4 },
"MD013": false,
"MD030": false,
"MD036": false,
"MD041": false,
"MD046": false
}
PDF and EPub¶
To create a PDF the following additions in mkdocs.yml
has to be made:
plugins:
- with-pdf:
cover_subtitle: Framework running powerful deep tests for standalone use or to enhance monitoring
cover_logo: https://assets.gitlab-static.net/uploads/-/system/project/avatar/12586261/images__1_.png
output_path: alinex-checkup.pdf
This will build the PDF, you can set more settings, see mkdocs-with-pdf.
An epub can be created using calibre, but the output is very ugly, so I won't do this at the moment.
ebook-convert site/$NAME.pdf site/$NAME.epub
In the setup below the documentation will be stored under
site/alinex-book.pdf
.
Allow Math¶
To enable math formulas, the following has to be added in mkdocs.yml
:
extra_javascript:
- assets/mathjax.js
- https://polyfill.io/v3/polyfill.min.js?features=es6
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
plugins:
- pymdownx.arithmatex:
generic: true
The mathjax.js
file has to contain:
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]],
processEscapes: true,
processEnvironments: true
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex"
}
};
Writing Documentation¶
Pages are written in markdown Format and stored as *.md
files within the doc
folder. The Markdown implementation is nearly
the same as used on GitHub but with some additions:
Navigation title¶
To set an alternative title within the navigation define it at YAML at the top:
title: Test Page
# Test
...
Simple Formats¶
Structure the text using headings:
# Heading 1
## Heading 2
### Heading 3
Blockquotes are done using >
signs:
> This is a block quote in which only the first line of the paragraph needs
> to be indented by `>` but it can also be done on each line.
This is a block quote in which only the first line of the paragraph needs to be indented by
>
but it can also be done on each line.
A horizontal line may be used to separate:
---
Use some inline text formatting:
Format | Example | Result |
---|---|---|
Italic | _Italic_ or *Italic* |
Italic |
Bold | __Bold__ or **Bold** |
Bold |
Superscript | H^2^O |
H2O |
Subscript | CH~3~CH~2~OH |
CH3CH2OH |
Insert | ^^Insert^^ |
Insert |
Delete | ~~Delete me~~ |
|
Mark | ==mark me== |
mark me |
Emoji | :smile: |
|
Code | `echo "Hello"` | echo "Hello" |
Code + Highlighting | `:::bash echo "Hello"` | echo "Hello" |
Keys | ++ctrl+alt+h++ |
Ctrl+Alt+H |
Link | [Text](http://my-site.com) |
Text |
Image |  |
![]() |
Image (Zoom) | {.tiny} |
![]() |
HTML¶
It is also possible to add HTML tags directly. But this should be done only if there is no other way around.
Example
To add SVG images with links they have to be put into <object>
tag:
<!--
To make this svg responsive add the following in svg:
preserveAspectRatio="xMinYMin meet" viewBox="0 0 {width} {height}"
-->
<object data="solutions.svg" type="image/svg+xml" width="100%">
{: .center}
</object>
Lists¶
Unordered list:
- water
- cola
- beer
- water
- cola
- beer
Ordered list:
1. select
2. take
3. buy
- select
- take
- buy
And finally a task list is also possible:
- [x] item 1
- [x] item A
- [ ] item B
more text
- [x] item a
- [ ] item b
- [x] item c
- [x] item C
- [ ] item 2
- [ ] item 3
- item 1
- item A
- item B
more text
- item a
- item b
- item c
- item C
- item 2
- item 3
Tables¶
Tables can have alignment:
| Left | Center | Right |
| :--- | :----: | ----: |
| one | two | three |
| 1 | 2 | 3 |
Left | Center | Right |
---|---|---|
one | two | three |
1 | 2 | 3 |
Block Messages¶
The Admonition extension configured above will allow to add text blocks.
!!! note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
The different types will look like:
Note
Type: note
, seealso
Abstract
Type: abstract
, summary
, tldr
Info
Type: info
, todo
Tip
Type: tip
, hint
, important
Success
Type: success
, check
, done
Question
Type: question
, help
, faq
Warning
Type: warning
, caution
, attention
Failure
Type: failure
, fail
, missing
Danger
Type: danger
, error
Bug
Type: bug
Example
Type: example
, snippet
Quote
Type: quote
, cite
The title can also be specified in double quotes behind the type or remove the title by setting ""
for title:
!!! note "Individual"
Individual
The PyMarkdown.Details
extension gives the same but as collapsible boxes:
??? note "Initially closed"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
???+ note "Initially opened"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Initially closed
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Initially opened
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Tabs¶
Using Tabbed groups as tabs can be defined:
=== "Bash"
```bash
#!/bin/bash
echo "Hello world!"
```
=== "Explanation"
This is only a short example of how to make tabs.
#!/bin/bash
echo "Hello world!"
This is only a short example of how to make tabs.
Code Blocks¶
CodeHilite
will help you in display code elements.
You have multiple options to specify the language of a code block:
```sql
SELECT count(*) FROM my_table;
```
SELECT count(*) FROM my_table;
Or by indention and using a shebang:
#!/bin/bash
grep $1 $2
#!/bin/bash
grep $1 $2
Or by indention and three colon start line:
:::bash
grep $1 $2
grep $1 $2
Using SuperFences specific lines can be highlighted by passing the line numbers to the hl_lines
argument placed right after the language identifier.
```python hl_lines="3 4"
""" Bubble sort """
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
```
""" Bubble sort """
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
Math¶
With the double dollar syntax math formulas can be added using the AsciiMath also MathML or LaTeX can be used.
$$
\operatorname{ker} f=\{g\in G:f(g)=e_{H}\}{\mbox{.}}
$$
Attention
This will currently not be interpreted in PDF and printed in source format.
Diagrams¶
Using the blockdiag module graphics can be aut generated out of text representations.
Simple Diagram:
Name the blocks and use arrows between them:
blockdiag {
// simple graph
A -> B -> C -> D;
A -> E -> F -> G;
}
Comments are also possible like shown in line 2. This will result in:
Style:
You can style nodes and edges:
blockdiag {
A [label = "foo"];
B [style = dotted];
C [style = dashed];
D [color = pink];
E [color = "#888888", textcolor="#FFFFFF"];
// Set labels to edges. (short text only)
A -> B [label = "click", textcolor="red"];
B -> C [style = dotted];
C -> D [style = dashed];
D -> E [color = "red"];
// Set numbered-badge to nodes.
F [numbered = 99];
G [label = "", background = "http://blockdiag.com/en/_static/python-logo.gif"];
H [thick];
// Set arrow direction to edges.
A -> F [dir = none];
F -> G [dir = forward];
B -> G [dir = back];
G -> H [dir = both];
C -> H [thick]
}
Branches and Direction:
blockdiag {
// branching edges to multiple children
A -> B, C;
D -> E <- F -- G <-> H;
}
Folding:
blockdiag {
A -> B -> C -> D -> E;
// fold edge at C to D (D will be layouted at top level; left side)
C -> D [folded];
}
Shapes:
blockdiag {
// standard node shapes
box [shape = box];
square [shape = square];
roundedbox [shape = roundedbox];
dots [shape = dots];
circle [shape = circle];
ellipse [shape = ellipse];
diamond [shape = diamond];
minidiamond [shape = minidiamond];
note [shape = note];
mail [shape = mail];
cloud [shape = cloud];
actor [shape = actor];
beginpoint [shape = beginpoint];
endpoint [shape = endpoint];
box -> square -> roundedbox -> dots;
circle -> ellipse -> diamond -> minidiamond;
note -> mail -> cloud -> actor;
beginpoint -> endpoint;
// node shapes for flowcharts
condition [shape = flowchart.condition];
database [shape = flowchart.database];
terminator [shape = flowchart.terminator];
input [shape = flowchart.input];
loopin [shape = flowchart.loopin];
loopout [shape = flowchart.loopout];
condition -> database -> terminator -> input;
loopin -> loopout;
// Set stacked to nodes.
stacked [stacked];
diamond [shape = "diamond", stacked];
database [shape = "flowchart.database", stacked];
stacked -> diamond -> database;
}
Groups:
Sorry, could not get this working in mkdocs
till now.
Classes:
blockdiag {
// Define class (list of attributes)
class emphasis [color = pink, style = dashed];
class redline [color = red, style = dotted];
A -> B -> C;
// Set class to node
A [class = "emphasis"];
// Set class to edge
A -> B [class = "redline"];
}
Portrait mode:
blockdiag {
orientation = portrait
A -> B -> C;
B -> D;
}
Abbreviations¶
Abbreviations are defined as an extra paragraph mostly at the end of the document:
The HTML specification
is maintained by the W3C.
_[HTML]: Hyper Text Markup Language
_[W3C]: World Wide Web Consortium
This will be rendered with a tooltip on each occurrence of this words:
The HTML specification is maintained by the W3C.
_[HTML]: Hyper Text Markup Language _[W3C]: World Wide Web Consortium
Combined with the later described
includes
it is also possible to place all abbreviations in a single file and include it at the end of each page.
Footnotes¶
The Footnote syntax follows the generally accepted syntax of the Markdown community. You add the footnote using [^1]
with the correct number and define the content of this footnote later:
Footnotes[^1] have a label[^@#$%] and the footnote's content.
[^1]: This is a footnote content.
[^@#$%]: A footnote on the label: "@#\$%".
This will look like:
Footnotes1 have a label2 and the footnote's content.
A footnote label must start with a caret ^
and may contain any inline text (including spaces) between a set of square brackets []
. Only the first caret has any special meaning.
A footnote content must start with the label followed by a colon and at least one space. The label used to define the content must exactly match the label used in the body (including capitalization and white space). The content would then follow the label either on the same line or on the next line. The content may contain multiple lines, paragraphs, code blocks, blockquotes and most any other markdown syntax. The additional lines must be indented one level (four spaces or one tab).
[^1]: The first paragraph of the definition.
Paragraph two of the definition.
> A blockquote with
> multiple lines.
a code block
A final paragraph.
Include¶
It is possible to include other markdown with a simple statement:
{ !.gitignore!}
No space after first curly brace to work!
This statement will be replaced by the contents of the given file. The include extension will work recursively, so any included files within will also be included. This replacement is done prior to any other Markdown processing, so any Markdown syntax that you want can be used within your included files.
The file path is relative to the project base (there mkdocs
is been executed).
Attributes¶
Using attributes it is possible to set the various HTML element's attributes for output. An example attribute list might look like this:
{: #someid .someclass somekey='some value' }
This shows the possible definitions:
- A word which starts with
#
will set the id of an element. - A word which starts with
.
will be added to the list of classes assigned to an element. - A key/value pair
somekey='some value'
will assign that pair to the element.
This can be set on block level elements if defined on the last line of the block by itself.
This is a paragraph.
{: #an_id .a_class }
The one exception is headers, as they are only ever allowed on one line. So there you neet to write:
### A hash style header ### {: #hash }
If used on inline elements the attributes are defined immediately after the element without any separation:
[link](http://example.com){: class="foo bar" title="Some title!" }
If classes are used you may define them in an additional CSS file.
GitLab CI¶
To get the documentation onto GitLab pages use the following configuration:
image: silentstorm/pandoc-mkdocs
before_script:
- pip install --upgrade pip
- pip install mkdocs-material
- pip install pymdown-extensions
- pip install markdown-blockdiag
- pip install markdown-include
- pip install mkdocs-with-pdf
pages:
stage: deploy
script:
- mkdocs build
- rm -rf public
- mv site public
artifacts:
paths:
- public
interruptible: true
Warning
The PDF generation is disabled here at the moment, because it will run in memory problems on gitlab.com.