Add more features

Cross-reference tracking/redlinks
Page title customisation
Last modified
This commit is contained in:
RunasSudo 2020-12-20 01:13:27 +11:00
parent a32795fbe6
commit 205a9a8c82
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
4 changed files with 122 additions and 28 deletions

View File

@ -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/<path:path>')
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)

View File

@ -37,24 +37,41 @@
{% endblock %}
{% block leftbox %}
{% if page.toc or page.meta.tags %}
<div>
{% if page.toc %}
<ul class="toc">
{% for item in page.toc %}
<li><a href="#{{ item.id }}">{{ item.name }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% if page.meta.tags %}
<p style="font-size: small;">
<em>Tags:</em>
{% for tag in page.meta.tags %}
<a href="{{ url_for('tag_view', name=tag) }}">{{ tag }}</a>{% if not loop.last %},{% endif %}
{% endfor %}
</p>
{% endif %}
</div>
{% if page.toc or page.meta.tags or (page.xrefs and not collapsed) %}
<div>
{% if page.toc %}
<ul class="toc">
{% for item in page.toc %}
<li><a href="#{{ item.id }}">{{ item.name }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% if page.meta.tags %}
<p style="font-size: small;">
<em>Tags:</em>
{% for tag in page.meta.tags %}
<a href="{{ url_for('tag_view', name=tag) }}">{{ tag }}</a>{% if not loop.last %},{% endif %}
{% endfor %}
</p>
{% endif %}
{% if page.xrefs and not collapsed %}
<div style="font-size: small;">
<p><em>Cross-references:</em></p>
<ul>
{% for xref in page.xrefs %}
<li><a href="{{ url_for('page_view', path=xref) }}">{{ xref.replace('/', ' › ') }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if page.meta.lastmod %}
<div style="font-size: small;">
<p><em>Last modified:</em> {{ page.meta.lastmod }}</p>
</div>
{% endif %}
</div>
{% endif %}
{% endblock %}

View File

@ -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

View File

@ -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;