class PlaybackControls extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.isPlaying = false; } connectedCallback() { this.render(); this.setupEventListeners(); } static get observedAttributes() { return ['duration', 'current-tick']; } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { this.render(); } } render() { const duration = parseInt(this.getAttribute('duration') || '0'); const currentTick = parseInt(this.getAttribute('current-tick') || '0'); const progress = duration > 0 ? (currentTick / duration) * 100 : 0; this.shadowRoot.innerHTML = `
${this.formatTime(currentTick)} / ${this.formatTime(duration)}
`; // Feather icons need to be replaced after rendering if (window.feather) { window.feather.replace(); } } setupEventListeners() { this.shadowRoot.querySelector('.play-pause').addEventListener('click', () => { this.togglePlayback(); }); this.shadowRoot.querySelector('.progress-bar').addEventListener('click', (e) => { const rect = e.target.getBoundingClientRect(); const percent = (e.clientX - rect.left) / rect.width; const duration = parseInt(this.getAttribute('duration') || '0'); const seekTick = Math.floor(percent * duration); this.setAttribute('current-tick', seekTick.toString()); window.playbackControls.seek(seekTick); }); this.shadowRoot.querySelector('.speed-control').addEventListener('click', () => { // Speed control logic would go here }); } togglePlayback() { this.isPlaying = !this.isPlaying; this.render(); if (this.isPlaying) { window.playbackControls.play(); } else { window.playbackControls.pause(); } } formatTime(ticks) { if (!ticks) return '0:00'; const seconds = Math.floor(ticks / 30); // Assuming 30 ticks per second const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; } } customElements.define('custom-playback-controls', PlaybackControls);