Login-Dropdown in Nav + Welcome-Overlay mit localStorage-Dismiss
- Login/Logout als Dropdown in der Header-Navigation (rechts) - Dynamisch: eingeloggt = Profil/Abmelden, nicht eingeloggt = Mini-Login-Formular - Offcanvas-Nav zeigt ebenfalls dynamisch Profil/Logout oder Registrieren/Login - Welcome-Overlay beim ersten Besuch mit Erklärung der Seite - Checkbox 'Nicht mehr anzeigen' speichert in localStorage - Backdrop-Blur wie bei anderen Overlays
This commit is contained in:
@@ -2626,6 +2626,35 @@ def public_frontend():
|
||||
"""Public frontend showing published submissions — SPIEL Essen inspired."""
|
||||
import base64
|
||||
db = get_db()
|
||||
user = _get_user_from_session(db) # für Login-Dropdown in Nav
|
||||
|
||||
# Hilfsfunktion: Login-Dropdown-HTML bauen
|
||||
def _build_login_dropdown(u):
|
||||
"""Baut das Login-Dropdown + Filter-Toggle für den Header."""
|
||||
h = '<div class="header-right">'
|
||||
h += '<a href="https://brettspiel-news.de" class="header-bsn-link">brettspiel-news.de</a>'
|
||||
h += '<button id="filterToggle" class="filter-toggle-btn" aria-label="Filter einblenden"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" style="vertical-align:middle;"><polyline points="6 9 12 15 18 9"/></svg></button>'
|
||||
if u:
|
||||
name = (u.get("name") or u.get("email") or "User")[:14]
|
||||
h += '<div class="login-dropdown">'
|
||||
h += '<button id="loginToggle" class="login-toggle-btn" aria-label="Benutzermenü"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="vertical-align:middle;margin-right:4px;"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>' + name + '</button>'
|
||||
h += '<div class="login-dropdown-menu" id="loginDropdown">'
|
||||
h += '<a href="/profile"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="vertical-align:middle;margin-right:6px;"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>Profil</a>'
|
||||
h += '<a href="/logout"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="vertical-align:middle;margin-right:6px;"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>Abmelden</a>'
|
||||
h += '</div></div>'
|
||||
else:
|
||||
h += '<div class="login-dropdown">'
|
||||
h += '<button id="loginToggle" class="login-toggle-btn" aria-label="Login"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="vertical-align:middle;"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></button>'
|
||||
h += '<div class="login-dropdown-menu" id="loginDropdown">'
|
||||
h += '<form method="post" action="/login" class="login-dropdown-form">'
|
||||
h += '<input name="login_id" placeholder="E-Mail oder Telefon" required>'
|
||||
h += '<input name="password" type="password" placeholder="Passwort" required>'
|
||||
h += '<button type="submit">Einloggen</button>'
|
||||
h += '</form>'
|
||||
h += '<a href="/register" class="login-dropdown-register">📋 Neu hier? Registrieren</a>'
|
||||
h += '</div></div>'
|
||||
h += '</div>' # close header-right
|
||||
return h
|
||||
|
||||
# Filters
|
||||
halle_filter = request.args.get("halle", "").strip()
|
||||
@@ -3119,19 +3148,72 @@ def public_frontend():
|
||||
.capture-btn svg { display:block; }
|
||||
.capture-btn:active { transform:scale(0.92); background:#f0f0f0; border-color:#20228a; }
|
||||
.capture-label { font-size:0.62rem; font-weight:600; color:#888; text-transform:uppercase; letter-spacing:0.04em; text-align:center; }
|
||||
|
||||
/* ── Login-Dropdown in der Navigation ─────────────────────── */
|
||||
.login-dropdown { position:relative; display:inline-block; }
|
||||
.login-toggle-btn { background:rgba(255,255,255,0.12); border:1.5px solid rgba(255,255,255,0.25); border-radius:8px; color:#fff; padding:0.35rem 0.7rem; font-size:0.78rem; font-weight:600; cursor:pointer; font-family:inherit; transition:all 0.15s; white-space:nowrap; line-height:1.3; }
|
||||
.login-toggle-btn:hover { background:rgba(255,255,255,0.22); border-color:rgba(255,255,255,0.5); }
|
||||
.login-toggle-btn.active { background:rgba(255,255,255,0.25); border-color:#fff; }
|
||||
.login-dropdown-menu { display:none; position:absolute; right:0; top:110%; background:#fff; border-radius:12px; box-shadow:0 8px 32px rgba(0,0,0,0.18); min-width:240px; z-index:300; overflow:hidden; }
|
||||
.login-dropdown-menu.open { display:block; animation:fadeDown 0.2s ease; }
|
||||
@keyframes fadeDown { from{opacity:0;transform:translateY(-8px);} to{opacity:1;transform:translateY(0);} }
|
||||
.login-dropdown-menu a { display:block; padding:0.65rem 1.1rem; color:#1a1a2e; text-decoration:none; font-size:0.85rem; font-weight:500; transition:background 0.15s; }
|
||||
.login-dropdown-menu a:hover { background:#f0ede6; }
|
||||
.login-dropdown-form { padding:0.8rem 1rem 0.5rem; }
|
||||
.login-dropdown-form input { width:100%; padding:0.5rem 0.7rem; margin:0.3rem 0; border:1.5px solid #ddd; border-radius:8px; font-size:0.82rem; font-family:inherit; outline:none; box-sizing:border-box; transition:border-color 0.15s; }
|
||||
.login-dropdown-form input:focus { border-color:#20228a; }
|
||||
.login-dropdown-form button { width:100%; padding:0.55rem; background:#20228a; color:#fff; border:none; border-radius:8px; font-size:0.82rem; font-weight:600; cursor:pointer; font-family:inherit; margin-top:0.4rem; transition:background 0.15s; }
|
||||
.login-dropdown-form button:hover { background:#161e6e; }
|
||||
.login-dropdown-register { border-top:1px solid #eee; font-size:0.78rem !important; color:#888 !important; text-align:center; }
|
||||
.login-dropdown-register:hover { color:#20228a !important; }
|
||||
.header-bsn-link { color:#aaa; text-decoration:none; font-size:0.8rem; transition:color 0.2s; }
|
||||
.header-bsn-link:hover { color:#fff; }
|
||||
|
||||
/* ── Welcome Overlay ──────────────────────────────────────── */
|
||||
.welcome-backdrop { position:fixed; inset:0; z-index:100000; background:rgba(0,0,0,0.4); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); display:none; }
|
||||
.welcome-backdrop.open { display:flex; align-items:center; justify-content:center; padding:1rem; }
|
||||
.welcome-dialog { background:#fff; border-radius:18px; box-shadow:0 16px 64px rgba(0,0,0,0.25); max-width:480px; width:100%; max-height:90vh; overflow-y:auto; animation:fadeUp 0.3s ease; }
|
||||
@keyframes fadeUp { from{opacity:0;transform:translateY(20px);} to{opacity:1;transform:translateY(0);} }
|
||||
.welcome-header { background:#20228a; color:#fff; padding:1.2rem 1.5rem; border-radius:18px 18px 0 0; font-weight:800; font-size:1.1rem; display:flex; align-items:center; gap:0.5rem; }
|
||||
.welcome-body { padding:1.5rem; color:#333; line-height:1.7; font-size:0.88rem; }
|
||||
.welcome-body strong { color:#20228a; }
|
||||
.welcome-body .welcome-feature { display:flex; gap:0.6rem; align-items:flex-start; margin:0.7rem 0; }
|
||||
.welcome-body .welcome-icon { font-size:1.2rem; flex-shrink:0; margin-top:0.1rem; }
|
||||
.welcome-footer { padding:0.8rem 1.5rem 1.2rem; border-top:1px solid #f0ede6; display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:0.5rem; }
|
||||
.welcome-footer label { font-size:0.78rem; color:#888; display:flex; align-items:center; gap:0.4rem; cursor:pointer; user-select:none; }
|
||||
.welcome-footer label input { width:16px; height:16px; accent-color:#20228a; cursor:pointer; }
|
||||
.welcome-footer button { background:#20228a; color:#fff; border:none; border-radius:10px; padding:0.55rem 1.4rem; font-size:0.85rem; font-weight:700; cursor:pointer; font-family:inherit; transition:background 0.15s; }
|
||||
.welcome-footer button:hover { background:#161e6e; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ── Welcome Overlay ──────────────────────────────────────── -->
|
||||
<div class="welcome-backdrop" id="welcomeBackdrop">
|
||||
<div class="welcome-dialog">
|
||||
<div class="welcome-header">🎲 Willkommen in der BSN Community!</div>
|
||||
<div class="welcome-body">
|
||||
<p>Hier teilen <strong>Brettspiel-Fans</strong> ihre Eindrücke direkt von der SPIEL Essen — und darüber hinaus.</p>
|
||||
<div class="welcome-feature"><span class="welcome-icon">📸</span><span><strong>Beiträge durchstöbern</strong> — Fotos, Videos, Sprachnachrichten und Texte aus der Community, sortiert nach Halle, Kategorie oder Beliebtheit.</span></div>
|
||||
<div class="welcome-feature"><span class="welcome-icon">➕</span><span><strong>Selbst einreichen</strong> — Über den <span style="background:#20228a;color:#fff;border-radius:50%;display:inline-block;width:22px;height:22px;text-align:center;line-height:22px;font-size:0.9rem;">+</span>-Button rechts unten kannst du eigene Fotos, Videos oder Texte beisteuern.</span></div>
|
||||
<div class="welcome-feature"><span class="welcome-icon">💬</span><span><strong>BSN Assistent</strong> — Der Chat-Button rechts unten beantwortet Fragen zu Spielen und Ständen — mit KI.</span></div>
|
||||
<div class="welcome-feature"><span class="welcome-icon">🔐</span><span><strong>Login</strong> — Oben rechts einloggen, um Benachrichtigungen zu erhalten und deine Beiträge zu verwalten.</span></div>
|
||||
<p style="margin-top:0.8rem;font-size:0.78rem;color:#888;">✨ Diese Seite ist ein Community-Projekt von <a href="https://brettspiel-news.de" style="color:#20228a;">brettspiel-news.de</a>.</p>
|
||||
</div>
|
||||
<div class="welcome-footer">
|
||||
<label><input type="checkbox" id="welcomeDismiss"> Nicht mehr anzeigen</label>
|
||||
<button id="welcomeClose">Alles klar!</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header class="site-header">
|
||||
<button id="navToggle" class="nav-toggle" aria-label="Menü öffnen">☰</button>
|
||||
<a href="/" class="site-logo">
|
||||
<img src="/static/logo.png" alt="Brettspiel News" style="height:38px;width:auto;display:block;">
|
||||
<span class="site-logo-sub">boardgame.network</span>
|
||||
</a>
|
||||
<div class="header-right">
|
||||
<a href="https://brettspiel-news.de">brettspiel-news.de</a>
|
||||
<button id="filterToggle" class="filter-toggle-btn" aria-label="Filter einblenden"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" style="vertical-align:middle;"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
</div>
|
||||
""" + _build_login_dropdown(user) + """
|
||||
</header>
|
||||
|
||||
<div id="filterBar" class="filter-collapsed">""" + filter_html + """</div>
|
||||
@@ -3613,8 +3695,7 @@ def public_frontend():
|
||||
<li class="nav-section">Navigation</li>
|
||||
<li><a href="/">Startseite</a></li>
|
||||
<li class="nav-section">Community</li>
|
||||
<li><a href="/register">📋 Registrieren</a></li>
|
||||
<li><a href="/login">🔐 Login</a></li>
|
||||
""" + ("<li><a href=\"/profile\">👤 Profil</a></li><li><a href=\"/logout\">🚪 Abmelden</a></li>" if user else "<li><a href=\"/register\">📋 Registrieren</a></li><li><a href=\"/login\">🔐 Login</a></li>") + """
|
||||
<li class="nav-section">Rechtliches</li>
|
||||
<li><a href="/impressum">Impressum</a></li>
|
||||
<li><a href="/datenschutz">Datenschutzerklärung</a></li>
|
||||
@@ -3656,6 +3737,49 @@ def public_frontend():
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// ── Login-Dropdown Toggle ──────────────────────────────────
|
||||
(function() {
|
||||
var btn = document.getElementById('loginToggle');
|
||||
var menu = document.getElementById('loginDropdown');
|
||||
if (btn && menu) {
|
||||
btn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
menu.classList.toggle('open');
|
||||
btn.classList.toggle('active');
|
||||
});
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!btn.contains(e.target) && !menu.contains(e.target)) {
|
||||
menu.classList.remove('open');
|
||||
btn.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
// ── Welcome Overlay ────────────────────────────────────────
|
||||
(function() {
|
||||
var backdrop = document.getElementById('welcomeBackdrop');
|
||||
var closeBtn = document.getElementById('welcomeClose');
|
||||
var checkbox = document.getElementById('welcomeDismiss');
|
||||
if (!backdrop) return;
|
||||
// Nur anzeigen, wenn nicht per localStorage ausgeblendet
|
||||
if (localStorage.getItem('welcomeDismissed') !== 'true') {
|
||||
backdrop.classList.add('open');
|
||||
}
|
||||
function dismiss() {
|
||||
if (checkbox && checkbox.checked) {
|
||||
localStorage.setItem('welcomeDismissed', 'true');
|
||||
}
|
||||
backdrop.classList.remove('open');
|
||||
}
|
||||
if (closeBtn) closeBtn.addEventListener('click', dismiss);
|
||||
backdrop.addEventListener('click', function(e) {
|
||||
if (e.target === backdrop) dismiss();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>""").replace("{LOGO_B64}", LOGO_B64)
|
||||
|
||||
@@ -3708,17 +3832,84 @@ def _legal_page(title, content_html):
|
||||
.legal-container a {{ color:#20228a; text-decoration:underline; }}
|
||||
.back-link {{ display:inline-block; margin-top:2rem; color:#20228a; text-decoration:none; font-weight:600; font-size:0.9rem; }}
|
||||
.back-link:hover {{ text-decoration:underline; }}
|
||||
.nav-toggle {{ background:none; border:none; color:#fff; font-size:1.3rem; cursor:pointer; padding:0.3rem 0.4rem; line-height:1; margin-right:0.5rem; transition:opacity 0.2s; }}
|
||||
.nav-toggle:hover {{ opacity:0.7; }}
|
||||
.offcanvas-backdrop {{ position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:200; opacity:0; pointer-events:none; transition:opacity 0.3s ease; }}
|
||||
.offcanvas-backdrop.open {{ opacity:1; pointer-events:auto; }}
|
||||
.offcanvas-nav {{ position:fixed; top:0; left:0; width:280px; height:100%; height:100dvh; background:#fff; z-index:201; transform:translateX(-100%); transition:transform 0.3s cubic-bezier(0.4,0,0.2,1); box-shadow:4px 0 24px rgba(0,0,0,0.15); display:flex; flex-direction:column; }}
|
||||
.offcanvas-nav.open {{ transform:translateX(0); }}
|
||||
.offcanvas-nav-header {{ background:#20228a; color:#fff; padding:1.2rem 1.5rem; display:flex; align-items:center; justify-content:space-between; }}
|
||||
.offcanvas-nav-header .nav-logo {{ font-weight:800; font-size:1rem; }}
|
||||
.offcanvas-nav-header .nav-close {{ background:none; border:none; color:#fff; font-size:1.4rem; cursor:pointer; line-height:1; }}
|
||||
.offcanvas-nav-links {{ list-style:none; padding:1rem 0; flex:1; }}
|
||||
.offcanvas-nav-links a {{ display:block; padding:0.75rem 1.5rem; color:#1a1a2e; text-decoration:none; font-size:0.95rem; font-weight:500; transition:background 0.15s; }}
|
||||
.offcanvas-nav-links a:hover {{ background:#f0ede6; }}
|
||||
.offcanvas-nav-links .nav-section {{ padding:0.5rem 1.5rem 0.2rem; font-size:0.7rem; font-weight:700; text-transform:uppercase; letter-spacing:0.05em; color:#888; }}
|
||||
.offcanvas-nav-footer {{ padding:1rem 1.5rem; border-top:1px solid #e0ddd6; font-size:0.75rem; color:#888; }}
|
||||
.site-header {{ display:flex; align-items:center; gap:0.5rem; }}
|
||||
@media(max-width:600px) {{ .legal-container {{ margin:1rem; padding:1.2rem; }} }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<a href="/">← BSN Community</a>
|
||||
<button id="navToggle" class="nav-toggle" aria-label="Menü öffnen">☰</button>
|
||||
<a href="/">BSN Community</a>
|
||||
</header>
|
||||
<main class="legal-container">
|
||||
{content_html}
|
||||
<a href="/" class="back-link">← Zurück zur Startseite</a>
|
||||
</main>
|
||||
|
||||
<div class="offcanvas-backdrop" id="offcanvasBackdrop"></div>
|
||||
<nav class="offcanvas-nav" id="offcanvasNav">
|
||||
<div class="offcanvas-nav-header">
|
||||
<span class="nav-logo">BSN Community</span>
|
||||
<button class="nav-close" id="navClose" aria-label="Menü schließen">✕</button>
|
||||
</div>
|
||||
<ul class="offcanvas-nav-links">
|
||||
<li class="nav-section">Navigation</li>
|
||||
<li><a href="/">Startseite</a></li>
|
||||
<li class="nav-section">Community</li>
|
||||
<li><a href="/register">📋 Registrieren</a></li>
|
||||
<li><a href="/login">🔐 Login</a></li>
|
||||
<li class="nav-section">Rechtliches</li>
|
||||
<li><a href="/impressum">Impressum</a></li>
|
||||
<li><a href="/datenschutz">Datenschutzerklärung</a></li>
|
||||
<li><a href="/agb">AGB</a></li>
|
||||
</ul>
|
||||
<div class="offcanvas-nav-footer">
|
||||
© 2026 Brettspiel-News.de
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
(function() {{
|
||||
var toggle = document.getElementById('navToggle');
|
||||
var close = document.getElementById('navClose');
|
||||
var nav = document.getElementById('offcanvasNav');
|
||||
var backdrop = document.getElementById('offcanvasBackdrop');
|
||||
var main = document.querySelector('main');
|
||||
var header = document.querySelector('.site-header');
|
||||
|
||||
function open() {{
|
||||
nav.classList.add('open');
|
||||
backdrop.classList.add('open');
|
||||
if (main) main.style.filter = 'blur(4px)';
|
||||
if (header) header.style.filter = 'blur(4px)';
|
||||
}}
|
||||
function closeNav() {{
|
||||
nav.classList.remove('open');
|
||||
backdrop.classList.remove('open');
|
||||
if (main) main.style.filter = '';
|
||||
if (header) header.style.filter = '';
|
||||
}}
|
||||
|
||||
toggle.addEventListener('click', open);
|
||||
close.addEventListener('click', closeNav);
|
||||
backdrop.addEventListener('click', closeNav);
|
||||
}})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
@@ -4495,7 +4686,21 @@ def public_detail(sub_id: int):
|
||||
<style>
|
||||
* {{ margin:0; padding:0; box-sizing:border-box; }}
|
||||
body {{ font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; background:#F3EDE4; color:#1a1a2e; min-height:100vh; }}
|
||||
.site-header {{ background:#20228a; padding:1rem 2rem; display:flex; align-items:center; gap:1rem; position:sticky; top:0; z-index:100; }}
|
||||
.site-header {{ background:#20228a; padding:1rem 2rem; display:flex; align-items:center; gap:0.5rem; position:sticky; top:0; z-index:100; }}
|
||||
.nav-toggle {{ background:none; border:none; color:#fff; font-size:1.3rem; cursor:pointer; padding:0.3rem 0.4rem; line-height:1; margin-right:0.5rem; transition:opacity 0.2s; }}
|
||||
.nav-toggle:hover {{ opacity:0.7; }}
|
||||
.offcanvas-backdrop {{ position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:200; opacity:0; pointer-events:none; transition:opacity 0.3s ease; }}
|
||||
.offcanvas-backdrop.open {{ opacity:1; pointer-events:auto; }}
|
||||
.offcanvas-nav {{ position:fixed; top:0; left:0; width:280px; height:100%; height:100dvh; background:#fff; z-index:201; transform:translateX(-100%); transition:transform 0.3s cubic-bezier(0.4,0,0.2,1); box-shadow:4px 0 24px rgba(0,0,0,0.15); display:flex; flex-direction:column; }}
|
||||
.offcanvas-nav.open {{ transform:translateX(0); }}
|
||||
.offcanvas-nav-header {{ background:#20228a; color:#fff; padding:1.2rem 1.5rem; display:flex; align-items:center; justify-content:space-between; }}
|
||||
.offcanvas-nav-header .nav-logo {{ font-weight:800; font-size:1rem; }}
|
||||
.offcanvas-nav-header .nav-close {{ background:none; border:none; color:#fff; font-size:1.4rem; cursor:pointer; line-height:1; }}
|
||||
.offcanvas-nav-links {{ list-style:none; padding:1rem 0; flex:1; }}
|
||||
.offcanvas-nav-links a {{ display:block; padding:0.75rem 1.5rem; color:#1a1a2e; text-decoration:none; font-size:0.95rem; font-weight:500; transition:background 0.15s; }}
|
||||
.offcanvas-nav-links a:hover {{ background:#f0ede6; }}
|
||||
.offcanvas-nav-links .nav-section {{ padding:0.5rem 1.5rem 0.2rem; font-size:0.7rem; font-weight:700; text-transform:uppercase; letter-spacing:0.05em; color:#888; }}
|
||||
.offcanvas-nav-footer {{ padding:1rem 1.5rem; border-top:1px solid #e0ddd6; font-size:0.75rem; color:#888; }}
|
||||
.site-logo {{ display:flex; align-items:center; gap:0.6rem; text-decoration:none; color:#fff; }}
|
||||
.site-logo .logo-icon {{ width:40px; height:40px; background:#20228a; border-radius:8px; display:flex; align-items:center; justify-content:center; font-size:1.3rem; }}
|
||||
.site-logo .logo-text {{ font-weight:800; font-size:1.15rem; color:#fff; }}
|
||||
@@ -4549,6 +4754,7 @@ def public_detail(sub_id: int):
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<button id="navToggle" class="nav-toggle" aria-label="Menü öffnen">☰</button>
|
||||
<a href="/" class="site-logo">
|
||||
<img src="/static/logo.png" alt="Brettspiel News" style="height:30px;width:auto;display:block;" width="160" height="30">
|
||||
<span class="site-logo-sub">boardgame.network</span>
|
||||
@@ -4698,11 +4904,61 @@ function submitComment(event, subId) {{
|
||||
return false;
|
||||
}}
|
||||
</script>
|
||||
|
||||
<div class="offcanvas-backdrop" id="offcanvasBackdrop"></div>
|
||||
<nav class="offcanvas-nav" id="offcanvasNav">
|
||||
<div class="offcanvas-nav-header">
|
||||
<span class="nav-logo">BSN Community</span>
|
||||
<button class="nav-close" id="navClose" aria-label="Menü schließen">✕</button>
|
||||
</div>
|
||||
<ul class="offcanvas-nav-links">
|
||||
<li class="nav-section">Navigation</li>
|
||||
<li><a href="/">Startseite</a></li>
|
||||
<li class="nav-section">Community</li>
|
||||
<li><a href="/register">📋 Registrieren</a></li>
|
||||
<li><a href="/login">🔐 Login</a></li>
|
||||
<li class="nav-section">Rechtliches</li>
|
||||
<li><a href="/impressum">Impressum</a></li>
|
||||
<li><a href="/datenschutz">Datenschutzerklärung</a></li>
|
||||
<li><a href="/agb">AGB</a></li>
|
||||
</ul>
|
||||
<div class="offcanvas-nav-footer">
|
||||
© 2026 Brettspiel-News.de
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
(function() {{
|
||||
var toggle = document.getElementById('navToggle');
|
||||
var close = document.getElementById('navClose');
|
||||
var nav = document.getElementById('offcanvasNav');
|
||||
var backdrop = document.getElementById('offcanvasBackdrop');
|
||||
var main = document.querySelector('main');
|
||||
var header = document.querySelector('.site-header');
|
||||
|
||||
function open() {{
|
||||
nav.classList.add('open');
|
||||
backdrop.classList.add('open');
|
||||
if (main) main.style.filter = 'blur(4px)';
|
||||
if (header) header.style.filter = 'blur(4px)';
|
||||
}}
|
||||
function closeNav() {{
|
||||
nav.classList.remove('open');
|
||||
backdrop.classList.remove('open');
|
||||
if (main) main.style.filter = '';
|
||||
if (header) header.style.filter = '';
|
||||
}}
|
||||
|
||||
toggle.addEventListener('click', open);
|
||||
close.addEventListener('click', closeNav);
|
||||
backdrop.addEventListener('click', closeNav);
|
||||
}})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
|
||||
@app.route("/api/like/<int:sub_id>", methods=["POST"])
|
||||
def api_like(sub_id: int):
|
||||
db = get_db()
|
||||
|
||||
Reference in New Issue
Block a user