diff --git a/README.md b/README.md
index 9c55ba1..3cb11dc 100644
--- a/README.md
+++ b/README.md
@@ -6,4 +6,4 @@ This project provides the pages and the webapp needed by the Platypush blog.
- `flask`
- `markdown`
-
+- `pygments`
diff --git a/app/__init__.py b/app/__init__.py
index 95fa1d1..8f8f3b3 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -1,8 +1,86 @@
-from flask import Flask
+import datetime
+import os
+import re
+from typing import Optional
-app = Flask(__name__)
+from markdown import markdown
+
+from flask import Flask, abort, send_from_directory, render_template
+
+basedir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..'))
+templates_dir = os.path.join(basedir, 'templates')
+static_dir = os.path.join(basedir, 'static')
+pages_dir = os.path.join(static_dir, 'pages')
+img_dir = os.path.join(static_dir, 'img')
+css_dir = os.path.join(static_dir, 'css')
+
+app = Flask(__name__, template_folder=templates_dir)
-@app.route('/')
-def test():
- return 'It works!'
+def parse_page_title(page: str) -> str:
+ if page.endswith('.md'):
+ page = page[:-3]
+
+ return page.replace('-', ' ')
+
+
+def get_page_metadata(page: str) -> dict:
+ if not page.endswith('.md'):
+ page = page + '.md'
+
+ if not os.path.isfile(os.path.join(pages_dir, page)):
+ abort(404)
+
+ metadata = {}
+ with open(os.path.join(pages_dir, page), 'r') as f:
+ for line in f.readlines():
+ if not line:
+ continue
+
+ if not (m := re.match(r'^\[//]: # \(([^:]+):\s*([^)]+)\)\s*$', line)):
+ break
+
+ metadata[m.group(1)] = m.group(2)
+
+ return metadata
+
+
+def get_page(page: str, title: Optional[str] = None):
+ if not page.endswith('.md'):
+ page = page + '.md'
+
+ metadata = get_page_metadata(page)
+ with open(os.path.join(pages_dir, page), 'r') as f:
+ return render_template('article.html',
+ title=title if title else metadata.get('title', 'Platypush Blog'),
+ published=(datetime.date.fromisoformat(metadata['published']).strftime('%b %d, %Y')
+ if metadata.get('published') else None),
+ content=markdown(f.read(),extensions=['fenced_code', 'codehilite']))
+
+
+@app.route('/', methods=['GET'])
+def home_route():
+ return get_page('Home', title='Platypush Blog')
+
+
+@app.route('/favicon.ico', methods=['GET'])
+def favicon_route():
+ return send_from_directory(img_dir, 'favicon.ico')
+
+
+@app.route('/img/', methods=['GET'])
+def img_route(img: str):
+ return send_from_directory(img_dir, img)
+
+
+@app.route('/css/