Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Admin - Mr.FLEN</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <link rel="stylesheet" href="style.css"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#0B2D2F', | |
| accent: '#FF914D', | |
| magenta: '#C5427A', | |
| paper: '#0A0F10' | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| </head> | |
| <body class="bg-paper text-white min-h-screen flex flex-col"> | |
| <custom-navbar></custom-navbar> | |
| <main class="flex-1 py-12 px-4"> | |
| <div class="max-w-6xl mx-auto"> | |
| <!-- Admin Header --> | |
| <div class="text-center mb-12"> | |
| <h1 class="text-4xl md:text-5xl font-bold mb-4"> | |
| <span class="bg-gradient-to-r from-accent to-magenta bg-clip-text text-transparent"> | |
| EMBEDS MANAGER | |
| </span> | |
| </h1> | |
| <p class="text-lg text-gray-400 max-w-2xl mx-auto"> | |
| Manage track embeds and export configuration | |
| </p> | |
| </div> | |
| <!-- Security Check --> | |
| <div id="securityCheck" class="max-w-md mx-auto bg-primary/20 rounded-2xl p-8 backdrop-blur-sm border border-accent/20"> | |
| <h3 class="text-xl font-semibold mb-4">Admin Access</h3> | |
| <p class="text-gray-400 mb-4">Enter PIN to access embeds manager</p> | |
| <input type="password" id="adminPin" | |
| placeholder="Enter 6-digit PIN" | |
| class="w-full bg-primary/10 border border-accent/20 rounded-full py-3 px-6 mb-4 focus:border-accent focus:outline-none transition-all duration-300"> | |
| <button onclick="checkAdminAccess()" | |
| class="w-full bg-accent hover:bg-accent/80 text-paper font-bold py-3 px-8 rounded-full transition-all duration-300"> | |
| Access Admin | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Embeds Manager (Hidden by default) --> | |
| <div id="embedsManager" class="hidden"> | |
| <!-- Export Controls --> | |
| <div class="flex justify-between items-center mb-8"> | |
| <h2 class="text-2xl font-bold">Track Embeds</h2> | |
| <div class="flex gap-4"> | |
| <button onclick="exportAlbumData()" | |
| class="flex items-center gap-2 bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300"> | |
| <i data-feather="download" class="w-4 h-4"></i> | |
| Export JSON | |
| </button> | |
| <button onclick="resetAlbumData()" | |
| class="flex items-center gap-2 bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300"> | |
| <i data-feather="refresh-cw" class="w-4 h-4"></i> | |
| Reset Data | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Tracks List --> | |
| <div id="tracksAdminList" class="space-y-6"> | |
| <!-- Tracks will be populated by JavaScript --> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <custom-footer></custom-footer> | |
| <script src="components/navbar.js"></script> | |
| <script src="components/footer.js"></script> | |
| <script src="script.js"></script> | |
| <script> | |
| feather.replace(); | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Check if already authenticated | |
| if (localStorage.getItem('mrflen_admin_auth') === 'true') { | |
| showEmbedsManager(); | |
| } | |
| }); | |
| function checkAdminAccess() { | |
| const pinInput = document.getElementById('adminPin'); | |
| const enteredPin = pinInput.value; | |
| // For MVP, use a simple PIN (in production, use environment variable) | |
| const adminPin = '123456'; // Should be from environment variable | |
| if (enteredPin === adminPin) { | |
| localStorage.setItem('mrflen_admin_auth', 'true'); | |
| showEmbedsManager(); | |
| } else { | |
| alert('Invalid PIN. Please try again.'); | |
| } | |
| } | |
| function showEmbedsManager() { | |
| document.getElementById('securityCheck').classList.add('hidden'); | |
| document.getElementById('embedsManager').classList.remove('hidden'); | |
| loadAdminTracks(); | |
| } | |
| function loadAdminTracks() { | |
| const container = document.getElementById('tracksAdminList'); | |
| if (!container) return; | |
| container.innerHTML = albumData.tracks.map(track => ` | |
| <div class="bg-primary/20 rounded-2xl p-6 backdrop-blur-sm border border-accent/20"> | |
| <div class="flex items-start justify-between mb-4"> | |
| <h3 class="text-xl font-semibold">${track.no}. ${track.title}</h3> | |
| <span class="text-sm ${track.embeds && track.embeds.length > 0 ? 'text-green-400' : 'text-red-400'}"> | |
| ${track.embeds && track.embeds.length > 0 ? `${track.embeds.length} embed(s)` : 'No embeds'}</span> | |
| </div> | |
| <!-- Embeds List for this track --> | |
| <div id="embeds-${track.slug}" class="space-y-4 mb-4"> | |
| ${track.embeds ? track.embeds.map((embed, index) => ` | |
| <div class="bg-primary/10 rounded-xl p-4"> | |
| <div class="flex items-center gap-4 mb-2"> | |
| <select class="provider-select bg-primary/20 border border-accent/20 rounded-full py-2 px-4 focus:border-accent focus:outline-none transition-all duration-300" | |
| onchange="updateEmbedProvider('${track.slug}', ${index}, this.value)"> | |
| <option value="soundcloud" ${embed.provider === 'soundcloud' ? 'selected' : ''}>SoundCloud</option> | |
| <option value="spotify" ${embed.provider === 'spotify' ? 'selected' : ''}>Spotify</option> | |
| <option value="youtube" ${embed.provider === 'youtube' ? 'selected' : ''}>YouTube</option> | |
| <option value="bandcamp" ${embed.provider === 'bandcamp' ? 'selected' : ''}>Bandcamp</option> | |
| </select> | |
| <input type="text" | |
| value="${embed.url}" | |
| placeholder="Embed URL" | |
| class="flex-1 bg-primary/20 border border-accent/20 rounded-full py-2 px-4 focus:border-accent focus:outline-none transition-all duration-300" | |
| oninput="updateEmbedUrl('${track.slug}', ${index}, this.value)" | |
| class="w-full"> | |
| </div> | |
| <div class="aspect-video rounded-lg bg-primary/10 border border-accent/20"> | |
| <iframe src="${embed.url}" class="w-full h-full rounded-lg" loading="lazy" allow="autoplay"></iframe> | |
| </div> | |
| `).join('') : '<p class="text-gray-400 text-sm">No embeds configured</p>'} | |
| </div> | |
| <!-- Add New Embed Button --> | |
| <button onclick="addNewEmbed('${track.slug}')" | |
| class="w-full border border-dashed border-accent/30 hover:border-accent/50 text-accent font-medium py-3 rounded-xl transition-all duration-300"> | |
| <i data-feather="plus" class="w-4 h-4 inline mr-2"></i> | |
| Add Embed | |
| </button> | |
| </div> | |
| </div> | |
| `).join(''); | |
| feather.replace(); | |
| } | |
| function updateEmbedProvider(trackSlug, embedIndex, newProvider) { | |
| const track = albumData.tracks.find(t => t.slug === trackSlug); | |
| if (track && track.embeds[embedIndex]) { | |
| track.embeds[embedIndex].provider = newProvider; | |
| saveAlbumData(); | |
| loadAdminTracks(); // Refresh to show updated preview | |
| } | |
| function updateEmbedUrl(trackSlug, embedIndex, newUrl) { | |
| const track = albumData.tracks.find(t => t.slug === trackSlug); | |
| if (track && track.embeds[embedIndex]) { | |
| track.embeds[embedIndex].url = newUrl; | |
| saveAlbumData(); | |
| loadAdminTracks(); // Refresh to show updated preview | |
| } | |
| function addNewEmbed(trackSlug) { | |
| const track = albumData.tracks.find(t => t.slug === trackSlug); | |
| if (track) { | |
| if (!track.embeds) track.embeds = []; | |
| track.embeds.push({ | |
| provider: 'soundcloud', | |
| url: '' | |
| }); | |
| saveAlbumData(); | |
| loadAdminTracks(); | |
| } | |
| } | |
| function resetAlbumData() { | |
| if (confirm('Are you sure you want to reset all album data? This cannot be undone.')) { | |
| localStorage.removeItem('mrflen_album_data'); | |
| window.location.reload(); | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> |