diff --git a/assets/css/main.css b/assets/css/main.css index b1fe270..f0232e2 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -425,6 +425,29 @@ footer.site-footer { font-size: .8rem; color: var(--text-muted); } +/* ---------- Live-Status-Punkt ---------- */ +.live-dot { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + background: #6b7280; /* grau = aktuell offline */ + margin-right: .45rem; + vertical-align: middle; +} +.live-dot.is-live { + background: #22c55e; /* grün = live */ + animation: live-pulse 1.6s infinite; +} +@keyframes live-pulse { + 0% { box-shadow: 0 0 0 0 rgba(34, 197, 94, .55); } + 70% { box-shadow: 0 0 0 10px rgba(34, 197, 94, 0); } + 100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); } +} +@media (prefers-reduced-motion: reduce) { + .live-dot.is-live { animation: none; } +} + /* ---------- Badges / Hierarchy ---------- */ .badge { display: inline-block; font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; padding: .2rem .6rem; border-radius: 999px; background: var(--bg-alt); border: 1px solid var(--border); color: var(--text-muted); } .badge.rank-1 { border-color: var(--accent); color: var(--accent); } diff --git a/cloudflare-worker/src/worker.js b/cloudflare-worker/src/worker.js index 84d37db..0c87478 100644 --- a/cloudflare-worker/src/worker.js +++ b/cloudflare-worker/src/worker.js @@ -24,6 +24,8 @@ POST /admin/roles/list { ownerCode } -> Helfer-Codes auflisten (nur Owner) POST /admin/roles/create { ownerCode, role, label } -> neuen Helfer-Code erzeugen (nur Owner) POST /admin/roles/revoke { ownerCode, keyId } -> Helfer-Code entziehen (nur Owner) + GET /live-status -> öffentlich: {live, updatedAt} + POST /live-status/set { ownerCode, live } -> Live-Status umschalten (nur Owner) GET /health -> einfacher Check ob der Worker läuft Secrets/Bindings (siehe wrangler.toml + README.md): @@ -33,6 +35,7 @@ const ALLOWED_TYPES = ["creator", "scout", "kooperation"]; const ROLE_KEY_PREFIX = "role:"; +const LIVE_STATUS_KEY = "meta:live"; function corsHeaders() { // TODO: sobald die Domain final steht, statt "*" die echte Domain eintragen @@ -40,7 +43,7 @@ function corsHeaders() { // an die API senden kann. return { "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type", }; } @@ -215,6 +218,30 @@ async function handleRolesRevoke(request, env) { return json({ ok: true }); } +async function handleLiveStatusGet(env) { + const raw = await env.BEWERBUNGEN.get(LIVE_STATUS_KEY); + const data = raw ? JSON.parse(raw) : { live: false, updatedAt: null }; + return json({ ok: true, ...data }); +} + +async function handleLiveStatusSet(request, env) { + let body; + try { + body = await request.json(); + } catch { + return json({ ok: false, error: "Ungültiges JSON." }, 400); + } + if (!(await requireOwner(body, env))) { + return json({ ok: false, error: "Nur Dogi darf den Live-Status ändern." }, 401); + } + + const live = !!(body && body.live); + const record = { live, updatedAt: new Date().toISOString() }; + await env.BEWERBUNGEN.put(LIVE_STATUS_KEY, JSON.stringify(record)); + + return json({ ok: true, ...record }); +} + export default { async fetch(request, env) { const url = new URL(request.url); @@ -247,6 +274,14 @@ export default { return handleRolesRevoke(request, env); } + if (url.pathname === "/live-status" && request.method === "GET") { + return handleLiveStatusGet(env); + } + + if (url.pathname === "/live-status/set" && request.method === "POST") { + return handleLiveStatusSet(request, env); + } + return json({ ok: false, error: "Not found." }, 404); }, }; diff --git a/dogfather.html b/dogfather.html index df80bb9..ffe337a 100644 --- a/dogfather.html +++ b/dogfather.html @@ -82,7 +82,7 @@

Nebenprojekte & Leidenschaften

-

🎵 Musik-Produzent

Eigene Songs unter dem Namen „Hasidog" auf Spotify.

+

🎵 Musik-Produzent

Eigene Songs unter dem Namen „Hasidog" auf Spotify.

🧸 Merchandise-Creator

Tassen, Decken, Popsockets, Schlüsselanhänger, Sticker.

📖 Autor

Ein Buch über Hasidog & Casper.

diff --git a/hasidog.html b/hasidog.html index 1091c97..002194d 100644 --- a/hasidog.html +++ b/hasidog.html @@ -41,7 +41,7 @@

Was ist HasiDog?

-

HasiDog ist mehr als ein Spitzname — es ist die verspielte, familiäre Marke rund um Dogfathers Community. Unter dem Namen „Hasidog" erscheint auch die eigene Musik auf Spotify.

+

HasiDog ist mehr als ein Spitzname — es ist die verspielte, familiäre Marke rund um Dogfathers Community. Unter dem Namen „Hasidog" erscheint auch die eigene Musik auf Spotify.

Zur Casper-Seite 🐾 Zur Community @@ -54,7 +54,7 @@

Die HasiDog-Familie

-

🎵 Musik

Songs unter dem Namen „Hasidog" auf Spotify.

+

🎵 Musik

Songs unter dem Namen „Hasidog" auf Spotify.

🐕 Casper

Der Husky, der zum Gesicht der HasiDog-Welt wurde — eigene Seite: Casper.

📖 Buch

„Hasidog & Casper" — die Geschichte in Buchform.

diff --git a/index.html b/index.html index 4a02733..22c7fea 100644 --- a/index.html +++ b/index.html @@ -34,7 +34,7 @@

Drei Welten, eine Familie: Team Dogi.

- 🔴 Live-Status + Aktuell offline

Dogfather geht jeden Tag ab 20 Uhr live — oft schon tagsüber, zu wechselnden Zeiten. Streamplan ansehen →

@@ -167,7 +167,30 @@