class SelfTalkRecorder extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = `

Record Your Self-Talk

Speak freely for 1 minute about your thoughts, feelings, or affirmations.

Video preview will appear here

01:00
`; this.mediaRecorder = null; this.recordedChunks = []; this.countdownInterval = null; this.timeLeft = 60; this.setupEventListeners(); feather.replace(); } setupEventListeners() { const recordBtn = this.shadowRoot.getElementById('recordBtn'); const stopBtn = this.shadowRoot.getElementById('stopBtn'); const videoPreview = this.shadowRoot.getElementById('videoPreview'); const videoPlaceholder = this.shadowRoot.getElementById('videoPlaceholder'); const timer = this.shadowRoot.getElementById('timer'); recordBtn.addEventListener('click', async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); videoPreview.srcObject = stream; videoPlaceholder.style.display = 'none'; videoPreview.style.display = 'block'; this.mediaRecorder = new MediaRecorder(stream); this.recordedChunks = []; this.mediaRecorder.ondataavailable = event => { if (event.data.size > 0) { this.recordedChunks.push(event.data); } }; this.mediaRecorder.onstop = () => { const blob = new Blob(this.recordedChunks, { type: 'video/webm' }); this.saveRecording(blob); }; this.mediaRecorder.start(100); recordBtn.classList.add('recording'); recordBtn.disabled = true; stopBtn.disabled = false; // Start countdown this.timeLeft = 60; this.countdownInterval = setInterval(() => { this.timeLeft--; const minutes = Math.floor(this.timeLeft / 60); const seconds = this.timeLeft % 60; timer.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; if (this.timeLeft <= 0) { this.stopRecording(); } }, 1000); } catch (error) { console.error('Error accessing media devices:', error); alert('Could not access camera/microphone. Please check permissions.'); } }); stopBtn.addEventListener('click', () => this.stopRecording()); } stopRecording() { if (this.countdownInterval) { clearInterval(this.countdownInterval); this.countdownInterval = null; } if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') { this.mediaRecorder.stop(); const videoPreview = this.shadowRoot.getElementById('videoPreview'); const stream = videoPreview.srcObject; stream.getTracks().forEach(track => track.stop()); this.shadowRoot.getElementById('recordBtn').classList.remove('recording'); this.shadowRoot.getElementById('recordBtn').disabled = false; this.shadowRoot.getElementById('stopBtn').disabled = true; this.shadowRoot.getElementById('timer').textContent = '01:00'; } } async saveRecording(blob) { // In a real app, this would upload to S3/CDN via your backend console.log('Recording saved:', blob); alert('Recording saved successfully! It will appear in your journal entries.'); // Simulate adding to entries list const entriesContainer = document.getElementById('entriesContainer'); if (entriesContainer) { const newEntry = { id: Date.now().toString(), date: new Date().toISOString().split('T')[0], duration: '1:00', thumbnail: 'http://static.photos/people/320x240/' + Math.floor(Math.random() * 10), mood: 'New' }; entriesContainer.insertAdjacentHTML('afterbegin', `
Entry thumbnail
${newEntry.duration}

${newEntry.date}

${newEntry.mood}

`); feather.replace(); } } } customElements.define('self-talk-recorder', SelfTalkRecorder);