1
0
mirror of https://github.com/tiyn/beaker-blog.git synced 2025-04-19 15:27:47 +02:00

Compare commits

..

9 Commits

Author SHA1 Message Date
b598b99c73 added favicon 2024-04-14 02:42:36 +02:00
1adad6762d improve style for code 2024-04-14 02:27:53 +02:00
e151dac3da make logo standard 2024-04-14 02:23:10 +02:00
98249bbbd9 added language support for german 2024-04-14 01:58:29 +02:00
1ac2ba220a improved light style for better readability 2024-04-14 00:44:27 +02:00
4679305c51 added more style and fixed a link bug 2024-04-14 00:31:07 +02:00
d83f66ab3d update automatically 2024-04-13 23:55:10 +02:00
6c586c6a89 minor style changes, added graphics volume 2024-04-13 23:41:02 +02:00
472d8c74c6 readme: fixed typo 2022-07-30 23:57:15 +02:00
16 changed files with 206 additions and 153 deletions

View File

@ -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" ]

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

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

View File

@ -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);

View File

@ -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
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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" />

View File

@ -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>