Skip to content

MkNavs

A quick overview

All elements which can become part of the "website tree" inherit from [MkNode][mknodes.MkNode]

Simplified, there are basically 3 different MkNode types:

  • MkNavs, used to structure the pages into a hierarchy
  • Mkpages, used as a container for the markdown elements
  • MkNode elements, used to display the markdown itself (and in some cases HTML)

Given a random Element from a full website tree, this is how the path from root to leaf element could look like:

graph LR
  c058d3b["Root nav
  (MkNav)"]
  b343f32["Sub-nav
  (MkNav)"]
  9308f79["Page
  (MkPage)"]
  c049bd5["Container element
  (MkTabbed)"]
  042e872["Container element
  (MkAdmonition)"]
  251098c["Atomic markdown element
  (MkText)"]
  c058d3b --> b343f32
  b343f32 --> 9308f79
  9308f79 --> c049bd5
  c049bd5 --> 042e872
  042e872 --> 251098c

In essence: A path can contain one or more MkNavs, exactly one MkPage, and one or more (nested) MkNode Elements.

Info

Because of the Markdown elements being part of the tree, the elements can behave quite intelligently in some situations. For example, code blocks automatically set the correct amount of fence backticks. That way you cant get conflicts because of two blocks having the same fence backtick sequence. The same accounts for the new Block extensions from pymdownx, which uses / as fence character.

MkNavs: General information

MkNavs are nodes to represent "sections", perhaps comparable to a folder (with MkPages being files in this analogy). MkNavs can contain other MkNavs to construct a hierarchical website tree structure, as well as MkPages and MkLinks. MkPages can be "regular" child of an [MkNav][mknodes.MkNav], or an index page. Index pages are dedicated pages which are shown when a site nav menu item containing children is clicked, or for the website root.

Theme support for index pages

Index pages need specific theme support (like MkDocs-Material has) or the mkdocs-section-index plugin.

MkNav metadata

MkNavs (as well as MkPages) own a metadata object, which can be set via the [MkPage.metadata][mknodes.Metadata] attribute. That metadata is not really useful for the [MkNav][mknodes.MkNav] itself. The metadata gets propagated to the child pages though, and thus this mechanism can be helpful to set metadata for a complete website branch / section in one go. Metadata is also inherited from the parent MkNavs in case they have metadata set. In other words: Template / Metadata inheritance happens through the whole chain of MkNavs / MkPages, from top to bottom.

Further info

See the [Metadata][mknodes.Metadata] section, the MkDocs Documentation as well as the MkDocs-Material docs for further info.

MkNav templates

Similar to metadata, page templates can also be set for MkNavs. (small difference: attribute is called page_template for MkNavs instead of template for MkPages) Again, they are not used by the MkNavs itself, but propagate to all child pages / navs. You will find more details in later parts of the docs.

Here is a quick example to show how easy a new template can get set up. Compare this one-liner to the "regular" process of creating an HTML file (with no markdown support) in a subfolder separated from your actual content:

nav = MkNav()
nav.page_template.announce.content = "Display **Markdown** in announcement bar!"

In the case of MkDocs, Template HTMLs will get created temporarily during the build process and will get deleted after deployment / serving.

Static templates

Apart from "page templates", which apply to specific (groups of) MkPages, there are also "static" templates which are part of the [Theme][mknodes.theme.theme.Theme] object (or of a Theme subclass). That way you can for example populate the 404 error page easily with Markdown.

Using MkNavs

The very first element you get in MkNodes is the root nav. The root nav is the node which will contain all other nodes at the end of the tree building process, in a nested, hierarchical structure.

Technically, there are no differences between the root MkNav and any other "nested" MkNav, except that the root MkNav does not have a parent.

You can construct sub-MkNavs by [instantiating][mknodes.MkNav.__init__] them, by using [MkNav.add_nav][mknodes.MkNav.add_nav] or by using the decorator routing mechanism.

Besides getting created via decorated functions, MkNavs can also get populated via decorators.

nav = MkNav()  # this nav will get populated with a sub-nav

@nav.route.nav("Path to", "Nav", optional=kw_args):  # Arguments reflect the "path" of newly created nav.
def _(sub_nav: MkNav)  # naming these methods is rather pointless, so we'll just call them "_".
    sub_nav += ...  #  this sub_nav is created via decorator


@nav.route.page("My page"):  # Pages can get routed, too, of course.
...

Another way to populate MkNavs is by using the [NavParser][mknodes.navs.navparser.NavParser] (parse attribute of an MkNav) The NavParser allows to read SUMMARY.md files (known from mkdocs-literate-nav ), "pure" markdown-file / folder structures and more. There is also an experimental support for index.py routing files as a replacement for SUMMARY.md files.

nav = MkNav()  # this nav will get populated with the *SUMMARY.md* content
nav.parse.file("path/to/SUMMARY.md")

Index pages

"Index pages" (the index.md files of the root and the subfolders) are a special case when it comes to building the tree. Each MkNav has a dedicated slot for an index page.

nav.index_page = my_mkpage_instance

Alternatively, [MkNav.add_page][mknodes.MkNav.add_page] takes the keyword argument is_index:

index_page = nav.add_page(is_index=True, ...)

Build process

During the build process, MkNavs get converted to SUMMARY.md files. These will then get picked up by MkDocs afterwards in order to build the MkDocs nav tree.

Info

In the future, MkNavs (as well as MkPages) will likely get converted to MkDocs.structure instances directly without taking the extra route of becoming a physical file on the hard drive.

Subclasses

MkNodes also contains a special subclass of [MkNav][mknodes.MkNav] called [MkDoc][mknodes.MkDoc]. This node is responsible for creating API documentation in an easy way, using templates (to get in impression, this is the default template for documenting classes ). [MkDoc][mknodes.MkDoc] objects have methods to collect submodules / classes from the module you want to document. The collected modules / classes are passed through the template render process in order to create Markdown text. That text will get added automatically to the [MkDoc][mknodes.MkDoc] nav as an MkPage.

Page info
Code for this section
mknodes.manual.navs_section._
@nav.route.page(is_index=True)
def _(page: mk.MkPage):
    variables = dict(mknode_cls=mk.MkNav)
    page += mk.MkTemplate("navs/navs_index.jinja", variables=variables)
Resources
Resources(css=[],
          markdown_extensions={'attr_list': {},
                               'md_in_html': {},
                               'pymdownx.emoji': {'emoji_generator': <function to_svg at 0x7fd7a6931800>,
                                                  'emoji_index': <function twemoji at 0x7fd7a69316c0>},
                               'pymdownx.magiclink': {'repo': 'mknodes',
                                                      'repo_url_shorthand': True,
                                                      'user': 'phil65'},
                               'pymdownx.superfences': {'custom_fences': [{'class': 'mermaid',
                                                                           'format': <function fence_code_format at 0x7fd7a64dc220>,
                                                                           'name': 'mermaid'}]}},
          plugins=[],
          js=[],
          assets=[],
          packages=[])
Metadata
created:
  source_filename: /home/runner/work/mknodes/mknodes/mknodes/manual/navs_section.py
  source_function: null
  source_line_no: 14
template: SUMMARY.html
title: MkNavs