U18: SQLite Klick-Adventure (Octan-Tower, Lego Movie) neben Kommentar-Funktion + Nav-Links
This commit is contained in:
parent
b6b8142707
commit
fc49784d66
15 changed files with 354 additions and 9 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -6,3 +6,7 @@ venv/
|
|||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# SQLite-Datenbank entsteht auf dem Server (untracked) – nie committen,
|
||||
# sonst würde ein Deploy die Server-Datenbank überschreiben
|
||||
*.db
|
||||
|
||||
|
|
|
|||
1
api.html
1
api.html
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html" class="active">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
203
app.py
203
app.py
|
|
@ -1,7 +1,19 @@
|
|||
from flask import Flask, request, redirect
|
||||
import os
|
||||
import sqlite3
|
||||
from flask import Flask, request, redirect, session
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = "octan-tower-kragle-everything-is-awesome-2026" # für session (Adventure-Fortschritt)
|
||||
|
||||
# ─── SQLite-Datenbank (U18) ──────────────────────────────────────────────────
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
DB_PATH = os.path.join(BASE_DIR, "adventure.db")
|
||||
|
||||
def get_db():
|
||||
db = sqlite3.connect(DB_PATH)
|
||||
db.row_factory = sqlite3.Row # Spalten per Name ansprechen
|
||||
return db
|
||||
|
||||
# ─── Zeitzone: CEST (UTC+2) ──────────────────────────────────────────────────
|
||||
BERLIN = timezone(timedelta(hours=2))
|
||||
|
|
@ -87,6 +99,7 @@ def seite(inhalt):
|
|||
<div class="topbar">
|
||||
<a href="/app/" class="topbar-logo">▶ Flask-App</a>
|
||||
<nav>
|
||||
<a href="/app/">🧱 Adventure</a>
|
||||
<a href="/app/pinnwand" class="aktiv">Kommentare</a>
|
||||
</nav>
|
||||
<a href="https://isa2.edumake.de" class="topbar-back">← Zurück zur Website</a>
|
||||
|
|
@ -98,19 +111,191 @@ def seite(inhalt):
|
|||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Route 1: Startseite
|
||||
# U18 – Klick-Adventure "Einbruch im Octan-Tower" (The-Lego-Movie-Style)
|
||||
# Räume, Ausgänge und Trivia-Fragen kommen aus der SQLite-Datenbank adventure.db
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
def adventure_seite(inhalt, akzent="#f59e0b"):
|
||||
kopf = """<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Einbruch im Octan-Tower – Klick-Adventure</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { background:#0f172a; color:#e5e7eb;
|
||||
font-family: system-ui, "Segoe UI", Arial, sans-serif;
|
||||
min-height:100vh; line-height:1.6; }
|
||||
.adv-topbar { display:flex; align-items:center; gap:10px; padding:12px 20px;
|
||||
background:#111827; border-bottom:2px solid ACCENT; }
|
||||
.adv-logo { font-weight:800; letter-spacing:-.5px; color:ACCENT;
|
||||
text-decoration:none; font-size:18px; }
|
||||
.adv-topbar .link { color:#93c5fd; text-decoration:none; font-size:14px;
|
||||
border:1px solid #334155; border-radius:8px; padding:6px 12px; }
|
||||
.adv-topbar .link:hover { background:#1e293b; }
|
||||
.adv-topbar .spacer { margin-left:auto; }
|
||||
.adv-wrap { max-width:680px; margin:44px auto; padding:0 18px; }
|
||||
.adv-card { background:#1e293b; border:1px solid #334155; border-radius:16px;
|
||||
padding:30px; box-shadow:0 10px 30px rgba(0,0,0,.35); }
|
||||
.adv-card h1 { font-size:26px; margin-bottom:6px; }
|
||||
.adv-floor { font-size:12px; text-transform:uppercase; letter-spacing:2px;
|
||||
color:ACCENT; font-weight:700; }
|
||||
.adv-desc { color:#cbd5e1; margin:14px 0 22px; }
|
||||
.adv-progress { font-size:13px; color:#94a3b8; margin-bottom:16px; }
|
||||
.adv-frage { font-size:19px; font-weight:600; margin-bottom:18px; }
|
||||
.opt-form { display:flex; flex-direction:column; gap:12px; }
|
||||
.opt-btn { display:block; width:100%; text-align:left; background:#0f172a;
|
||||
color:#e5e7eb; border:1px solid #334155; border-radius:10px;
|
||||
padding:14px 16px; font-size:16px; cursor:pointer;
|
||||
transition:.15s; font-family:inherit; }
|
||||
.opt-btn:hover { border-color:ACCENT; background:#172033; transform:translateY(-1px); }
|
||||
.exit-link { display:inline-block; background:ACCENT; color:#111827; font-weight:700;
|
||||
text-decoration:none; border-radius:10px; padding:12px 18px;
|
||||
margin:6px 8px 0 0; }
|
||||
.exit-link:hover { filter:brightness(1.08); }
|
||||
.ghost-link { display:inline-block; color:#93c5fd; text-decoration:none;
|
||||
border:1px solid #334155; border-radius:10px; padding:12px 18px;
|
||||
margin:6px 8px 0 0; }
|
||||
.ghost-link:hover { background:#0f172a; }
|
||||
.feedback-bad { background:#7f1d1d; border:1px solid #b91c1c; color:#fecaca;
|
||||
border-radius:10px; padding:12px 14px; margin-bottom:16px; font-weight:600; }
|
||||
.win-emoji { font-size:54px; text-align:center; margin-bottom:8px; }
|
||||
.muted { color:#94a3b8; font-size:14px; margin-top:20px; }
|
||||
.muted a { color:#93c5fd; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="adv-topbar">
|
||||
<a href="/app/" class="adv-logo">🧱 Octan-Tower</a>
|
||||
<a href="/app/pinnwand" class="link spacer">💬 Kommentare</a>
|
||||
<a href="https://isa2.edumake.de" class="link">← Website</a>
|
||||
</div>
|
||||
<div class="adv-wrap">""".replace("ACCENT", akzent)
|
||||
fuss = """</div>
|
||||
</body>
|
||||
</html>"""
|
||||
return kopf + inhalt + fuss
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def hello():
|
||||
return redirect("/app/pinnwand")
|
||||
def start():
|
||||
# Fortschritt für einen frischen Durchlauf zurücksetzen
|
||||
for key in [k for k in session.keys() if k.startswith("raum_")]:
|
||||
session.pop(key, None)
|
||||
inhalt = """
|
||||
<div class="adv-card">
|
||||
<div class="adv-floor">LEGO • Geheimmission</div>
|
||||
<h1>Einbruch im Octan-Tower 🧱</h1>
|
||||
<p class="adv-desc">Präsident Business hortet ganz oben in seinem Wolkenkratzer
|
||||
das <strong>Kragle</strong> – und will damit die ganze Welt für immer festkleben.
|
||||
Nur du kannst ihn stoppen! Kämpf dich Etage für Etage nach oben: vorbei an
|
||||
<strong>Haien</strong> 🦈, <strong>Lasern</strong> 🔴 und – natürlich –
|
||||
<strong>Laserhaien</strong> 🦈⚡. Auf jeder Etage prüfen dich die Sicherheitssysteme
|
||||
mit Trivia-Fragen. Nur wer alle knackt, kommt weiter.</p>
|
||||
<a href="/app/raum/1" class="exit-link">Abenteuer starten ▶</a>
|
||||
<p class="muted">Lieber quatschen statt einbrechen?
|
||||
<a href="/app/pinnwand">Zu den Kommentaren →</a></p>
|
||||
</div>"""
|
||||
return adventure_seite(inhalt)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Route 2: Frage-Formular (GET + POST)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@app.route("/frage", methods=["GET", "POST"])
|
||||
@app.route("/frage")
|
||||
def frage():
|
||||
return redirect("/app/pinnwand")
|
||||
return redirect("/app/")
|
||||
|
||||
|
||||
@app.route("/raum/<int:id>", methods=["GET", "POST"])
|
||||
def raum(id):
|
||||
db = get_db()
|
||||
r = db.execute("SELECT * FROM raeume WHERE id=?", (id,)).fetchone()
|
||||
if r is None:
|
||||
db.close()
|
||||
return adventure_seite(
|
||||
'<div class="adv-card"><div class="adv-floor">Fehler</div>'
|
||||
'<h1>Diese Etage existiert nicht 🤖</h1>'
|
||||
'<p class="adv-desc">Da hat sich wohl ein Bauplan verheddert.</p>'
|
||||
'<a href="/app/" class="exit-link">Zurück zum Start</a></div>')
|
||||
|
||||
fragen = db.execute(
|
||||
"SELECT * FROM fragen WHERE raum_id=? ORDER BY id", (id,)
|
||||
).fetchall()
|
||||
|
||||
prog_key = "raum_%d_idx" % id
|
||||
idx = session.get(prog_key, 0)
|
||||
|
||||
# ── Es sind noch Sicherheitsfragen offen ──
|
||||
if fragen and idx < len(fragen):
|
||||
aktuelle = fragen[idx]
|
||||
feedback = ""
|
||||
if request.method == "POST":
|
||||
gewaehlt = request.form.get("antwort", "").strip()
|
||||
if gewaehlt.lower() == aktuelle["antwort"].strip().lower():
|
||||
session[prog_key] = idx + 1
|
||||
session.modified = True
|
||||
db.close()
|
||||
return redirect("/app/raum/%d" % id)
|
||||
feedback = ('<div class="feedback-bad">🚨 Alarm! Falsche Antwort – '
|
||||
'die Wächter wurden fast auf dich aufmerksam. Versuch es nochmal.</div>')
|
||||
optionen = aktuelle["optionen"].split("|")
|
||||
db.close()
|
||||
|
||||
buttons = ""
|
||||
for opt in optionen:
|
||||
buttons += ('<button class="opt-btn" name="antwort" value="%s">%s</button>'
|
||||
% (esc(opt), esc(opt)))
|
||||
inhalt = ("""
|
||||
<div class="adv-card">
|
||||
<div class="adv-floor">🔐 Sicherheitsprüfung · %s</div>
|
||||
<h1>%s</h1>
|
||||
<p class="adv-progress">Frage %d von %d</p>
|
||||
%s
|
||||
<p class="adv-frage">%s</p>
|
||||
<form method="post" class="opt-form">%s</form>
|
||||
</div>""" % (esc(r["name"]), esc(r["name"]), idx + 1, len(fragen),
|
||||
feedback, esc(aktuelle["frage"]), buttons))
|
||||
return adventure_seite(inhalt)
|
||||
|
||||
# ── Alle Fragen gelöst (oder keine) → Beschreibung + Ausgänge / Sieg ──
|
||||
ausgaenge = db.execute(
|
||||
"SELECT richtung, nach_raum FROM ausgaenge WHERE von_raum=? ORDER BY rowid", (id,)
|
||||
).fetchall()
|
||||
db.close()
|
||||
|
||||
if r["ist_ziel"]:
|
||||
inhalt = ("""
|
||||
<div class="adv-card" style="text-align:center">
|
||||
<div class="win-emoji">🎉🧱🎉</div>
|
||||
<div class="adv-floor">Mission erfüllt</div>
|
||||
<h1>%s</h1>
|
||||
<p class="adv-desc">%s</p>
|
||||
<p class="adv-frage" style="color:#f59e0b">„Everything is awesome!“ 🎵</p>
|
||||
<a href="/app/" class="exit-link">Nochmal spielen 🔁</a>
|
||||
<a href="/app/pinnwand" class="ghost-link">Sieg in den Kommentaren feiern 💬</a>
|
||||
</div>""" % (esc(r["name"]), esc(r["beschreibung"])))
|
||||
return adventure_seite(inhalt)
|
||||
|
||||
exits_html = ""
|
||||
for a in ausgaenge:
|
||||
exits_html += ('<a class="exit-link" href="/app/raum/%d">%s</a>'
|
||||
% (a["nach_raum"], esc(a["richtung"])))
|
||||
if not ausgaenge:
|
||||
exits_html = '<a class="exit-link" href="/app/">Zurück zum Start</a>'
|
||||
|
||||
geschafft = ""
|
||||
if fragen: # Etage hatte Fragen und alle wurden gelöst
|
||||
geschafft = ('<p class="adv-progress">✅ Alle Sicherheitsfragen geknackt – '
|
||||
'der Weg ist frei!</p>')
|
||||
|
||||
inhalt = ("""
|
||||
<div class="adv-card">
|
||||
<div class="adv-floor">🏢 %s</div>
|
||||
<h1>%s</h1>
|
||||
<p class="adv-desc">%s</p>
|
||||
%s
|
||||
<div>%s</div>
|
||||
</div>""" % (esc(r["name"]), esc(r["name"]), esc(r["beschreibung"]),
|
||||
geschafft, exits_html))
|
||||
return adventure_seite(inhalt)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
144
init_db.py
Normal file
144
init_db.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
"""
|
||||
U18 – Klick-Adventure "Einbruch im Octan-Tower" (The-Lego-Movie-Style)
|
||||
=====================================================================
|
||||
Legt die SQLite-Datenbank `adventure.db` an und befüllt sie mit:
|
||||
- raeume : die Etagen des Octan-Towers
|
||||
- ausgaenge : welcher Ausgang führt in welche Etage
|
||||
- fragen : Trivia-Fragen pro Etage (Multiple-Choice)
|
||||
|
||||
Leitprinzip (wie in U17):
|
||||
LOKAL schreiben & pushen – auf dem SERVER einmalig ausführen:
|
||||
python3 init_db.py
|
||||
Danach entsteht adventure.db direkt neben diesem Skript.
|
||||
"""
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
# adventure.db immer neben dieser Datei ablegen (unabhängig vom Arbeitsverzeichnis)
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
DB_PATH = os.path.join(BASE_DIR, "adventure.db")
|
||||
|
||||
db = sqlite3.connect(DB_PATH)
|
||||
|
||||
# Tabellen bei jedem Lauf sauber neu aufbauen (DROP statt DELETE, damit auch
|
||||
# geänderte Spalten greifen).
|
||||
db.executescript("""
|
||||
DROP TABLE IF EXISTS raeume;
|
||||
DROP TABLE IF EXISTS ausgaenge;
|
||||
DROP TABLE IF EXISTS fragen;
|
||||
|
||||
CREATE TABLE raeume (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT,
|
||||
beschreibung TEXT,
|
||||
ist_ziel INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE ausgaenge (
|
||||
von_raum INTEGER,
|
||||
richtung TEXT,
|
||||
nach_raum INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE fragen (
|
||||
id INTEGER PRIMARY KEY,
|
||||
raum_id INTEGER,
|
||||
frage TEXT,
|
||||
antwort TEXT,
|
||||
optionen TEXT -- Antwortmöglichkeiten, per | getrennt
|
||||
);
|
||||
""")
|
||||
|
||||
# ─── Räume: der Aufstieg durch den Octan-Tower ───────────────────────────────
|
||||
raeume = [
|
||||
(1, "Lobby des Octan-Towers",
|
||||
"Die Türen fallen hinter dir zu. Präsident Business' Wolkenkratzer ragt "
|
||||
"über dir auf. Ein gläserner Aufzug führt nach oben – ganz oben wartet das "
|
||||
"Kragle. Everything is ... noch nicht awesome.", 0),
|
||||
|
||||
(2, "1. Etage – Die Hai-Etage 🦈",
|
||||
"Ein tiefer Wassergraben voller hungriger Haie trennt dich vom nächsten "
|
||||
"Aufzug. Der Sicherheits-Wächter lässt dich nur weiter, wenn du seine "
|
||||
"Fragen richtig beantwortest.", 0),
|
||||
|
||||
(3, "2. Etage – Die Laser-Etage 🔴",
|
||||
"Rote Laserstrahlen zerschneiden den Raum zu einem glühenden Gitter. Ein "
|
||||
"Terminal blinkt: Beantworte die Fragen korrekt, sonst bleibt das "
|
||||
"Laser-Gitter für immer aktiv.", 0),
|
||||
|
||||
(4, "3. Etage – Die Laserhai-Etage 🦈⚡",
|
||||
"Und dann ... Haie. Mit Laserstrahlen. Auf dem Kopf. Präsident Business "
|
||||
"meint es wirklich ernst. Nur wer clever genug ist, kommt am "
|
||||
"Laserhai-Becken vorbei.", 0),
|
||||
|
||||
(5, "Das Dach – Der Kragle-Tresor 🏆",
|
||||
"Du stehst vor dem Kragle – ein einziger Klecks Kleber, der die ganze "
|
||||
"Welt für immer einfrieren könnte. Doch du hast es rechtzeitig geschafft "
|
||||
"und Präsident Business gestoppt!", 1),
|
||||
]
|
||||
db.executemany(
|
||||
"INSERT INTO raeume (id, name, beschreibung, ist_ziel) VALUES (?,?,?,?)",
|
||||
raeume,
|
||||
)
|
||||
|
||||
# ─── Ausgänge: linearer Aufstieg (jede Etage → nächste Etage) ────────────────
|
||||
ausgaenge = [
|
||||
(1, "Aufzug nach oben 🛗", 2),
|
||||
(2, "Treppe hoch 🪜", 3),
|
||||
(3, "Treppe hoch 🪜", 4),
|
||||
(4, "Aufs Dach 🏢", 5),
|
||||
]
|
||||
db.executemany(
|
||||
"INSERT INTO ausgaenge (von_raum, richtung, nach_raum) VALUES (?,?,?)",
|
||||
ausgaenge,
|
||||
)
|
||||
|
||||
# ─── Trivia-Fragen pro Etage ─────────────────────────────────────────────────
|
||||
# Pro Etage 4 Fragen: 1–2 thematisch passend, danach Popkultur.
|
||||
# "antwort" ist die korrekte Option, "optionen" alle Auswahlmöglichkeiten (|-getrennt).
|
||||
fragen = [
|
||||
# ── Etage 1: Haie ─────────────────────────────────────────────
|
||||
(2, "🦈 Welcher Hai ist der größte Fisch der Welt?",
|
||||
"Walhai", "Weißer Hai|Walhai|Hammerhai"),
|
||||
(2, "🦈 Wie heißt Steven Spielbergs berühmter Hai-Film von 1975?",
|
||||
"Der weiße Hai", "Der weiße Hai|Free Willy|Findet Nemo"),
|
||||
(2, "🎮 Wie heißt Marios grün gekleideter Bruder?",
|
||||
"Luigi", "Luigi|Wario|Yoshi"),
|
||||
(2, "🎬 In welcher Weltraum-Saga kämpfen Jedi gegen Sith?",
|
||||
"Star Wars", "Star Trek|Star Wars|Herr der Ringe"),
|
||||
|
||||
# ── Etage 2: Laser ────────────────────────────────────────────
|
||||
(3, "🔴 Wofür steht das Akronym LASER?",
|
||||
"Light Amplification by Stimulated Emission of Radiation",
|
||||
"Light Amplification by Stimulated Emission of Radiation|"
|
||||
"Large Automatic System for Energy Reflection|"
|
||||
"Leuchtende Aktive Strahlen Emissions-Röhre"),
|
||||
(3, "⚔️ Welche leuchtende Laser-Waffe führt ein Jedi in Star Wars?",
|
||||
"Lichtschwert", "Lichtschwert|Laserpistole|Zauberstab"),
|
||||
(3, "🦸 Welcher Superheld trägt ein blaues Kostüm mit rotem Umhang und einem 'S'?",
|
||||
"Superman", "Batman|Superman|Spider-Man"),
|
||||
(3, "🎮 In welchem Spiel fängt man Kreaturen in kleinen Bällen?",
|
||||
"Pokémon", "Minecraft|Tetris|Pokémon"),
|
||||
|
||||
# ── Etage 3: Laserhaie ────────────────────────────────────────
|
||||
(4, "🦈⚡ In welchem Film wünscht sich Dr. Evil „Haie mit Laserstrahlen auf dem Kopf“?",
|
||||
"Austin Powers", "James Bond|Austin Powers|Men in Black"),
|
||||
(4, "🧱 Wie heißt der Bösewicht, in dessen Turm du gerade einbrichst?",
|
||||
"Lord Business", "Lord Business|Lord Vader|Lord Farquaad"),
|
||||
(4, "🎵 Wie lautet der Ohrwurm-Titelsong aus „The Lego Movie“?",
|
||||
"Everything Is Awesome", "Everything Is Awesome|Let It Go|Happy"),
|
||||
(4, "🧙 Welches Zauberer-Internat besucht Harry Potter?",
|
||||
"Hogwarts", "Narnia|Hogwarts|Mordor"),
|
||||
]
|
||||
db.executemany(
|
||||
"INSERT INTO fragen (raum_id, frage, antwort, optionen) VALUES (?,?,?,?)",
|
||||
fragen,
|
||||
)
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
print("Datenbank adventure.db angelegt:", DB_PATH)
|
||||
print(" Räume:", len(raeume),
|
||||
"| Ausgänge:", len(ausgaenge),
|
||||
"| Fragen:", len(fragen))
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html" class="active">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html" class="active">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<a href="api.html">API Demo</a>
|
||||
<a href="kanban.html">Kanban</a>
|
||||
<a href="quiz.html">Quiz</a>
|
||||
<a href="/app/">Adventure</a>
|
||||
<a href="/app/pinnwand">Kommentare</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue