// Variables globales let isScrolling = false; let scrollInterval; let currentSpeed = 1; let currentTheme = 'blue'; let currentTextSize = 'medium'; let currentAlignment = 'center'; let currentFont = 'sans'; let mirroredView = false; // Elementos DOM const elements = { speedSlider: document.getElementById('speed-slider'), speedValue: document.getElementById('speed-value'), scriptTextarea: document.getElementById('script-textarea'), previewText: document.getElementById('preview-text'), previewContainer: document.getElementById('preview-container'), textSizeSelect: document.getElementById('text-size'), scriptTitle: document.getElementById('script-title'), fileInput: document.getElementById('file-input') }; // Inicializar todos los componentes function initializeComponents() { setupEventListeners(); loadSettings(); updatePreview(); setupKeyboardShortcuts(); } // Configurar escuchadores de eventos function setupEventListeners() { // Control de velocidad elements.speedSlider.addEventListener('input', handleSpeedChange); // Cambios en el área de texto elements.scriptTextarea.addEventListener('input', updatePreview); // Cambios en tamaño de texto elements.textSizeSelect.addEventListener('change', handleTextSizeChange); // Selección de tema document.querySelectorAll('.theme-btn').forEach(button => { button.addEventListener('click', () => handleThemeChange(button.dataset.theme)); }); // Alineación de texto document.getElementById('align-left').addEventListener('click', () => handleAlignmentChange('left')); document.getElementById('align-center').addEventListener('click', () => handleAlignmentChange('center')); document.getElementById('align-right').addEventListener('click', () => handleAlignmentChange('right')); // Estilo de fuente document.getElementById('font-sans').addEventListener('click', () => handleFontChange('sans')); document.getElementById('font-serif').addEventListener('click', () => handleFontChange('serif')); // Botones de formato document.getElementById('format-bold').addEventListener('click', () => toggleFormatting('bold')); document.getElementById('format-italic').addEventListener('click', () => toggleFormatting('italic')); document.getElementById('format-underline').addEventListener('click', () => toggleFormatting('underline')); // Botones de control document.getElementById('start-scroll').addEventListener('click', toggleScrolling); document.getElementById('save-script').addEventListener('click', saveScript); document.getElementById('load-script').addEventListener('click', loadScript); document.getElementById('export-script').addEventListener('click', exportScript); document.getElementById('import-script').addEventListener('click', () => elements.fileInput.click()); document.getElementById('clear-script').addEventListener('click', clearScript); document.getElementById('toggle-preview').addEventListener('click', togglePreviewMode); document.getElementById('mirror-preview').addEventListener('click', toggleMirrorView); // Entrada de archivo elements.fileInput.addEventListener('change', importScriptFromFile); // Eventos de ventana window.addEventListener('beforeunload', saveSettings); } // Manejar cambio de velocidad function handleSpeedChange() { currentSpeed = parseFloat(elements.speedSlider.value); elements.speedValue.textContent = `${currentSpeed.toFixed(1)}x`; if (isScrolling) { clearInterval(scrollInterval); startScrolling(); } } // Manejar cambio de tamaño de texto function handleTextSizeChange() { currentTextSize = elements.textSizeSelect.value; updatePreview(); } // Manejar cambio de tema function handleThemeChange(theme) { currentTheme = theme; // Actualizar botón activo document.querySelectorAll('.theme-btn').forEach(btn => { btn.classList.remove('active'); }); document.querySelector(`.theme-btn[data-theme="${theme}"]`).classList.add('active'); // Aplicar tema a la vista previa const themeColors = { blue: 'from-blue-500 to-blue-700', green: 'from-green-500 to-green-700', purple: 'from-purple-500 to-purple-700', red: 'from-red-500 to-red-700', yellow: 'from-yellow-500 to-yellow-700', pink: 'from-pink-500 to-pink-700' }; const gradientClass = themeColors[theme]; document.querySelector('.bg-gradient-to-r').className = `p-6 bg-gradient-to-r ${gradientClass} relative`; updatePreview(); } // Manejar cambio de alineación function handleAlignmentChange(alignment) { currentAlignment = alignment; // Actualizar botón activo document.querySelectorAll('#align-left, #align-center, #align-right').forEach(btn => { btn.classList.remove('active'); }); document.getElementById(`align-${alignment}`).classList.add('active'); updatePreview(); } // Manejar cambio de fuente function handleFontChange(font) { currentFont = font; // Actualizar botón activo document.getElementById('font-sans').classList.toggle('active', font === 'sans'); document.getElementById('font-serif').classList.toggle('active', font === 'serif'); updatePreview(); } // Alternar formato de texto function toggleFormatting(format) { const button = document.getElementById(`format-${format}`); button.classList.toggle('active'); // En una implementación real, esto aplicaría formato al texto seleccionado showToast(`Alternado formato ${format}`); } // Actualizar vista previa function updatePreview() { const text = elements.scriptTextarea.value || "Su script aparecerá aquí..."; elements.previewText.textContent = text; // Aplicar tamaño de texto const sizeClasses = { small: 'text-sm', medium: 'text-base', large: 'text-lg', 'x-large': 'text-xl' }; elements.previewText.className = sizeClasses[currentTextSize] || 'text-base'; // Aplicar alineación elements.previewText.classList.remove('text-left', 'text-center', 'text-right'); elements.previewText.classList.add(`text-${currentAlignment}`); // Aplicar fuente elements.previewText.classList.toggle('font-serif', currentFont === 'serif'); // Aplicar clases de formato elements.previewText.classList.toggle('bold', document.getElementById('format-bold').classList.contains('active')); elements.previewText.classList.toggle('italic', document.getElementById('format-italic').classList.contains('active')); elements.previewText.classList.toggle('underline', document.getElementById('format-underline').classList.contains('active')); } // Alternar desplazamiento function toggleScrolling() { const button = document.getElementById('start-scroll'); if (isScrolling) { stopScrolling(); button.innerHTML = ' Iniciar Desplazamiento'; feather.replace(); } else { startScrolling(); button.innerHTML = ' Pausar Desplazamiento'; feather.replace(); } } // Iniciar animación de desplazamiento function startScrolling() { isScrolling = true; // Limpiar cualquier intervalo existente if (scrollInterval) { clearInterval(scrollInterval); } // Calcular duración basada en velocidad (en segundos) const baseDuration = 30; // Duración base para velocidad 1x const duration = (baseDuration / currentSpeed) * 1000; // Convertir a milisegundos // Reiniciar animación elements.previewText.style.animation = 'none'; void elements.previewText.offsetWidth; // Activar reflow // Aplicar animación de desplazamiento elements.previewText.style.animation = `scroll ${duration}ms linear infinite`; // Agregar clase de desplazamiento para estilizar elements.previewContainer.classList.add('scrolling'); } // Detener animación de desplazamiento function stopScrolling() { isScrolling = false; clearInterval(scrollInterval); elements.previewText.style.animation = 'none'; elements.previewContainer.classList.remove('scrolling'); } // Guardar script en localStorage function saveScript() { const scriptData = { title: elements.scriptTitle.value, content: elements.scriptTextarea.value, speed: currentSpeed, theme: currentTheme, textSize: currentTextSize, alignment: currentAlignment, font: currentFont }; localStorage.setItem('teleprompterScript', JSON.stringify(scriptData)); showToast('¡Script guardado exitosamente!'); } // Cargar script desde localStorage function loadScript() { const savedData = localStorage.getItem('teleprompterScript'); if (savedData) { const scriptData = JSON.parse(savedData); elements.scriptTitle.value = scriptData.title || ''; elements.scriptTextarea.value = scriptData.content || ''; elements.speedSlider.value = scriptData.speed || 1; currentSpeed = scriptData.speed || 1; elements.speedValue.textContent = `${currentSpeed.toFixed(1)}x`; handleThemeChange(scriptData.theme || 'blue'); elements.textSizeSelect.value = scriptData.textSize || 'medium'; currentTextSize = scriptData.textSize || 'medium'; handleAlignmentChange(scriptData.alignment || 'center'); handleFontChange(scriptData.font || 'sans'); updatePreview(); showToast('¡Script cargado exitosamente!'); } else { showToast('No se encontró script guardado.'); } } // Exportar script como archivo function exportScript() { const content = elements.scriptTextarea.value; const title = elements.scriptTitle.value || 'teleprompter-script'; const blob = new Blob([content], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${title}.txt`; document.body.appendChild(a); a.click(); setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 100); showToast('¡Script exportado exitosamente!'); } // Importar script desde archivo function importScriptFromFile(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { elements.scriptTextarea.value = e.target.result; elements.scriptTitle.value = file.name.replace(/\.[^/.]+$/, ""); // Eliminar extensión updatePreview(); showToast('¡Script importado exitosamente!'); }; reader.readAsText(file); // Reiniciar entrada de archivo elements.fileInput.value = ''; } // Limpiar script function clearScript() { if (confirm('¿Está seguro de que desea limpiar el script actual?')) { elements.scriptTextarea.value = ''; elements.scriptTitle.value = ''; updatePreview(); showToast('Script limpiado.'); } } // Alternar modo de vista previa function togglePreviewMode() { elements.previewContainer.classList.toggle('bg-black'); elements.previewContainer.classList.toggle('bg-gray-900'); showToast('Modo de vista previa alternado.'); } // Alternar vista espejo function toggleMirrorView() { mirroredView = !mirroredView; elements.previewContainer.classList.toggle('mirror', mirroredView); showToast(mirroredView ? 'Vista espejo habilitada.' : 'Vista espejo deshabilitada.'); } // Configurar atajos de teclado function setupKeyboardShortcuts() { document.addEventListener('keydown', function(e) { // Solo activar atajos cuando no esté en campos de entrada if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; // Barra espaciadora para alternar desplazamiento if (e.code === 'Space') { e.preventDefault(); toggleScrolling(); } // Ctrl+S para guardar if (e.ctrlKey && e.code === 'KeyS') { e.preventDefault(); saveScript(); } // Ctrl+O para cargar if (e.ctrlKey && e.code === 'KeyO') { e.preventDefault(); loadScript(); } // Ctrl+E para exportar if (e.ctrlKey && e.code === 'KeyE') { e.preventDefault(); exportScript(); } // Flechas Arriba/Abajo para ajustar velocidad if (e.code === 'ArrowUp') { e.preventDefault(); const newValue = Math.min(5, parseFloat(elements.speedSlider.value) + 0.1); elements.speedSlider.value = newValue.toFixed(1); handleSpeedChange(); } if (e.code === 'ArrowDown') { e.preventDefault(); const newValue = Math.max(0.1, parseFloat(elements.speedSlider.value) - 0.1); elements.speedSlider.value = newValue.toFixed(1); handleSpeedChange(); } }); } // Guardar configuraciones en localStorage function saveSettings() { const settings = { speed: currentSpeed, theme: currentTheme, textSize: currentTextSize, alignment: currentAlignment, font: currentFont, mirroredView: mirroredView }; localStorage.setItem('teleprompterSettings', JSON.stringify(settings)); } // Cargar configuraciones desde localStorage function loadSettings() { const savedSettings = localStorage.getItem('teleprompterSettings'); if (savedSettings) { const settings = JSON.parse(savedSettings); currentSpeed = settings.speed || 1; elements.speedSlider.value = currentSpeed; elements.speedValue.textContent = `${currentSpeed.toFixed(1)}x`; handleThemeChange(settings.theme || 'blue'); elements.textSizeSelect.value = settings.textSize || 'medium'; currentTextSize = settings.textSize || 'medium'; handleAlignmentChange(settings.alignment || 'center'); handleFontChange(settings.font || 'sans'); if (settings.mirroredView) { mirroredView = true; elements.previewContainer.classList.add('mirror'); } } } // Mostrar notificación toast function showToast(message) { const toast = document.createElement('div'); toast.className = 'toast show'; toast.textContent = message; document.body.appendChild(toast); setTimeout(() => { toast.classList.remove('show'); setTimeout(() => { document.body.removeChild(toast); }, 300); }, 3000); } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', initializeComponents);