mirror of
https://github.com/guyg1474/hcrb.git
synced 2026-10-15 23:13:28 +02:00
Spiel-Events, Kalenderdateien, Patches-Seite und neues Design
- Kalender: Termine als Spiel-Event markieren (nur diese zählen in der Statistik), optionale Uhrzeiten, Termine bearbeiten - .ics-Download für einzelne und alle kommenden Termine - Neue Seite Patches: Upload (PNG, JPEG, WebP, geprüftes SVG), Status "Gibt es schon" / "In Planung", Bilder in data/patches/ - Volle Seitenbreite mit Spaltenlayouts, neues Design mit selbst gehosteten Schriften, Startseite mit Zoom und drehendem Zahnrad - Bestehende Daten werden beim Laden ergänzt, keine Migration nötig Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
43356a120c
commit
486e6f6784
23 files changed
+1757
-387
No files matched your search
+24
-4
@@ -80,11 +80,13 @@ const NAV = [
|
||||
{ href: '/fahrt', key: 'fahrt', label: 'Fahrtplaner' },
|
||||
{ href: '/gruppe', key: 'gruppe', label: 'Gruppe' },
|
||||
{ href: '/statistik', key: 'statistik', label: 'Statistik' },
|
||||
{ href: '/patches', key: 'patches', label: 'Patches' },
|
||||
];
|
||||
|
||||
export function renderHeader(active) {
|
||||
// overlay: Kopfzeile liegt durchsichtig über dem Hero und wird erst beim Scrollen fest (Startseite)
|
||||
export function renderHeader(active, { overlay = false } = {}) {
|
||||
const header = document.createElement('header');
|
||||
header.className = 'site-header';
|
||||
header.className = overlay ? 'site-header overlay' : 'site-header';
|
||||
header.innerHTML = `
|
||||
<div class="inner">
|
||||
<a class="brand" href="/"><img src="/img/logo.png" alt="" width="40" height="40">HCRB<small>Highcap Rasselbande</small></a>
|
||||
@@ -98,6 +100,11 @@ export function renderHeader(active) {
|
||||
</nav>
|
||||
</div>`;
|
||||
document.body.prepend(header);
|
||||
if (overlay) {
|
||||
const update = () => header.classList.toggle('scrolled', scrollY > 40);
|
||||
addEventListener('scroll', update, { passive: true });
|
||||
update();
|
||||
}
|
||||
// Auf schmalen Bildschirmen klappt das Menü über die Schaltfläche auf
|
||||
const toggle = header.querySelector('.nav-toggle');
|
||||
toggle.addEventListener('click', () => {
|
||||
@@ -114,7 +121,7 @@ export function renderHeader(active) {
|
||||
export function renderFooter() {
|
||||
const footer = document.createElement('footer');
|
||||
footer.innerHTML = `
|
||||
HCRB · Highcap Rasselbande · Berlin
|
||||
<span class="f-brand"><img src="/img/logo.png" alt="" width="32" height="32">HCRB · Highcap Rasselbande · Berlin</span>
|
||||
<div class="footer-links">
|
||||
<a href="https://www.youtube.com/@highcaprasselbande" target="_blank" rel="noopener">YouTube</a>
|
||||
<a href="https://www.instagram.com/hcrb.airsoft" target="_blank" rel="noopener">Instagram</a>
|
||||
@@ -122,8 +129,15 @@ export function renderFooter() {
|
||||
document.body.append(footer);
|
||||
}
|
||||
|
||||
// Einmal pro Seite abfragen, ob jemand angemeldet ist
|
||||
let mePromise;
|
||||
export function currentUser() {
|
||||
mePromise ??= api('GET', '/me').then(({ user }) => user || null).catch(() => null);
|
||||
return mePromise;
|
||||
}
|
||||
|
||||
async function renderAuthLink(nav) {
|
||||
const { user } = await api('GET', '/me').catch(() => ({}));
|
||||
const user = await currentUser();
|
||||
if (!user) {
|
||||
nav.insertAdjacentHTML('beforeend', '<a href="/login">Anmelden</a>');
|
||||
return;
|
||||
@@ -138,3 +152,9 @@ async function renderAuthLink(nav) {
|
||||
});
|
||||
nav.append(btn);
|
||||
}
|
||||
|
||||
// Kurzes Zeitformat für Termine: "09:00 Uhr" oder "09:00–15:00 Uhr"
|
||||
export function formatTime(ev) {
|
||||
if (!ev.time) return '';
|
||||
return `${ev.time}${ev.endTime ? `–${ev.endTime}` : ''} Uhr`;
|
||||
}
|
||||
Reference in new issue
Block a user