Refactored blog home template
This commit is contained in:
parent
d81abaa984
commit
b8df9f73a0
8 changed files with 286 additions and 113 deletions
|
@ -1,11 +1,12 @@
|
|||
import datetime
|
||||
import os
|
||||
import re
|
||||
|
||||
from glob import glob
|
||||
from typing import Optional
|
||||
|
||||
from markdown import markdown
|
||||
|
||||
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__), '..', '..'))
|
||||
templates_dir = os.path.join(basedir, 'templates')
|
||||
|
@ -33,6 +34,8 @@ def get_page_metadata(page: str) -> dict:
|
|||
|
||||
metadata = {}
|
||||
with open(os.path.join(pages_dir, page), 'r') as f:
|
||||
metadata['uri'] = '/article/' + page[:-3]
|
||||
|
||||
for line in f.readlines():
|
||||
if not line:
|
||||
continue
|
||||
|
@ -40,6 +43,9 @@ def get_page_metadata(page: str) -> dict:
|
|||
if not (m := re.match(r'^\[//]: # \(([^:]+):\s*([^)]+)\)\s*$', line)):
|
||||
break
|
||||
|
||||
if m.group(1) == 'published':
|
||||
metadata[m.group(1)] = datetime.date.fromisoformat(m.group(2))
|
||||
else:
|
||||
metadata[m.group(1)] = m.group(2)
|
||||
|
||||
return metadata
|
||||
|
@ -52,15 +58,27 @@ def get_page(page: str, title: Optional[str] = None):
|
|||
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')
|
||||
title=title if title else metadata.get('title', 'Platypush blog'),
|
||||
image=metadata.get('image'),
|
||||
description=metadata.get('description'),
|
||||
published=(metadata['published'].strftime('%b %d, %Y')
|
||||
if metadata.get('published') else None),
|
||||
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'])
|
||||
def home_route():
|
||||
return get_page('Home', title='Platypush Blog')
|
||||
return render_template('index.html', pages=get_pages())
|
||||
|
||||
|
||||
@app.route('/favicon.ico', methods=['GET'])
|
||||
|
@ -78,9 +96,6 @@ def css_route(style: str):
|
|||
return send_from_directory(css_dir, style)
|
||||
|
||||
|
||||
@app.route('/<path:path>', methods=['GET'])
|
||||
def catch_all(path: str):
|
||||
if path.endswith('.md'):
|
||||
return get_page(path)
|
||||
|
||||
abort(404)
|
||||
@app.route('/article/<article>', methods=['GET'])
|
||||
def article_route(article: str):
|
||||
return get_page(article)
|
||||
|
|
|
@ -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 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -79,31 +10,26 @@ main .content code, .codehilite {
|
|||
font-size: .85em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
line-height: 1.1em;
|
||||
.description h3 {
|
||||
font-weight: normal;
|
||||
opacity: 0.6;
|
||||
margin: -.5em auto .5em auto;
|
||||
}
|
||||
|
||||
.published-date {
|
||||
font-size: 0.75em;
|
||||
opacity: .75;
|
||||
margin-top: -1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
main .content, main .title {
|
||||
main .container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
main .content, main .title {
|
||||
main .container {
|
||||
max-width: 768px;
|
||||
}
|
||||
}
|
||||
|
|
78
static/css/common.css
Normal file
78
static/css/common.css
Normal 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
94
static/css/home.css
Normal 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
BIN
static/img/dashboard-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 727 KiB |
|
@ -1,4 +1,6 @@
|
|||
[//]: # (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)
|
||||
|
||||
In the last few years we have experienced a terrific spike of products and solutions targeting home automation and
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<html lang="en">
|
||||
<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/code.css">
|
||||
<title>{{ title }}</title>
|
||||
|
@ -9,23 +10,32 @@
|
|||
<header>
|
||||
<a href="/">
|
||||
<div class="icon"></div>
|
||||
<div class="title">Platypush Blog</div>
|
||||
<div class="title">Platypush blog</div>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="title">
|
||||
<h1>{{ title }}</h1>
|
||||
</div>
|
||||
|
||||
{% if description %}
|
||||
<div class="description">
|
||||
<h3>{{ description }}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if published %}
|
||||
<div class="published-date">
|
||||
Published on {{ published }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
48
templates/index.html
Normal file
48
templates/index.html
Normal 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>
|
Loading…
Reference in a new issue