Skip to content

Commit d176053

Browse files
committed
A naive but enjoyable static site generator
0 parents  commit d176053

File tree

8 files changed

+201
-0
lines changed

8 files changed

+201
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__

blog/__init__.py

Whitespace-only changes.

blog/flatpages.py

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import logging
2+
import os
3+
from itertools import takewhile
4+
from typing import List
5+
6+
import markdown
7+
import yaml
8+
from flask import Flask
9+
10+
BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../')
11+
12+
config = {
13+
'root': os.path.join(BASE_DIR, 'pages'),
14+
'encoding': 'utf-8',
15+
'extension': '.md',
16+
'html_renderer': markdown,
17+
}
18+
19+
logger = logging.getLogger(__name__)
20+
21+
def discover_pages(app: Flask) -> List[dict]:
22+
"""
23+
Walk the flatpage directory, finding, parsing, and
24+
storing all pages in an index
25+
"""
26+
page_index = {}
27+
for current_path, _, file_list in os.walk(config['root']):
28+
relative_path = current_path.replace(config['root'], '').lstrip(os.sep)
29+
30+
for name in file_list:
31+
if not name.endswith(config['extension']):
32+
continue
33+
34+
name_without_extension = os.path.splitext(name)[0]
35+
full_path = os.path.join(relative_path, name_without_extension)
36+
37+
page = get_page(full_path)
38+
page_index[full_path] = page
39+
40+
# If the file name is index, strip the name and add a pointer
41+
# from the base directory to the full content.
42+
if name_without_extension == 'index':
43+
page_index[full_path.rsplit('/', 1)[0]] = page
44+
45+
app.page_index = page_index
46+
return app
47+
48+
def parse_page(content: str) -> dict:
49+
"""
50+
Given the contents of a Markdown file, parse
51+
the YAML config and HTML content
52+
"""
53+
lines = iter(content.split('\n'))
54+
55+
# Read lines until we hit the empty line
56+
meta = '\n'.join(takewhile(lambda l: l != '---', lines))
57+
meta = yaml.safe_load(meta)
58+
content = '\n'.join(lines)
59+
60+
# Render the Markdown content as HTML
61+
html = markdown.markdown(content)
62+
63+
return dict(
64+
**meta,
65+
**{'html': html},
66+
)
67+
68+
def get_page(path: str, encoding: str=None) -> dict:
69+
"""
70+
Accept a path in the vein of the blog, open it
71+
within the filesystem, and parse its contents
72+
"""
73+
logger.debug("Getting %s", path)
74+
if encoding is None:
75+
encoding = config['encoding']
76+
77+
path = os.path.join(config['root'], path + ".md")
78+
79+
with open(path, encoding=encoding) as file:
80+
content = file.read()
81+
return parse_page(content)

requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Flask==1.1.1
2+
Frozen-Flask==0.15
3+
Markdown==3.1.1

site.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import sys
2+
3+
from flask import Flask, abort, render_template
4+
from flask_frozen import Freezer
5+
6+
from blog.flatpages import discover_pages
7+
8+
app = Flask(__name__)
9+
freezer = Freezer(app)
10+
11+
# Upon app load, we store all page content into memory. This is obviously
12+
# obscene but warrants itself sufficient at time of writing. If I ever
13+
# get around to writing more than a couple of things on here, I'll blow this
14+
# up into something more sane.
15+
discover_pages(app)
16+
17+
@app.route('/')
18+
def index():
19+
return render_template('index.html')
20+
21+
@freezer.register_generator
22+
def pages():
23+
for key in app.page_index.keys():
24+
yield 'page', {'path': key}
25+
26+
@app.route('/<path:path>/')
27+
def page(path):
28+
p = app.page_index.get(path)
29+
if not p:
30+
abort(404)
31+
return render_template('page.html', page=p)
32+
33+
if __name__ == '__main__':
34+
if len(sys.argv) > 1 and sys.argv[1] == "build":
35+
freezer.freeze()
36+
else:
37+
app.run(port=4000, debug=True)

templates/base.html

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset='utf-8'>
5+
<title> Bartek Ciszkowski </title>
6+
<style type='text/css'>
7+
body {
8+
margin: 1em 10em;
9+
font-family: sans-serif;
10+
}
11+
12+
h1 {
13+
font-weight: 400;
14+
}
15+
16+
h1 a { text-decoration: none; }
17+
h1 a:hover { text-decoration: underline; }
18+
19+
p {
20+
line-height: 1.4em;
21+
}
22+
23+
li {
24+
line-height: 1.4em;
25+
}
26+
</style>
27+
</head>
28+
<body>
29+
{% block content %}
30+
{% endblock content %}
31+
</body>
32+
</html>
33+

templates/index.html

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
<h1><a href='{{ url_for("index") }}'>👋 Hello, I'm Bartek</a></h1>
4+
5+
<p>I'm a 30-something Polish dude raised mostly in Toronto, Canada, currently living
6+
in Boston, Massachusetts. Apart from building software, I spend most of my
7+
time being a loving father, cooking, travelling, and nerding out over
8+
transportation systems.</p>
9+
10+
<h3>A little more about me</h3>
11+
12+
<p>I work at <a href='https://www.gadventures.com'>G Adventures</a>, a
13+
sustainable tourism company working hard to make the world a better place.
14+
I've been there longer than I ever anticipated, but the challenges keep
15+
coming. Want to work with us? <a href='mailto:[email protected]'>Talk to me</a>.</p>
16+
17+
<p>I'm currently reading Edward Snowden's <a href='https://en.wikipedia.org/wiki/Permanent_Record_(autobiography)'>Permanent Record</a></p>
18+
19+
<p>My current project revolves around improving the ability for
20+
documentation to be discovered and connected within an organization. I hope
21+
to have more to share soon.</p>
22+
23+
<p>My current travel ambitions are to see more of the United States, now
24+
that I'm here (since September 2019)</p>
25+
26+
<p>You can also find me here:</p>
27+
28+
<ul>
29+
<li><a href='https://github.com'>github/bartek</a></li>
30+
<li><a href='https://twitter.com/bartekci'>twitter/bartekci</a></li>
31+
<li><a href='https://stackoverflow.com/users/95509/bartek'>stack overflow</a></li>
32+
<li><a href='https://familymeals.substack.com'>family meal night blog</a></li>
33+
</ul>
34+
35+
<p>Although I have lingering profiles on Facebook and LinkedIn, I do not
36+
actively use them, so please do not send me messages there.</p>
37+
38+
<p>Want to get in touch? <a href='mailto:[email protected]'>Email</a> is best.</p>
39+
{% endblock %}

templates/page.html

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{% extends "base.html" %}
2+
3+
{% block content %}
4+
<h2>{{ page.title }}</h2>
5+
<h3>{{ page.date }}</h3>
6+
{{ page.html|safe }}
7+
{% endblock content %}

0 commit comments

Comments
 (0)