class JukeboxComponent extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); // Use global singleton 🎵 this.api = window.netNaviAPI; this.playlist = []; this.currentTrackIndex = 0; this.bgMusic = null; this.isMuted = false; this.hasInteracted = false; this.theme = null; this.isPlaylistMode = false; } connectedCallback() { this.render(); this.setupAPIListeners(); } disconnectedCallback() { // Cleanup listeners when component is removed if (this.unsubscribeWorld) this.unsubscribeWorld(); } setupAPIListeners() { // Listen for world loaded events to auto-load music 🎧 this.unsubscribeWorld = this.api.on('world:loaded', (data) => { console.log('🎵 Jukebox detected world loaded:', data.theme.name); if (data.theme?.music) { this.loadMusic(data.theme.music, data.theme); } }); } render() { this.shadowRoot.innerHTML = ` `; this.shadowRoot.getElementById('simple-mute-btn').addEventListener('click', () => this.toggleMute()); this.shadowRoot.getElementById('mute-btn').addEventListener('click', () => this.toggleMute()); this.shadowRoot.getElementById('prev-btn').addEventListener('click', () => this.previousTrack()); this.shadowRoot.getElementById('next-btn').addEventListener('click', () => this.nextTrack()); } loadMusic(musicConfig, theme) { if (!musicConfig) return; this.theme = theme; this.isPlaylistMode = Array.isArray(musicConfig) && musicConfig.length > 1; this.playlist = Array.isArray(musicConfig) ? musicConfig : [musicConfig]; this.currentTrackIndex = 0; this.applyThemeColors(); if (this.isPlaylistMode) { this.shadowRoot.getElementById('simple-mute-btn').classList.add('hidden'); this.shadowRoot.getElementById('playlist-controls').classList.remove('hidden'); } else { this.shadowRoot.getElementById('simple-mute-btn').classList.remove('hidden'); this.shadowRoot.getElementById('playlist-controls').classList.add('hidden'); } this.loadTrack(this.currentTrackIndex); } loadTrack(index) { if (this.bgMusic) { this.bgMusic.pause(); this.bgMusic = null; } if (index >= 0 && index < this.playlist.length) { this.bgMusic = new Audio(this.playlist[index]); this.bgMusic.volume = 0.5; if (this.isPlaylistMode) { this.bgMusic.addEventListener('ended', () => { this.currentTrackIndex = (this.currentTrackIndex + 1) % this.playlist.length; this.loadTrack(this.currentTrackIndex); }); this.updateTrackDisplay(); } else { this.bgMusic.loop = true; } this.setupAutoplayHandler(); if (this.hasInteracted && !this.isMuted) { this.bgMusic.play(); } } } updateTrackDisplay() { const trackName = this.shadowRoot.getElementById('track-name'); const fileName = this.playlist[this.currentTrackIndex].split('/').pop(); const trackNum = String(this.currentTrackIndex + 1).padStart(2, '0'); trackName.textContent = `[${trackNum}] ${fileName}`; } applyThemeColors() { if (!this.theme) return; const root = this.shadowRoot.host.style; Object.entries(this.theme.colors).forEach(([key, value]) => { const cssVar = '--' + key.replace(/([A-Z])/g, '-$1').toLowerCase(); root.setProperty(cssVar, value); }); } setupAutoplayHandler() { const startMusic = () => { if (!this.hasInteracted && !this.isMuted && this.bgMusic) { this.hasInteracted = true; this.bgMusic.play(); } }; const interactionEvents = ['click', 'keydown', 'touchstart']; interactionEvents.forEach(event => { document.addEventListener(event, startMusic, { once: true }); }); } previousTrack() { if (!this.isPlaylistMode) return; this.currentTrackIndex = (this.currentTrackIndex - 1 + this.playlist.length) % this.playlist.length; this.loadTrack(this.currentTrackIndex); } nextTrack() { if (!this.isPlaylistMode) return; this.currentTrackIndex = (this.currentTrackIndex + 1) % this.playlist.length; this.loadTrack(this.currentTrackIndex); } toggleMute() { this.isMuted = !this.isMuted; const simpleMuteBtn = this.shadowRoot.getElementById('simple-mute-btn'); const muteBtn = this.shadowRoot.getElementById('mute-btn'); const mutedSVG = ''; const unmutedSVG = ''; if (this.bgMusic) { if (this.isMuted) { this.bgMusic.pause(); simpleMuteBtn.innerHTML = mutedSVG; muteBtn.innerHTML = mutedSVG; } else { if (!this.hasInteracted) this.hasInteracted = true; this.bgMusic.play(); simpleMuteBtn.innerHTML = unmutedSVG; muteBtn.innerHTML = unmutedSVG; } } } } customElements.define('jukebox-component', JukeboxComponent);