From cf0623407ca341d24bd397ce089430766735efaa Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Mon, 29 Jan 2024 12:43:38 -0500 Subject: [PATCH] docs: add support for badge shortcodes in documentation This will allow us to add little icons to various parts of the docs to denote when something is for a particular scheduler only. --- contrib/write-mkdocs | 1 - docs/_build/hooks.py | 125 ++++++++++++++++++++++++++++++++++++++++++ docs/assets/extra.css | 18 ++++++ mkdocs.yml | 6 +- 4 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 docs/_build/hooks.py diff --git a/contrib/write-mkdocs b/contrib/write-mkdocs index 67170e435..38bd08ae2 100644 --- a/contrib/write-mkdocs +++ b/contrib/write-mkdocs @@ -6,7 +6,6 @@ import sys from collections.abc import Callable import yaml - from bs4 import BeautifulSoup diff --git a/docs/_build/hooks.py b/docs/_build/hooks.py new file mode 100644 index 000000000..5246cd583 --- /dev/null +++ b/docs/_build/hooks.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python + +import posixpath +import re + +from re import Match +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import File, Files +from mkdocs.structure.pages import Page + + +def on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files: Files): + """ + This hook is called after the page's markdown is loaded from file and can be + """ + + def replace(match: Match): + badge_type, args = match.groups() + args = args.strip() + if badge_type == "version": + return _badge_for_version(args, page, files) + if badge_type == "scheduler": + return _badge_for_scheduler(args, page, files) + if type == "flag": + return flag(args, page, files) + + # Otherwise, raise an error + raise RuntimeError(f"Unknown shortcode: {badge_type}") + + return re.sub(r"", replace, markdown, flags=re.I | re.M) + + +def _badge(icon: str, text: str = "", badge_type: str = ""): + """ + Create badge + """ + classes = f"mdx-badge mdx-badge--{badge_type}" if badge_type else "mdx-badge" + text = f"{text}{{ data-preview='' }}" if text.endswith(")") else text + return "".join( + [ + f'', + *([f'{icon}'] if icon else []), + *([f'{text}'] if text else []), + "", + ] + ) + + +def _badge_for_scheduler(text: str, page: Page, files: Files): + """ + Create badge for scheduler + """ + + # Return badge + icon = "simple-docker" + if text in ["kubernetes", "k3s"]: + icon = "simple-kubernetes" + text = "k3s" + elif text == "nomad": + icon = "simple-nomad" + elif text in ["docker", "docker-local"]: + icon = "simple-docker" + text = "docker-local" + + href = f"https://dokku.com/docs/deployment/schedulers/{text}/" + return _badge( + icon=f"[:{icon}:]({href} '{text}')", + text=f"[{text}]({href})", + ) + + +def _badge_for_version(text: str, page: Page, files: Files): + """ + Create badge for version + """ + + # Return badge + icon = "material-tag-outline" + href = f"https://github.com/dokku/dokku/releases/tag/v{text}" + return _badge( + icon=f"[:{icon}:]({href} 'Since {text}')", + text=f"[{text}]({href})", + ) + + +def flag(args: str, page: Page, files: Files): + """ + Create flag + """ + + flag_type, *_ = args.split(" ", 1) + if flag_type == "experimental": + return _badge_for_experimental(page, files) + raise RuntimeError(f"Unknown flag type: {flag_type}") + + +def _badge_for_experimental(page: Page, files: Files): + """ + Create badge for experimental + """ + + icon = "material-flask-outline" + href = _resolve_path("conventions.md#experimental", page, files) + return _badge(icon=f"[:{icon}:]({href} 'Experimental')") + + +def _resolve_path(path: str, page: Page, files: Files): + """ + Resolve path of file relative to given page - the posixpath always includes + one additional level of `..` which we need to remove + """ + + path, anchor, *_ = f"{path}#".split("#") + path = _resolve(files.get_file_from_path(path), page) + return "#".join([path, anchor]) if anchor else path + + +def _resolve(file: File, page: Page): + """ + Resolve path of file relative to given page - the posixpath always includes + one additional level of `..` which we need to remove + """ + + path = posixpath.relpath(file.src_uri, page.file.src_uri) + return posixpath.sep.join(path.split(posixpath.sep)[1:]) diff --git a/docs/assets/extra.css b/docs/assets/extra.css index d52a3ca82..c9ff785f5 100644 --- a/docs/assets/extra.css +++ b/docs/assets/extra.css @@ -3,3 +3,21 @@ --md-primary-fg-color--light: #ECB7B7; --md-primary-fg-color--dark: #90030C; } + +.md-typeset .mdx-badge { + font-size: .80em; +} + +.md-typeset .mdx-badge__icon { + background: var(--md-accent-fg-color--transparent); + padding: 0.2rem; + border-top-left-radius: 0.1rem; + border-bottom-left-radius: 0.1rem +} + +.md-typeset .mdx-badge__text { + box-shadow: 0 0 0 1px inset var(--md-accent-fg-color--transparent); + padding: 0.2rem 0.3rem; + border-bottom-right-radius: 0.1rem; + border-top-right-radius: 0.1rem; +} diff --git a/mkdocs.yml b/mkdocs.yml index 00e40cc96..2bff8a2d2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,8 +8,8 @@ markdown_extensions: - md_in_html - pymdownx.details - pymdownx.emoji: - emoji_generator: !!python/name:materialx.emoji.to_svg - emoji_index: !!python/name:materialx.emoji.twemoji + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg - pymdownx.highlight: anchor_linenums: true - pymdownx.inlinehilite @@ -47,6 +47,8 @@ extra: link: https://dokku.dpdcart.com/cart/add?product_id=217344&method_id=236878 version: provider: mike +hooks: + - docs/_build/hooks.py theme: custom_dir: docs/_overrides