Start building a blog page

This commit is contained in:
2026-10-04 21:01:24 +01:00
parent e0f85235f2
commit 179a830fa9
10 changed files with 167 additions and 19 deletions
+1
View File
@@ -1,3 +1,4 @@
__pycache__
.vscode
.buildinfo.json
*.md
+14 -2
View File
@@ -22,11 +22,23 @@ app = Flask(__name__)
md_path = path.join(path.realpath(path.dirname(__file__)), path.normpath('../projects/'))
projects = ContentArea(
directory=LocalStorage(md_path),
directory=LocalStorage(path.join(md_path, 'projects')),
root_templ='projects.html',
post_templ='article.html',
name='projects',
import_name=__name__)
import_name=__name__
)
blog = ContentArea(
directory=LocalStorage(path.join(md_path, 'blog')),
root_templ='blog.html',
post_templ='post.html',
name='blog',
import_name=__name__
)
app.register_blueprint(projects, url_prefix='/projects')
app.register_blueprint(blog, url_prefix='/blog')
app.register_blueprint(ContactForm('contact', __name__), url_prefix='/contact')
app.register_blueprint(Links(path.join(md_path, 'links.json'), 'links', __name__), url_prefix='/links')
+7 -13
View File
@@ -10,12 +10,11 @@ from flask import render_template, Response, Blueprint
from .storage import LocalStorage
class ContentArea(Blueprint):
def __init__(self, directory: LocalStorage, *args, **kwargs):
def __init__(self, directory: LocalStorage, root_templ: str, post_templ: str, *args, **kwargs):
self.md_directory = directory
super().__init__(*args, **kwargs)
self.add_app_template_filter(self.category_title, 'category_title')
self.add_app_template_filter(self.human_date, 'human_date')
self.add_app_template_filter(self.to_html, 'to_html')
@@ -24,7 +23,9 @@ class ContentArea(Blueprint):
self.add_url_rule('/', view_func=self.projects)
self.add_url_rule('/category/<category_id>/', view_func=self.category)
self.add_url_rule('/<article_id>', view_func=self.article)
#self.add_url_rule('/image/<image_name>', view_func=self.image)
self.root_templ = root_templ
self.post_templ = post_templ
def processor(self) -> dict:
''' Jninja processors '''
@@ -35,13 +36,6 @@ class ContentArea(Blueprint):
return ' '.join(all_text.split()[:200])
return dict(get_excerpt=get_excerpt)
def category_title(self, category_id: str) -> str:
''' Jninja filter to get a category title by its ID '''
with self.md_directory.open('categories.json') as categories_file:
categories = json.load(categories_file)
return categories.get(category_id).get('title', '')
def human_date(self, iso_date: str) -> str:
''' Jninja filter to convert an ISO date to human readable. '''
try:
@@ -90,7 +84,7 @@ class ContentArea(Blueprint):
error='There\'s nothing here... yet.',
description='I\'m still working on this page. Check back soon for some content.')
return render_template('projects.html',
return render_template(self.root_templ,
articles=articles_to_return,
all_categories=categories,
title='Projects',
@@ -123,7 +117,7 @@ class ContentArea(Blueprint):
error='There\'s nothing here... yet.',
description='I\'m still working on this page. Check back soon for some content.')
return render_template('projects.html', articles=articles_to_return,
return render_template(self.root_templ, articles=articles_to_return,
title=the_category['title'],
description=the_category['long_description'],
page_title=f'{the_category["title"]} - ',
@@ -140,6 +134,6 @@ class ContentArea(Blueprint):
return Response(status=500)
the_article = articles[0]
return render_template('article.html', post=markdown(the_article.content),
return render_template(self.post_templ, post=markdown(the_article.content),
metadata=the_article.metadata,
page_title=f'{the_article.metadata["title"]} - ')
+57
View File
@@ -0,0 +1,57 @@
{% extends 'main.html' %}
{% block content %}
<main id="blog-main">
<nav id="filter">
<label for="filter_category">Filter:</label>
<select id="filter_category" name="filter_category" onchange="update_filter()">
<option value="all">All Categories</option>
{% for category in all_categories %}
<option {{ 'selected' if current_category==category }} value="{{ category }}">
{{all_categories.get(category).get('title')}}</option>
{% endfor %}
</select>
</nav>
<h2>{{ title }}</h2>
<p>{{ description }}</p>
<p style="text-align: center; font-weight: bold; font-style: italic;">This page is relatively new. I'm adding projects as fast as I can but feel free to <a href="/contact">contact me</a> if you want to know about something in particular.</p>
<section id="blog">
{% for row in articles %}
<div class="blog-post">
{% if row.get('link') is not none %}
<a href="{{ row.link }}">
{% else %}
<a href="/blog/{{ row.id }}">
{% endif %}
<img class="blogpost-thumb"
alt="{{ row.alt }}"
srcset="
{% for i in range(200, 5100, 100) %}
/image/{{ row.image }}?w={{i}} {{i}}w{{"," if not loop.last}}
{% endfor %}
"
sizes="
(max-width: 999px) 80vw,
(min-width: 1000px) 20vw
"
src="/image/{{ row.image }}">
</a>
<div class="blogpost-text">
{% if row.get('link') is not none %}
<a href="{{ row.link }}">
{% else %}
<a href="/blog/{{ row.id }}">
{% endif %}
<h3>{{ row.title }}</h3>
</a>
<p class="blogpost-description">{{ row.description }}</p>
<p class="blogpost-date">{{ row.date | human_date }}</p>
{% for category in row.categories %}
<a class="blogpost-category" href="/projects/category/{{ category }}"> {{ all_categories.get(category, {}).get('title', '') }}{{ ", " if not loop.last }}</loop></a>
{% endfor %}
</div>
</div>
{% endfor %}
</section>
</main>
{% endblock %}
+1
View File
@@ -59,6 +59,7 @@
<nav id="top-nav">
<a href="/">About</a>
<a href="/projects/">Projects</a>
<a href="/blog">Blog</a>
<a href="/contact/">Contact</a>
<a href="/links/">Links</a>
</nav>
+64
View File
@@ -0,0 +1,64 @@
{% extends 'main.html' %}
{% block description %}{{ metadata.description }}{% endblock %}
{% block head %}
{% if metadata.gallery %}
<script>
document.addEventListener("DOMContentLoaded",function(){
post_gallery = new Viewer(document.getElementById('article'), {
'url': 'realsrc',
'title': false
});
});
</script>
{% endif %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": {{ metadata.title | tojson }},
"description": {{ metadata.description | tojson }},
"datePublished": "{{ metadata.date }}",
{% if metadata.updated %}
"dateModified": "{{ metadata.updated }}",
{% endif %}
"image": "https://{{ url }}/image/{{ metadata.image }}",
"author": {
"@type": "Person",
"name": "Jake Charman",
"url": "https://{{ url }}/"
},
"publisher": {
"@type": "Person",
"name": "Jake Charman",
"url": "https://{{ url }}/"
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://{{ url }}/writing/{{ metadata.id }}"
},
"url": "https://{{ url }}/writing/{{ metadata.id }}",
"inLanguage": "en-GB"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{"@type": "ListItem", "position": 1, "name": "Projects", "item": "https://{{url}}/projects/"},
{"@type": "ListItem", "position": 2, "name": {{ metadata.title | tojson }}, "item": "https://{{url}}/projects/{{ metadata.id }}"}
]
}
</script>
{% endblock %}
{% block content %}
<main>
<section id="article">
<h1>{{ metadata.title}} </h1>
<p>{{ metadata.date | human_date }}</p>
<hr />
{{post|safe}}
</section>
</main>
{% endblock %}
+1 -1
View File
@@ -47,7 +47,7 @@
<p class="article-description">{{ row.description }}</p>
<p class="article-date">{{ row.date | human_date }}</p>
{% for category in row.categories %}
<a class="article-category" href="/projects/category/{{ category }}">{{ category | category_title }}{{ ", " if not loop.last }}</loop></a>
<a class="article-category" href="/projects/category/{{ category }}"> {{ all_categories.get(category, {}).get('title', '') }}{{ ", " if not loop.last }}</loop></a>
{% endfor %}
</div>
</div>
+3 -2
View File
@@ -1,10 +1,11 @@
function update_filter() {
var section = window.location.pathname.split('/')[1]
var project_filter = document.getElementById("filter_category");
console.log(project_filter.value)
if (project_filter.value == 'all') {
window.location.href = '/projects';
window.location.href = '/'+section;
}
else {
window.location.href = '/projects/category/' + project_filter.value;
window.location.href = '/'+section+'/category/' + project_filter.value;
}
}
+4
View File
@@ -129,4 +129,8 @@
padding: 10px;
height: 14vw;
}
.blogpost-thumb {
width: 12.5vw;
}
}
+14
View File
@@ -338,3 +338,17 @@ pre{
height: 31vw;
object-fit: cover;
}
.blog-post {
border: 5px solid #e5e5e5;
padding: 10px;
margin: 10px;
border-radius: 15px;
overflow: hidden;
}
.blogpost-thumb {
float: left;
padding-right: 20px;
width: 25vw;
}