Prenatal Yoga Routine Generator

Prenatal Yoga Routine Generator

Add Poses to Your Routine

seconds

Your Custom Routine

Drag and drop to reorder poses.

  • Your routine is empty. Add poses to get started.

${pose.name}

${pose.duration} seconds

`; routineList.appendChild(li); }); } // --- DRAG & DROP LOGIC --- function getDragAfterElement(container, y) { const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]; return draggableElements.reduce((closest, child) => { const box = child.getBoundingClientRect(); const offset = y - box.top - box.height / 2; if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY }).element; } function updateRoutineOrder() { const newOrderIds = [...routineList.querySelectorAll('.draggable')].map(el => parseInt(el.dataset.id)); routine.sort((a, b) => newOrderIds.indexOf(a.id) - newOrderIds.indexOf(b.id)); } // --- PLAYER LOGIC --- function setupPlayer() { playerState.currentPoseIndex = 0; playerState.isRunning = false; clearInterval(playerState.interval); if (routine.length > 0) { playerState.timeRemaining = routine[0].duration; updatePlayerDisplay(); startRoutineBtn.disabled = false; } else { playerPoseName.textContent = 'Build a routine first.'; playerTimer.textContent = '00:00'; playerNextPose.textContent = 'Next: -'; startRoutineBtn.disabled = true; } } function updatePlayerDisplay() { const currentPose = routine[playerState.currentPoseIndex]; const nextPose = routine[playerState.currentPoseIndex + 1]; playerPoseName.textContent = currentPose ? currentPose.name : "Routine Complete!"; const minutes = Math.floor(playerState.timeRemaining / 60).toString().padStart(2, '0'); const seconds = (playerState.timeRemaining % 60).toString().padStart(2, '0'); playerTimer.textContent = `${minutes}:${seconds}`; playerNextPose.textContent = nextPose ? `Next: ${nextPose.name}` : "Next: -"; } function handleStartStopRoutine() { initializeAudio(); if (playerState.isRunning) { // Pause clearInterval(playerState.interval); playerState.isRunning = false; startRoutineBtn.textContent = "Resume"; } else { // Start/Resume if (routine.length === 0) return; playerState.isRunning = true; startRoutineBtn.textContent = "Pause"; playerState.interval = setInterval(tick, 1000); } } function tick() { playerState.timeRemaining--; if (playerState.timeRemaining < 0) { if (synth) synth.triggerAttackRelease("C5", "0.5s"); playerState.currentPoseIndex++; if (playerState.currentPoseIndex >= routine.length) { clearInterval(playerState.interval); playerState.isRunning = false; startRoutineBtn.textContent = "Start Routine"; playerPoseName.textContent = "Routine Complete!"; return; } playerState.timeRemaining = routine[playerState.currentPoseIndex].duration; } updatePlayerDisplay(); } function resetPlayer() { setupPlayer(); } // --- TAB NAVIGATION & SUMMARY --- window.changeTab = function(tabNumber) { if (tabNumber === currentTab) return; if (tabNumber === 2) { renderSummary(); setupPlayer(); } document.getElementById(`tab-panel-${currentTab}`).classList.add('hidden'); document.getElementById(`tab-btn-${currentTab}`).classList.remove('active'); document.getElementById(`tab-btn-${currentTab}`).classList.add('inactive'); document.getElementById(`tab-panel-${tabNumber}`).classList.remove('hidden'); document.getElementById(`tab-btn-${tabNumber}`).classList.add('active'); document.getElementById(`tab-btn-${tabNumber}`).classList.remove('inactive'); currentTab = tabNumber; updateNavButtons(); }; window.navigateTabs = function(direction) { const newTab = direction === 'next' ? currentTab + 1 : currentTab - 1; if (newTab >= 1 && newTab <= 2) { changeTab(newTab); } }; function updateNavButtons() { prevBtn.disabled = (currentTab === 1); nextBtn.disabled = (currentTab === 2); } function renderSummary() { summaryTableBody.innerHTML = ''; if (routine.length === 0) { summaryTableBody.innerHTML = 'Your routine is empty.'; totalTimeDisplay.textContent = 'Total time: 0 minutes'; return; } let totalSeconds = 0; routine.forEach(pose => { totalSeconds += pose.duration; const row = summaryTableBody.insertRow(); row.innerHTML = ` ${pose.name} ${pose.duration}s `; }); const totalMinutes = Math.ceil(totalSeconds / 60); totalTimeDisplay.textContent = `Total time: ~${totalMinutes} minutes`; } // --- PDF GENERATION --- function generatePdf() { const contentToPrint = document.getElementById('pdf-content-container'); const pdfButtonWrapper = document.getElementById('pdf-button-wrapper'); if (routine.length === 0) { alert("Routine is empty. There is nothing to download."); return; } if (pdfButtonWrapper) pdfButtonWrapper.style.display = 'none'; html2canvas(contentToPrint, { scale: 2, useCORS: true, logging: false }) .then(canvas => { if (pdfButtonWrapper) pdfButtonWrapper.style.display = 'block'; const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const canvasAspectRatio = canvas.width / canvas.height; const imgWidth = pdfWidth - 80; const imgHeight = imgWidth / canvasAspectRatio; pdf.addImage(imgData, 'PNG', 40, 40, imgWidth, imgHeight); pdf.save('My-Prenatal-Yoga-Routine.pdf'); }).catch(err => { if (pdfButtonWrapper) pdfButtonWrapper.style.display = 'block'; console.error("Error generating PDF:", err); alert("Sorry, an error occurred while creating the PDF."); }); } // --- START THE APP --- initialize(); });
Scroll to Top