Compare commits

...

9 Commits

@ -8,8 +8,20 @@ WORKDIR /blog
RUN pip3 install -r requirements.txt RUN pip3 install -r requirements.txt
RUN apt-get update && \
apt-get install -y locales && \
sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
dpkg-reconfigure --frontend=noninteractive locales
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
VOLUME /blog/templates/entry VOLUME /blog/templates/entry
VOLUME /blog/static/graphics
EXPOSE 5000 EXPOSE 5000
ENTRYPOINT [ "python3" ] ENTRYPOINT [ "python3" ]

@ -26,6 +26,9 @@ via plain text files.
- [x] Switchable CSS - [x] Switchable CSS
- [x] CSS dark-theme - [x] CSS dark-theme
- [x] CSS light-theme - [x] CSS light-theme
- [x] Language Support
- [x] English
- [x] German
- [x] Config file - [x] Config file
- [x] Docker installation - [x] Docker installation
- [x] Logo - [x] Logo
@ -58,12 +61,13 @@ The `config.py` can be found in the `src` folder.
Set the following volumes with the -v tag. Set the following volumes with the -v tag.
| Volume-Name | Container mount | Description | | Volume-Name | Container mount | Description |
| ------------- | --------------------------- | ------------------------------------------------------------ | | ------------- | ----------------------- | ------------------------------------------------------------ |
| `config-file` | `/blog/src/config.py` | Config file | | `config-file` | `/blog/config.py` | Config file |
| `entries` | `/blog/src/templates/entry` | Directory for blog entries | | `entries` | `/blog/templates/entry` | Directory for blog entries |
| `css` | `/blog/src/static/css` | (optional) Directory for css files | | `graphics` | `/blog/static/graphics` | Directory for images needed for entries |
| `html` | `/blog/src/templates` | (optional) Directory for templates (entry-volume not needed) | | `css` | `/blog/static/css` | (optional) Directory for css files |
| `html` | `/blog/templates` | (optional) Directory for templates (entry-volume not needed) |
#### Ports #### Ports

@ -6,4 +6,6 @@ docker run --name beaker-blog \
--restart unless-stopped \ --restart unless-stopped \
-p "5000:5000" \ -p "5000:5000" \
-e FLASK_ENV=development \ -e FLASK_ENV=development \
-v entries:/blog/templates/entry \
-v graphics:/blog/static/graphics \
-d tiyn/beaker-blog -d tiyn/beaker-blog

@ -8,33 +8,34 @@ app = Flask(__name__)
TITLE = config.TITLE TITLE = config.TITLE
STYLE = config.STYLE STYLE = config.STYLE
LANGUAGE = config.LANGUAGE
DESCRIPTION = config.DESCRIPTION DESCRIPTION = config.DESCRIPTION
WEBSITE = config.WEBSITE WEBSITE = config.WEBSITE
@app.errorhandler(404) @app.errorhandler(404)
def page_not_found(e): def page_not_found(e):
return render_template("error.html", title=TITLE, errorcode="404", style=STYLE), 404 return render_template("error.html", title=TITLE, errorcode="404", style=STYLE, language=LANGUAGE), 404
@app.route("/") @app.route("/")
@app.route("/index.html") @app.route("/index.html")
def index(): def index():
content = con_gen.gen_index_string() content = con_gen.gen_index_string()
return render_template("index.html", title=TITLE, content_string=content, style=STYLE) return render_template("index.html", title=TITLE, content_string=content, style=STYLE, language=LANGUAGE)
@app.route("/archive") @app.route("/archive")
@app.route("/archive.html") @app.route("/archive.html")
def archive(): def archive():
content = con_gen.gen_arch_string() content = con_gen.gen_arch_string()
return render_template("archive.html", title=TITLE, content_string=content, style=STYLE) return render_template("archive.html", title=TITLE, content_string=content, style=STYLE, language=LANGUAGE)
@app.route("/entry/<path>") @app.route("/entry/<path>")
def entry(path): def entry(path):
content = con_gen.gen_stand_string(path) content = con_gen.gen_stand_string(path)
if content != "": if content != "":
return render_template("standalone.html", title=TITLE, content_string=content, style=STYLE) return render_template("standalone.html", title=TITLE, content_string=content, style=STYLE, language=LANGUAGE)
abort(404) abort(404)

@ -9,3 +9,6 @@ WEBSITE = "localhost:5000"
# Theme for the blog: dark, light # Theme for the blog: dark, light
STYLE = "dark" STYLE = "dark"
# Language for the titles: en-us or de-de
LANGUAGE = "en-us"

@ -1,97 +1,101 @@
from datetime import datetime import locale
import markdown
import os import os
from os import path
import pathlib import pathlib
from datetime import datetime
from os import path
import config import config
import markdown
ENTRY_DIR = "templates/entry" ENTRY_DIR = "templates/entry"
LANGUAGE = config.LANGUAGE
LOCAL = "de_DE.UTF-8" if LANGUAGE == "de-de" else "en_US.UTF-8"
locale.setlocale(locale.LC_TIME, LOCAL)
standalone_str = "Artikel" if LANGUAGE == "de-de" else "standalone"
def gen_arch_string(): def gen_arch_string():
""" """
Creates and returns a archive string of every file in ENTRY_DIR. Creates and returns a archive string of every file in ENTRY_DIR.
Returns: Returns:
string: html-formatted archive-string string: html-formatted archive-string
""" """
path_ex = ENTRY_DIR path_ex = ENTRY_DIR
if path.exists(path_ex): if path.exists(path_ex):
name_list = os.listdir(path_ex) name_list = os.listdir(path_ex)
full_list = [os.path.join(path_ex, i) for i in name_list] full_list = [os.path.join(path_ex, i) for i in name_list]
contents = sorted(full_list, key=os.path.getctime) contents = sorted(full_list, key=os.path.getctime)
content_string = "" content_string = ""
last_month = "" last_month = ""
for file in reversed(contents): for file in reversed(contents):
curr_date = datetime.fromtimestamp( curr_date = datetime.fromtimestamp(os.path.getctime(file)).strftime("%Y-%m-%d")
os.path.getctime(file)).strftime("%Y-%m-%d") curr_month = datetime.fromtimestamp(os.path.getctime(file)).strftime("%B %Y")
curr_month = datetime.fromtimestamp( if curr_month != last_month:
os.path.getctime(file)).strftime("%b %Y") if last_month != "":
if curr_month != last_month: content_string += "</ul>\n"
if last_month != "": content_string += "<h2>" + curr_month + "</h2>\n"
content_string += "</ul>\n" content_string += "<ul>\n"
content_string += "<h2>" + curr_month + "</h2>\n" last_month = curr_month
content_string += "<ul>\n" filename = pathlib.PurePath(file)
last_month = curr_month title = open(filename).readline().rstrip("\n")
filename = pathlib.PurePath(file) filename = filename.name
title = open(filename).readline().rstrip("\n") if filename[0] != ".":
filename = filename.name filename = filename.split(".", 1)[0]
if filename[0] != ".": content_string += "<li>"
filename = filename.split(".", 1)[0] content_string += "<a href=\"" + "/index.html#" + \
content_string += "<li>" filename + "\">" + curr_date + "</a> - "
content_string += curr_date + " - " content_string += "<a href=\"" + "/entry/" + \
content_string += title + " [" pathlib.PurePath(file).name + "\"><b>" + title + "</b></a>"
content_string += "<a href=\"" + "/index.html#" + \ content_string += "<br>"
filename + "\">" + "link" + "</a> - " content_string += "</li>\n"
content_string += "<a href=\"" + "/entry/" + \ content_string += "</ul>\n"
pathlib.PurePath(file).name + "\">" + "standalone" + "</a>" return content_string
content_string += "] <br>"
content_string += "</li>\n"
content_string += "</ul>\n"
return content_string
def gen_index_string(): def gen_index_string():
""" """
Create and returns a string including every file in the ENTRY_DIR as an index. Create and returns a string including every file in the ENTRY_DIR as an index.
Returns: Returns:
string: html-formatted index string string: html-formatted index string
""" """
path_ex = ENTRY_DIR path_ex = ENTRY_DIR
content_string = "" content_string = ""
if path.exists(path_ex): if path.exists(path_ex):
name_list = os.listdir(path_ex) name_list = os.listdir(path_ex)
full_list = [os.path.join(path_ex, i) for i in name_list] full_list = [os.path.join(path_ex, i) for i in name_list]
contents = sorted(full_list, key=os.path.getctime) contents = sorted(full_list, key=os.path.getctime)
for file in reversed(contents): for file in reversed(contents):
filename = pathlib.PurePath(file) filename = pathlib.PurePath(file)
purefile = filename purefile = filename
title = open(filename).readline().rstrip("\n") title = open(filename).readline().rstrip("\n")
text = open(filename).readlines()[1:] text = open(filename).readlines()[1:]
filename = filename.name filename = filename.name
if filename[0] != ".": if filename[0] != ".":
filename = filename.split(".", 1)[0] filename = filename.split(".", 1)[0]
content_string += "<div class=\"entry\">\n" content_string += "<div class=\"entry\">\n"
content_string += "<h2 id=\"" + filename + "\">" + title + "</h2>\n" content_string += "<h2 id=\"" + filename + "\">"
content_string += "[<a href=\"" + "/entry/" + \ content_string += "<a href=\"" + "/entry/" + \
pathlib.PurePath(file).name + "\">" + \ pathlib.PurePath(file).name + "\">" + \
"standalone" + "</a>]<br>\n" title + "</a>" +"</h2>\n"
if file.endswith(".html"): content_string += "<small>" + \
for line in text: datetime.fromtimestamp(os.path.getctime(
content_string += line file)).strftime("%Y-%m-%d") + "</small><br><br>"
content_string += "<br>" if file.endswith(".html"):
if file.endswith(".md"): for line in text:
content_string += gen_md_content(file, 2) content_string += line
content_string += "<small>" + \ content_string += "<br>"
datetime.fromtimestamp(os.path.getctime( if file.endswith(".md"):
file)).strftime("%Y-%m-%d") + "</small>" content_string += gen_md_content(file, 2)
content_string += "</div>" content_string += "</div>"
return content_string return content_string
def gen_stand_string(path_ex): def gen_stand_string(path_ex):
""" """
Creates a html-string for a file. Creates a html-string for a file.
If the file is markdown it will convert it. If the file is markdown it will convert it.
This functions ensures upscaling for future formats. This functions ensures upscaling for future formats.
@ -102,28 +106,29 @@ def gen_stand_string(path_ex):
Returns: Returns:
string: html-formatted string string equivalent to the file string: html-formatted string string equivalent to the file
""" """
filename = os.path.join(ENTRY_DIR, path_ex) filename = os.path.join(ENTRY_DIR, path_ex)
content_string = "" content_string = ""
if path.exists(filename): if path.exists(filename):
title = open(filename).readline().rstrip("\n") title = open(filename).readline().rstrip("\n")
text = open(filename).readlines()[1:] text = open(filename).readlines()[1:]
filename_no_end = filename.split(".", 1)[0] curr_date = datetime.fromtimestamp(os.path.getctime(filename)).strftime("%Y-%m-%d")
content_string += "<h1>" + title + "</h1>\n" filename_no_end = filename.split(".", 1)[0]
content_string += "[" filename_no_end = filename_no_end.split("/")[-1]
content_string += "<a href=\"" + "/index.html#" + \ content_string += "<h1>" + title + "</h1>\n"
filename_no_end + "\">" + "link" + "</a>" content_string += "<a href=\"" + "/index.html#" + \
content_string += "]<br>\n" filename_no_end + "\">" + curr_date + "</a>"
if filename.endswith(".html"): content_string += "<br>\n"
for line in text: if filename.endswith(".html"):
content_string += line for line in text:
content_string += "<br>" content_string += line
if filename.endswith(".md"): content_string += "<br>"
content_string += gen_md_content(filename, 1) if filename.endswith(".md"):
return content_string content_string += gen_md_content(filename, 1)
return content_string
def gen_md_content(path_ex, depth): def gen_md_content(path_ex, depth):
""" """
Convert a markdown file to a html string. Convert a markdown file to a html string.
Parameters: Parameters:
@ -133,54 +138,52 @@ def gen_md_content(path_ex, depth):
Returns: Returns:
string: html-formatted string string equivalent to the markdown file string: html-formatted string string equivalent to the markdown file
""" """
content_string = "" content_string = ""
if path.exists(path_ex): if path.exists(path_ex):
filename = path_ex.split(".", 1) filename = path_ex.split(".", 1)
fileend = filename[len(filename) - 1] fileend = filename[len(filename) - 1]
header = "#" header = "#"
for i in range(depth): for i in range(depth):
header += "#" header += "#"
header += " " header += " "
markdown_lines = open(path_ex, "r").readlines()[1:] markdown_lines = open(path_ex, "r").readlines()[1:]
markdown_text = "" markdown_text = ""
for line in markdown_lines: for line in markdown_lines:
markdown_text += line.replace("# ", header) markdown_text += line.replace("# ", header)
content_string = markdown.markdown( content_string = markdown.markdown(markdown_text, extensions=["fenced_code", "tables"])
markdown_text, extensions=["fenced_code", "tables"] return content_string
)
return content_string
def get_rss_string(): def get_rss_string():
""" """
Create a rss-string of the blog and return it. Create a rss-string of the blog and return it.
Returns: Returns:
string: rss-string of everything that is in the ENTRY_DIR. string: rss-string of everything that is in the ENTRY_DIR.
""" """
path_ex = ENTRY_DIR path_ex = ENTRY_DIR
if path.exists(path_ex): if path.exists(path_ex):
name_list = os.listdir(path_ex) name_list = os.listdir(path_ex)
full_list = [os.path.join(path_ex, i) for i in name_list] full_list = [os.path.join(path_ex, i) for i in name_list]
contents = sorted(full_list, key=os.path.getctime) contents = sorted(full_list, key=os.path.getctime)
content_string = "" content_string = ""
for file in reversed(contents): for file in reversed(contents):
filename = pathlib.PurePath(file) filename = pathlib.PurePath(file)
title = open(filename).readline().rstrip("\n") title = open(filename).readline().rstrip("\n")
text = open(filename).readlines()[1:] text = open(filename).readlines()[1:]
filename = filename.name filename = filename.name
if filename[0] != ".": if filename[0] != ".":
filename = filename.split(".", 1)[0] filename = filename.split(".", 1)[0]
content_string += "<item>\n" content_string += "<item>\n"
content_string += "<title>" + title + "</title>\n" content_string += "<title>" + title + "</title>\n"
content_string += "<guid>" + config.WEBSITE + \ content_string += "<guid>" + config.WEBSITE + \
"/index.html#" + filename + "</guid>\n" "/index.html#" + filename + "</guid>\n"
content_string += "<pubDate>" + \ content_string += "<pubDate>" + \
datetime.fromtimestamp(os.path.getctime(file)).strftime( datetime.fromtimestamp(os.path.getctime(file)).strftime(
"%Y-%m-%d") + "</pubDate>\n" "%Y-%m-%d") + "</pubDate>\n"
content_string += "<description>" content_string += "<description>"
for line in text: for line in text:
content_string += line content_string += line
content_string += "</description>\n" content_string += "</description>\n"
content_string += "</item>\n" content_string += "</item>\n"
return content_string return content_string

@ -1,2 +1,2 @@
Flask==1.1.2 Flask
Markdown==3.1.1 Markdown

@ -6,7 +6,7 @@
--error: rgb(255,0,0); --error: rgb(255,0,0);
--footerbg0: rgb(192,192,192); --footerbg0: rgb(192,192,192);
--link0: rgb(0,0,120); --link0: rgb(0,0,120);
--link1: rgb(255,255,255); --link1: rgb(0,0,0);
--menulink0: rgb(0,0,120); --menulink0: rgb(0,0,120);
--menulink1: rgb(255,255,255); --menulink1: rgb(255,255,255);
--menubg0: rgb(192,192,192); --menubg0: rgb(192,192,192);

@ -76,6 +76,10 @@ footer .center {
padding-top: 10px; padding-top: 10px;
} }
.main-menu-dropdown img {
float: left;
}
.main-menu-dropdown span { .main-menu-dropdown span {
float: left; float: left;
font-family: monospace; font-family: monospace;
@ -167,3 +171,24 @@ footer .center {
padding-left: 20; padding-left: 20;
} }
figure {
padding:20px;
}
ul {
padding-left:20px;
}
ol {
padding-left:20px;
}
code {
border-radius: 25px;
padding-left: 20px;
padding-right: 20px;
page-break-inside: avoid;
font-family: monospace;
white-space: pre;
display: inline-block
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div class="blogarchive"> <div class="blogarchive">
<h1>Archive</h1><br> <h1>{% if language=="de-de" %}Archiv{% else %}Archive{% endif %}</h1><br>
{% autoescape off %} {% autoescape off %}
{{ content_string }} {{ content_string }}
{% endautoescape %} {% endautoescape %}

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div class="important"> <div class="important">
Error<br> {% if language=="de-de" %}Fehler{% else %}Error{% endif %}<br>
<span>{{ errorcode }}</span> <span>{{ errorcode }}</span>
</div> </div>
</div> </div>

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div class="blog"> <div class="blog">
<h1>Index</h1><br> <h1>Feed</h1><br>
{% autoescape off %} {% autoescape off %}
{{ content_string }} {{ content_string }}
{% endautoescape %} {% endautoescape %}

@ -4,7 +4,7 @@
<channel> <channel>
<title>{{ title }}</title> <title>{{ title }}</title>
<description>{{ description }}</description> <description>{{ description }}</description>
<language>en-us</language> <language>{{ language }}</language>
<link>{{ website }}/feed.xml</link> <link>{{ website }}/feed.xml</link>
<atom:link href="/feed.xml" rel="self" type="application/rss+xml" /> <atom:link href="/feed.xml" rel="self" type="application/rss+xml" />

@ -2,19 +2,22 @@
<head> <head>
<title>{{ title }}</title> <title>{{ title }}</title>
<link href="{{ url_for('static', filename='css/' + style + '.css') }}" rel="stylesheet" type="text/css"> <link href="{{ url_for('static', filename='css/' + style + '.css') }}" rel="stylesheet" type="text/css">
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='graphics/logo.png') }}">
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width" initial-scale=1.0> <meta name="viewport" content="width=device-width" initial-scale=1.0>
</head> </head>
<body> <body>
<!-- Menu --> <!-- Menu -->
<div class="main-menu-dropdown"> <div class="main-menu-dropdown">
<!-- <img class="logo" src="/static/images/logo.png"> --> <a href="{{ url_for('index') }}">
<span>{{ title }}</span> <img class="logo" src="{{ url_for('static', filename='graphics/logo.png') }}">
<span>{{ title }}</span>
</a>
<input type="checkbox" id="main-menu-check"> <input type="checkbox" id="main-menu-check">
<label for="main-menu-check" class="show-menu">&#9776;</label> <label for="main-menu-check" class="show-menu">&#9776;</label>
<div class="main-menu"> <div class="main-menu">
<a href="{{ url_for('index') }}">Blog</a> <a href="{{ url_for('index') }}">Blog</a>
<a href="{{ url_for('archive') }}">Archive</a> <a href="{{ url_for('archive') }}">{% if language=="de-de" %}Archiv{% else %}Archive{% endif %}</a>
<label for="main-menu-check" class="hide-menu">X</label> <label for="main-menu-check" class="hide-menu">X</label>
</div> </div>
</div> </div>
@ -25,7 +28,7 @@
<!-- Content --> <!-- Content -->
<footer> <footer>
<div class="center"> <div class="center">
Made with <a href="https://github.com/tiyn/beaker-blog">Beaker Blog </a>. Made with <a href="https://github.com/tiyn/beaker-blog">Beaker Blog</a>.
</div> </div>
</footer> </footer>
</body> </body>

Loading…
Cancel
Save