Add radio embed widget, SSE real-time, song history, moderation panel, and Auto DJ

- Embed widget: standalone iframe player with dark/light/transparent themes, copy-paste embed code admin page
- Real-time SSE: streaming now-playing/listeners/dj events, replaces polling in radio-player and embed
- Song history: auto-records song changes to radio_song_plays table, Filament resource to view
- DJ moderation: unified panel for shouts approval, song request queue, DJ applications
- Auto DJ: playlist management with round-robin playback when no DJ is live
- Refactored radio-player Alpine component to use EventSource API with auto-reconnect
This commit is contained in:
root
2026-05-24 14:07:32 +02:00
parent 5476dce882
commit 0c6c558a59
32 changed files with 2236 additions and 29 deletions
@@ -0,0 +1,26 @@
<?php
?>
<x-filament-panels::page>
@if($newKey = $this->getNewKey())
<div class="bg-success-50 dark:bg-success-950 border border-success-300 dark:border-success-700 rounded-lg p-4 mb-4">
<div class="flex items-center gap-2 mb-2">
<x-filament::icon name="heroicon-o-key" class="w-5 h-5 text-success-600 dark:text-success-400" />
<strong class="text-success-700 dark:text-success-300">Nieuwe API Sleutel Aangemaakt!</strong>
</div>
<p class="text-sm text-success-600 dark:text-success-400 mb-2">Kopieer deze sleutel nu. Deze wordt niet meer getoond:</p>
<div class="flex gap-2">
<input type="text" value="{{ $newKey }}" readonly
class="flex-1 bg-white dark:bg-gray-900 border border-success-300 dark:border-success-700 rounded-lg px-3 py-2 text-sm font-mono"
id="newApiKey" />
<button onclick="navigator.clipboard.writeText('{{ $newKey }}').then(() => { this.textContent = 'Gekopieerd!'; setTimeout(() => this.textContent = 'Kopieer', 2000); })"
class="px-4 py-2 bg-success-600 text-white rounded-lg text-sm hover:bg-success-700 transition">
Kopieer
</button>
</div>
</div>
@endif
{{ $this->table }}
</x-filament-panels::page>