ed
This commit is contained in:
		
							parent
							
								
									585ee069c2
								
							
						
					
					
						commit
						b0f9fbee65
					
				
					 3 changed files with 620 additions and 6 deletions
				
			
		|  | @ -123,6 +123,20 @@ | |||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|  | ||||
|                 <div class="playlist-browser"> | ||||
|     <div class="browser-header"> | ||||
|         <h4>PLAYLISTS</h4> | ||||
|         <button id="create-playlist-btn" class="create-playlist-btn"> | ||||
|             <i class="fas fa-plus"></i> Neue Playlist | ||||
|         </button> | ||||
|     </div> | ||||
|     <div id="playlist-container" class="playlist-container"> | ||||
|         <!-- Playlists werden hier dynamisch eingefügt --> | ||||
|     </div> | ||||
| </div> | ||||
|  | ||||
|  | ||||
|                 <!-- Channel Controls --> | ||||
|                 <div class="channel-controls"> | ||||
|                     <!-- Channel A --> | ||||
|  |  | |||
|  | @ -91,6 +91,49 @@ function initializeDJSystem() { | |||
|     console.log('DJ System: Professional interface ready!'); | ||||
| } | ||||
|  | ||||
| function initializeDJSystem() { | ||||
|     console.log('DJ System: Initializing professional interface...'); | ||||
|      | ||||
|     // Initialisiere Interface-Einstellungen | ||||
|     initializeInterfaceSettings(); | ||||
|      | ||||
|     // Initialize audio players | ||||
|     djInterface.decks.A.player = document.getElementById('audio-player-a'); | ||||
|     djInterface.decks.B.player = document.getElementById('audio-player-b'); | ||||
|      | ||||
|     // Setup audio event listeners | ||||
|     setupAudioEventListeners(); | ||||
|      | ||||
|     // Initialize waveforms | ||||
|     initializeWaveforms(); | ||||
|      | ||||
|     // Start time display | ||||
|     updateTimeDisplay(); | ||||
|     setInterval(updateTimeDisplay, 1000); | ||||
|      | ||||
|     // Start VU meters animation | ||||
|     startVUMeters(); | ||||
|      | ||||
|     // Setup Interface-Kontrollen | ||||
|     setupInterfaceControls(); | ||||
|      | ||||
|     // Lade Playlists | ||||
|     loadPlaylists(); | ||||
|      | ||||
|     // Setup Playlist Event Listeners | ||||
|     setupPlaylistEventListeners(); | ||||
|      | ||||
|     // Event-Listener für "Neue Playlist"-Button | ||||
|     const createPlaylistBtn = document.getElementById('create-playlist-btn'); | ||||
|     if (createPlaylistBtn) { | ||||
|         createPlaylistBtn.addEventListener('click', createNewPlaylist); | ||||
|     } | ||||
|      | ||||
|     console.log('DJ System: Professional interface ready!'); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| function setupEventListeners() { | ||||
|     // Knob interactions | ||||
|     setupKnobControls(); | ||||
|  | @ -1410,22 +1453,40 @@ function extractYouTubeVideoId(url) { | |||
|     return null; | ||||
| } | ||||
|  | ||||
| // FiveM Integration | ||||
| function notifyFiveM(event, data) { | ||||
| // Verbesserte notifyFiveM-Funktion mit Callback-Unterstützung | ||||
| function notifyFiveM(event, data, callback) { | ||||
|     const callbackId = callback ? Date.now().toString() + Math.random().toString(36).substr(2, 5) : null; | ||||
|      | ||||
|     if (callback) { | ||||
|         window.callbacks = window.callbacks || {}; | ||||
|         window.callbacks[callbackId] = callback; | ||||
|     } | ||||
|      | ||||
|     fetch(`https://${GetParentResourceName()}/${event}`, { | ||||
|         method: 'POST', | ||||
|         headers: { | ||||
|             'Content-Type': 'application/json' | ||||
|         }, | ||||
|         body: JSON.stringify(data) | ||||
|         body: JSON.stringify({ | ||||
|             ...data, | ||||
|             callbackId: callbackId | ||||
|         }) | ||||
|     }).catch(err => { | ||||
|         console.error('DJ System: Failed to notify FiveM:', err); | ||||
|         if (callback) { | ||||
|             delete window.callbacks[callbackId]; | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function GetParentResourceName() { | ||||
|     return window.location.hostname; | ||||
| } | ||||
| // Callback-Handler | ||||
| window.handleCallback = function(callbackId, data) { | ||||
|     if (window.callbacks && window.callbacks[callbackId]) { | ||||
|         window.callbacks[callbackId](data); | ||||
|         delete window.callbacks[callbackId]; | ||||
|     } | ||||
| }; | ||||
|  | ||||
|  | ||||
| // Message Handler for FiveM | ||||
| window.addEventListener('message', function(event) { | ||||
|  | @ -1589,3 +1650,290 @@ function stopAllAudioAndCloseInterface() { | |||
|         stopMusic: true | ||||
|     }); | ||||
| } | ||||
|  | ||||
|  | ||||
| // Playlist-Verwaltung | ||||
| let playlists = []; | ||||
| let currentPlaylist = null; | ||||
| let currentPlaylistIndex = 0; | ||||
|  | ||||
| // Playlist laden | ||||
| function loadPlaylists() { | ||||
|     // Lade Playlists vom Server | ||||
|     notifyFiveM('getPlaylists', {}, function(response) { | ||||
|         if (response.success && response.playlists) { | ||||
|             playlists = response.playlists; | ||||
|             updatePlaylistDisplay(); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| // Playlist-Anzeige aktualisieren | ||||
| function updatePlaylistDisplay() { | ||||
|     const playlistContainer = document.getElementById('playlist-container'); | ||||
|     if (!playlistContainer) return; | ||||
|      | ||||
|     playlistContainer.innerHTML = ''; | ||||
|      | ||||
|     if (playlists.length === 0) { | ||||
|         playlistContainer.innerHTML = '<div class="no-playlists">Keine Playlists gefunden</div>'; | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Erstelle Playlist-Elemente | ||||
|     playlists.forEach((playlist, index) => { | ||||
|         const playlistElement = document.createElement('div'); | ||||
|         playlistElement.className = 'playlist-item'; | ||||
|         if (currentPlaylist && currentPlaylist.id === playlist.id) { | ||||
|             playlistElement.classList.add('active'); | ||||
|         } | ||||
|          | ||||
|         playlistElement.innerHTML = ` | ||||
|             <div class="playlist-header"> | ||||
|                 <span class="playlist-name">${playlist.name}</span> | ||||
|                 <span class="playlist-count">${playlist.songs.length} Songs</span> | ||||
|             </div> | ||||
|             <div class="playlist-actions"> | ||||
|                 <button class="playlist-play-btn" title="Play"><i class="fas fa-play"></i></button> | ||||
|                 <button class="playlist-edit-btn" title="Edit"><i class="fas fa-edit"></i></button> | ||||
|                 ${playlist.isOwner ? '<button class="playlist-delete-btn" title="Delete"><i class="fas fa-trash"></i></button>' : ''} | ||||
|             </div> | ||||
|         `; | ||||
|          | ||||
|         // Event-Listener für Playlist-Aktionen | ||||
|         const playBtn = playlistElement.querySelector('.playlist-play-btn'); | ||||
|         if (playBtn) { | ||||
|             playBtn.addEventListener('click', () => playPlaylist(playlist)); | ||||
|         } | ||||
|          | ||||
|         const editBtn = playlistElement.querySelector('.playlist-edit-btn'); | ||||
|         if (editBtn) { | ||||
|             editBtn.addEventListener('click', () => editPlaylist(playlist)); | ||||
|         } | ||||
|          | ||||
|         const deleteBtn = playlistElement.querySelector('.playlist-delete-btn'); | ||||
|         if (deleteBtn) { | ||||
|             deleteBtn.addEventListener('click', () => deletePlaylist(playlist)); | ||||
|         } | ||||
|          | ||||
|         playlistContainer.appendChild(playlistElement); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| // Playlist abspielen | ||||
| function playPlaylist(playlist) { | ||||
|     if (!playlist || !playlist.songs || playlist.songs.length === 0) { | ||||
|         showNotification('Diese Playlist enthält keine Songs', 'warning'); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     currentPlaylist = playlist; | ||||
|     currentPlaylistIndex = 0; | ||||
|      | ||||
|     // Ersten Song abspielen | ||||
|     playPlaylistSong(currentPlaylistIndex); | ||||
| } | ||||
|  | ||||
| // Playlist-Song abspielen | ||||
| function playPlaylistSong(index) { | ||||
|     if (!currentPlaylist || !currentPlaylist.songs || index >= currentPlaylist.songs.length) { | ||||
|         showNotification('Playlist beendet', 'info'); | ||||
|         currentPlaylist = null; | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     const song = currentPlaylist.songs[index]; | ||||
|      | ||||
|     // Lade Song in Deck A | ||||
|     const trackData = { | ||||
|         title: song.title, | ||||
|         artist: song.artist || '', | ||||
|         url: song.url | ||||
|     }; | ||||
|      | ||||
|     loadTrackToPlayer('A', trackData); | ||||
|      | ||||
|     // Starte Wiedergabe | ||||
|     if (!djInterface.decks.A.isPlaying) { | ||||
|         togglePlay('A'); | ||||
|     } | ||||
|      | ||||
|     showNotification(`Playlist: ${currentPlaylist.name} - Song ${index + 1}/${currentPlaylist.songs.length}`, 'info'); | ||||
| } | ||||
|  | ||||
| // Nächster Song in Playlist | ||||
| function playNextSong() { | ||||
|     if (!currentPlaylist) return; | ||||
|      | ||||
|     currentPlaylistIndex++; | ||||
|     if (currentPlaylistIndex < currentPlaylist.songs.length) { | ||||
|         playPlaylistSong(currentPlaylistIndex); | ||||
|     } else { | ||||
|         showNotification('Playlist beendet', 'info'); | ||||
|         currentPlaylist = null; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Playlist bearbeiten | ||||
| function editPlaylist(playlist) { | ||||
|     openPlaylistEditor(playlist); | ||||
| } | ||||
|  | ||||
| // Playlist löschen | ||||
| function deletePlaylist(playlist) { | ||||
|     if (confirm(`Möchtest du die Playlist "${playlist.name}" wirklich löschen?`)) { | ||||
|         notifyFiveM('deletePlaylist', { playlistId: playlist.id }, function(response) { | ||||
|             if (response.success) { | ||||
|                 showNotification('Playlist gelöscht', 'success'); | ||||
|                 loadPlaylists(); // Playlists neu laden | ||||
|             } else { | ||||
|                 showNotification('Fehler beim Löschen der Playlist', 'error'); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Neue Playlist erstellen | ||||
| function createNewPlaylist() { | ||||
|     const playlistName = prompt('Name der neuen Playlist:'); | ||||
|     if (!playlistName) return; | ||||
|      | ||||
|     notifyFiveM('createPlaylist', {  | ||||
|         name: playlistName, | ||||
|         isPublic: confirm('Soll die Playlist öffentlich sein?') | ||||
|     }, function(response) { | ||||
|         if (response.success) { | ||||
|             showNotification('Playlist erstellt', 'success'); | ||||
|             loadPlaylists(); // Playlists neu laden | ||||
|         } else { | ||||
|             showNotification('Fehler beim Erstellen der Playlist', 'error'); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| // Song zu Playlist hinzufügen | ||||
| function addSongToPlaylist(song, playlistId) { | ||||
|     notifyFiveM('addToPlaylist', {  | ||||
|         playlistId: playlistId, | ||||
|         track: song | ||||
|     }, function(response) { | ||||
|         if (response.success) { | ||||
|             showNotification('Song zur Playlist hinzugefügt', 'success'); | ||||
|             loadPlaylists(); // Playlists neu laden | ||||
|         } else { | ||||
|             showNotification('Fehler beim Hinzufügen des Songs', 'error'); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| // Playlist-Editor öffnen | ||||
| function openPlaylistEditor(playlist) { | ||||
|     // Implementiere einen Playlist-Editor | ||||
|     // Dies könnte ein Modal sein, in dem Songs hinzugefügt/entfernt werden können | ||||
|     console.log('Playlist Editor für:', playlist); | ||||
|      | ||||
|     // Beispiel für ein einfaches Modal | ||||
|     const modal = document.createElement('div'); | ||||
|     modal.className = 'modal'; | ||||
|     modal.innerHTML = ` | ||||
|         <div class="modal-content"> | ||||
|             <div class="modal-header"> | ||||
|                 <h3>Playlist bearbeiten: ${playlist.name}</h3> | ||||
|                 <button class="close-modal">×</button> | ||||
|             </div> | ||||
|             <div class="modal-body"> | ||||
|                 <div class="playlist-songs"> | ||||
|                     ${playlist.songs.map((song, idx) => ` | ||||
|                         <div class="playlist-song"> | ||||
|                             <span>${idx + 1}. ${song.title}</span> | ||||
|                             <button class="remove-song" data-index="${idx}"> | ||||
|                                 <i class="fas fa-times"></i> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                     `).join('')} | ||||
|                 </div> | ||||
|                 <div class="add-song-form"> | ||||
|                     <h4>Song hinzufügen</h4> | ||||
|                     <div class="input-group"> | ||||
|                         <input type="text" id="song-title" placeholder="Titel"> | ||||
|                     </div> | ||||
|                     <div class="input-group"> | ||||
|                         <input type="text" id="song-artist" placeholder="Künstler (optional)"> | ||||
|                     </div> | ||||
|                     <div class="input-group"> | ||||
|                         <input type="text" id="song-url" placeholder="URL (YouTube oder direkt)"> | ||||
|                     </div> | ||||
|                     <button id="add-song-btn">Song hinzufügen</button> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     `; | ||||
|      | ||||
|     document.body.appendChild(modal); | ||||
|      | ||||
|     // Event-Listener für Modal | ||||
|     const closeBtn = modal.querySelector('.close-modal'); | ||||
|     if (closeBtn) { | ||||
|         closeBtn.addEventListener('click', () => { | ||||
|             document.body.removeChild(modal); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // Event-Listener für Song-Entfernung | ||||
|     const removeBtns = modal.querySelectorAll('.remove-song'); | ||||
|     removeBtns.forEach(btn => { | ||||
|         btn.addEventListener('click', () => { | ||||
|             const index = parseInt(btn.dataset.index); | ||||
|             removeSongFromPlaylist(playlist.id, playlist.songs[index].id); | ||||
|         }); | ||||
|     }); | ||||
|      | ||||
|     // Event-Listener für Song-Hinzufügung | ||||
|     const addBtn = modal.querySelector('#add-song-btn'); | ||||
|     if (addBtn) { | ||||
|         addBtn.addEventListener('click', () => { | ||||
|             const title = modal.querySelector('#song-title').value; | ||||
|             const artist = modal.querySelector('#song-artist').value; | ||||
|             const url = modal.querySelector('#song-url').value; | ||||
|              | ||||
|             if (!title || !url) { | ||||
|                 showNotification('Titel und URL sind erforderlich', 'error'); | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
|             addSongToPlaylist({ | ||||
|                 title: title, | ||||
|                 artist: artist, | ||||
|                 url: url | ||||
|             }, playlist.id); | ||||
|              | ||||
|             // Modal schließen | ||||
|             document.body.removeChild(modal); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Song aus Playlist entfernen | ||||
| function removeSongFromPlaylist(playlistId, songId) { | ||||
|     notifyFiveM('removeSongFromPlaylist', {  | ||||
|         playlistId: playlistId, | ||||
|         songId: songId | ||||
|     }, function(response) { | ||||
|         if (response.success) { | ||||
|             showNotification('Song aus Playlist entfernt', 'success'); | ||||
|             loadPlaylists(); // Playlists neu laden | ||||
|         } else { | ||||
|             showNotification('Fehler beim Entfernen des Songs', 'error'); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| // Event-Listener für Song-Ende (für Playlist-Fortsetzung) | ||||
| function setupPlaylistEventListeners() { | ||||
|     // Wenn ein Song endet, spiele den nächsten in der Playlist | ||||
|     document.addEventListener('songEnded', function(e) { | ||||
|         if (currentPlaylist) { | ||||
|             playNextSong(); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -1454,3 +1454,255 @@ body { | |||
| .p-15 { padding: 15px; } | ||||
| .p-20 { padding: 20px; } | ||||
|  | ||||
| /* Playlist Styles */ | ||||
| .playlist-browser { | ||||
|     flex: 1; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     background: linear-gradient(145deg, #0f0f23, #1a1a2e); | ||||
|     border-radius: 15px; | ||||
|     padding: 15px; | ||||
|     border: 1px solid rgba(255, 255, 255, 0.1); | ||||
|     overflow: hidden; | ||||
| } | ||||
|  | ||||
| .browser-header { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     margin-bottom: 15px; | ||||
|     padding-bottom: 10px; | ||||
|     border-bottom: 1px solid rgba(255, 255, 255, 0.1); | ||||
| } | ||||
|  | ||||
| .create-playlist-btn { | ||||
|     padding: 8px 12px; | ||||
|     border: none; | ||||
|     border-radius: 8px; | ||||
|     background: linear-gradient(145deg, #4ecdc4, #45b7d1); | ||||
|     color: #ffffff; | ||||
|     font-size: 12px; | ||||
|     font-weight: 600; | ||||
|     cursor: pointer; | ||||
|     transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| .create-playlist-btn:hover { | ||||
|     transform: translateY(-2px); | ||||
|     box-shadow: 0 4px 12px rgba(78, 205, 196, 0.4); | ||||
| } | ||||
|  | ||||
| .playlist-container { | ||||
|     flex: 1; | ||||
|     overflow-y: auto; | ||||
|     scrollbar-width: thin; | ||||
|     scrollbar-color: #4ecdc4 transparent; | ||||
| } | ||||
|  | ||||
| .playlist-container::-webkit-scrollbar { | ||||
|     width: 6px; | ||||
| } | ||||
|  | ||||
| .playlist-container::-webkit-scrollbar-track { | ||||
|     background: transparent; | ||||
| } | ||||
|  | ||||
| .playlist-container::-webkit-scrollbar-thumb { | ||||
|     background: #4ecdc4; | ||||
|     border-radius: 3px; | ||||
| } | ||||
|  | ||||
| .playlist-item { | ||||
|     padding: 10px; | ||||
|     margin-bottom: 8px; | ||||
|     background: rgba(0, 0, 0, 0.3); | ||||
|     border-radius: 8px; | ||||
|     border: 1px solid rgba(255, 255, 255, 0.05); | ||||
|     transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| .playlist-item:hover { | ||||
|     background: rgba(78, 205, 196, 0.1); | ||||
|     border-color: rgba(78, 205, 196, 0.3); | ||||
| } | ||||
|  | ||||
| .playlist-item.active { | ||||
|     background: rgba(78, 205, 196, 0.2); | ||||
|     border-color: rgba(78, 205, 196, 0.5); | ||||
| } | ||||
|  | ||||
| .playlist-header { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     margin-bottom: 8px; | ||||
| } | ||||
|  | ||||
| .playlist-name { | ||||
|     font-weight: 600; | ||||
|     color: #ffffff; | ||||
| } | ||||
|  | ||||
| .playlist-count { | ||||
|     font-size: 12px; | ||||
|     color: #888888; | ||||
| } | ||||
|  | ||||
| .playlist-actions { | ||||
|     display: flex; | ||||
|     gap: 8px; | ||||
| } | ||||
|  | ||||
| .playlist-actions button { | ||||
|     width: 30px; | ||||
|     height: 30px; | ||||
|     border: none; | ||||
|     border-radius: 50%; | ||||
|     background: rgba(0, 0, 0, 0.3); | ||||
|     color: #ffffff; | ||||
|     cursor: pointer; | ||||
|     transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| .playlist-play-btn { | ||||
|     background: linear-gradient(145deg, #4ecdc4, #45b7d1) !important; | ||||
| } | ||||
|  | ||||
| .playlist-edit-btn { | ||||
|     background: linear-gradient(145deg, #feca57, #ff9ff3) !important; | ||||
| } | ||||
|  | ||||
| .playlist-delete-btn { | ||||
|     background: linear-gradient(145deg, #ff6b6b, #ff5722) !important; | ||||
| } | ||||
|  | ||||
| .playlist-actions button:hover { | ||||
|     transform: scale(1.1); | ||||
| } | ||||
|  | ||||
| .no-playlists { | ||||
|     text-align: center; | ||||
|     color: #888888; | ||||
|     padding: 20px; | ||||
| } | ||||
|  | ||||
| /* Playlist Editor Modal */ | ||||
| .modal { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background: rgba(0, 0, 0, 0.8); | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     z-index: 2000; | ||||
| } | ||||
|  | ||||
| .modal-content { | ||||
|     background: linear-gradient(145deg, #1e1e2e, #2a2a3e); | ||||
|     border-radius: 20px; | ||||
|     padding: 20px; | ||||
|     width: 500px; | ||||
|     max-width: 90%; | ||||
|     max-height: 90%; | ||||
|     overflow-y: auto; | ||||
|     box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); | ||||
| } | ||||
|  | ||||
| .modal-header { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     margin-bottom: 15px; | ||||
|     padding-bottom: 10px; | ||||
|     border-bottom: 1px solid rgba(255, 255, 255, 0.1); | ||||
| } | ||||
|  | ||||
| .modal-header h3 { | ||||
|     color: #4ecdc4; | ||||
|     font-size: 18px; | ||||
| } | ||||
|  | ||||
| .close-modal { | ||||
|     width: 30px; | ||||
|     height: 30px; | ||||
|     border: none; | ||||
|     border-radius: 50%; | ||||
|     background: rgba(255, 0, 0, 0.7); | ||||
|     color: #ffffff; | ||||
|     font-size: 18px; | ||||
|     cursor: pointer; | ||||
|     transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| .close-modal:hover { | ||||
|     background: rgba(255, 0, 0, 0.9); | ||||
|     transform: scale(1.1); | ||||
| } | ||||
|  | ||||
| .playlist-songs { | ||||
|     margin-bottom: 20px; | ||||
|     max-height: 200px; | ||||
|     overflow-y: auto; | ||||
| } | ||||
|  | ||||
| .playlist-song { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     padding: 8px; | ||||
|     margin-bottom: 5px; | ||||
|     background: rgba(0, 0, 0, 0.2); | ||||
|     border-radius: 5px; | ||||
| } | ||||
|  | ||||
| .remove-song { | ||||
|     width: 24px; | ||||
|     height: 24px; | ||||
|     border: none; | ||||
|     border-radius: 50%; | ||||
|     background: rgba(255, 0, 0, 0.7); | ||||
|     color: #ffffff; | ||||
|     cursor: pointer; | ||||
| } | ||||
|  | ||||
| .add-song-form { | ||||
|     padding: 15px; | ||||
|     background: rgba(0, 0, 0, 0.2); | ||||
|     border-radius: 10px; | ||||
| } | ||||
|  | ||||
| .add-song-form h4 { | ||||
|     margin-bottom: 10px; | ||||
|     color: #4ecdc4; | ||||
| } | ||||
|  | ||||
| .input-group { | ||||
|     margin-bottom: 10px; | ||||
| } | ||||
|  | ||||
| .input-group input { | ||||
|     width: 100%; | ||||
|     padding: 8px 12px; | ||||
|     border: none; | ||||
|     border-radius: 5px; | ||||
|     background: rgba(0, 0, 0, 0.3); | ||||
|     color: #ffffff; | ||||
|     outline: none; | ||||
| } | ||||
|  | ||||
| #add-song-btn { | ||||
|     padding: 8px 15px; | ||||
|     border: none; | ||||
|     border-radius: 5px; | ||||
|     background: linear-gradient(145deg, #4ecdc4, #45b7d1); | ||||
|     color: #ffffff; | ||||
|     cursor: pointer; | ||||
|     transition: all 0.3s ease; | ||||
| } | ||||
|  | ||||
| #add-song-btn:hover { | ||||
|     transform: translateY(-2px); | ||||
|     box-shadow: 0 4px 12px rgba(78, 205, 196, 0.4); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Nordi98
						Nordi98