feat: PWA-Unterstützung und Mobile-Responsiveness
Macht Calendarr installierbar (Manifest + Service Worker) und auf Smartphones bedienbar — additive Änderungen, kein Refactoring der bestehenden Logik, Theme/Variablen unverändert. PWA: - frontend/manifest.json (theme #4285f4, bg #0e0e14, name/icons/scope) - frontend/sw.js (cache-first für Statics, network-first für /api/*) - frontend/icons/icon-192.png + icon-512.png + icon.svg - backend/main.py: Routen für /manifest.json, /sw.js, /icons/* damit diese Pfade nicht vom SPA-Fallback abgefangen werden - index.html: manifest-Link, theme-color, apple-touch-icon, apple-* Meta - app.js: Service-Worker-Registrierung am Ende Mobile (≤ 768px, additiv am Ende von app.css): - Sidebar als Overlay mit body.sidebar-open + Backdrop-Element - View-Switcher horizontal scrollbar wenn er nicht passt - Monatsansicht zeigt nur farbige Punkte statt Titel - Wochenansicht reduziert auf Tagesspalte (heute) wenn heute in der Woche ist (via :has()), sonst Standard-7-Spalten - Modale auf voller Breite/Höhe - Tap-Targets ≥ 44px (icon-btn, btn) - Kein horizontaler Page-Overflow - iOS-Safe-Area für Notch/Home-Indicator Version v2 → v3.
This commit is contained in:
@@ -115,6 +115,29 @@ FRONTEND_DIR = Path(__file__).parent.parent / "frontend"
|
||||
app.mount("/static", StaticFiles(directory=str(FRONTEND_DIR)), name="static")
|
||||
|
||||
|
||||
# ── PWA assets that must live at root scope ──────────────
|
||||
@app.get("/manifest.json")
|
||||
async def pwa_manifest():
|
||||
return FileResponse(str(FRONTEND_DIR / "manifest.json"), media_type="application/manifest+json")
|
||||
|
||||
|
||||
@app.get("/sw.js")
|
||||
async def pwa_service_worker():
|
||||
return FileResponse(
|
||||
str(FRONTEND_DIR / "sw.js"),
|
||||
media_type="application/javascript",
|
||||
headers={"Service-Worker-Allowed": "/", "Cache-Control": "no-cache"},
|
||||
)
|
||||
|
||||
|
||||
@app.get("/icons/{icon_name}")
|
||||
async def pwa_icon(icon_name: str):
|
||||
icon_path = FRONTEND_DIR / "icons" / icon_name
|
||||
if not icon_path.exists() or not icon_path.is_file():
|
||||
raise HTTPException(status_code=404, detail="Icon not found")
|
||||
return FileResponse(str(icon_path))
|
||||
|
||||
|
||||
@app.get("/{full_path:path}")
|
||||
async def spa_fallback(full_path: str):
|
||||
if full_path.startswith("api/"):
|
||||
|
||||
Reference in New Issue
Block a user