Refactored blog home template

This commit is contained in:
Fabio Manganiello 2021-01-24 23:24:49 +01:00
parent d81abaa984
commit b8df9f73a0
8 changed files with 286 additions and 113 deletions

View file

@ -1,11 +1,12 @@
import datetime import datetime
import os import os
import re import re
from glob import glob
from typing import Optional from typing import Optional
from markdown import markdown
from flask import Flask, abort, send_from_directory, render_template from flask import Flask, abort, send_from_directory, render_template
from markdown import markdown
basedir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..')) basedir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..'))
templates_dir = os.path.join(basedir, 'templates') templates_dir = os.path.join(basedir, 'templates')
@ -33,6 +34,8 @@ def get_page_metadata(page: str) -> dict:
metadata = {} metadata = {}
with open(os.path.join(pages_dir, page), 'r') as f: with open(os.path.join(pages_dir, page), 'r') as f:
metadata['uri'] = '/article/' + page[:-3]
for line in f.readlines(): for line in f.readlines():
if not line: if not line:
continue continue
@ -40,6 +43,9 @@ def get_page_metadata(page: str) -> dict:
if not (m := re.match(r'^\[//]: # \(([^:]+):\s*([^)]+)\)\s*$', line)): if not (m := re.match(r'^\[//]: # \(([^:]+):\s*([^)]+)\)\s*$', line)):
break break
if m.group(1) == 'published':
metadata[m.group(1)] = datetime.date.fromisoformat(m.group(2))
else:
metadata[m.group(1)] = m.group(2) metadata[m.group(1)] = m.group(2)
return metadata return metadata
@ -52,15 +58,27 @@ def get_page(page: str, title: Optional[str] = None):
metadata = get_page_metadata(page) metadata = get_page_metadata(page)
with open(os.path.join(pages_dir, page), 'r') as f: with open(os.path.join(pages_dir, page), 'r') as f:
return render_template('article.html', return render_template('article.html',
title=title if title else metadata.get('title', 'Platypush Blog'), title=title if title else metadata.get('title', 'Platypush blog'),
published=(datetime.date.fromisoformat(metadata['published']).strftime('%b %d, %Y') image=metadata.get('image'),
description=metadata.get('description'),
published=(metadata['published'].strftime('%b %d, %Y')
if metadata.get('published') else None), if metadata.get('published') else None),
content=markdown(f.read(),extensions=['fenced_code', 'codehilite'])) content=markdown(f.read(),extensions=['fenced_code', 'codehilite']))
def get_pages() -> list:
return sorted([
{
'path': path,
**get_page_metadata(os.path.basename(path)),
}
for path in glob(os.path.join(pages_dir, '*.md'))
], key=lambda page: page.get('published'), reverse=True)
@app.route('/', methods=['GET']) @app.route('/', methods=['GET'])
def home_route(): def home_route():
return get_page('Home', title='Platypush Blog') return render_template('index.html', pages=get_pages())
@app.route('/favicon.ico', methods=['GET']) @app.route('/favicon.ico', methods=['GET'])
@ -78,9 +96,6 @@ def css_route(style: str):
return send_from_directory(css_dir, style) return send_from_directory(css_dir, style)
@app.route('/<path:path>', methods=['GET']) @app.route('/article/<article>', methods=['GET'])
def catch_all(path: str): def article_route(article: str):
if path.endswith('.md'): return get_page(article)
return get_page(path)
abort(404)

View file

@ -1,72 +1,3 @@
html {
font-size: calc(1em + 1vw);
}
@media screen and (min-width: 1024px) {
html {
font-size: 20px;
}
}
body {
margin: 0;
width: 100%;
height: 100%;
}
a, a:visited {
color: #555;
border-bottom: 1px dashed #999;
text-decoration: none;
}
a:hover {
opacity: 0.7;
}
header {
display: flex;
align-items: center;
height: 3em;
padding: 0 .5em;
box-shadow: 1px 3px 3px 0 #bbb;
}
@media screen and (max-width: 767px) {
header {
height: 4em;
}
}
header > a {
display: flex;
align-items: center;
border-bottom: none;
}
header .icon {
background: url(/img/icon.png);
background-size: 40px;
width: 40px;
height: 40px;
display: inline-flex;
margin-right: 1em;
}
header .title {
display: inline-flex;
}
main {
height: calc(100% - 3em);
overflow: auto;
display: flex;
flex-direction: column;
align-items: center;
font-family: Avenir, Palatino, Georgia, Verdana, Helvetica, Arial, sans-serif;
padding: 0 2em;
}
main .content { main .content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -79,31 +10,26 @@ main .content code, .codehilite {
font-size: .85em; font-size: .85em;
} }
h1 { .description h3 {
font-size: 2em; font-weight: normal;
line-height: 1.2em; opacity: 0.6;
} margin: -.5em auto .5em auto;
h2 {
font-size: 1.5em;
line-height: 1.1em;
} }
.published-date { .published-date {
font-size: 0.75em; font-size: 0.75em;
opacity: .75; opacity: .75;
margin-top: -1em;
margin-bottom: 2em; margin-bottom: 2em;
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
main .content, main .title { main .container {
width: 100%; width: 100%;
} }
} }
@media screen and (min-width: 1024px) { @media screen and (min-width: 1024px) {
main .content, main .title { main .container {
max-width: 768px; max-width: 768px;
} }
} }

78
static/css/common.css Normal file
View file

@ -0,0 +1,78 @@
html {
font-size: calc(1em + 1vw);
}
@media screen and (min-width: 1024px) {
html {
font-size: 20px;
}
}
body {
margin: 0;
width: 100%;
height: 100%;
}
a, a:visited {
color: #555;
border-bottom: 1px dashed #999;
text-decoration: none;
}
a:hover {
opacity: 0.7;
}
header {
display: flex;
align-items: center;
height: 3em;
padding: 0 .5em;
box-shadow: 1px 3px 3px 0 #bbb;
}
@media screen and (max-width: 767px) {
header {
height: 4em;
}
}
header > a {
display: flex;
align-items: center;
border-bottom: none;
}
header .icon {
background: url(/img/icon.png);
background-size: 40px;
width: 40px;
height: 40px;
display: inline-flex;
margin-right: 1em;
}
header .title {
display: inline-flex;
}
main {
height: calc(100% - 3em);
overflow: auto;
display: flex;
flex-direction: column;
align-items: center;
font-family: Avenir, Palatino, Georgia, Verdana, Helvetica, Arial, sans-serif;
padding: 0 2em;
}
h1 {
font-size: 2em;
line-height: 1.2em;
}
h2 {
font-size: 1.5em;
line-height: 1.1em;
}

94
static/css/home.css Normal file
View file

@ -0,0 +1,94 @@
main {
padding: 0;
}
.articles {
width: 100%;
display: flex;
}
.article {
display: block;
box-shadow: 0 1px 3px 1px #ddd;
overflow: hidden;
text-overflow: ellipsis;
max-height: 30em;
color: black !important;
}
.article:hover {
box-shadow: 0 1px 4px 2px #bcbcbc;
}
@media screen and (max-width: 767px) {
.article {
width: 100%;
}
}
@media screen and (min-width: 768px) and (max-width: 990px) {
.article {
width: 50%;
}
}
@media screen and (min-width: 990px) and (max-width: 1023px) {
.article {
width: 33%;
}
}
@media screen and (min-width: 1024px) and (max-width: 1279px) {
.article {
width: 25%;
}
}
@media screen and (min-width: 1280px) {
.article {
width: 20%;
}
}
.article .container {
height: 100%;
padding: 2em;
}
.image {
height: 35%;
z-index: 1;
}
.image img {
width: 100%;
height: 100%;
}
.article .title {
font-size: 1.2em;
font-weight: bold;
margin-top: .4em;
text-align: center;
}
a {
border-bottom: 0;
}
.description {
color: rgba(0, 0, 0, 0.7);
font-size: .9em;
}
.published-date {
font-size: .8em;
color: rgba(0, 0, 0, 0.4);
margin: .5em 0 2em 0;
text-align: center;
}
h3 {
margin: 40px 0 0;
}

BIN
static/img/dashboard-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 KiB

View file

@ -1,4 +1,6 @@
[//]: # (title: Ultimate self-hosted automation with Platypush) [//]: # (title: Ultimate self-hosted automation with Platypush)
[//]: # (description: Get started with Platypush to automate your smart home and beyond)
[//]: # (image: /img/dashboard-1.png)
[//]: # (published: 2019-07-28) [//]: # (published: 2019-07-28)
In the last few years we have experienced a terrific spike of products and solutions targeting home automation and In the last few years we have experienced a terrific spike of products and solutions targeting home automation and

View file

@ -1,5 +1,6 @@
<html lang="en"> <html lang="en">
<head> <head>
<link rel="stylesheet" type="text/css" href="/css/common.css">
<link rel="stylesheet" type="text/css" href="/css/blog.css"> <link rel="stylesheet" type="text/css" href="/css/blog.css">
<link rel="stylesheet" type="text/css" href="/css/code.css"> <link rel="stylesheet" type="text/css" href="/css/code.css">
<title>{{ title }}</title> <title>{{ title }}</title>
@ -9,23 +10,32 @@
<header> <header>
<a href="/"> <a href="/">
<div class="icon"></div> <div class="icon"></div>
<div class="title">Platypush Blog</div> <div class="title">Platypush blog</div>
</a> </a>
</header> </header>
<main> <main>
<div class="container">
<div class="title"> <div class="title">
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
</div>
{% if description %}
<div class="description">
<h3>{{ description }}</h3>
</div>
{% endif %}
{% if published %} {% if published %}
<div class="published-date"> <div class="published-date">
Published on {{ published }} Published on {{ published }}
</div> </div>
{% endif %} {% endif %}
</div>
<div class="content"> <div class="content">
{{ content | safe }} {{ content | safe }}
</div> </div>
</div>
</main> </main>
</body> </body>
</html> </html>

48
templates/index.html Normal file
View file

@ -0,0 +1,48 @@
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="/css/common.css">
<link rel="stylesheet" type="text/css" href="/css/home.css">
<title>Platypush blog</title>
</head>
<body>
<header>
<a href="/">
<div class="icon"></div>
<div class="title">Platypush blog</div>
</a>
</header>
<main>
<div class="articles">
{% for page in pages %}
<a class="article" href="{{ page['uri'] }}">
<div class="container">
{% if page['image'] %}
<div class="image">
<img src="{{ page['image'] }}" alt="">
</div>
{% endif %}
<div class="title">
{{ page['title'] }}
</div>
{% if page['published'] %}
<div class="published-date">
{{ page['published'].strftime('%b %d, %Y') }}
</div>
{% endif %}
{% if page['description'] %}
<div class="description">
{{ page['description'] }}
</div>
{% endif %}
</div>
</a>
{% endfor %}
</div>
</main>
</body>
</html>