@ -0,0 +1,68 @@ |
|||
# Python Flask Wiki |
|||
|
|||
This is a simple wiki based on Pythons Flask framework. |
|||
There is much great wiki software. |
|||
Most of them are using some kind of database. |
|||
I however just want to put my markdown files in a directory and get a working wiki. |
|||
|
|||
## Features/To-Dos |
|||
|
|||
- [ ] Plain text support for blog entries |
|||
- [ ] Markdown Files (.md) |
|||
- [ ] Entry page |
|||
- [ ] Navigation |
|||
- [ ] Header |
|||
- [ ] Footer |
|||
- [ ] Switchable CSS |
|||
- [ ] CSS dark-theme |
|||
- [ ] CSS light-theme |
|||
- [ ] Config file |
|||
- [ ] Docker installation |
|||
- [ ] Enable variables/environment variables |
|||
- [ ] Logo |
|||
|
|||
## Usage |
|||
|
|||
### Create entries |
|||
|
|||
Wiki entries are managed by plain markdown files in the `templates/entry/` directory. |
|||
The first line of each document is reserved as the title of the document. |
|||
|
|||
## Deployment |
|||
|
|||
### PIP/Python |
|||
|
|||
- `git clone https://github.com/tiyn/tiyny-blog` |
|||
- `cd flaskblog/src` |
|||
- edit the `config.py` file according to your needs |
|||
- `pip3install -r requirements.txt` - install depenencies |
|||
- run `python app.py` |
|||
- blog is available on port 5000 |
|||
|
|||
### Docker |
|||
|
|||
Make sure you copy an example `config.py` and edit it before running the container. |
|||
The `config.py` can be found in the `src` folder. |
|||
|
|||
#### Volumes |
|||
|
|||
Set the following volumes with the -v tag. |
|||
|
|||
| Volume-Name | Container mount | Description | |
|||
|-------------|---------------------------|--------------------------------------------------------------| |
|||
| config-file | /blog/src/config.py | Config file | |
|||
| entries | /blog/src/templates/entry | Directory for blog entries | |
|||
| css | /blog/src/static/css | (optional) Directory for css files | |
|||
| html | /blog/src/templates | (optional) Directory for templates (entry-volume not needed) | |
|||
|
|||
#### Ports |
|||
|
|||
Set the following ports with the -p tag. |
|||
|
|||
| Container-Port | Recommended outside port | Protocol | Description | |
|||
|----------------|--------------------------|----------|-------------| |
|||
| 5000 | 80 | TCP | HTTP port | |
|||
|
|||
#### Example run-command |
|||
|
|||
`docker run --name wiki --restart unless-stopped -v ./config.py:/wiki/src/config.py -v entries:/wiki/src/templates/entry -p 80:5000 -d tiynger/tiyny-wiki` |
|||
@ -0,0 +1,21 @@ |
|||
FROM ubuntu |
|||
|
|||
MAINTAINER Tiyn tiyn@martenkante.eu |
|||
|
|||
RUN apt-get update |
|||
|
|||
RUN apt-get install python3 python3-pip git -y |
|||
|
|||
RUN git clone https://github.com/tiyn/tiyny-wiki /wiki |
|||
|
|||
WORKDIR /wiki/src |
|||
|
|||
RUN pip3 install -r requirements.txt |
|||
|
|||
VOLUME /wiki/src/templates/entry |
|||
|
|||
EXPOSE 5000 |
|||
|
|||
ENTRYPOINT [ "python3" ] |
|||
|
|||
CMD [ "app.py" ] |
|||
@ -0,0 +1,22 @@ |
|||
from flask import Flask, flash, make_response, render_template, request, redirect, abort |
|||
|
|||
import content as con_gen |
|||
import config |
|||
|
|||
|
|||
app = Flask(__name__) |
|||
|
|||
|
|||
@app.errorhandler(404) |
|||
def page_not_found(e): |
|||
return render_template('error.html', title=config.TITLE, errorcode='404', style=config.STYLE), 404 |
|||
|
|||
|
|||
@app.route('/') |
|||
@app.route('/index.html') |
|||
def index(): |
|||
return 'ok' |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
app.run(host='0.0.0.0') |
|||
@ -0,0 +1,8 @@ |
|||
# Name/title of your blog |
|||
TITLE = 'Tiyny-Wiki' |
|||
|
|||
# URL for your website: e.g. https://domain.tld |
|||
WEBSITE = 'localhost:5000' |
|||
|
|||
# Theme for the blog: dark, light |
|||
STYLE = 'dark' |
|||
@ -0,0 +1,10 @@ |
|||
import datetime |
|||
from datetime import datetime |
|||
import markdown |
|||
import os |
|||
from os import path |
|||
import pathlib |
|||
|
|||
import config |
|||
|
|||
ENTRY_DIR = 'templates/entry' |
|||
@ -0,0 +1,2 @@ |
|||
Flask==1.1.2 |
|||
Markdown==3.1.1 |
|||
@ -0,0 +1,72 @@ |
|||
@import 'style.css'; |
|||
|
|||
:root { |
|||
--bg0: rgb(29,32,33); |
|||
--color0: rgb(220,120,0); |
|||
--error: rgb(255,0,0); |
|||
--footerbg0: rgb(29,32,33); |
|||
--link0: rgb(220, 120, 0); |
|||
--link1: rgb(255,255,255); |
|||
--menulink0: rgb(220, 120, 0); |
|||
--menulink1: rgb(255,255,255); |
|||
--menubg0: rgb(29,32,33); |
|||
--text0: rgb(235,219,178); |
|||
--text1: rgb(220, 120, 0); |
|||
} |
|||
|
|||
a { |
|||
color: var(--link0); |
|||
transition: var(--transtime); |
|||
} |
|||
|
|||
a:hover { |
|||
color: var(--link1); |
|||
} |
|||
|
|||
body { |
|||
background: var(--bg0); |
|||
} |
|||
|
|||
footer { |
|||
background: var(--footerbg0); |
|||
color: var(--text0); |
|||
} |
|||
|
|||
span { |
|||
color: var(--text1); |
|||
} |
|||
|
|||
.container { |
|||
color: var(--text0); |
|||
} |
|||
|
|||
.container h1, |
|||
.container h2 { |
|||
color: var(--text1); |
|||
} |
|||
|
|||
.container .flash { |
|||
background-color: var(--error); |
|||
} |
|||
|
|||
.hide-menu:hover, |
|||
.main-menu a:hover, |
|||
.show-menu:hover { |
|||
color: var(--menulink1); |
|||
} |
|||
|
|||
.main-menu a { |
|||
color: var(--menulink0); |
|||
} |
|||
|
|||
.main-menu-dropdown { |
|||
background: var(--menubg0); |
|||
color: var(--menulink0); |
|||
} |
|||
|
|||
@media screen and (max-width:800px) { |
|||
|
|||
.main-menu { |
|||
background: var(--menubg0); |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
@import 'style.css'; |
|||
|
|||
:root { |
|||
--bg0: rgb(255,255,255); |
|||
--color0: rgb(0,0,120); |
|||
--error: rgb(255,0,0); |
|||
--footerbg0: rgb(192,192,192); |
|||
--link0: rgb(0,0,120); |
|||
--link1: rgb(255,255,255); |
|||
--menulink0: rgb(0,0,120); |
|||
--menulink1: rgb(255,255,255); |
|||
--menubg0: rgb(192,192,192); |
|||
--text0: rgb(0,0,0); |
|||
--text1: rgb(0,0,120); |
|||
} |
|||
|
|||
a { |
|||
color: var(--link0); |
|||
transition: var(--transtime); |
|||
} |
|||
|
|||
a:hover { |
|||
color: var(--link1); |
|||
} |
|||
|
|||
body { |
|||
background: var(--bg0); |
|||
} |
|||
|
|||
footer { |
|||
background: var(--footerbg0); |
|||
color: var(--text0); |
|||
} |
|||
|
|||
span { |
|||
color: var(--text1); |
|||
} |
|||
|
|||
.container { |
|||
color: var(--text0); |
|||
} |
|||
|
|||
.container h1, |
|||
.container h2 { |
|||
color: var(--text1); |
|||
} |
|||
|
|||
.container .flash { |
|||
background-color: var(--error); |
|||
} |
|||
|
|||
.hide-menu:hover, |
|||
.main-menu a:hover, |
|||
.show-menu:hover { |
|||
color: var(--menulink1); |
|||
} |
|||
|
|||
.main-menu a { |
|||
color: var(--menulink0); |
|||
} |
|||
|
|||
.main-menu-dropdown { |
|||
background: var(--menubg0); |
|||
color: var(--menulink0); |
|||
} |
|||
|
|||
@media screen and (max-width:800px) { |
|||
|
|||
.main-menu { |
|||
background: var(--menubg0); |
|||
} |
|||
} |
|||
@ -0,0 +1,153 @@ |
|||
:root { |
|||
--error: rgb(255,0,0); |
|||
--transtime: 0.7s; |
|||
} |
|||
|
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
a { |
|||
text-decoration: none; |
|||
transition: var(--transtime); |
|||
} |
|||
|
|||
a:hover { |
|||
cursor: pointer; |
|||
} |
|||
|
|||
body { |
|||
margin: 0; |
|||
} |
|||
|
|||
body, |
|||
html { |
|||
font-family: sans-serif; |
|||
height: 100%; |
|||
max-width: 100%; |
|||
overflow-x: hidden; |
|||
} |
|||
|
|||
footer { |
|||
height: 100px; |
|||
padding-top: 20px; |
|||
} |
|||
|
|||
footer .center { |
|||
text-align: center; |
|||
} |
|||
|
|||
.container { |
|||
min-height: 100%; |
|||
padding-bottom: 50px; |
|||
padding-left: 10%; |
|||
padding-right: 10%; |
|||
padding-top: 5%; |
|||
} |
|||
|
|||
.container .flash { |
|||
padding: 10px; |
|||
width: 400px; |
|||
} |
|||
|
|||
.hide-menu, |
|||
.show-menu { |
|||
cursor: pointer; |
|||
display: none; |
|||
font-size: 30px; |
|||
transition: var(--transtime); |
|||
} |
|||
|
|||
.important { |
|||
font-size: xx-large; |
|||
padding-left: 25vw; |
|||
padding-right: 25vw; |
|||
padding-top: 30vh; |
|||
text-align: left; |
|||
} |
|||
|
|||
.important span { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.logo { |
|||
height: 80px; |
|||
padding-top: 10px; |
|||
} |
|||
|
|||
.main-menu-dropdown span { |
|||
float: left; |
|||
font-family: monospace; |
|||
font-size: 30px; |
|||
font-weight: bold; |
|||
line-height: 100px; |
|||
padding: 0 10px; |
|||
text-decoration: none; |
|||
text-transform: uppercase; |
|||
transition: 0.7s; |
|||
} |
|||
|
|||
.main-menu { |
|||
float: right; |
|||
font-family: monospace; |
|||
font-size: 30px; |
|||
font-weight: bold; |
|||
line-height: 100px; |
|||
} |
|||
|
|||
.main-menu a { |
|||
padding: 0 10px; |
|||
text-decoration: none; |
|||
text-transform: uppercase; |
|||
transition: 0.7s; |
|||
} |
|||
|
|||
.main-menu-dropdown { |
|||
height: 100px; |
|||
padding: 0 20px; |
|||
} |
|||
|
|||
.show-menu { |
|||
float: right; |
|||
line-height: 100px; |
|||
} |
|||
|
|||
#main-menu-check { |
|||
position: absolute; |
|||
visibility: hidden; |
|||
z-index: -1111; |
|||
} |
|||
|
|||
@media screen and (max-width:800px) { |
|||
.hide-menu { |
|||
position: absolute; |
|||
right: 40px; |
|||
top: 40px; |
|||
} |
|||
|
|||
.hide-menu, |
|||
.show-menu { |
|||
display: block; |
|||
} |
|||
|
|||
.main-menu { |
|||
height: 100vh; |
|||
line-height: normal; |
|||
padding: 80px 0; |
|||
position: fixed; |
|||
right: -100%; |
|||
text-align: center; |
|||
top: 0; |
|||
transition: var(--transtime); |
|||
width: 100%; |
|||
} |
|||
.main-menu a { |
|||
display: block; |
|||
padding: 20px; |
|||
} |
|||
|
|||
#main-menu-check:checked ~ .main-menu { |
|||
right: 0; |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
Test Entry Title 3 |
|||
This is a markdown file |
|||
|
|||
- list entry |
|||
- list entry |
|||
- list entry |
|||
|
|||
# md-header |
|||
|
|||
more content |
|||
@ -0,0 +1,10 @@ |
|||
Test Entry Title 3 |
|||
This is a markdown file |
|||
|
|||
- list entry |
|||
- list entry |
|||
- list entry |
|||
|
|||
# md-header |
|||
|
|||
more content |
|||
@ -0,0 +1,10 @@ |
|||
Test Entry Title 3 |
|||
This is a markdown file |
|||
|
|||
- list entry |
|||
- list entry |
|||
- list entry |
|||
|
|||
# md-header |
|||
|
|||
more content |
|||
@ -0,0 +1,9 @@ |
|||
{% extends "template.html" %} |
|||
{% block content %} |
|||
<div class="container"> |
|||
<div class="important"> |
|||
Error<br> |
|||
<span>{{ errorcode }}</span> |
|||
</div> |
|||
</div> |
|||
{% endblock %} |
|||
@ -0,0 +1,32 @@ |
|||
<html> |
|||
<head> |
|||
<title>{{ title }}</title> |
|||
<link href="{{ url_for('static', filename='css/' + style + '.css') }}" rel="stylesheet" type="text/css"> |
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width", initial-scale=1.0> |
|||
</head> |
|||
<body> |
|||
<!-- Menu --> |
|||
<div class="main-menu-dropdown"> |
|||
<!-- <img class="logo" src="/static/images/logo.png"> --> |
|||
<span>{{ title }}</span> |
|||
<input type="checkbox" id="main-menu-check"> |
|||
<label for="main-menu-check" class="show-menu">☰</label> |
|||
<div class="main-menu"> |
|||
<a href="/">Startpage</a> |
|||
<label for="main-menu-check" class="hide-menu">X</label> |
|||
</div> |
|||
</div> |
|||
<!-- Menu --> |
|||
<!-- Content --> |
|||
{% block content %} |
|||
{% endblock %} |
|||
<!-- Content --> |
|||
<footer> |
|||
<div class="center"> |
|||
Dieser Blog enthält kein Javascript oder PHP.<br> |
|||
Dies ist eine Instanz vom <a href="https://github.com/tiyn/tiyny-wiki">Tiyny-Wiki</a>. |
|||
</div> |
|||
</footer> |
|||
</body> |
|||
</html> |
|||