Compare commits

...

3 Commits

Author SHA1 Message Date
Tim Van Baak 276a77b67e Fix pointer on index tab 2021-02-12 10:06:51 -08:00
Tim Van Baak aac4c8477f Finish index document building 2021-02-11 18:09:29 -08:00
Tim Van Baak 1cf820377d Set up infrastructure for index page 2021-02-11 17:06:50 -08:00
5 changed files with 125 additions and 11 deletions

69
redstring/library.py Normal file
View File

@ -0,0 +1,69 @@
"""
Logic for operations that depend on a whole collection of documents.
"""
import os
from redstring.parser import load, TagOptions, DocumentTag, TabOptions, DocumentTab, Document
def generate_index_document(directory: str) -> Document:
"""
Generate a document describing a document collection.
"""
categories: dict = {}
for filename in os.listdir(directory):
with open(os.path.join(directory, filename)) as f:
document: Document = load(f)
# Check if this document specifies a tab, and create it if necessary.
category = document.get_tag('category')
if not category:
category = 'index'
if category not in categories:
categories[category] = {}
category_tab = categories[category]
# Check if this document specifies a topic, and create it if necessary.
topic = document.get_tag('topic')
if not topic:
topic = 'uncategorized'
if '.' in topic:
topic, subtopic = topic.split('.', maxsplit=1)
else:
subtopic = None
if topic not in category_tab:
category_tab[topic] = []
topic_tag = category_tab[topic]
# Save the title and id.
doc_id = document.get_tag('id').value
if doc_title_tag := document.get_tag('title'):
doc_title = doc_title_tag.value
else:
doc_title = None
topic_tag.append((doc_id, doc_title))
# Build an index document
def document_link(info):
doc_id, doc_title = info
return (
f'<a href="/doc/{doc_id}">{doc_title} ({doc_id})</a>'
if doc_title else
f'<a href="/doc/{doc_id}">{doc_id}</a>'
)
built_tabs: list = []
for category in sorted(categories.keys()):
built_tags: list = []
for topic in sorted(categories[category].keys()):
docs = sorted(categories[category][topic], key=lambda x: x[0])
doc_links = map(document_link, docs)
value = '- ' + '<br>- '.join(doc_links)
built_tags.append(DocumentTag(topic, value, TagOptions(), []))
built_tabs.append(DocumentTab(category, built_tags, TabOptions()))
return Document(built_tabs)

View File

@ -130,6 +130,12 @@ class DocumentTab:
self.tags: List[DocumentTag] = tags
self.options: TabOptions = options
def get_tag(self, name: str):
for tag in self.tags:
if tag.name == name:
return tag
return None
class Document:
"""
@ -141,6 +147,19 @@ class Document:
def __iter__(self):
return self.tabs.__iter__()
def get_tab(self, name: str):
for tab in self.tabs:
if tab.name == name:
return tab
return None
def get_tag(self, name: str):
for tab in self.tabs:
for tag in tab.tags:
if tag.name == name:
return tag
return None
#
# Parsing functions

View File

@ -4,8 +4,17 @@ Logic for serving a collection of documents through a web frontend.
import argparse
import os
from flask import Flask, redirect, url_for, current_app, render_template
from flask import (
abort,
current_app,
Flask,
redirect,
render_template,
safe_join,
url_for,
)
from redstring.library import generate_index_document
from redstring.parser import load
@ -21,9 +30,18 @@ def root():
@app.route('/index/')
def index():
with open('scratch/test.json') as f:
document = load(f)
return render_template('doc.jinja', document=document)
document = generate_index_document(current_app.config['root'])
return render_template('doc.jinja', document=document, index=True)
@app.route('/doc/<document_id>')
def document(document_id):
doc_path = safe_join(current_app.config['root'], f'{document_id}.json')
if not os.path.isfile(doc_path):
return abort(404)
with open(doc_path) as f:
doc = load(f)
return render_template('doc.jinja', document=doc, index=False)
def main():

View File

@ -24,21 +24,30 @@
}
/* Tabs setup */
div#tabs {
display: flex;
width: 100%;
}
div.tab {
display: inline-block;
padding: 5px;
background-color: #333;
border-style: solid;
border-color: #888;
border-width: 2px 2px 0 2px;
border-radius: 10px 10px 0px 0px;
margin: 0 0 0 4px;
margin: 0 4px;
font-family: monospace;
font-weight: bold;
color: #888;
cursor: pointer;
user-select: none
}
div.tab a {
color: #888;
text-decoration: none;
}
div.tab-content {
cursor: pointer;
}
div.tab-down {
background-color: #333;
border-color: #bbb;
@ -47,8 +56,7 @@
top: 2px;
}
div.tab-right {
float: right;
margin: 0 4px 0 0;
margin-left: auto;
}
div.tab-page {
width: 100%;

View File

@ -31,7 +31,7 @@ window.onload = function () {
{% endblock page_scripts %}
{% macro make_content_tab(tab, selected) -%}
<div id="{{ tab.name }}" class="tab tab-content{% if selected %} tab-down{% endif %}" onclick="javascript:selectTab('{{ tab.name }}')">{{ tab.name }}</div>
<div id="{{ tab.name }}" class="tab tab-content{% if selected %} tab-down{% endif %}{% if index %} tab-right{% endif %}" onclick="javascript:selectTab('{{ tab.name }}')">{{ tab.name }}</div>
{%- endmacro %}
{% macro make_tab_page(tab, selected) %}
@ -64,6 +64,6 @@ window.onload = function () {
{# TODO: tab.priority and tab.private support #}
{% block page_content %}
{% for tab in document %}{{ make_content_tab(tab, loop.first) }}{% endfor %}<a href="/index/"><div id="index" class="tab tab-right">index</div></a>
<div id="tabs">{% for tab in document %}{{ make_content_tab(tab, loop.first) }}{% endfor %}{% if not index %}<div id="index" class="tab tab-right"><a href="/index/">index</a></div>{% endif %}</div>
{% for tab in document %}{{ make_tab_page(tab, loop.first) }}{% endfor %}
{% endblock page_content %}