- base.html: [x-cloak]-CSS gegen Alpine-Flackern - Neues zentrales Icon-Makro-Template (icons.html, Heroicons-Stil, currentColor, aria-hidden) - Logo-Würfelbecher, Sync-Pfeile, Sortier-Chevrons, Warn-/Check-Icons, dedup-Karten (Gebäude/Tag/Buch/Dokument), Cover-Platzhalter als SVG - Cover-Platzhalter: 'Kein Cover'-Text in Großansicht, Mindestgröße 48x68 px in der Kartenansicht
89 lines
4.8 KiB
HTML
89 lines
4.8 KiB
HTML
<!doctype html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{% block titel %}{{ app_name }}{% endblock %}</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.9/dist/cdn.min.js"></script>
|
|
<style>[x-cloak] { display: none !important; }</style>
|
|
</head>
|
|
<body class="bg-slate-100 text-slate-800 min-h-screen flex flex-col">
|
|
<header class="bg-white border-b border-slate-200" x-data="{ menue: false }">
|
|
<nav class="max-w-6xl mx-auto px-4 py-2 md:py-3 flex items-center gap-5" aria-label="Hauptnavigation">
|
|
<a href="/" class="font-bold text-emerald-700 whitespace-nowrap inline-flex items-center gap-1.5">
|
|
{% from "icons.html" import icon_wuerfelbecher %}{{ icon_wuerfelbecher("h-5 w-5") }} {{ app_name }}
|
|
</a>
|
|
<!-- Desktop: horizontale Navigationsleiste -->
|
|
<span class="hidden md:flex items-center gap-5 flex-1">
|
|
{% for eintrag in plugin_nav %}
|
|
<a href="{{ eintrag.url }}" class="text-sm text-slate-600 hover:text-emerald-700">{{ eintrag.label }}</a>
|
|
{% endfor %}
|
|
</span>
|
|
<!-- Mobil: Burger-Button (Alpine.js), Touch-Ziel ≥≥ 44px -->
|
|
<button type="button" @click="menue = !menue" :aria-expanded="menue.toString()"
|
|
aria-controls="hauptmenue-mobil" aria-label="Navigation umschalten"
|
|
class="md:hidden ml-auto inline-flex items-center justify-center min-h-[44px] min-w-[44px] rounded-lg text-slate-600 hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-emerald-500">
|
|
<svg x-show="!menue" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none"
|
|
viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16"/>
|
|
</svg>
|
|
<svg x-show="menue" x-cloak xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none"
|
|
viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
<div class="relative" x-data="{ offen: false }">
|
|
{% if user %}
|
|
<button type="button" @click="offen = !offen"
|
|
class="text-sm font-medium px-2 py-1 rounded hover:bg-slate-100 inline-flex items-center min-h-[44px] md:min-h-0">
|
|
{{ user.display_name }}
|
|
{% from "icons.html" import icon_chevron_unten %}{{ icon_chevron_unten("h-3.5 w-3.5") }}
|
|
</button>
|
|
<div x-show="offen" x-cloak @click.outside="offen = false"
|
|
class="absolute right-0 mt-2 w-56 bg-white border border-slate-200 rounded-lg shadow-lg p-3 text-sm z-10">
|
|
<p class="text-slate-500 mb-2">Angemeldet als<br><span class="font-medium text-slate-800">{{ user.username }}</span></p>
|
|
<p class="text-slate-500 mb-3">Rolle: <span class="font-medium text-slate-800">{{ rollen_anzeige[user.role] or user.role }}</span></p>
|
|
{% if user.role == 'admin' %}
|
|
<a href="/admin/benutzer" class="block px-2 py-1 rounded hover:bg-slate-100 mb-1">Benutzerverwaltung</a>
|
|
{% endif %}
|
|
<form method="post" action="/logout">
|
|
<button type="submit" class="w-full text-left px-2 py-1 rounded hover:bg-red-50 text-red-600">Abmelden</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<a href="/login" class="text-sm font-medium text-emerald-700 inline-flex items-center min-h-[44px] md:min-h-0 px-2">Anmelden</a>
|
|
{% endif %}
|
|
</div>
|
|
</nav>
|
|
<!-- Mobil: ausklappbare Navigation (Burger-Menü) -->
|
|
<div id="hauptmenue-mobil" x-show="menue" x-cloak @click.outside="menue = false"
|
|
class="md:hidden border-t border-slate-200 bg-white px-4 pb-3 pt-2">
|
|
{% for eintrag in plugin_nav %}
|
|
<a href="{{ eintrag.url }}" @click="menue = false"
|
|
class="block py-3 text-sm font-medium text-slate-700 hover:text-emerald-700 border-b border-slate-100 last:border-0">
|
|
{{ eintrag.label }}
|
|
</a>
|
|
{% endfor %}
|
|
{% if not user %}
|
|
<a href="/login" @click="menue = false"
|
|
class="block py-3 text-sm font-medium text-emerald-700 border-t border-slate-100 mt-1">Anmelden</a>
|
|
{% endif %}
|
|
</div>
|
|
</header>
|
|
<main class="flex-1 max-w-6xl w-full mx-auto px-4 py-6">
|
|
{% block inhalt %}{% endblock %}
|
|
</main>
|
|
<footer class="text-center text-xs text-slate-400 py-4">
|
|
{{ app_name }} · Plugin-Anzahl: {{ geladene_plugins|length }}
|
|
<div class="mt-2">
|
|
<a href="https://boardgamegeek.com" target="_blank" rel="noopener noreferrer">
|
|
<img src="/static/powered-by-bgg.png" alt="Powered by BoardGameGeek"
|
|
width="120" height="35" class="inline-block opacity-80 hover:opacity-100">
|
|
</a>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|