diff options
Diffstat (limited to 'kyrias_website')
-rw-r--r-- | kyrias_website/__init__.py | 66 | ||||
-rw-r--r-- | kyrias_website/config.py | 13 | ||||
-rw-r--r-- | kyrias_website/static/base.css | 88 | ||||
-rw-r--r-- | kyrias_website/templates/archive.html | 12 | ||||
-rw-r--r-- | kyrias_website/templates/base.html | 41 | ||||
-rw-r--r-- | kyrias_website/templates/entry.html | 41 | ||||
-rw-r--r-- | kyrias_website/templates/page.html | 27 | ||||
-rw-r--r-- | kyrias_website/templates/tags.html | 19 | ||||
-rw-r--r-- | kyrias_website/util.py | 14 | ||||
-rw-r--r-- | kyrias_website/views.py | 38 |
10 files changed, 359 insertions, 0 deletions
diff --git a/kyrias_website/__init__.py b/kyrias_website/__init__.py new file mode 100644 index 0000000..474663d --- /dev/null +++ b/kyrias_website/__init__.py @@ -0,0 +1,66 @@ +import os + +import flask_assets +from flask import Flask +from flask_flatpages import FlatPages +from werkzeug.utils import cached_property + + +class CustomFlatPages(FlatPages): + def __init__(self, app=None, name=None): + super(CustomFlatPages, self).__init__(app=app, name=name) + self.app = app + + @cached_property + def _pages(self): + """Forget all pages and nuke our own cache""" + try: + del app.__dict__['journal_entries'] + del app.__dict__['journal_tags'] + except KeyError: + pass + return super(CustomFlatPages, self)._pages + + +class CustomFlask(Flask): + def __init__(self, *args, **kwargs): + super(CustomFlask, self).__init__(*args, **kwargs) + + config = { + 'default': 'kyrias_website.config.BaseConfig', + 'development': 'kyrias_website.config.DevelopmentConfig', + } + + config_name = os.getenv('WEBSITE_CONFIGURATION', 'default') + self.config.from_object(config[config_name]) + + assets = flask_assets.Environment(self) + css = flask_assets.Bundle('base.css', filters='cssmin', output='screen.css') + assets.register('css_all', css) + + self.pages = CustomFlatPages(self, 'pages') + self.journal = CustomFlatPages(self, 'journal') + + @cached_property + def journal_entries(self): + return sorted(self.journal, key=lambda x: x.meta.get('date')) + + @cached_property + def journal_tags(self): + tags = {} + for entry in self.journal_entries: + if 'tags' not in entry.meta: + tags.setdefault('untagged', set()).add(entry) + else: + for tag in entry.meta.get('tags'): + tags.setdefault(tag, set()).add(entry) + + return tags + + +app = CustomFlask(__name__) + +import kyrias_website.views + +if __name__ == '__main__': + app.run(port=5000) diff --git a/kyrias_website/config.py b/kyrias_website/config.py new file mode 100644 index 0000000..6c22a09 --- /dev/null +++ b/kyrias_website/config.py @@ -0,0 +1,13 @@ +class BaseConfig(): + DEBUG = False + + FLATPAGES_PAGES_EXTENSION = '.rst' + FLATPAGES_PAGES_HTML_RENDERER = 'kyrias_website.util.rst_renderer' + + FLATPAGES_JOURNAL_EXTENSION = '.rst' + FLATPAGES_JOURNAL_HTML_RENDERER = 'kyrias_website.util.rst_renderer' + FLATPAGES_JOURNAL_ROOT = 'entries' + + +class DevelopmentConfig(BaseConfig): + DEBUG = True diff --git a/kyrias_website/static/base.css b/kyrias_website/static/base.css new file mode 100644 index 0000000..55d2ee0 --- /dev/null +++ b/kyrias_website/static/base.css @@ -0,0 +1,88 @@ +body { + font-family: "Linux Libertine", "Linux Libertine O", "TeX Gyre Termes", "Constantia", "Liberation Serif", "Cambria", "Times New Roman", "Times", serif; + text-rendering: optimizeLegibility; + max-width: 37.5rem; +} +a, a:visited { + text-decoration: none; + color: #32609C; +} +a:hover { + color: #339; +} +a.permalink { + color: #eeeeee; + border: none; +} +:hover > a.permalink { + color: #cccccc; +} +a.permalink:hover, +:target a.permalink { + color: #aaaaaa; +} +header nav ul { + padding: 0rem; + list-style-type: none; +} +header nav ul li { + display: inline; + margin-right: 0.3125rem; +} +header nav a, header nav a:visited { + color: #444; +} +header nav a:hover { + color: #111; +} +.padded-box { + font-size: 1rem; + padding-left: 0.625rem; + padding-right: 0.625rem; +} +hr { + margin-top: 1.25rem; + margin-bottom: 1.25rem; +} +article header h1 { + margin-top: 1.25rem; + margin-bottom: 0.3125rem; +} +article p { + white-space: pre-wrap; + text-align: justify; +} +#tags { + padding-bottom: 0.15625rem; +} +#post-nav { + padding-bottom: 0rem; +} +ul#archive-list, +ul#tag-list { + list-style-type: none; + padding-left: 0; +} +ul.contact-addresses { + list-style-type: circle; + padding-left: 1.25rem; +} +footer#bottom div { + margin-bottom: 0.15625rem; +} +footer#bottom p#copy { + margin: 0rem; + padding-top: 0.15625rem; + padding-bottom: 0.15625rem; +} +footer#bottom ul#contact-info { + margin: 0; + padding: 0rem; + padding-top: 0.15625rem; + padding-bottom: 0.15625rem; + list-style-type: none; +} +footer#bottom ul#contact-info li { + display: inline; + margin-right: 0.15625rem; +} diff --git a/kyrias_website/templates/archive.html b/kyrias_website/templates/archive.html new file mode 100644 index 0000000..2399c90 --- /dev/null +++ b/kyrias_website/templates/archive.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} +<section> + <h1>Archive</h1> + <ul id="archive-list"> + {% for entry in entries %} + <li>{{ entry.date }} — <a href="{{ url_for('entry', name=entry.path) }}">{{ entry.meta.title }}</a></li> + {% endfor %} + </ul> +</section> +{% endblock %} diff --git a/kyrias_website/templates/base.html b/kyrias_website/templates/base.html new file mode 100644 index 0000000..7664e57 --- /dev/null +++ b/kyrias_website/templates/base.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + {% assets "css_all" %} + <link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}"> + {% endassets %} +{% block head %}{% endblock %} + </head> + + <body> + <header class="padded-box"> + <nav> + <ul> + <li><a href="{{ url_for("index") }}">index</a></li> + <li><a href="{{ url_for("archive") }}">archive</a></li> + <li><a href="{{ url_for("tags") }}">tags</a></li> + <li><a href="{{ url_for("page", path='about') }}">about</a></li> + </ul> + </nav> + </header> + <hr /> + <div class="padded-box"> +{% block content %}{% endblock %} + </div> + <hr /> + <footer id="bottom" class="padded-box"> + <div> + <p id="copy">© 2017 Johannes Löthberg</p> + </div> + + <div> + <ul id="contact-info"> + <li><a rel="me" href="mailto:johannes@kyriasis.com">Email</a></li> + <li><a rel="me" href="https://twitter.com/kyriasis">Twitter</a></li> + </ul> + </div> + </footer> + </body> +</html> diff --git a/kyrias_website/templates/entry.html b/kyrias_website/templates/entry.html new file mode 100644 index 0000000..8391505 --- /dev/null +++ b/kyrias_website/templates/entry.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} + +{% block head %} +<title>{{ entry.title }}</title> +{% endblock %} + +{% block content %} +<article itemscope itemtype="http://schema.org/Article"> + <header> + <h1>{{ entry.title }}</h1> + <time itemprop="datePublished" datetime="{{ entry.meta.date }}">{{ entry.meta.date }}</time> + </header> + <div> + {{ entry.html|safe }} + </div> + <footer> + {% if 'tags' in entry.meta %} + <div id="tags"> + Tags: + {% set comma = joiner(",") %} + {% for tag in entry.meta.tags %}{{ comma() }} + <a href="{{ url_for('tags', _anchor=tag) }}">{{ tag }}</a>{% endfor %} + </div> + {% endif %} + </footer> +</article> +{% if older or newer %} +<nav> +<div id="post-nav"> +{% if older and newer %} + <a href="{{ url_for('entry', name=older.path) }}">Older ({{ older.meta.title }})</a> — <a href="{{ url_for('entry', name=newer.path) }}">Newer ({{ newer.meta.title }})</a> +{% elif older %} + <a href="{{ url_for('entry', name=older.path) }}">Older ({{ older.meta.title }})</a> +{% elif newer %} + <a href="{{ url_for('entry', name=newer.path) }}">Newer ({{ newer.meta.title }})</a> +{% endif %} +</div> +</nav> +{% endif %} +{% endblock %} + diff --git a/kyrias_website/templates/page.html b/kyrias_website/templates/page.html new file mode 100644 index 0000000..cca59af --- /dev/null +++ b/kyrias_website/templates/page.html @@ -0,0 +1,27 @@ +{% extends 'base.html' %} + +{% block head %} +<title>{{ page.title }}</title> +{% endblock %} + +{% block content %} +<article itemscope itemtype="http://schema.org/Article"> + <header> + <h1>{{ page.title }}</h1> + <time itemprop="datePublished" datetime="{{ page.meta.date }}">{{ page.meta.date }}</time> + </header> + <div> + {{ page.html|safe }} + </div> + <footer> + {% if 'tags' in page.meta %} + <div id="tags"> + Tags: + {% set comma = joiner(",") %} + {% for tag in page.meta.tags %}{{ comma() }} + <a href="{{ url_for('tags', _anchor=tag) }}">{{ tag }}</a>{% endfor %} + </div> + {% endif %} + </footer> +</article> +{% endblock %} diff --git a/kyrias_website/templates/tags.html b/kyrias_website/templates/tags.html new file mode 100644 index 0000000..a553523 --- /dev/null +++ b/kyrias_website/templates/tags.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} + +{% block content %} +<section> + <h1>Tags</h1> + {% for tag in tags %} + <div id="{{ tag }}"> + <h2>{{ tag }} <a class="permalink" href="#{{ tag }}" title="Link to this tag">§</a></h2> + + <ul id="tag-list"> + {% for entry in tags[tag] %} + <li>{{ entry.meta.date }} — <a href="{{ url_for('entry', name=entry.path) }}">{{ entry.title }}</a></li> + {% endfor %} + </ul> + </div> + {% endfor %} +</section> +{% endblock %} + diff --git a/kyrias_website/util.py b/kyrias_website/util.py new file mode 100644 index 0000000..10ede77 --- /dev/null +++ b/kyrias_website/util.py @@ -0,0 +1,14 @@ +from docutils.core import publish_parts + +def rst_renderer(text): + settings_overrides = { + 'footnote_references': 'superscript', + 'auto_id_prefix': 'id-', + 'initial_header_level': 3, + 'doctitle_xform': False, + } + + parts = publish_parts(source=text, + writer_name='html5_polyglot', + settings_overrides=settings_overrides) + return parts['fragment'] diff --git a/kyrias_website/views.py b/kyrias_website/views.py new file mode 100644 index 0000000..a7e7555 --- /dev/null +++ b/kyrias_website/views.py @@ -0,0 +1,38 @@ +from kyrias_website import app +from flask import render_template + + +# Render all static pages as fallback +@app.route('/<path:path>/') +def page(path): + page = app.pages.get_or_404(path) + return render_template('page.html', page=page) + + +@app.route('/blog/') +@app.route('/') +def index(): + current = app.journal_entries[-1] + older = next(iter(app.journal_entries[-2:-1]), None) + return render_template('entry.html', entry=current, older=older) + + +@app.route('/archive/') +def archive(): + return render_template('archive.html', entries=app.journal_entries) + + +@app.route('/tags/') +def tags(): + return render_template('tags.html', tags=app.journal_tags) + + +@app.route('/blog/<path:name>/') +def entry(name): + entry = app.journal.get_or_404(name) + + index = app.journal_entries.index(entry) + older = next(iter(app.journal_entries[index-1:index]), None) + newer = next(iter(app.journal_entries[index+1:index+2]), None) + + return render_template('entry.html', entry=entry, older=older, newer=newer) |