From 1f9bbbd2cab687c1dcc6d05969e01b66d04f4867 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Thu, 9 Jul 2020 11:26:30 +0200 Subject: [PATCH] Initial --- .gitignore | 7 + README.md | 106 +++++++++++++++ config.json | 10 ++ markdown/example_markdown.md | 54 ++++++++ news/example_news.json | 10 ++ people/10_john_doe.json | 6 + people/20_jane_doe.json | 6 + sections/00-example-section.json | 7 + sections/10-example-section.json | 5 + sections/20-example-section.json | 7 + server.py | 197 ++++++++++++++++++++++++++++ static/defaultFavicon.ico | Bin 0 -> 15406 bytes static/pictures/placeholder.png | Bin 0 -> 2186 bytes static/pictures/wallpaper.jpg | 1 + static/site.css | 70 ++++++++++ static/toggle_button.css | 63 +++++++++ templates/announcements.html | 18 +++ templates/events.html | 43 ++++++ templates/footer.html | 3 + templates/head.html | 14 ++ templates/impressum.html | 51 +++++++ templates/impressum_text.html | 21 +++ templates/index.html | 126 ++++++++++++++++++ templates/navbar.html | 61 +++++++++ templates/news.html | 28 ++++ templates/people.html | 34 +++++ templates/subpage_example.html | 23 ++++ templates/subpage_example_text.html | 21 +++ 28 files changed, 992 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config.json create mode 100644 markdown/example_markdown.md create mode 100644 news/example_news.json create mode 100644 people/10_john_doe.json create mode 100644 people/20_jane_doe.json create mode 100644 sections/00-example-section.json create mode 100644 sections/10-example-section.json create mode 100644 sections/20-example-section.json create mode 100755 server.py create mode 100644 static/defaultFavicon.ico create mode 100644 static/pictures/placeholder.png create mode 120000 static/pictures/wallpaper.jpg create mode 100644 static/site.css create mode 100644 static/toggle_button.css create mode 100644 templates/announcements.html create mode 100644 templates/events.html create mode 100644 templates/footer.html create mode 100644 templates/head.html create mode 100644 templates/impressum.html create mode 100644 templates/impressum_text.html create mode 100644 templates/index.html create mode 100644 templates/navbar.html create mode 100644 templates/news.html create mode 100644 templates/people.html create mode 100644 templates/subpage_example.html create mode 100644 templates/subpage_example_text.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51ef840 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +js/ +css/ +*.swp +*.jpg +*.png +cache.json +auth.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..4eecf3c --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +# Requirements +This Softwares runs python3-flask with markdown, json and caldav. + + python3 -m pip install flask, json, caldav, markdown2 + +This Software requires bootstrap > 4.13 which can be downloaded [here](https://getbootstrap.com/docs/4.3/getting-started/download/). It must be unpacked into the *static/*-directory into *js* and *css* respectively. + +Additionally bootstrap depends on [jquery](https://code.jquery.com) which you have to download into a file called *jquery.min.js* in *static/js/*. + +# Usage + + ./server.py -h + usage: server.py [-h] [-i INTERFACE] [-p PORT] --cal-info CAL_INFO + [--no-update-on-start] + + optional arguments: + -h, --help show this help message and exit + -i INTERFACE Interface to listen on (default: 0.0.0.0) + -p PORT, --port PORT Port to listen on (default: 5000) + --cal-info CAL_INFO File Containing a public calendar link (default: None) + --no-update-on-start Don't update the calendar on start (default: False) + + +# Configuration +The page and most of it's content is configured via json. To use the CalDav-events section, you need to add a comma seperated file with the following format format/information: + + URL,USER,PASSWORD + +## Main Config +The main Config ``config.json`` which must be placed in the project-root must contain the following values: + + { + "siteTitle":"the default site title", + } + +Additionally it may contain the following information: + + "teamspeak-server" : "TS_SERVER", + "discord-server" : "DISCORD_LINK", + "facebook" : "FACEBOOK_LINK", + "instagram" : "INSTAGRAM_LINK", + "twitter" : "TWITTER_LINK" + +## Startpage Sections +### Events +The events section from the start-page is imported from the calendar and will show events a given time in the future or past. It will by default show three events. If there are more than three events, a *'More'*-button will be displayed. If there are no events the section will not be shown at all. + +### News/Announcements +This Section will read and display JSON configuration from the *news/*-direcotry. A news-configuration must contain these information: + + { + "title" : "title of the announcement", + "uid" : a_unique_integer_number, + "markdown-file" : "path to markdown file containing the actual announcement", + "active" : boolean_if_it_should_be_displayed, + "description" : "a short description", + "date" : date_posted_as_unix_timestamp, + } + +Additionally it must contain either a 'fixed-timeout' or 'relative-timeout-weeks' after which it will no longer be displayed. If both a specified the fixed timeout takes precedence. + + "timeout-relative-weeks" : 12, + "timeout-fixed" : a_date_as_unix_timestamp + +Finally it MAY contain a text to display on the button leading to the article (otherwise it will use a default). + + "link-text" : "maximum 25 characters" + +Obviously the markdown file referenced in the configuration must also be created. + +### Other Sections +All following sections are read and created from the *vereinSection* directory. Json configuration for these sections much contain these information. The pictures for all the sections should have a similar aspect ratio. + + { + "picture" : "path to a picture for this section", + "title" : "A title for this card", + "text" : "A potentially very long text of multiple lines that will be displayed next to the picture...", + } + +The configuration may contain the following information, which add a button-like link to the section. + + "moreInfoButtonText" : "less than 25 charaters", + "moreInfoButtonHref" : "href to go to" + +The alpha-numeric order of the filenames specifies the order in which the sections will be displayed on the website, so the files should be prefixed with a number, for example *10_section_hello.json* and *90_section_ending.json*. + +## People +To display a person on the people-subpage create a JSON-file in the *people/*-directory containing the following information: + + { + "title" : "Name of the Person", + "subtitle" : "Function of the Person", + "image" : "path to image", + "text" : "Potentially long text describing the person and their functions." + } + +The order is again specified by the alpha-numeric order of the files. + +# Adding new Subpages +New subpages must be added as a new location in the *server.py* like this: + + @app.route("/subpage") + def subpage(): + return flask.render_template("subpage.html", conf=mainConfig) + +See the example subpage-templates in *templates/*. diff --git a/config.json b/config.json new file mode 100644 index 0000000..767c897 --- /dev/null +++ b/config.json @@ -0,0 +1,10 @@ +{ + "siteTitle":"Site Title", + "teamspeak-server" : "teamspeak.com", + "discord-server" : "https://discord.gg/", + "facebook" : "https://www.facebook.com/", + "instagram" : "https://www.instagram.com/", + "twitter" : "https://twitter.com/its_a_sheppy", + "twitch-channel" : "esports-erlangen", + "twitch-placeholder-img" : "placeholder.png" +} diff --git a/markdown/example_markdown.md b/markdown/example_markdown.md new file mode 100644 index 0000000..c534768 --- /dev/null +++ b/markdown/example_markdown.md @@ -0,0 +1,54 @@ +# Utero est + +## Plurima duro adeo viros spargere fletumque feras + +Lorem markdownum Eurytion Troiana *nescioquam* fuit, tenuesque manebant illic +admittitur vultu. Praereptaque potitus vento. + +1. Nec ostia sinus tellure +2. Esse focus labori hastas quippe +3. Vivos misit claustraque ille +4. Nusquam simulacra daedalus inde servor accessit obliquis +5. Restabam aestusque videri puerum dum videri nomen +6. Et radice cladis natus surgit ante + +## Indicio hoc + +Te spoliare lux sonuere genas: et medi Iuppiter litoris fama Piraeaque Phrygia +amorem obsessa animas? Nostros sustulit cauda cautus videntur consiste si +videtur *copia sed* inmemor ope nimia, proles. Sumpta Calydonida avido ipsorum +Phoebus tum fortuna rupit res: haud illa inpulsu et referre duabus. Ossaque +[albescere](http://contra-servavique.net/) nulla facta foedumque thalamos +deposuit accipit imago iactu percutiens **hostes**. + +**Utinam versasse** sorores mirantes: rigidum cognoscite vicit ulterius famulis, +suis. Iam navita ferarum cacumina sincera tuli, iusserat pharetrae quod carne +at? Sororum videbitur aethera amor, mera lugubre [aetas artes +captantur](http://levibus.net/) conantem suae thalamos Minervaetransformabantur, +querenda capro ab media *quoque*. Cum sibila ait illa velo, et ab vestes iubent +crevit. + +## Primusque Phaethon ramis + +[Felici maduisse](http://latonaetransitus.io/non). Sub bimembres decipienda est +texta stipes. Ense ordine poscit rescindere **vidit** fulmina cubile leones! +Virgo per quatit ducem intabescere locus et superi ab quotiens amantes nos +dissimiles si pateres hastas. Magna imago, imperat discederet tanto loquebatur +turbatus, aether esse missus, in. + +## Socialis Amor delubraque non et anseribus bracchia + +Addicere graia qualis passu orantemque honorem Achaia coruscant Talia in ripae +perstat refert mediusve nemorum parentis. Cupit specie patuisse ad laniata et +patuit capillis pulsatus; primo est bis! Minervae accensus unda, tactosque +corpus, dea Iuppiter, vota herba, per deam inmitem **negata** visa inmania +extimuit? *Forent atque fulvis* vultu fidibusque causa, maestis purus per. + +> In meritorum Lycaona in est velum ambo: si dixit et nubibus, illa quid Icelon. +> Sententia possis dumque; relinquam mandatam, ad leti terrebat gramen aenum, +> templis Issen atrorum. + +Et tegebat eodem minimus curae, miseri illo huic *viscera ulli*, atque toros non +ego certaminis facibus. Sinus nec [Althaea](http://www.fortiatelum.io/), cum +Laelapa arbore, [contentus quam](http://www.vincere.io/nostras-qui): non, *et*. +Manebit dentes dedisses licet Vix Ilion quam putares gemino. diff --git a/news/example_news.json b/news/example_news.json new file mode 100644 index 0000000..93ccad6 --- /dev/null +++ b/news/example_news.json @@ -0,0 +1,10 @@ +{ + "title" : "Title", + "uid" : 15, + "markdown-file" : "markdown/example_markdown.md", + "active" : true, + "description" : "Lorem markdownum Eurytion Troiana *nescioquam* fuit, tenuesque manebant illic admittitur vultu. Praereptaque potitus vento.", + "date" : 1594282463, + "timeout-relative-weeks" : 60, + "timeout-fixed" : 2094282463 +} diff --git a/people/10_john_doe.json b/people/10_john_doe.json new file mode 100644 index 0000000..a63fa3d --- /dev/null +++ b/people/10_john_doe.json @@ -0,0 +1,6 @@ +{ + "title" : "John Doe", + "subtitle" : "CEO & Founder", + "image" : "placeholder.png", + "text" : "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English." +} diff --git a/people/20_jane_doe.json b/people/20_jane_doe.json new file mode 100644 index 0000000..1ea105c --- /dev/null +++ b/people/20_jane_doe.json @@ -0,0 +1,6 @@ +{ + "title" : "Jane Doe", + "subtitle" : "COO & Founder", + "image" : "placeholder.png", + "text" : "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English." +} diff --git a/sections/00-example-section.json b/sections/00-example-section.json new file mode 100644 index 0000000..5f0d994 --- /dev/null +++ b/sections/00-example-section.json @@ -0,0 +1,7 @@ +{ + "picture" : "/static/pictures/placeholder.png", + "title" : "Section Title", + "text" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + "moreInfoButtonText" : "Mehr..", + "moreInfoButtonHref" : "/impressum" +} diff --git a/sections/10-example-section.json b/sections/10-example-section.json new file mode 100644 index 0000000..595a094 --- /dev/null +++ b/sections/10-example-section.json @@ -0,0 +1,5 @@ +{ + "picture" : "/static/pictures/placeholder.png", + "title" : "Section Title", + "text" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." +} diff --git a/sections/20-example-section.json b/sections/20-example-section.json new file mode 100644 index 0000000..5f0d994 --- /dev/null +++ b/sections/20-example-section.json @@ -0,0 +1,7 @@ +{ + "picture" : "/static/pictures/placeholder.png", + "title" : "Section Title", + "text" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + "moreInfoButtonText" : "Mehr..", + "moreInfoButtonHref" : "/impressum" +} diff --git a/server.py b/server.py new file mode 100755 index 0000000..074ccc2 --- /dev/null +++ b/server.py @@ -0,0 +1,197 @@ +#!/usr/bin/python3 +import json +import os +import flask +import argparse + +import caldav +import datetime as dt +import markdown2 + +VEREIN_SECTIONS_DIR = "sections/" +MAIN_LINKS_DIR = "main-links/" +NEWS_DIR = "news/" + +app = flask.Flask("athq-landing-page") +mainConfig = dict() +with open("config.json") as f: + mainConfig = json.load(f) + +caldavUrl = None +caldavPassword = None +caldavUsername = None + +def updateEventsFromCalDav(): + + + if app.config["USE_CALENDAR"]: + client = caldav.DAVClient(url=caldavUrl, username=caldavUsername, password=caldavPassword) + authenticatedClient = client.principal() + defaultCal = authenticatedClient.calendars()[0] + + start = dt.datetime.now() + start = start - dt.timedelta(seconds=start.timestamp() % dt.timedelta(days=1).total_seconds()) + end = start + dt.timedelta(days=90) + + # TODO remove this + # start = start - dt.timedelta(days=90) + + events = sorted(defaultCal.date_search(start, end), + key=lambda e: e.vobject_instance.vevent.dtstart.value) + eventsDictList = [] + for e in events: + date = e.vobject_instance.vevent.dtstart.value + date += dt.timedelta(hours=2) + newEventDict = { "description" : e.vobject_instance.vevent.summary.value, + "time" : date.strftime("%H:%M"), + "day" : date.strftime("%d"), + "month" : date.strftime("%b"), + "year" : date.strftime("%Y") } + try: + newEventDict.update({ "location" : e.vobject_instance.vevent.location.value }) + except AttributeError: + pass + eventsDictList += [newEventDict] + else: + eventsDictList = [] + + with open("cache.json", "w") as f: + json.dump(eventsDictList, f) + + +def getEventsCache(): + with open("cache.json", "r") as f: + return json.load(f) + +def readJsonDir(basedir): + + # load json files from projects/ dir # + jsonDictList =[] + for root, dirs, files in os.walk(basedir): + for filename in sorted(files): + if filename.endswith(".json"): + with open(os.path.join(basedir, filename)) as f: + jsonDictList += [json.load(f)] + + return jsonDictList + +def parseNewsDirWithTimeout(): + + TIMEOUT_RELATIVE = "timeout-relative-weeks" + TIMEOUT_FIXED = "timeout-fixed" + PARSED_TIME = "parsed-time" + ACTIVE = "active" + DATE = "date" + + news = readJsonDir(NEWS_DIR) + now = dt.datetime.now() + for n in news: + n.update( { PARSED_TIME : dt.datetime.fromtimestamp(n[DATE]) } ) + if n.get(ACTIVE): + continue + if n.get(TIMEOUT_FIXED): + if dt.datetime.fromtimestamp(n[TIMEOUT_FIXED]) < now: + n[ACTIVE] = False + elif n.get(TIMEOUT_RELATIVE): + if n[PARSED_TIME] + dt.timedelta(weeks=n[TIMEOUT_RELATIVE]) < now: + n[ACTIVE] = False + else: + raise ValueError("No timeout for news {} specified!", n) + + return sorted(news, key=lambda n: n[PARSED_TIME], reverse=True) + + +@app.route("/invalidate") +def invalidateEventCache(): + updateEventsFromCalDav(); + return ("", 204) + +@app.route("/") +def root(): + announcements = parseNewsDirWithTimeout() + return flask.render_template("index.html", mainLinks=readJsonDir(MAIN_LINKS_DIR), + siteTitle=mainConfig["siteTitle"], + conf=mainConfig, + events=getEventsCache(), + moreEvents=len(getEventsCache())>3, + vereinSections=readJsonDir(VEREIN_SECTIONS_DIR), + announcements=announcements) + +@app.route("/impressum") +def impressum(): + return flask.render_template("impressum.html", conf=mainConfig) + +@app.route("/verein") +def verein(): + return flask.render_template("verein.html", conf=mainConfig) + +@app.route("/stammtisch") +def stammtisch(): + return flask.render_template("stammtisch.html", conf=mainConfig) + +@app.route("/people") +def people(): + return flask.render_template("people.html", conf=mainConfig, + people=readJsonDir("people/")) + +@app.route("/news") +def news(): + + uid = int(flask.request.args.get("uid")) + + news = parseNewsDirWithTimeout() + newsDict = dict() + for n in news: + newsDict.update( { n["uid"] : n } ) + + if not uid or not newsDict[uid]: + return ("", 404) + + article = newsDict[uid] + try: + with open(article["markdown-file"]) as f: + article.update( { "markdown-content" : markdown2.markdown(f.read()) } ) + except FileNotFoundError as e: + return ("File not found Error ({})".format(e), 404) + + return flask.render_template("news.html", conf=mainConfig, article=article) + +@app.route("/static/") +def sendStatic(path): + if "pictures" in path: + cache_timeout = 2592000 + else: + cache_timeout = None + return flask.send_from_directory('static', path, cache_timeout=cache_timeout) + +@app.route('/defaultFavicon.ico') +def icon(): + return app.send_static_file('defaultFavicon.ico') + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Projects Showcase', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + # general parameters # + parser.add_argument("-i", "--interface", default="0.0.0.0", help="Interface to listen on") + parser.add_argument("-p", "--port", default="5000", help="Port to listen on") + parser.add_argument("--cal-info", help="File Containing a public calendar link") + parser.add_argument("--no-update-on-start", action="store_const", const=True, default=False, + help="Don't update the calendar on start") + + # startup # + app.config['TEMPLATES_AUTO_RELOAD'] = True + args = parser.parse_args() + + if args.cal_info: + app.config["USE_CALENDAR"] = True + with open(args.cal_info) as f: + caldavUrl, caldavUsername, caldavPassword = f.read().strip().split(",") + else: + app.config["USE_CALENDAR"] = False + + if not args.no_update_on_start: + updateEventsFromCalDav() + + app.run(host=args.interface, port=args.port) diff --git a/static/defaultFavicon.ico b/static/defaultFavicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..76aa37753f9d212837c3e4f228fe7781a372f5fe GIT binary patch literal 15406 zcmeI2SBq6i5XaB5`vKgCeV?brN1yh2zl1rBn8tvjm=mHH5VM$b#4IW*CNK^NDu@YG z7<0}!|M&dpEl#+7t~29aon`t$(f9PJ>Z-1;Q(axvQS?jnYt*7e6t`7T&2LfkR}@86 zRqnav?@_cO?rYWR-}iq;QSBd5)H242Nn#4uA2;4#>()|phj#6x>gohcA6>gj?b|#3 zv}u#P2NxQ{n=nB-dQ@7o#zBuB($1aI+O^W2J<`gRj`sZd1gCG`EdBK9$+L}X?cu|Y ze%m%b4*a)om!?dSh7C(_ka6;4Y2Q9aUt8;N#*a^M-~s)H4bte*(!hc4-Ktg6#*Nar zagxpb$PtG#e0V8+T7K{k9?asPvvTquJ0`7PFD+Z<=r(VbcItrr+k=dYwW8I`K1AG5j3^{;BBKoOK-L9=^3;15L*U zx^De>s z%NObXeQDvsWL$9hy?9YN&ZbQXp7FI7{wGcpzh~TCyOLM{I`-T7^QE_MrNxUKt?^Iq z#m1vt`z`+EXqPXSZru2J{3lIv`bNedJ%4QTF=Nay?fIB{aF|~)Nd2SZgb~K zSFcJpZ%TdoWcd@HrpK}vu4o-u|GK&)7Ph!~(4Z{;nKLC~KJ5SaacRbkY}{@7Cw8?l zXlKpJj+2+8KK8eJxAfqFGaL(;Wt5@!vI)oFY6N@V&T{+~ZP-->@V;CyC!?$ANnyH|Sm&glYQj85*}O>m4q zKGDXocJSZ?&&ITtb7k+|rBJlT@V#+fOrLES3%m4+Ne5)kSD3Et%Ywn=r`Cvuz_F$!3Kg21RDr8(0Cgl=R!?+%$RS3FAoMi z`3rJM)RKn`Da~V~*N56{eR!qo+-ds!fAToDZ%bdlx||w$_adPF4Lx}lY_tL3TZa&nQ(>#%#Uz)~f)9v-^60)Ufeg94VSFfZkTco8+i^1};vuC?}6nS#$ z@Z3XKvc%QasSA)pe)-bjkULGUo5_FfoJ6j@h~Jz!^~*7t{Er@G>j}QOS|9l<TlzkO$>Ye-7cZ6qwOpV4_)hL~agXcPE$3@k$17K))vNt_H2EJtmM&c?AQUE-z!b=cXV(@^K#( zpS5nC^Wphej5*>P^8J;PAAgKL;a;l`CQi)inZ4)C8Fyy5d|Bc?0DhZzn7EiYntQc* zI+LG!3*h^B(Py!GxwYh-`A_VbJ*)`w_j%ASwuAoJr#QDj%bIYvfb$9c^X6seZSos_ z5x;5EvUElBKo0gG&VA*eU%%q<@JE~lMvipActtS)-+nnh_KrI(MKXu}pqpR=!3Kg2 c1RDr85NsgWK(K)yWdrf`pzsSCXtW0Y0Yx3)tpET3 literal 0 HcmV?d00001 diff --git a/static/pictures/placeholder.png b/static/pictures/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..9260c977ae3a198e18719b75a9af19b93b91154a GIT binary patch literal 2186 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4kn<;H+e}VAjMc5^hd!9ald;Dvf+P2m+u^7Bj*GS7+Ge82ZtP(gsJM)?be00*nz4Bc4_ zjsL@^FflT%Z4lh{?-J(^p;ruzQ3s}P*w^r@Zq5jFyL^wZq`75FfC(-u(814>FVdQ&MBb@032 + {% for a in announcements if a.get("active") %} +
+
+
+

{{ a["parsed-time"].strftime("%d.%m.%y") }}

+

{{ a["title"] }}

+

{{ a["description"] }}

+

+ + {% if a["link-title"] %} {{ a["link-title"] }} {% else %} Mehr.. {% endif %} + +

+
+
+
+ {% endfor %} + diff --git a/templates/events.html b/templates/events.html new file mode 100644 index 0000000..0b181b2 --- /dev/null +++ b/templates/events.html @@ -0,0 +1,43 @@ +{% if events %} +
+
+
+
+ {% for event in events %} +
3 %} style="display: none;" {% endif %}> +
+
+
+

{{ event["day"] }}

+
+

{{ event["month"] }}

+

{{ event["year"] }}

+
+
+
+
+

+ {{ event["description"] }} + {% if event.get("location") %} @{{ event["location"] }} {% endif %} +

+

{{ event["time"] }}

+
+
+
+ {% endfor %} + {% if moreEvents %} + + {% endif %} +
+
+
+ + +{% endif %} diff --git a/templates/footer.html b/templates/footer.html new file mode 100644 index 0000000..d343b83 --- /dev/null +++ b/templates/footer.html @@ -0,0 +1,3 @@ + diff --git a/templates/head.html b/templates/head.html new file mode 100644 index 0000000..51b3cb8 --- /dev/null +++ b/templates/head.html @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/impressum.html b/templates/impressum.html new file mode 100644 index 0000000..9264649 --- /dev/null +++ b/templates/impressum.html @@ -0,0 +1,51 @@ + + + + + {% include 'head.html' %} + + {{ conf["siteTitle"] }} + + + + + {% include 'navbar.html' %} + +
+

Impressum

+
+
+

Hello World

+

Organisation
+ Hello World: Hello World
+ Hello World: Hello World
+ Mail: + noreply@example.com

+

Person

+

John Doe
+ Location
Postal City
+ Phone: 12345 6789

+
+
+

Hello World

+

Jane Doe
+ Location
Postal City
+

+

+

Admin C/Hello World

+

+ Free Text +

+ +
+
+
+
+ {% include 'impressum_text.html' %} +
+
+ + + {% include 'footer.html' %} + + diff --git a/templates/impressum_text.html b/templates/impressum_text.html new file mode 100644 index 0000000..c984b70 --- /dev/null +++ b/templates/impressum_text.html @@ -0,0 +1,21 @@ +

HTML Ipsum

+ +

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

+ +

Header Level 2

+ +
    +
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. +
  3. Aliquam tincidunt mauris eu risus.
  4. +
+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

+ +

Header Level 3

+ +
    +
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • +
  • Aliquam tincidunt mauris eu risus.
  • +
+ +

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus

diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..07b3464 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,126 @@ + + + + + + {% include 'head.html' %} + + {{ conf["siteTitle"] }} + + + + + + + + +{% include 'navbar.html' %} + + +
+
+
+
+
+
+ +
+
+
+
+ + +
+
+ {% include 'events.html' %} +
+
+ + +{% if announcements %} +
+
+ {% include 'announcements.html' %} +
+
+{% endif %} + + + {% if conf["twitch-channel"] %} +
+
+ + + +
+ + + + +
+
+ {% endif %} + + {% for section in vereinSections %} +
+
+
+
+ +
+
+

{{ section['title'] }}

+

+ {{ section["text"] }} +

+ {% if section["moreInfoButtonText"] %} + + {% endif %} +
+
+
+
+ {% endfor %} + + {% include 'footer.html' %} + + diff --git a/templates/navbar.html b/templates/navbar.html new file mode 100644 index 0000000..fc32ace --- /dev/null +++ b/templates/navbar.html @@ -0,0 +1,61 @@ + + diff --git a/templates/news.html b/templates/news.html new file mode 100644 index 0000000..f6382e2 --- /dev/null +++ b/templates/news.html @@ -0,0 +1,28 @@ + + + + + {% include 'head.html' %} + {{ article["title"] }} + + + + + {% include 'navbar.html' %} +
+
+
+

{{ article["parsed-time"].strftime("%d.%m. %Y") }}

+ {{ article["markdown-content"] | safe }} +
+
+
+ + {% include 'footer.html' %} + + + diff --git a/templates/people.html b/templates/people.html new file mode 100644 index 0000000..8e7eeff --- /dev/null +++ b/templates/people.html @@ -0,0 +1,34 @@ + + + + + Menschen + {% include 'head.html' %} + + + + + {% include 'navbar.html' %} + +
+ {% for p in people if not p.get("inactive") %} +
+
+

{{ p["title"] }}

+

{{ p["subtitle"] }}

+

+ {{ p["text"] }} +

+
+
+ +
+
+ {% endfor %} +
+ + {% include 'footer.html' %} + + + diff --git a/templates/subpage_example.html b/templates/subpage_example.html new file mode 100644 index 0000000..d62f9ba --- /dev/null +++ b/templates/subpage_example.html @@ -0,0 +1,23 @@ + + + + + {% include 'head.html' %} + Stammtisch + + + + + {% include 'navbar.html' %} +
+
+
+ {% include 'stammtisch_text.html' %} +
+
+
+ + {% include 'footer.html' %} + + + diff --git a/templates/subpage_example_text.html b/templates/subpage_example_text.html new file mode 100644 index 0000000..c984b70 --- /dev/null +++ b/templates/subpage_example_text.html @@ -0,0 +1,21 @@ +

HTML Ipsum

+ +

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

+ +

Header Level 2

+ +
    +
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. +
  3. Aliquam tincidunt mauris eu risus.
  4. +
+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

+ +

Header Level 3

+ +
    +
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • +
  • Aliquam tincidunt mauris eu risus.
  • +
+ +

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus