diff options
Diffstat (limited to 'pysite')
-rw-r--r-- | pysite/rst/__init__.py | 4 | ||||
-rw-r--r-- | pysite/rst/directives/__init__.py | 69 | ||||
-rw-r--r-- | pysite/views/wiki/render.py | 2 |
3 files changed, 74 insertions, 1 deletions
diff --git a/pysite/rst/__init__.py b/pysite/rst/__init__.py index 744dd269..54dbba9c 100644 --- a/pysite/rst/__init__.py +++ b/pysite/rst/__init__.py @@ -1,8 +1,10 @@ import re from docutils.core import publish_parts +from docutils.parsers.rst.directives import register_directive from docutils.parsers.rst.roles import register_canonical_role +from pysite.rst.directives import ButtonDirective from pysite.rst.roles import icon_role, page_role, url_for_role RST_TEMPLATE = """.. contents:: @@ -97,3 +99,5 @@ def render(rst: str, link_headers=True): register_canonical_role("icon", icon_role) register_canonical_role("page", page_role) register_canonical_role("url_for", url_for_role) + +register_directive("button", ButtonDirective) diff --git a/pysite/rst/directives/__init__.py b/pysite/rst/directives/__init__.py index e69de29b..2df1d734 100644 --- a/pysite/rst/directives/__init__.py +++ b/pysite/rst/directives/__init__.py @@ -0,0 +1,69 @@ +import pprint + +from docutils import nodes +from docutils.parsers.rst import Directive +from docutils.parsers.rst.directives import unchanged, unchanged_required +from flask import url_for +from jinja2 import escape + +BUTTON_TYPES = ("default", "primary", "secondary", "danger", "darkish", "darker") + +ICON_WEIGHT_TABLE = { + "light": "fal", + "regular": "far", + "solid": "fas", + "branding": "fab" +} +ICON_WEIGHTS = tuple(ICON_WEIGHT_TABLE.values()) + + +class ButtonDirective(Directive): + has_content = True + + option_spec = { + "icon": unchanged_required, + "text": unchanged_required, + "type": unchanged, + "url": unchanged, + } + + def run(self): + pprint.pprint(self.__dict__) # DEBUG + + icon = self.options.get("icon", "") + button_type = self.options.get("type", "primary") + + text = self.options["text"] + url = self.options["url"] + + if icon: + parts = [escape(x) for x in icon.split("/")] + + if len(parts) != 2: + raise self.error("Icon specification must be in the form <type>/<name>") + elif parts: + weight = parts[0] + + if weight not in ICON_WEIGHTS: + weight = ICON_WEIGHT_TABLE.get(weight) + + if not weight: + raise self.error( + "Icon type must be one of light, regular, solid or " + "branding, or a font-awesome weight class" + ) + + icon_html = f"""<i class="uk-icon fa-fw {weight} fa-{parts[1]}"></i>""" + else: + icon_html = "" + + if button_type not in BUTTON_TYPES: + self.error(f"Button type must be one of {', '.join(BUTTON_TYPES[:-1])} or {[-1]}") + + if url.startswith("flask://"): + url = url_for(url.split("://", 1)[1]) + elif url.startswith("wiki://"): + url = url_for("wiki.page", page=url.split("://", 1)[1]) + html = f"""<a class="uk-button uk-button-{button_type}" href=\"{url}\">{icon_html} {text}</a>""" + + return [nodes.raw(html, html, format="html", **{})] diff --git a/pysite/views/wiki/render.py b/pysite/views/wiki/render.py index 40e5d3f4..39bdd133 100644 --- a/pysite/views/wiki/render.py +++ b/pysite/views/wiki/render.py @@ -13,7 +13,7 @@ SCHEMA = Schema([{ "data": str }]) -MESSAGE_REGEX = re.compile(r"<string>:(\d+): \([A-Z]+/\d\) (.*)") +MESSAGE_REGEX = re.compile(r"<string>:(\d+): \([A-Z]+/\d\) (.*)", flags=re.S) class RenderView(APIView): |