From 205a9a8c8224a714808990bab99b3301c8f87c65 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Sun, 20 Dec 2020 01:13:27 +1100 Subject: [PATCH] Add more features Cross-reference tracking/redlinks Page title customisation Last modified --- wikinote/__init__.py | 49 +++++++++++++++++++++++--- wikinote/jinja2/page_rendered.html | 55 +++++++++++++++++++----------- wikinote/markup_custom.py | 25 ++++++++++++++ wikinote/static/css/main.css | 21 +++++++++--- 4 files changed, 122 insertions(+), 28 deletions(-) diff --git a/wikinote/__init__.py b/wikinote/__init__.py index 2930462..67cd694 100644 --- a/wikinote/__init__.py +++ b/wikinote/__init__.py @@ -123,12 +123,13 @@ def page_view(path): return flask.render_template('page_rendered.html', page={ 'path': path, - 'title': path.split('/')[-1], + 'title': md.meta['title'] if 'title' in md.meta else path.split('/')[-1], 'content': page_content, 'toc': md.toc_tokens, 'meta': md.meta, - 'children': children - }) + 'children': children, + 'xrefs': index['xrefs'].get(path, []) + }, collapsed='collapsed' in flask.request.args) @app.route('/preview/') def page_preview(path): @@ -214,11 +215,12 @@ def cli_index(): with app.app_context(): tags = {} + xrefs = {} base_path = './data/pages' for dirpath, dirnames, filenames in os.walk(base_path): for fname in filenames: - if fname.endswith('.md'): + if fname.endswith('.md') and not os.path.islink(flask.safe_join(dirpath, fname)): page_path = dirpath[len(base_path)+1:] + '/' + fname[:-3] with(open(flask.safe_join(dirpath, fname), 'r')) as f: @@ -230,6 +232,16 @@ def cli_index(): if tag not in tags: tags[tag] = [] tags[tag].append({'kind': 'page', 'path': page_path}) + + for ref in md.meta.get('refs', []): + fname_ref = flask.safe_join('./data/pages', ref) + '.md' + if os.path.islink(fname_ref): + ref = '/'.join(ref.split('/')[:-1]) + '/' + os.path.splitext(os.readlink(fname_ref))[0] + + if ref not in xrefs: + xrefs[ref] = [] + if page_path not in xrefs[ref]: + xrefs[ref].append(page_path) base_path = './data/images' for dirpath, dirnames, filenames in os.walk(base_path): @@ -251,5 +263,32 @@ def cli_index(): with open('index.pickle', 'wb') as f: pickle.dump({ - 'tags': tags + 'tags': tags, + 'xrefs': xrefs }, f) + +@app.cli.command('redlinks') +def cli_redlinks(): + app.config['SERVER_NAME'] = 'localhost' + + redlinks = set() + + with app.app_context(): + base_path = './data/pages' + for dirpath, dirnames, filenames in os.walk(base_path): + for fname in filenames: + if fname.endswith('.md'): + page_path = dirpath[len(base_path)+1:] + '/' + fname[:-3] + + with(open(flask.safe_join(dirpath, fname), 'r')) as f: + page_source = f.read() + md = WNMarkdown() + md.convert(page_source) + + for redlink in md.meta.get('redlinks', []): + redlinks.add(redlink) + + redlinks = sorted(list(redlinks)) + + for redlink in redlinks: + print(redlink) diff --git a/wikinote/jinja2/page_rendered.html b/wikinote/jinja2/page_rendered.html index acdae34..b6d67cb 100644 --- a/wikinote/jinja2/page_rendered.html +++ b/wikinote/jinja2/page_rendered.html @@ -37,24 +37,41 @@ {% endblock %} {% block leftbox %} - {% if page.toc or page.meta.tags %} -
- {% if page.toc %} - - {% endif %} - - {% if page.meta.tags %} -

- Tags: - {% for tag in page.meta.tags %} - {{ tag }}{% if not loop.last %},{% endif %} - {% endfor %} -

- {% endif %} -
+ {% if page.toc or page.meta.tags or (page.xrefs and not collapsed) %} +
+ {% if page.toc %} + + {% endif %} + + {% if page.meta.tags %} +

+ Tags: + {% for tag in page.meta.tags %} + {{ tag }}{% if not loop.last %},{% endif %} + {% endfor %} +

+ {% endif %} + + {% if page.xrefs and not collapsed %} +
+

Cross-references:

+ +
+ {% endif %} + + {% if page.meta.lastmod %} +
+

Last modified: {{ page.meta.lastmod }}

+
+ {% endif %} +
{% endif %} {% endblock %} diff --git a/wikinote/markup_custom.py b/wikinote/markup_custom.py index fcf5f0f..a92e926 100644 --- a/wikinote/markup_custom.py +++ b/wikinote/markup_custom.py @@ -50,6 +50,16 @@ def capitalise(n): return '(' + capitalise(n[1:]) return n[0].upper() + n[1:] +class DirectiveTitle(Directive): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.md.meta['title'] = self.arg + + def render(self): + return DirectiveElement('div') + +directives['title'] = DirectiveTitle + class DirectiveTag(Directive): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -60,6 +70,16 @@ class DirectiveTag(Directive): directives['tag'] = DirectiveTag +class DirectiveLastmod(Directive): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.md.meta['lastmod'] = self.arg + + def render(self): + return DirectiveElement('div') + +directives['lastmod'] = DirectiveLastmod + class DirectiveInclude(Directive): def render(self): el = DirectiveElement('div') @@ -102,6 +122,8 @@ def make_role_ref(is_upper): div.set('class', 'tooltip-content') div.text = 'Loading…' + self.md.meta['refs'] = self.md.meta.get('refs', []) + [path] + return el return RoleRef @@ -119,6 +141,9 @@ class RoleImage(Role): img.set('src', flask.url_for('image_view', name=image)) if style: img.set('style', style) + + self.md.meta['refs'] = self.md.meta.get('refs', []) + [image] + return el roles['image'] = RoleImage diff --git a/wikinote/static/css/main.css b/wikinote/static/css/main.css index 3af4cae..5925122 100644 --- a/wikinote/static/css/main.css +++ b/wikinote/static/css/main.css @@ -77,7 +77,7 @@ html, body { max-height: calc(100% - 1cm); } - aside.leftbox > div :last-child, aside.rightbox > div :last-child { + aside.leftbox > div p:last-child, aside.rightbox > div p:last-child { margin-bottom: 0; } } @@ -141,9 +141,11 @@ h4, h5, h6 { font-size: 1rem; /* 10.5pt */ margin-top: 0.4cm; font-weight: normal; + font-style: italic; } -section > div.two-columns > aside > h3:first-child { +section > div.two-columns > aside > h3:first-child, +section > div.two-columns > aside > h4:first-child { margin-top: 0.15cm; /* Adjust for 0.25cm of heading above */ } @@ -243,7 +245,8 @@ div.two-columns > aside:not(:last-of-type) { /* Remove trailing margins */ -div.admonition > p:last-child, +div.admonition > p:last-child, div.admonition > div > p:last-child, +div.admonition > ul:last-child, div.admonition > ol:last-child, td > ul:last-child { margin-bottom: 0; } @@ -291,13 +294,23 @@ div.admonition.pharm a.drug { color: black; font-weight: 600; } -div.admonition.pharm span.alt-drugs { +span.alt-drugs { color: #888a85; text-decoration: underline; text-decoration-style: dashed; cursor: pointer; } +div.admonition.buzzword { + background-color: #d8f6bcff; + display: flex; + align-items: center; +} +div.admonition.buzzword > img { + width: 32px; + margin-right: 8px; +} + /* Tooltips */ .tooltip { position: relative;