diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..bad1be9
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,4 @@
+graft flaskr/static
+graft flaskr/templates
+graft flaskr/blog
+global-exclude *.pyc
\ No newline at end of file
diff --git a/flaskr/__init__.py b/flaskr/__init__.py
new file mode 100644
index 0000000..40e61ce
--- /dev/null
+++ b/flaskr/__init__.py
@@ -0,0 +1,159 @@
+from flask import Flask, render_template, send_from_directory, abort, request, make_response
+from werkzeug.middleware.proxy_fix import ProxyFix
+import markdown2
+import datetime
+import os
+import ast
+
+markdown_extras = ["fenced-code-blocks", "footnotes", "strike", "tables", "metadata"]
+
+data = {
+ "feet": [
+ "🐝",
+ "Best viewed using Internet Explorer 6 or earlier",
+ "The HORSE is a noble animal",
+ "🦀",
+ "segmentation fault (core dumped)
",
+ "Bees land on thyme",
+ "☃",
+ "# cat /dev/urandom > /dev/sda
",
+ ":(){ :|: & };:
",
+ "Formal complaints will recieve responses within 5-7 business days",
+ "++++[->++++<]>+[->++++++>+++++++>++<<<]>.>--------..+++++.<-.>--.>--.<++.<.>++++.----.
",
+ "Copywrong © 3034. All rights unreserved.",
+ "[citation needed]",
+ "Best viewed with eyes",
+ "Your browser does not support 7D graphics. Please update for the best user experience.",
+ "Press SPACE to jump",
+ "🐀",
+ "If problems persist, please return to the nearest Blockbuster Video® establishment",
+ "Oversalt to taste",
+ "curl -s -L http://bit.ly/10hA8iC | bash",
+ "Submit footer text via carrier pigeon to [REDACTED]
",
+ "GEORGE is inevitable."
+ ],
+ "next_theme": {
+ "system": "dark",
+ "dark": "light",
+ "light": "contrast",
+ "contrast": "system"
+ }
+}
+
+def index_projects(app):
+ projects = []
+ proj_dir = os.path.join(app.root_path, app.template_folder, "projects")
+ for root, dirs, files in os.walk(proj_dir):
+ for file in files:
+ try:
+ with open(os.path.join(root, file)) as f:
+ metaline = f.read().splitlines()[0]
+ if metaline.startswith("{% set meta="):
+ meta = metaline[12:-2].strip()
+ meta = ast.literal_eval(meta)
+ meta["path"] = os.path.relpath(root, start=proj_dir)
+ meta["file"] = file
+ projects.append(meta)
+ except Exception as e:
+ print(e)
+ return sorted(projects, key=lambda p: p.get("title"))
+
+def index_blog(app):
+ blogposts = []
+ blog_dir = os.path.join(app.root_path, "blog")
+ for file in os.listdir(blog_dir):
+ with open(os.path.join(blog_dir, file)) as f:
+ contents = f.read()
+ html = markdown2.markdown(contents, extras=markdown_extras)
+ meta = html.metadata
+ meta["file"] = file
+ date_parts = file.removesuffix(".md").split("-")
+ date = datetime.date(int(date_parts[0]), int(date_parts[1]), int(date_parts[2]))
+ meta["timestamp"] = datetime.datetime.fromisoformat(meta["timestamp"])
+ meta["date"] = date
+ meta["n"] = int(date_parts[3])
+ meta["url"] = f"/blog/{date.isoformat().replace('-','/')}/{meta['n']}"
+ blogposts.append(meta)
+ return sorted(blogposts, key=lambda post:[post["date"], post["n"]], reverse=True)
+
+def create_app():
+ app = Flask(__name__)
+ app.wsgi_app = ProxyFix(
+ app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
+ )
+ data["blogposts"] = index_blog(app)
+ data["projects"] = index_projects(app)
+
+ @app.route("/favicon.ico")
+ def favicon():
+ path = os.path.join(app.root_path, "static")
+ return send_from_directory(path, "favicon.ico", mimetype="image/vnd.microsoft.icon")
+
+ @app.errorhandler(404)
+ def four_oh_four(e):
+ theme = request.cookies.get("theme") or "dark"
+ return render_template("404.html", data=data, theme=theme)
+
+ def load_page(url):
+ if url.endswith(".html"):
+ path = os.path.join(app.root_path, app.template_folder, url)
+ if os.path.exists(path):
+ theme = request.cookies.get("theme") or "dark"
+ return render_template(url, data=data, theme=theme)
+ else:
+ return abort(404)
+ else:
+ return send_from_directory("templates", url)
+
+ @app.route("/")
+ @app.route("/index.html")
+ def home():
+ return load_page("index.html")
+
+ @app.route("/projects/")
+ @app.route("/projects/index.html")
+ def projects_index():
+ return load_page("projects.html")
+
+ @app.route("/projects//")
+ @app.route("/projects//")
+ def project(page, file="index.html"):
+ return load_page(f"projects/{page}/{file}")
+
+ @app.route("/blog/")
+ def blog_list():
+ theme = request.cookies.get("theme") or "dark"
+ return render_template("blog.html", data=data, theme=theme)
+
+
+ @app.route("/blog////")
+ @app.route("/blog////")
+ def blog_page(y, m, d, n=0):
+ date = datetime.date(y, m, d)
+ print(date.isoformat())
+ path = os.path.join(app.root_path, "blog", f"{date.isoformat()}-{n}.md")
+ if os.path.exists(path):
+ with open(path) as f:
+ contents = f.read()
+ content = markdown2.markdown(contents, extras=markdown_extras)
+ meta = content.metadata
+ theme = request.cookies.get("theme") or "dark"
+ return render_template("_blog.html", data=data, theme=theme, content=content, date=date, meta=meta)
+ else:
+ return abort(404)
+
+ @app.route("/blog/rss.xml")
+ def blog_rss():
+ xml = render_template("rss.xml", data=data)
+ response = make_response(xml)
+ response.headers["Content-Type"] = "application/rss+xml; charset=utf-8"
+ return response
+
+ @app.route("/blog/atom.xml")
+ def blog_atom():
+ xml = render_template("atom.xml", data=data)
+ response = make_response(xml)
+ response.headers["Content-Type"] = "application/atom+xml; charset=utf-8"
+ return response
+
+ return app
\ No newline at end of file
diff --git a/src/blog/2022-02-25-0.md b/flaskr/blog/2022-02-25-0.md
similarity index 100%
rename from src/blog/2022-02-25-0.md
rename to flaskr/blog/2022-02-25-0.md
diff --git a/src/blog/2022-06-01-0.md b/flaskr/blog/2022-06-01-0.md
similarity index 100%
rename from src/blog/2022-06-01-0.md
rename to flaskr/blog/2022-06-01-0.md
diff --git a/src/blog/2022-06-02-0.md b/flaskr/blog/2022-06-02-0.md
similarity index 100%
rename from src/blog/2022-06-02-0.md
rename to flaskr/blog/2022-06-02-0.md
diff --git a/src/blog/2022-06-03-0.md b/flaskr/blog/2022-06-03-0.md
similarity index 100%
rename from src/blog/2022-06-03-0.md
rename to flaskr/blog/2022-06-03-0.md
diff --git a/src/static/favicon.ico b/flaskr/static/favicon.ico
similarity index 100%
rename from src/static/favicon.ico
rename to flaskr/static/favicon.ico
diff --git a/src/static/i/apioform1.png b/flaskr/static/i/apioform1.png
similarity index 100%
rename from src/static/i/apioform1.png
rename to flaskr/static/i/apioform1.png
diff --git a/src/static/i/blog/tau-day1.png b/flaskr/static/i/blog/tau-day1.png
similarity index 100%
rename from src/static/i/blog/tau-day1.png
rename to flaskr/static/i/blog/tau-day1.png
diff --git a/src/static/i/blog/tau-day2.png b/flaskr/static/i/blog/tau-day2.png
similarity index 100%
rename from src/static/i/blog/tau-day2.png
rename to flaskr/static/i/blog/tau-day2.png
diff --git a/src/static/i/blog/tau-day3.png b/flaskr/static/i/blog/tau-day3.png
similarity index 100%
rename from src/static/i/blog/tau-day3.png
rename to flaskr/static/i/blog/tau-day3.png
diff --git a/src/static/i/flappy/background1.png b/flaskr/static/i/flappy/background1.png
similarity index 100%
rename from src/static/i/flappy/background1.png
rename to flaskr/static/i/flappy/background1.png
diff --git a/src/static/i/flappy/background2.png b/flaskr/static/i/flappy/background2.png
similarity index 100%
rename from src/static/i/flappy/background2.png
rename to flaskr/static/i/flappy/background2.png
diff --git a/src/static/i/flappy/bird.png b/flaskr/static/i/flappy/bird.png
similarity index 100%
rename from src/static/i/flappy/bird.png
rename to flaskr/static/i/flappy/bird.png
diff --git a/src/static/logo16.png b/flaskr/static/logo16.png
similarity index 100%
rename from src/static/logo16.png
rename to flaskr/static/logo16.png
diff --git a/src/static/logo32.png b/flaskr/static/logo32.png
similarity index 100%
rename from src/static/logo32.png
rename to flaskr/static/logo32.png
diff --git a/src/static/logo320.png b/flaskr/static/logo320.png
similarity index 100%
rename from src/static/logo320.png
rename to flaskr/static/logo320.png
diff --git a/src/static/logo64.png b/flaskr/static/logo64.png
similarity index 100%
rename from src/static/logo64.png
rename to flaskr/static/logo64.png
diff --git a/src/static/logo640.png b/flaskr/static/logo640.png
similarity index 100%
rename from src/static/logo640.png
rename to flaskr/static/logo640.png
diff --git a/src/static/style.css b/flaskr/static/style.css
similarity index 99%
rename from src/static/style.css
rename to flaskr/static/style.css
index a7635c5..820f02c 100644
--- a/src/static/style.css
+++ b/flaskr/static/style.css
@@ -65,7 +65,7 @@
:root[theme="contrast"] {
--bg: white;
--bg-intense: white;
- --bg-faded: #c0c0c0;
+ --bg-faded: #d0d0d0;
--fg: black;
--fg-faded: #444444;
--accent-1: blue;
diff --git a/src/templates/404.html b/flaskr/templates/404.html
similarity index 100%
rename from src/templates/404.html
rename to flaskr/templates/404.html
diff --git a/src/templates/_base.html b/flaskr/templates/_base.html
similarity index 100%
rename from src/templates/_base.html
rename to flaskr/templates/_base.html
diff --git a/src/templates/_blog.html b/flaskr/templates/_blog.html
similarity index 100%
rename from src/templates/_blog.html
rename to flaskr/templates/_blog.html
diff --git a/src/templates/atom.xml b/flaskr/templates/atom.xml
similarity index 100%
rename from src/templates/atom.xml
rename to flaskr/templates/atom.xml
diff --git a/src/templates/blog.html b/flaskr/templates/blog.html
similarity index 100%
rename from src/templates/blog.html
rename to flaskr/templates/blog.html
diff --git a/src/templates/index.html b/flaskr/templates/index.html
similarity index 100%
rename from src/templates/index.html
rename to flaskr/templates/index.html
diff --git a/src/templates/projects.html b/flaskr/templates/projects.html
similarity index 100%
rename from src/templates/projects.html
rename to flaskr/templates/projects.html
diff --git a/src/templates/projects/complex_grapher/grammar.js b/flaskr/templates/projects/complex_grapher/grammar.js
similarity index 100%
rename from src/templates/projects/complex_grapher/grammar.js
rename to flaskr/templates/projects/complex_grapher/grammar.js
diff --git a/src/templates/projects/complex_grapher/grammar.pegjs b/flaskr/templates/projects/complex_grapher/grammar.pegjs
similarity index 100%
rename from src/templates/projects/complex_grapher/grammar.pegjs
rename to flaskr/templates/projects/complex_grapher/grammar.pegjs
diff --git a/src/templates/projects/complex_grapher/help.html b/flaskr/templates/projects/complex_grapher/help.html
similarity index 100%
rename from src/templates/projects/complex_grapher/help.html
rename to flaskr/templates/projects/complex_grapher/help.html
diff --git a/src/templates/projects/complex_grapher/index.html b/flaskr/templates/projects/complex_grapher/index.html
similarity index 97%
rename from src/templates/projects/complex_grapher/index.html
rename to flaskr/templates/projects/complex_grapher/index.html
index b11171c..687562a 100644
--- a/src/templates/projects/complex_grapher/index.html
+++ b/flaskr/templates/projects/complex_grapher/index.html
@@ -3,7 +3,6 @@
{% block head %}