diff options
-rw-r--r-- | pysite/rst/__init__.py | 5 | ||||
-rw-r--r-- | pysite/rst/roles.py | 37 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | static/css/pygments-monokai.css | 70 | ||||
-rw-r--r-- | templates/main/base.html | 1 | ||||
-rw-r--r-- | templates/wiki/base.html | 3 | ||||
-rw-r--r-- | templates/wiki/page_edit.html | 20 |
7 files changed, 129 insertions, 8 deletions
diff --git a/pysite/rst/__init__.py b/pysite/rst/__init__.py index 0e5f6ffe..815ad058 100644 --- a/pysite/rst/__init__.py +++ b/pysite/rst/__init__.py @@ -2,13 +2,14 @@ from docutils.core import publish_parts from docutils.parsers.rst.roles import register_canonical_role -from pysite.rst.roles import icon_role +from pysite.rst.roles import icon_role, url_for_role def render(rst: str): return publish_parts( - source=rst, writer_name="html5", settings_overrides={"halt_level": 2} + source=rst, writer_name="html5", settings_overrides={"halt_level": 2, "syntax_highlight": "short"} )["html_body"] register_canonical_role("icon", icon_role) +register_canonical_role("url_for", url_for_role) diff --git a/pysite/rst/roles.py b/pysite/rst/roles.py index bff00533..414832df 100644 --- a/pysite/rst/roles.py +++ b/pysite/rst/roles.py @@ -2,6 +2,7 @@ from docutils import nodes from docutils.parsers.rst.roles import set_classes from docutils.parsers.rst.states import Inliner +from flask import url_for from jinja2 import escape @@ -44,3 +45,39 @@ def icon_role(_role: str, rawtext: str, text: str, lineno: int, inliner: Inliner node = nodes.raw(html, html, format="html", **options) return [node], [] + + +def url_for_role(_role: str, rawtext: str, text: str, lineno: int, inliner: Inliner, + options: dict = None, _content: dict = None): + if options is None: + options = {} + + set_classes(options) + + if "/" in text: + parts = [escape(x) for x in text.split("/")] + else: + msg = inliner.reporter.error("URL specification must be in the form <page.name>/<text>", line=lineno) + prb = inliner.problematic(text, rawtext, msg) + + return [prb], [msg] + + if len(parts) != 2: + msg = inliner.reporter.error("URL specification must be in the form <page.name>/<text>", line=lineno) + prb = inliner.problematic(text, rawtext, msg) + + return [prb], [msg] + else: + try: + url = url_for(parts[0]) + name = parts[1] + + html = f"""<a href="{url}">{name}</a>""" + + node = nodes.raw(html, html, format="html", **options) + return [node], [] + except Exception as e: + msg = inliner.reporter.error(str(e), line=lineno) + prb = inliner.problematic(text, rawtext, msg) + + return [prb], [msg] diff --git a/requirements.txt b/requirements.txt index f7afea00..bb66b59d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,3 +11,4 @@ Flask-Dance logmatic-python flask-wtf docutils +pygments diff --git a/static/css/pygments-monokai.css b/static/css/pygments-monokai.css new file mode 100644 index 00000000..250c8d44 --- /dev/null +++ b/static/css/pygments-monokai.css @@ -0,0 +1,70 @@ +.code .hll { background-color: #49483e } +.code { background: #272822; color: #f8f8f2 } +.code .c { color: #75715e } /* Comment */ +.code .err { color: #960050; background-color: #1e0010 } /* Error */ +.code .k { color: #66d9ef } /* Keyword */ +.code .l { color: #ae81ff } /* Literal */ +.code .n { color: #f8f8f2 } /* Name */ +.code .o { color: #f92672 } /* Operator */ +.code .p { color: #f8f8f2 } /* Punctuation */ +.code .ch { color: #75715e } /* Comment.Hashbang */ +.code .cm { color: #75715e } /* Comment.Multiline */ +.code .cp { color: #75715e } /* Comment.Preproc */ +.code .cpf { color: #75715e } /* Comment.PreprocFile */ +.code .c1 { color: #75715e } /* Comment.Single */ +.code .cs { color: #75715e } /* Comment.Special */ +.code .gd { color: #f92672 } /* Generic.Deleted */ +.code .ge { font-style: italic } /* Generic.Emph */ +.code .gi { color: #a6e22e } /* Generic.Inserted */ +.code .gs { font-weight: bold } /* Generic.Strong */ +.code .gu { color: #75715e } /* Generic.Subheading */ +.code .kc { color: #66d9ef } /* Keyword.Constant */ +.code .kd { color: #66d9ef } /* Keyword.Declaration */ +.code .kn { color: #f92672 } /* Keyword.Namespace */ +.code .kp { color: #66d9ef } /* Keyword.Pseudo */ +.code .kr { color: #66d9ef } /* Keyword.Reserved */ +.code .kt { color: #66d9ef } /* Keyword.Type */ +.code .ld { color: #e6db74 } /* Literal.Date */ +.code .m { color: #ae81ff } /* Literal.Number */ +.code .s { color: #e6db74 } /* Literal.String */ +.code .na { color: #a6e22e } /* Name.Attribute */ +.code .nb { color: #f8f8f2 } /* Name.Builtin */ +.code .nc { color: #a6e22e } /* Name.Class */ +.code .no { color: #66d9ef } /* Name.Constant */ +.code .nd { color: #a6e22e } /* Name.Decorator */ +.code .ni { color: #f8f8f2 } /* Name.Entity */ +.code .ne { color: #a6e22e } /* Name.Exception */ +.code .nf { color: #a6e22e } /* Name.Function */ +.code .nl { color: #f8f8f2 } /* Name.Label */ +.code .nn { color: #f8f8f2 } /* Name.Namespace */ +.code .nx { color: #a6e22e } /* Name.Other */ +.code .py { color: #f8f8f2 } /* Name.Property */ +.code .nt { color: #f92672 } /* Name.Tag */ +.code .nv { color: #f8f8f2 } /* Name.Variable */ +.code .ow { color: #f92672 } /* Operator.Word */ +.code .w { color: #f8f8f2 } /* Text.Whitespace */ +.code .mb { color: #ae81ff } /* Literal.Number.Bin */ +.code .mf { color: #ae81ff } /* Literal.Number.Float */ +.code .mh { color: #ae81ff } /* Literal.Number.Hex */ +.code .mi { color: #ae81ff } /* Literal.Number.Integer */ +.code .mo { color: #ae81ff } /* Literal.Number.Oct */ +.code .sa { color: #e6db74 } /* Literal.String.Affix */ +.code .sb { color: #e6db74 } /* Literal.String.Backtick */ +.code .sc { color: #e6db74 } /* Literal.String.Char */ +.code .dl { color: #e6db74 } /* Literal.String.Delimiter */ +.code .sd { color: #e6db74 } /* Literal.String.Doc */ +.code .s2 { color: #e6db74 } /* Literal.String.Double */ +.code .se { color: #ae81ff } /* Literal.String.Escape */ +.code .sh { color: #e6db74 } /* Literal.String.Heredoc */ +.code .si { color: #e6db74 } /* Literal.String.Interpol */ +.code .sx { color: #e6db74 } /* Literal.String.Other */ +.code .sr { color: #e6db74 } /* Literal.String.Regex */ +.code .s1 { color: #e6db74 } /* Literal.String.Single */ +.code .ss { color: #e6db74 } /* Literal.String.Symbol */ +.code .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ +.code .fm { color: #a6e22e } /* Name.Function.Magic */ +.code .vc { color: #f8f8f2 } /* Name.Variable.Class */ +.code .vg { color: #f8f8f2 } /* Name.Variable.Global */ +.code .vi { color: #f8f8f2 } /* Name.Variable.Instance */ +.code .vm { color: #f8f8f2 } /* Name.Variable.Magic */ +.code .il { color: #ae81ff } /* Literal.Number.Integer.Long */ diff --git a/templates/main/base.html b/templates/main/base.html index cbdd937b..cfe41099 100644 --- a/templates/main/base.html +++ b/templates/main/base.html @@ -17,6 +17,7 @@ <link rel="shortcut icon" href="{{ static_file('favicon.ico') }}"> <link rel="stylesheet" href="{{ static_file('uikit_blurple.css') }}"/> <link rel="stylesheet" href="{{ static_file('style.css') }}"/> + <link rel="stylesheet" href="{{ static_file('css/pygments-monokai.css') }}"/> <!-- OpenGraph metadata --> <meta property="og:title" content="Python Discord | {% block og_title %}{% endblock %}"> diff --git a/templates/wiki/base.html b/templates/wiki/base.html index 02ab1b55..4bb227df 100644 --- a/templates/wiki/base.html +++ b/templates/wiki/base.html @@ -16,6 +16,7 @@ <link rel="shortcut icon" href="{{ static_file('favicon.ico') }}"> <link rel="stylesheet" href="{{ static_file('uikit_blurple.css') }}"/> <link rel="stylesheet" href="{{ static_file('style.css') }}"/> + <link rel="stylesheet" href="{{ static_file('css/pygments-monokai.css') }}"/> <!-- OpenGraph metadata --> <meta property="og:title" content="Python Discord | {% block og_title %}{% endblock %}"> @@ -30,7 +31,7 @@ <div class="uk-offcanvas-content uk-flex uk-flex-column"> {% include "main/navigation.html" %} <div class="uk-flex uk-flex-row uk-flex-1"> - <div class="uk-card uk-card-body uk-flex-left uk-flex"> + <div class="uk-card uk-card-body uk-flex-left uk-flex uk-card-primary"> <ul class="uk-nav-default uk-nav-parent-icon" uk-nav> {% if (can_edit or debug) and current_page == "page" %} <li> diff --git a/templates/wiki/page_edit.html b/templates/wiki/page_edit.html index 7664511e..b797577d 100644 --- a/templates/wiki/page_edit.html +++ b/templates/wiki/page_edit.html @@ -14,7 +14,7 @@ <button class="uk-button uk-button-secondary" type="button" value="Preview" id="preview">Preview</button> </div> <div class="uk-width-auto"> - <input class="uk-button uk-button-primary" type="submit" value="Save" /> + <input class="uk-button uk-button-primary" type="submit" id="submit" value="Save" /> </div> <div class="uk-width-1-1"> <div id="editor" class="uk-textarea" style="resize: vertical; min-height: 15rem;">{{ rst }}</div> @@ -24,10 +24,12 @@ <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> </form> - <h2>Preview</h2> + <div class="uk-container uk-container-small" style="padding: 1rem 1rem 0.1rem;"> + <h2 id="preview-title">{{ title }}</h2> - <div class="uk-alert" id="preview-div" style="padding: 1rem 1rem 0.1rem;"> - {{ preview | safe }} + <div id="preview-div"> + {{ preview | safe }} + </div> </div> <script type="application/javascript"> @@ -42,6 +44,8 @@ let response = JSON.parse(this.responseText); if (response.error !== undefined) { + document.getElementById("submit").disabled = true; + if (response.error_lines !== undefined) { editor.session.setAnnotations(response.error_lines); document.getElementById("preview-div").innerHTML ="<h3>Error - see editor margin</h3>"; @@ -50,7 +54,9 @@ document.getElementById("preview-div").innerHTML ="<h3>Error</h3><p>" + response.error + "<p>"; } } else { + document.getElementById("submit").disabled = false; document.getElementById("preview-div").innerHTML = response.data; + editor.session.setAnnotations([]); } }); @@ -81,6 +87,10 @@ clearTimeout(timer); } timer = setTimeout(function() {document.getElementById("preview").click()}, 1000); - }) + }); + + document.getElementById("title").oninput = function() { + document.getElementById("preview-title").textContent = document.getElementById("title").value; + } </script> {% endblock %}
\ No newline at end of file |