Öffentliche /help-Seite — Server-rendered FAQ ohne Login
Apple-Reviewer braucht eine publik erreichbare Support-URL. Die SPA-Hilfeseite (/#hilfe) ist hinter dem Welcome-Overlay für nicht angemeldete User versteckt. Neue /help-Route rendert serverseitig: - Holt aktive FAQ-Artikel aus help_articles (über bestehendes TTL-Cache _load_active_help_articles). - Gruppiert nach Kategorie mit deutschen Labels. - Native HTML5 <details>/<summary> Akkordeon — kein JS nötig. - Dark Mode via prefers-color-scheme. - Direkter mailto support@banyaro.app + Verweis auf die volle Hilfe nach Login. Damit haben wir https://banyaro.app/help als Support-URL für App Store Connect.
This commit is contained in:
parent
d23d696745
commit
2d907f6370
6 changed files with 156 additions and 16 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1140
|
||||
1141
|
||||
140
backend/main.py
140
backend/main.py
|
|
@ -1702,6 +1702,146 @@ async def presse():
|
|||
return FileResponse(f"{STATIC_DIR}/presse.html", headers={"Cache-Control": "max-age=3600"})
|
||||
|
||||
|
||||
@app.get("/help")
|
||||
async def help_page():
|
||||
"""Öffentliche, server-gerenderte Hilfe/FAQ-Seite. Kein Login nötig —
|
||||
Apple-Reviewer und Suchmaschinen kommen hier direkt rein."""
|
||||
from fastapi.responses import HTMLResponse
|
||||
import html as _html
|
||||
from routes.help import _load_active_help_articles
|
||||
|
||||
KAT_LABEL = {
|
||||
"installation": "Installation & PWA",
|
||||
"erste_schritte": "Erste Schritte",
|
||||
"standort": "Standort & Wetter",
|
||||
"account": "Account & Passwort",
|
||||
"features": "Features erklärt",
|
||||
"probleme": "Technische Probleme",
|
||||
}
|
||||
articles = _load_active_help_articles()
|
||||
# Gruppieren nach Kategorie, Reihenfolge aus KAT_LABEL
|
||||
by_kat: dict[str, list] = {}
|
||||
for a in articles:
|
||||
by_kat.setdefault(a["kategorie"], []).append(a)
|
||||
kat_order = [k for k in KAT_LABEL.keys() if k in by_kat] + [
|
||||
k for k in by_kat.keys() if k not in KAT_LABEL
|
||||
]
|
||||
|
||||
sections_html = ""
|
||||
for kat in kat_order:
|
||||
label = KAT_LABEL.get(kat, kat.replace("_", " ").title())
|
||||
items = "".join(
|
||||
f'<details><summary>{_html.escape(a["frage"])}</summary>'
|
||||
f'<div class="answer">{_html.escape(a["antwort"]).replace(chr(10), "<br>")}</div></details>'
|
||||
for a in by_kat[kat]
|
||||
)
|
||||
sections_html += f'<section><h2>{_html.escape(label)}</h2>{items}</section>'
|
||||
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Hilfe & FAQ — Ban Yaro</title>
|
||||
<meta name="description" content="Antworten zu Ban Yaro und Ban Yaro Go: Installation, Standort, Account, Features.">
|
||||
<link rel="icon" href="/icons/icon-180.png">
|
||||
<style>
|
||||
:root {{
|
||||
--c-bg: #fbfaf6;
|
||||
--c-text: #1c1917;
|
||||
--c-text-sec: #57534e;
|
||||
--c-primary: #C4843A;
|
||||
--c-border: #e7e5e0;
|
||||
--c-card: #fff;
|
||||
}}
|
||||
@media (prefers-color-scheme: dark) {{
|
||||
:root {{
|
||||
--c-bg: #0c0a09; --c-text: #f5f5f4; --c-text-sec: #a8a29e;
|
||||
--c-border: #292524; --c-card: #1c1917;
|
||||
}}
|
||||
}}
|
||||
* {{ box-sizing: border-box; }}
|
||||
body {{
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
background: var(--c-bg); color: var(--c-text);
|
||||
max-width: 760px; margin: 0 auto;
|
||||
padding: 2rem 1.25rem 4rem; line-height: 1.55;
|
||||
}}
|
||||
a {{ color: var(--c-primary); text-decoration: none; }}
|
||||
a:hover {{ text-decoration: underline; }}
|
||||
h1 {{ font-size: 1.8rem; margin: 0 0 .25rem; font-weight: 800; }}
|
||||
.lead {{ color: var(--c-text-sec); margin: 0 0 2rem; }}
|
||||
section {{ margin-bottom: 2rem; }}
|
||||
h2 {{ font-size: 1.1rem; margin: 0 0 .75rem;
|
||||
color: var(--c-text); font-weight: 700;
|
||||
padding-bottom: .25rem; border-bottom: 1px solid var(--c-border); }}
|
||||
details {{
|
||||
background: var(--c-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
margin-bottom: .6rem;
|
||||
padding: 0;
|
||||
}}
|
||||
details summary {{
|
||||
cursor: pointer;
|
||||
padding: .9rem 1rem;
|
||||
font-weight: 600;
|
||||
list-style: none;
|
||||
position: relative;
|
||||
padding-right: 2.5rem;
|
||||
}}
|
||||
details summary::-webkit-details-marker {{ display: none; }}
|
||||
details summary::after {{
|
||||
content: "+";
|
||||
position: absolute; right: 1rem; top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-weight: 400; color: var(--c-primary);
|
||||
font-size: 1.4rem; transition: transform .15s;
|
||||
}}
|
||||
details[open] summary::after {{ content: "−"; }}
|
||||
.answer {{
|
||||
padding: 0 1rem 1rem;
|
||||
color: var(--c-text-sec);
|
||||
}}
|
||||
.contact {{
|
||||
background: var(--c-card);
|
||||
border: 1px solid var(--c-border);
|
||||
border-radius: 12px;
|
||||
padding: 1.25rem;
|
||||
margin-top: 2.5rem;
|
||||
}}
|
||||
.contact h2 {{ border-bottom: none; padding-bottom: 0; margin-bottom: .5rem; }}
|
||||
.contact p {{ margin: .25rem 0; color: var(--c-text-sec); }}
|
||||
nav.top {{ margin-bottom: 1.5rem; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="top"><a href="/">← banyaro.app</a></nav>
|
||||
<h1>Hilfe & FAQ</h1>
|
||||
<p class="lead">
|
||||
Antworten zu Ban Yaro und Ban Yaro Go — der nativen iOS-App für unterwegs.
|
||||
</p>
|
||||
|
||||
{sections_html}
|
||||
|
||||
<div class="contact">
|
||||
<h2>Direkt-Kontakt</h2>
|
||||
<p>Wenn du hier nichts findest, schreib uns:</p>
|
||||
<p><a href="mailto:support@banyaro.app">support@banyaro.app</a></p>
|
||||
<p style="font-size:.85rem;margin-top:1rem">
|
||||
Mehr Hilfe gibt es nach dem Anmelden im Suchbereich von
|
||||
<a href="/#hilfe">banyaro.app/#hilfe</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="text-align:center;margin-top:3rem;font-size:.85rem;color:var(--c-text-sec)">
|
||||
<a href="/impressum">Impressum</a> · <a href="/datenschutz">Datenschutz</a> · <a href="/agb">AGB</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>"""
|
||||
return HTMLResponse(content=html, headers={"Cache-Control": "max-age=600"})
|
||||
|
||||
|
||||
@app.get("/konto-loeschen")
|
||||
async def konto_loeschen():
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
|
|
|||
|
|
@ -86,14 +86,14 @@
|
|||
<title>Ban Yaro</title>
|
||||
|
||||
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
|
||||
<script src="/js/boot-early.js?v=1140"></script>
|
||||
<script src="/js/boot-early.js?v=1141"></script>
|
||||
|
||||
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1140">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1140">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1140">
|
||||
<link rel="stylesheet" href="/css/utilities.css?v=1140">
|
||||
<link rel="stylesheet" href="/css/lists.css?v=1140">
|
||||
<link rel="stylesheet" href="/css/design-system.css?v=1141">
|
||||
<link rel="stylesheet" href="/css/layout.css?v=1141">
|
||||
<link rel="stylesheet" href="/css/components.css?v=1141">
|
||||
<link rel="stylesheet" href="/css/utilities.css?v=1141">
|
||||
<link rel="stylesheet" href="/css/lists.css?v=1141">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
@ -617,11 +617,11 @@
|
|||
<div id="modal-container"></div>
|
||||
|
||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||
<script src="/js/api.js?v=1140"></script>
|
||||
<script src="/js/ui.js?v=1140"></script>
|
||||
<script src="/js/app.js?v=1140"></script>
|
||||
<script src="/js/worlds.js?v=1140"></script>
|
||||
<script src="/js/offline-indicator.js?v=1140"></script>
|
||||
<script src="/js/api.js?v=1141"></script>
|
||||
<script src="/js/ui.js?v=1141"></script>
|
||||
<script src="/js/app.js?v=1141"></script>
|
||||
<script src="/js/worlds.js?v=1141"></script>
|
||||
<script src="/js/offline-indicator.js?v=1141"></script>
|
||||
|
||||
<!-- Feature-Seiten werden lazy geladen -->
|
||||
|
||||
|
|
@ -631,7 +631,7 @@
|
|||
|
||||
|
||||
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
|
||||
<script src="/js/boot.js?v=1140"></script>
|
||||
<script src="/js/boot.js?v=1141"></script>
|
||||
|
||||
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '1140'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '1141'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
||||
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
||||
window.APP_VERSION = APP_VERSION;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<script src="/js/landing-init.js?v=1140"></script>
|
||||
<script src="/js/landing-init.js?v=1141"></script>
|
||||
<title>Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz</title>
|
||||
<meta name="description" content="Ban Yaro: Die kostenlose All-in-One Hunde-App für DACH. Tagebuch, Giftköder-Alarm, Training mit KI, Forum, Wurfbörse, Stammbaum, Inzucht-Check — DSGVO-konform, offline-fähig, ohne App Store.">
|
||||
<meta name="keywords" content="Hunde App, Hunde Community, Wurfbörse, Züchter, Welpen kaufen, Stammbaum Hund, Inzuchtkoeffizient, Hundezucht, Impfpass Hund, Giftköder Alarm, Gassi Community, Hundetraining App, Hunde Forum, Hunde KI, Hundefilm Datenbank, Welpen Marktplatz">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
============================================================ */
|
||||
|
||||
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
||||
const VER = '1140';
|
||||
const VER = '1141';
|
||||
const CACHE_VERSION = `by-v${VER}`;
|
||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue