Cargando...

Configuración del Entorno HTML

Html-Setup es la base fundamental de cualquier sitio web, como construir los cimientos de una casa antes de levantar las paredes. Es el proceso de crear la estructura inicial de un documento HTML que le dice al navegador cómo mostrar tu contenido. Html-Setup incluye la declaración DOCTYPE, la etiqueta html, la sección head y la sección body. Este paso es esencial para cualquier proyecto web - ya sea creando un sitio web de portafolio, desarrollando un blog personal, construyendo una tienda e-commerce, creando un sitio de noticias o diseñando una plataforma social. Sin un Html-Setup adecuado, tu sitio web sería como una biblioteca sin organización, donde los libros están esparcidos sin orden alguno. En este tutorial aprenderás cómo crear una estructura HTML limpia y profesional, usar elementos básicos correctamente y evitar errores comunes. Esta base te permitirá agregar posteriormente estilización CSS y funcionalidades JavaScript. Dominar Html-Setup es como aprender a escribir una carta correctamente - necesitas conocer el formato estándar antes de personalizar el contenido.

Ejemplo básico de configuración HTML

html
HTML Code
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mi Sitio Web</title> <!-- Page title for browser tab -->
</head>
<body>
<h1>Bienvenido a Mi Sitio Web</h1> <!-- Main heading -->
<p>¡Esta es mi primera página web!</p> <!-- Paragraph text -->
</body>
</html>

El código anterior muestra la estructura básica de un documento HTML completo. La declaración <!DOCTYPE html> le dice al navegador que este es un documento HTML5. La etiqueta envuelve todo el documento y el atributo lang especifica el idioma español. La sección contiene metadatos que no son visibles en la página pero son importantes para el navegador. La etiqueta asegura la codificación adecuada de caracteres para que las tildes y caracteres especiales se muestren correctamente. La etiqueta define el texto que aparece en la pestaña del navegador. La sección <body> contiene el contenido real que ven los usuarios. La etiqueta <h1> se usa para el título principal y <p> para texto de párrafo. Esta estructura es la fundación de toda página HTML, ya sea escribiendo una entrada simple de blog o construyendo un sitio de e-commerce complejo. Sin esta configuración adecuada, tu contenido no se renderizará correctamente en los navegadores. Cada elemento tiene su función específica, como habitaciones diferentes en una casa bien organizada.</p> </div> <!-- Enhanced Code Block --> <div class="code-editor-container"> <div class="code-editor-header"> <h3 class="code-title">Ejemplo práctico de configuración HTML</h3> <span class="code-language-badge html">html</span> </div> <div class="code-display"> <div class="code-display-header"> <span>HTML Code</span> <div class="flex flex-col sm:flex-row gap-2"> <button type="button" class="copy-button" onclick="copyStaticCode('code-42', this)"> 📋 Copiar </button> <button type="button" class="copy-button bg-green-600 hover:bg-green-700 text-white" onclick="openCodeRunner('html', 'Ejemplo práctico de configuración HTML', 42)"> 🚀 Pruébalo en Vivo </button> </div> </div> <div class="code-block"> <pre><code id="code-42" class="language-html"><!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="Portafolio de Carlos Mendoza - Desarrollador Web"> <title>Carlos Mendoza | Portafolio - Desarrollador Web</title> </head> <body> <header> <h1>Carlos Mendoza</h1> <nav> <a href="#acerca">Acerca de</a> <a href="#proyectos">Proyectos</a> <a href="#contacto">Contacto</a> </nav> </header> <main> <section id="acerca"> <h2>Acerca de Mí</h2> <p>Soy un desarrollador web apasionado con 3 años de experiencia.</p> </section> </main> </body> </html></code></pre> </div> </div> </div> <!-- Enhanced Text Block with Smart Links --> <div class="prose prose-lg max-w-none"> <p>Las mejores prácticas incluyen usar HTML semántico - elementos como header, nav, main, section que tienen significado específico. La meta etiqueta viewport es esencial para responsividad móvil. Siempre mantén una estructura de documento adecuada con metadatos en head y contenido en body. Usa elementos semánticos en lugar de div genéricos cuando sea posible. Los errores más comunes incluyen olvidar la declaración DOCTYPE, lo que hace que los navegadores entren en modo quirks. No definir meta charset puede causar problemas de visualización de caracteres especiales. Anidación inadecuada como poner div dentro de p es inválido. Olvidar la etiqueta title perjudica el SEO. Para debugging, usa las herramientas de desarrollador del navegador presionando F12 para inspeccionar la estructura HTML. Utiliza herramientas de validación como W3C Markup Validator. Mantén siempre indentación consistente para legibilidad. Agrega comentarios para secciones complejas. Prueba en diferentes navegadores para asegurar compatibilidad. Organiza tu código lógicamente, como decorar habitaciones de una casa de manera funcional y estéticamente agradable.</p> </div> <!-- Enhanced Reference Table --> <div class="table-responsive"> <div class="bg-white p-6"> <h3 class="text-xl font-semibold mb-4 text-gray-800">📊 Referencia rápida de configuración HTML</h3> <div class="overflow-x-auto"> <table class="w-full table-auto border-collapse"> <thead> <tr class="bg-gradient-to-r from-gray-50 to-gray-100"> <th class="border border-gray-300 px-4 py-3 text-left font-semibold text-gray-700">Elemento</th> <th class="border border-gray-300 px-4 py-3 text-left font-semibold text-gray-700">Descripción</th> <th class="border border-gray-300 px-4 py-3 text-left font-semibold text-gray-700">Ejemplo</th> </tr> </thead> <tbody> <tr class="hover:bg-gray-50 transition-colors"> <td class="border border-gray-300 px-4 py-3 text-gray-600"><!DOCTYPE html></td> <td class="border border-gray-300 px-4 py-3 text-gray-600">Declara documento HTML5</td> <td class="border border-gray-300 px-4 py-3 text-gray-600"><!DOCTYPE html></td> </tr> <tr class="hover:bg-gray-50 transition-colors"> <td class="border border-gray-300 px-4 py-3 text-gray-600"><html lang="es"></td> <td class="border border-gray-300 px-4 py-3 text-gray-600">Elemento raíz con idioma</td> <td class="border border-gray-300 px-4 py-3 text-gray-600"><html lang="es"></td> </tr> <tr class="hover:bg-gray-50 transition-colors"> <td class="border border-gray-300 px-4 py-3 text-gray-600"><meta charset="UTF-8"></td> <td class="border border-gray-300 px-4 py-3 text-gray-600">Codificación de caracteres</td> <td class="border border-gray-300 px-4 py-3 text-gray-600"><meta charset="UTF-8"></td> </tr> <tr class="hover:bg-gray-50 transition-colors"> <td class="border border-gray-300 px-4 py-3 text-gray-600"><title></td> <td class="border border-gray-300 px-4 py-3 text-gray-600">Título de página para pestaña del navegador</td> <td class="border border-gray-300 px-4 py-3 text-gray-600"><title>Mi Sitio Web</title></td> </tr> <tr class="hover:bg-gray-50 transition-colors"> <td class="border border-gray-300 px-4 py-3 text-gray-600"><meta name="viewport"></td> <td class="border border-gray-300 px-4 py-3 text-gray-600">Meta etiqueta para responsividad móvil</td> <td class="border border-gray-300 px-4 py-3 text-gray-600"><meta name="viewport" content="width=device-width, initial-scale=1.0"></td> </tr> <tr class="hover:bg-gray-50 transition-colors"> <td class="border border-gray-300 px-4 py-3 text-gray-600"><meta name="description"></td> <td class="border border-gray-300 px-4 py-3 text-gray-600">Descripción de página para SEO</td> <td class="border border-gray-300 px-4 py-3 text-gray-600"><meta name="description" content="Descripción de la página"></td> </tr> </tbody> </table> </div> </div> </div> <!-- Enhanced Text Block with Smart Links --> <div class="prose prose-lg max-w-none"> <p>En este tutorial has aprendido a crear la estructura adecuada de un documento HTML. Los puntos clave incluyen que toda página HTML debe tener elementos DOCTYPE, html, head y body. Las meta etiquetas son importantes para SEO y accesibilidad. La estructura HTML semántica crea código más limpio y significativo. Esta base te permitirá agregar estilización CSS donde definirás colores, fuentes y diseños. Para interacciones JavaScript, una estructura HTML adecuada también es fundamental. Los próximos temas a estudiar incluyen fundamentos de CSS, diseño responsivo y elementos de formulario. Para practicar, crea estructuras básicas para diferentes tipos de sitios web. Siempre usa herramientas de validación y verifica compatibilidad entre navegadores. Con práctica regular, podrás construir sitios web de calidad profesional. Recuerda que Html-Setup es como organizar una biblioteca - una buena organización inicial facilita encontrar y usar todo más tarde. Continúa practicando y experimentando con diferentes estructuras para solidificar tu conocimiento.</p> </div> </div> <!-- Keywords Section --> <!-- Content Reporting Widget --> <!-- Content Reporting Widget --> <div class="content-report-container" id="report-container" data-content-type-id="10" data-object-id="2"> <div class="report-dropdown" id="report-dropdown"> <button type="button" class="report-button" id="report-button"> <span>👋</span> <span>Report Issue</span> </button> <div class="dropdown-menu" id="dropdown-menu"> <!-- Categories will be loaded dynamically by JavaScript --> </div> </div> </div> <!-- Load Required CSS and JS --> <link rel="stylesheet" href="/static/css/content-reporting.3f7dc51ec48b.css"> <script src="/static/js/content-reporting.37a7bd46d1db.js" defer></script> <!-- Enhanced Quiz Section --> <div class="mb-8"> <h2 class="text-2xl md:text-3xl font-bold mb-6 bg-clip-text"> 🧠 Pon a Prueba tu Conocimiento </h2> <!-- Modern Quiz Container - Direct Display --> <div id="quiz-container" class="quiz-modern-container"> <!-- Hidden CSRF Token --> <input type="hidden" name="csrfmiddlewaretoken" value="mwV3ptxjox84fl1Oe1x7PU13hUhjEXcYwnGjkiImOiAjKLVdUycNXPlIIGguzU3S"> <!-- Quiz Header with Progress --> <div class="quiz-header"> <div class="quiz-progress-wrapper"> <div class="quiz-progress-track"> <div id="quiz-progress-fill" class="quiz-progress-fill"></div> </div> <div class="quiz-progress-info"> <span id="progress-text" class="progress-current">Listo para Empezar</span> <span id="progress-stats" class="progress-stats"></span> </div> </div> <!-- Timer (if applicable) --> <div id="quiz-timer-wrapper" class="quiz-timer-wrapper" style="display: none;"> <div class="timer-icon">⏱️</div> <span id="timer-display" class="timer-display">10:00</span> </div> </div> <!-- Quiz Content Area --> <div class="quiz-content-area"> <!-- Quiz Introduction - Now Always Visible --> <div id="quiz-intro" class="quiz-intro-section"> <div class="quiz-intro-icon"> <div class="icon-circle"> <svg class="brain-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/> </svg> </div> </div> <h3 class="quiz-intro-title">Test Your Html-Setup Knowledge</h3> <p class="quiz-intro-subtitle">Challenge yourself with this interactive quiz and see how well you understand the topic</p> <!-- Quiz Stats Grid --> <div id="quiz-stats-grid" class="quiz-stats-grid"> <div class="quiz-stat-card"> <span class="stat-icon">❓</span> <div class="stat-value">3</div> <div class="stat-label">Preguntas</div> </div> <div class="quiz-stat-card"> <span class="stat-icon">🎯</span> <div class="stat-value">70%</div> <div class="stat-label">Para Aprobar</div> </div> <div class="quiz-stat-card"> <span class="stat-icon">♾️</span> <div class="stat-value">∞</div> <div class="stat-label">Tiempo</div> </div> <div class="quiz-stat-card"> <span class="stat-icon">🔄</span> <div class="stat-value">∞</div> <div class="stat-label">Intentos</div> </div> </div> <!-- Quiz Instructions --> <div class="quiz-instructions"> <h4 class="instructions-title">📝 Instrucciones</h4> <ul class="instructions-list"> <li>Lee cada pregunta cuidadosamente</li> <li>Selecciona la mejor respuesta para cada pregunta</li> <li>Puedes repetir el quiz tantas veces como quieras</li> <li>Tu progreso se mostrará en la parte superior</li> </ul> </div> <button id="start-quiz-btn" class="quiz-start-button" onclick="startQuiz(2)"> <span class="button-content"> <svg class="button-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h1m4 0h1m-6 4h8"/> </svg> Iniciar Quiz </span> <div class="button-ripple"></div> </button> </div> <!-- Quiz Questions Section --> <div id="quiz-questions" class="quiz-questions-section" style="display: none;"> <!-- Question Header --> <div class="question-header"> <div class="question-meta"> <span id="question-number" class="question-counter">Pregunta 1</span> <div class="question-type-badge" id="question-type"> <span>📝</span> </div> </div> </div> <!-- Question Content --> <div id="current-question" class="question-content"> <!-- Question will be loaded here --> </div> <!-- Question Actions --> <div class="question-actions"> <button id="submit-answer" class="submit-answer-btn" onclick="submitAnswer()" disabled> <span class="btn-text">Enviar Respuesta</span> <div class="btn-loader" style="display: none;"> <div class="loader-spinner"></div> </div> </button> </div> </div> <!-- Quiz Results Section --> <div id="quiz-results" class="quiz-results-section" style="display: none;"> <!-- Results will be populated here --> </div> <!-- Loading State --> <div id="quiz-loading" class="quiz-loading-section" style="display: none;"> <div class="loading-animation"> <div class="loading-spinner"></div> <div class="loading-dots"> <span></span> <span></span> <span></span> </div> </div> <p class="loading-text">Cargando tu quiz...</p> </div> </div> <!-- Error Display --> <div id="quiz-error" class="quiz-error-display" style="display: none;"> <div class="error-content"> <div class="error-icon">⚠️</div> <div class="error-message"></div> <button class="error-close" onclick="hideError()">✕</button> </div> </div> </div> <script> let currentQuiz = null; let currentQuestionIndex = 0; let selectedAnswer = null; let quizTimer = null; let timeRemaining = null; let currentQuestionData = null; let quizSessionData = null; // Store quiz session data for answer sheet function getCsrfToken() { let token = null; const quizContainer = document.getElementById('quiz-container'); if (quizContainer) { const tokenInput = quizContainer.querySelector('input[name="csrfmiddlewaretoken"]'); if (tokenInput) { token = tokenInput.value; } } if (!token) { const tokenInput = document.querySelector('input[name="csrfmiddlewaretoken"]'); if (tokenInput) { token = tokenInput.value; } } if (!token) { const cookieMatch = document.cookie.match(/csrftoken=([^;]+)/); if (cookieMatch) { token = cookieMatch[1]; } } return token; } function startQuiz(topicId) { console.log('Starting quiz for topic:', topicId); // Reset quiz session data quizSessionData = { questions: [], answers: {}, correctAnswers: {}, explanations: {}, startTime: new Date().toISOString() }; // Show loading showSection('quiz-loading'); updateProgress(0, 'Inicializando Quiz...', ''); const csrfToken = getCsrfToken(); if (!csrfToken) { console.error('CSRF token not found'); showError('Security token not found. Please refresh the page.'); showSection('quiz-intro'); return; } const formData = new FormData(); formData.append('csrfmiddlewaretoken', csrfToken); const url = `/es/quiz/${topicId}/start/`; fetch(url, { method: 'POST', body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { if (data.success) { currentQuiz = data.quiz; currentQuestionIndex = 0; // Setup timer if quiz has time limit if (currentQuiz.time_limit) { setupTimer(currentQuiz.time_limit); } // Show quiz questions section showSection('quiz-questions'); // Load first question loadQuestion(data.current_question, data.question_number, data.total_questions); } else { console.error('Quiz start failed:', data.error); showError(data.error || 'Failed to start quiz'); showSection('quiz-intro'); } }) .catch(error => { console.error('Fetch error:', error); showError('No se pudo iniciar el quiz. Por favor, inténtalo de nuevo.'); showSection('quiz-intro'); }); } function loadQuestion(question, questionNumber, totalQuestions) { console.log('Loading question:', question); // Store current question data currentQuestionData = question; // Store question in session data quizSessionData.questions[questionNumber - 1] = question; // Update progress const progressPercent = (questionNumber / totalQuestions) * 100; updateProgress(progressPercent, `Pregunta ${questionNumber}`, `${questionNumber} de ${totalQuestions}`); // Update question number const questionNumberEl = document.getElementById('question-number'); if (questionNumberEl) { questionNumberEl.textContent = `Pregunta ${questionNumber}`; } // Update question type badge const questionTypeEl = document.getElementById('question-type'); if (questionTypeEl) { const typeIcons = { 'multiple_choice': '📝', 'true_false': '✅', 'fill_code': '💻' }; questionTypeEl.innerHTML = `<span>${typeIcons[question.type] || '📝'}</span>`; } // Reset selected answer selectedAnswer = null; const submitBtn = document.getElementById('submit-answer'); if (submitBtn) { submitBtn.disabled = true; submitBtn.querySelector('.btn-text').textContent = 'Enviar Respuesta'; } // Generate question HTML let questionHTML = ` <div class="question-text">${escapeHtml(question.text)}</div> `; // Add code template if exists if (question.code_template && question.code_template.trim()) { questionHTML += ` <div class="code-block"> <pre><code>${escapeHtml(question.code_template)}</code></pre> </div> `; } // Add options questionHTML += '<div class="options-container">'; if (question.options && question.options.length > 0) { question.options.forEach((option, index) => { questionHTML += ` <div class="option-item" onclick="selectOption(${option.id}, this)"> <input type="radio" name="quiz-option" value="${option.id}" style="display: none;"> <div class="option-content"> <div class="option-indicator"></div> <div class="option-text">${escapeHtml(option.text)}</div> </div> </div> `; }); } else { questionHTML += '<p class="error-message">No options available for this question.</p>'; } questionHTML += '</div>'; // Insert question content with animation const questionContainer = document.getElementById('current-question'); if (questionContainer) { questionContainer.style.opacity = '0'; questionContainer.innerHTML = questionHTML; // Animate in setTimeout(() => { questionContainer.style.transition = 'opacity 0.3s ease'; questionContainer.style.opacity = '1'; }, 100); } } function selectOption(optionId, element) { console.log('Option selected:', optionId); selectedAnswer = optionId; // Update visual feedback document.querySelectorAll('.option-item').forEach(item => { item.classList.remove('selected'); }); element.classList.add('selected'); // Enable submit button const submitBtn = document.getElementById('submit-answer'); if (submitBtn) { submitBtn.disabled = false; } } function submitAnswer() { if (!selectedAnswer || !currentQuestionData) { console.log('No answer selected or no question data'); return; } console.log('Submitting answer:', selectedAnswer, 'for question:', currentQuestionData.id); // Store user answer in session data quizSessionData.answers[currentQuestionData.id] = { selectedOptionId: selectedAnswer, selectedOptionText: getSelectedOptionText(selectedAnswer) }; const submitBtn = document.getElementById('submit-answer'); if (!submitBtn) return; // Show loading state submitBtn.disabled = true; submitBtn.querySelector('.btn-text').style.opacity = '0'; submitBtn.querySelector('.btn-loader').style.display = 'block'; const csrfToken = getCsrfToken(); if (!csrfToken) { console.error('CSRF token not found for submit'); showError('Security token not found. Please refresh the page.'); resetSubmitButton(submitBtn); return; } const formData = new FormData(); formData.append('question_id', currentQuestionData.id); formData.append('selected_option', selectedAnswer); formData.append('csrfmiddlewaretoken', csrfToken); const url = `/es/quiz/${currentQuiz.id}/submit/`; fetch(url, { method: 'POST', body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { if (data.success) { if (data.completed) { // Quiz completed - load results loadQuizResults(data.redirect_url); } else { // Load next question setTimeout(() => { loadQuestion(data.current_question, data.question_number, data.total_questions); resetSubmitButton(submitBtn); }, 500); } } else { console.error('Submit failed:', data.error); showError(data.error || 'Failed to submit answer'); resetSubmitButton(submitBtn); } }) .catch(error => { console.error('Submit fetch error:', error); showError('No se pudo enviar la respuesta. Por favor, inténtalo de nuevo.'); resetSubmitButton(submitBtn); }); } function getSelectedOptionText(optionId) { if (!currentQuestionData || !currentQuestionData.options) return ''; const option = currentQuestionData.options.find(opt => opt.id == optionId); return option ? option.text : ''; } function loadQuizResults(resultUrl) { console.log('Loading results from:', resultUrl); // Show loading while fetching results showSection('quiz-loading'); updateProgress(100, 'Calculando resultados...', 'Por favor espera'); fetch(resultUrl, { headers: { 'HX-Request': 'true' } }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.text(); }) .then(html => { // Parse the results and extract detailed information const tempDiv = document.createElement('div'); tempDiv.innerHTML = html; // Extract score data from the response const scoreElement = tempDiv.querySelector('.score-percentage') || tempDiv.querySelector('[data-score]'); let scoreValue = 0; if (scoreElement) { const scoreText = scoreElement.textContent || scoreElement.getAttribute('data-score') || '0'; scoreValue = parseInt(scoreText.replace('%', '')) || 0; } const correctElement = tempDiv.querySelector('.correct-answers') || tempDiv.querySelector('[data-correct]'); let correctAnswers = 0; if (correctElement) { const correctText = correctElement.textContent || correctElement.getAttribute('data-correct') || '0'; correctAnswers = parseInt(correctText) || 0; } const totalElement = tempDiv.querySelector('.total-questions') || tempDiv.querySelector('[data-total]'); let totalQuestions = currentQuiz.total_questions || 0; if (totalElement) { const totalText = totalElement.textContent || totalElement.getAttribute('data-total') || '0'; totalQuestions = parseInt(totalText) || totalQuestions; } // Extract detailed question results extractQuestionResults(tempDiv); // Save quiz result for authenticated users if (window.siteConfig && window.siteConfig.isAuthenticated && window.saveQuizResult) { const quizData = { quiz_id: currentQuiz.id, score: correctAnswers, total_questions: totalQuestions, correct_answers: correctAnswers, time_spent: calculateQuizTime(), answers: quizSessionData, passing_score: currentQuiz.passing_score || 70 }; window.saveQuizResult(quizData).catch(error => { console.error('Failed to save quiz result:', error); }); } displayResults(scoreValue, correctAnswers, totalQuestions); // Stop timer if running if (quizTimer) { clearInterval(quizTimer); hideTimer(); } }) .catch(error => { console.error('Results fetch error:', error); showError('No se pudieron cargar los resultados. Por favor, actualiza la página.'); showSection('quiz-questions'); }); } function calculateQuizTime() { // Calculate time spent from quiz session start if (quizSessionData && quizSessionData.startTime) { const startTime = new Date(quizSessionData.startTime); const endTime = new Date(); return Math.floor((endTime - startTime) / 1000); // Return seconds } return 0; } function extractQuestionResults(resultContainer) { // Extract detailed results from the Django-generated HTML const questionContainers = resultContainer.querySelectorAll('.border-b, .border'); questionContainers.forEach((container, index) => { try { // Extract question text const questionTextEl = container.querySelector('p.text-gray-700, .text-gray-700'); const questionText = questionTextEl ? questionTextEl.textContent.trim() : `Question ${index + 1}`; // Extract correct/incorrect status const correctSpan = container.querySelector('.bg-green-100'); const incorrectSpan = container.querySelector('.bg-red-100'); const isCorrect = correctSpan !== null; // Extract user's answer let userAnswer = ''; const userAnswerSpans = container.querySelectorAll('.text-red-600, .text-green-600'); for (let span of userAnswerSpans) { const text = span.textContent; if (text.includes('Your answer:')) { userAnswer = text.replace('Your answer:', '').trim(); break; } } // Extract correct answer let correctAnswer = ''; const greenSpans = container.querySelectorAll('.text-green-600'); for (let span of greenSpans) { const text = span.textContent.trim(); const parentText = span.parentElement ? span.parentElement.textContent : ''; // Check if this span contains "Correct answer:" in its parent context if (parentText.includes('Correct answer:') && !text.includes('Your answer:')) { // Extract only the answer part after "Correct answer:" const parts = parentText.split('Correct answer:'); if (parts.length > 1) { correctAnswer = parts[1].split('Explanation:')[0].trim(); break; } } } // Fallback: if still empty, use user answer for correct questions if (!correctAnswer && isCorrect) { correctAnswer = userAnswer; } // Extract explanation let explanation = ''; const explanationEl = container.querySelector('.bg-blue-50 p'); if (explanationEl) { explanation = explanationEl.textContent.replace('Explanation:', '').trim(); } // Store in session data const questionId = quizSessionData.questions[index] ? quizSessionData.questions[index].id : index + 1; quizSessionData.correctAnswers[questionId] = { isCorrect: isCorrect, correctAnswer: correctAnswer, explanation: explanation, questionText: questionText }; } catch (error) { console.error('Error extracting question result:', error); } }); } function displayResults(scoreValue, correctAnswers, totalQuestions) { const passed = scoreValue >= (currentQuiz.passing_score || 70); const resultsSection = document.getElementById('quiz-results'); if (!resultsSection) return; resultsSection.innerHTML = ` <div class="result-header"> <div class="result-status-icon ${passed ? 'passed' : 'failed'}"> ${passed ? '🎉' : '📚'} </div> <h3 class="result-title"> ${passed ? '¡Felicitaciones!' : '¡Sigue Aprendiendo!'} </h3> <p class="result-subtitle"> ${passed ? '¡Aprobaste el quiz!' : 'Puedes hacerlo mejor. ¡Inténtalo de nuevo!'} </p> </div> <div class="score-display"> <div class="score-percentage ${passed ? 'passed' : 'failed'}">${scoreValue}%</div> <div class="score-details"> ${correctAnswers} de ${totalQuestions} correctas </div> <div class="score-bar"> <div class="score-fill" style="width: 0%"></div> </div> <div style="margin-top: 1rem; font-size: 0.875rem; opacity: 0.8;"> Puntuación para aprobar: ${currentQuiz.passing_score || 70}% </div> </div> <div class="result-actions"> <button class="result-btn primary" onclick="retakeQuiz()"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> </svg> Repetir Quiz </button> <button class="result-btn secondary" onclick="toggleAnswerSheet()" id="view-answers-btn"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/> </svg> Ver Respuestas </button> <button class="result-btn secondary" onclick="closeQuiz()"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> </svg> Cerrar </button> </div> <!-- Answer Sheet Section --> <div id="answer-sheet" class="answer-sheet-section" style="display: none;"> <div class="answer-sheet-header"> <h4>📋 Hoja de Respuestas</h4> <button class="close-answer-sheet" onclick="toggleAnswerSheet()">✕</button> </div> <div id="answer-sheet-content" class="answer-sheet-content"> Cargando respuestas... </div> </div> `; // Show results section showSection('quiz-results'); updateProgress(100, '¡Quiz Completado!', `${scoreValue}% Puntuación`); // Animate score bar setTimeout(() => { const scoreFill = resultsSection.querySelector('.score-fill'); if (scoreFill) { scoreFill.style.width = `${scoreValue}%`; } }, 500); } // Answer sheet functions function toggleAnswerSheet() { const answerSheet = document.getElementById('answer-sheet'); const btn = document.getElementById('view-answers-btn'); if (answerSheet.style.display === 'none' || answerSheet.style.display === '') { answerSheet.style.display = 'block'; loadAnswerSheet(); btn.innerHTML = ` <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> </svg> Ocultar Respuestas `; } else { answerSheet.style.display = 'none'; btn.innerHTML = ` <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/> </svg> Ver Respuestas `; } } function loadAnswerSheet() { const answerSheetContent = document.getElementById('answer-sheet-content'); if (!answerSheetContent || !quizSessionData) return; let correctCount = 0; let incorrectCount = 0; let answerSheetHTML = ` <div class="answer-summary"> <div class="summary-stat total"> <div class="number">${currentQuiz.total_questions || 0}</div> <div class="label">Total de Preguntas</div> </div> <div class="summary-stat correct"> <div class="number" id="correct-count">0</div> <div class="label">Correcto</div> </div> <div class="summary-stat incorrect"> <div class="number" id="incorrect-count">0</div> <div class="label">Incorrecto</div> </div> </div> <div class="answer-grid"> `; // Generate answer sheet for each question quizSessionData.questions.forEach((question, index) => { if (!question) return; const questionId = question.id; const userAnswer = quizSessionData.answers[questionId]; const correctInfo = quizSessionData.correctAnswers[questionId]; if (!userAnswer || !correctInfo) return; const isCorrect = correctInfo.isCorrect; if (isCorrect) { correctCount++; } else { incorrectCount++; } answerSheetHTML += ` <div class="answer-item ${isCorrect ? 'correct' : 'incorrect'}"> <div class="question-number">Q${index + 1}</div> <div class="question-details"> <div class="question-text">${escapeHtml(correctInfo.questionText || question.text)}</div> <div class="answer-comparison"> <div class="user-answer"> <span class="label">Your Answer:</span> <span class="value ${isCorrect ? 'correct' : 'incorrect'}">${escapeHtml(userAnswer.selectedOptionText)}</span> </div> ${!isCorrect ? ` <div class="correct-answer"> <span class="label">Correct Answer:</span> <span class="value correct">${escapeHtml(correctInfo.correctAnswer)}</span> </div> ` : ''} ${correctInfo.explanation ? ` <div class="explanation"> <span class="label">Explicación:</span> <span class="explanation-text">${escapeHtml(correctInfo.explanation)}</span> </div> ` : ''} </div> </div> <div class="result-icon"> ${isCorrect ? '✅' : '❌'} </div> </div> `; }); answerSheetHTML += '</div>'; answerSheetContent.innerHTML = answerSheetHTML; // Update summary counts document.getElementById('correct-count').textContent = correctCount; document.getElementById('incorrect-count').textContent = incorrectCount; } function retakeQuiz() { // Reset quiz state currentQuiz = null; currentQuestionIndex = 0; selectedAnswer = null; currentQuestionData = null; quizSessionData = null; if (quizTimer) { clearInterval(quizTimer); hideTimer(); } // Show intro section showSection('quiz-intro'); updateProgress(0, 'Listo para Empezar', ''); } function closeQuiz() { // Just reset and hide for now since we're directly displaying retakeQuiz(); } function showSection(sectionId) { const sections = ['quiz-intro', 'quiz-questions', 'quiz-results', 'quiz-loading']; sections.forEach(id => { const element = document.getElementById(id); if (element) { element.style.display = id === sectionId ? 'block' : 'none'; } }); } function updateProgress(percentage, currentText, statsText) { const progressFill = document.getElementById('quiz-progress-fill'); const progressText = document.getElementById('progress-text'); const progressStats = document.getElementById('progress-stats'); if (progressFill) { progressFill.style.width = `${percentage}%`; } if (progressText) { progressText.textContent = currentText; } if (progressStats) { progressStats.textContent = statsText; } } function setupTimer(timeLimit) { const timerWrapper = document.getElementById('quiz-timer-wrapper'); const timerDisplay = document.getElementById('timer-display'); if (!timerWrapper || !timerDisplay) return; timeRemaining = timeLimit * 60; // Convert to seconds timerWrapper.style.display = 'flex'; quizTimer = setInterval(() => { const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; timerDisplay.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`; // Warning when time is running out if (timeRemaining <= 60) { timerWrapper.style.color = '#ef4444'; timerWrapper.style.animation = 'pulse 1s infinite'; } if (timeRemaining <= 0) { clearInterval(quizTimer); if (selectedAnswer) { submitAnswer(); } else { showError('¡Se acabó el tiempo! El quiz se enviará automáticamente.'); } } timeRemaining--; }, 1000); } function hideTimer() { const timerWrapper = document.getElementById('quiz-timer-wrapper'); if (timerWrapper) { timerWrapper.style.display = 'none'; } } function resetSubmitButton(button) { if (!button) return; button.disabled = false; button.querySelector('.btn-text').style.opacity = '1'; button.querySelector('.btn-loader').style.display = 'none'; } function showError(message) { console.log('Showing error:', message); const errorDisplay = document.getElementById('quiz-error'); if (!errorDisplay) return; const errorMessage = errorDisplay.querySelector('.error-message'); if (errorMessage) { errorMessage.textContent = message; } errorDisplay.style.display = 'block'; // Auto-hide after 5 seconds setTimeout(() => { hideError(); }, 5000); } function hideError() { const errorDisplay = document.getElementById('quiz-error'); if (errorDisplay) { errorDisplay.style.display = 'none'; } } function escapeHtml(unsafe) { if (typeof unsafe !== 'string') { return unsafe; } return unsafe .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // Initialize quiz when page loads document.addEventListener('DOMContentLoaded', function() { // Quiz is now directly visible, no need for showQuiz() function console.log('Quiz components loaded'); }); // HTMX after-swap event document.body.addEventListener('htmx:afterSwap', function() { // Reinitialize quiz if it exists on the swapped content console.log('Quiz components reloaded after HTMX swap'); }); </script> </div> <!-- Enhanced Navigation --> <div class="topic-navigation"> <div class="nav-links"> <div></div> <div class="nav-center"> <div class="text-sm font-semibold">Tema 1 de 1</div> <div class="text-xs mt-1 opacity-75">Html Tutorial</div> </div> <div></div> </div> </div> </div> <script> const sessionKey = `code_session_${codeExampleId}`; // Smart Link Click Tracking document.addEventListener('click', function(event) { const smartLink = event.target.closest('.smart-link'); if (smartLink) { const keywordId = smartLink.getAttribute('data-keyword-id'); if (keywordId) { // Track click asynchronously fetch('/es/api/smart-link-click/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': 'mwV3ptxjox84fl1Oe1x7PU13hUhjEXcYwnGjkiImOiAjKLVdUycNXPlIIGguzU3S' }, body: JSON.stringify({ keyword_id: keywordId, source_content_type: 'topic', source_content_id: 2, user_agent: navigator.userAgent }) }).catch(error => { console.debug('Smart link tracking failed:', error); }); } } }); function openCodeRunner(language, title, codeExampleId) { const codeElement = document.getElementById('code-' + codeExampleId); const code = codeElement.textContent; const formData = new FormData(); formData.append('language', language); formData.append('title', title); formData.append('code', code); formData.append('source_example_id', codeExampleId); formData.append('csrfmiddlewaretoken', 'mwV3ptxjox84fl1Oe1x7PU13hUhjEXcYwnGjkiImOiAjKLVdUycNXPlIIGguzU3S'); fetch('/es/create-code-session/', { method: 'POST', body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => response.json()) .then(data => { if (data.success) { window.open(data.url, '_blank'); } else { console.error('Error creating session:', data.error); window.open('/es/try-it/' + language + '/', '_blank'); } }) .catch(error => { console.error('Error:', error); window.open('/es/try-it/' + language + '/', '_blank'); }); } document.body.addEventListener('htmx:afterSwap', function() { window.scrollTo({ top: 0, behavior: 'smooth' }); if (typeof Prism !== 'undefined') { Prism.highlightAll(); } if (typeof populateQuizStats === 'function') { populateQuizStats(); } if (window.mobileMenu && window.mobileMenu.isMenuOpen && window.mobileMenu.isMenuOpen()) { window.mobileMenu.forceClose(); } initializeEnhancedFeatures(); }); function initializeEnhancedFeatures() { // Initialize topic tracking for authenticated users if (window.siteConfig && window.siteConfig.isAuthenticated) { initializeTopicTracking(); } document.querySelectorAll('.nav-link, .custom-sidebar-item').forEach(link => { link.addEventListener('click', function() { if (this.hasAttribute('hx-get')) { this.classList.add('loading'); setTimeout(() => { this.classList.remove('loading'); }, 1000); } }); }); document.querySelectorAll('.code-block pre').forEach(pre => { const code = pre.querySelector('code'); if (code && code.textContent.split('\n').length > 3) { pre.classList.add('line-numbers'); } }); } function initializeTopicTracking() { // Track topic view for authenticated users const topicId = getTopicIdFromCurrentUrl(); const categorySlug = getCategorySlugFromCurrentUrl(); if (topicId && categorySlug) { // Track initial view trackTopicView({ topic_id: topicId, category_slug: categorySlug }); // Track scroll percentage let maxScrollPercentage = 0; let timeSpent = 0; let startTime = Date.now(); window.addEventListener('scroll', throttle(function() { const scrollPercentage = calculateScrollPercentage(); if (scrollPercentage > maxScrollPercentage) { maxScrollPercentage = scrollPercentage; } }, 1000)); // Track time spent setInterval(() => { if (!document.hidden) { timeSpent += 5; // Add 5 seconds } }, 5000); // Send final data on page unload window.addEventListener('beforeunload', function() { if (maxScrollPercentage > 0 || timeSpent > 0) { trackTopicView({ topic_id: topicId, category_slug: categorySlug, scroll_percentage: maxScrollPercentage, time_spent: timeSpent, completed: maxScrollPercentage >= 80 // Consider 80% as completed }); } }); } } function getTopicIdFromCurrentUrl() { const pathParts = window.location.pathname.split('/').filter(Boolean); const languages = ['en', 'fa', 'ar', 'zh', 'hi', 'fr', 'de', 'ru', 'tr', 'pt', 'es']; let startIndex = 0; if (languages.includes(pathParts[0])) { startIndex = 1; } if (pathParts.length >= startIndex + 2) { return pathParts[startIndex + 1]; // Return topic slug } return null; } function getCategorySlugFromCurrentUrl() { const pathParts = window.location.pathname.split('/').filter(Boolean); const languages = ['en', 'fa', 'ar', 'zh', 'hi', 'fr', 'de', 'ru', 'tr', 'pt', 'es']; let startIndex = 0; if (languages.includes(pathParts[0])) { startIndex = 1; } if (pathParts.length >= startIndex + 1) { return pathParts[startIndex]; // Return category slug } return null; } function trackTopicView(data) { if (!window.siteConfig || !window.siteConfig.isAuthenticated) { return Promise.resolve(); } return fetch('/account/ajax/track-topic-view/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': window.siteConfig.csrfToken || getCsrfToken() }, body: JSON.stringify(data) }).catch(error => { console.debug('Topic view tracking failed:', error); }); } function calculateScrollPercentage() { const scrollTop = window.pageYOffset; const docHeight = document.documentElement.scrollHeight - window.innerHeight; return Math.min(100, Math.max(0, (scrollTop / docHeight) * 100)); } function throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } function getCsrfToken() { const tokenInput = document.querySelector('input[name="csrfmiddlewaretoken"]'); if (tokenInput) { return tokenInput.value; } const cookieMatch = document.cookie.match(/csrftoken=([^;]+)/); return cookieMatch ? cookieMatch[1] : null; } document.addEventListener('DOMContentLoaded', function() { initializeEnhancedFeatures(); if (typeof Prism !== 'undefined') { Prism.highlightAll(); } document.body.addEventListener('htmx:beforeRequest', function(event) { const target = event.target; if (target.classList.contains('nav-link') || target.classList.contains('custom-sidebar-item')) { target.style.opacity = '0.7'; target.style.pointerEvents = 'none'; } }); document.body.addEventListener('htmx:afterRequest', function(event) { const target = event.target; if (target.classList.contains('nav-link') || target.classList.contains('custom-sidebar-item')) { target.style.opacity = '1'; target.style.pointerEvents = 'auto'; } }); }); window.addEventListener('error', function(event) { console.error('JavaScript error:', event.error); if (window.innerWidth <= 768) { const errorDiv = document.createElement('div'); errorDiv.className = 'fixed top-4 left-4 right-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg z-50 shadow-lg'; errorDiv.innerHTML = ` <div class="flex items-center justify-between"> <div class="flex items-center"> <span class="text-red-500 mr-2">⚠️</span> <span><strong>Error:</strong> Algo salió mal. Por favor, actualiza la página.</span> </div> <button onclick="this.parentElement.parentElement.remove()" class="text-red-500 hover:text-red-700 ml-2">✕</button> </div> `; document.body.appendChild(errorDiv); setTimeout(() => { if (errorDiv.parentElement) { errorDiv.remove(); } }, 5000); } }); const style = document.createElement('style'); style.textContent = ` @keyframes ripple { to { transform: scale(4); opacity: 0; } } .copy-button { position: relative; overflow: hidden; } `; document.head.appendChild(style); </script> </main> </div> <!-- Coming Soon Course Modal --> <div id="coming-soon-modal" class="coming-soon-modal hidden"> <div class="coming-soon-backdrop"></div> <div class="coming-soon-content"> <!-- Modal Header --> <div class="coming-soon-header"> <div class="flex items-center space-x-3 "> <div class="coming-soon-icon"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"></path> </svg> </div> <h3 class="coming-soon-title"> 🚧 Curso Próximamente </h3> </div> <button id="close-coming-soon-modal" class="coming-soon-close"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <!-- Modal Body --> <div class="coming-soon-body"> <div class="course-info-section"> <h4 id="course-name" class="course-name">Course Name</h4> <div class="course-status"> <span class="status-badge">En Desarrollo</span> </div> <p class="course-description"> Este curso completo está siendo desarrollado actualmente con los últimos estándares de la industria y mejores prácticas. Nuestro equipo experto está creando contenido de alta calidad para asegurar que obtengas la mejor experiencia de aprendizaje. </p> </div> <div class="estimated-release"> <div class="flex items-center space-x-2 "> <svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path> </svg> <span class="text-sm text-gray-600 dark:text-gray-400"> Lanzamiento Estimado: 2-4 semanas </span> </div> </div> <!-- Notify Me Section --> <div class="notify-section"> <h5 class="notify-title">Recibir Notificación Cuando Esté Disponible</h5> <form id="notify-form" class="notify-form"> <div class="email-input-group"> <input type="email" id="notify-email" name="email" placeholder="Ingresa tu dirección de correo electrónico" class="notify-email-input" required> <button type="submit" class="notify-submit-btn"> <span class="btn-text">Notificarme</span> <svg class="btn-icon w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path> </svg> </button> </div> <p class="email-disclaimer"> Te enviaremos una sola notificación cuando este curso esté disponible. ¡Sin spam, lo prometemos! </p> </form> </div> <!-- Related Courses --> <div class="related-courses"> <h5 class="related-title">Disponible Ahora</h5> <div class="related-links"> <a href="/es/html/" class="related-link"> <i class="fab fa-html5 text-orange-500"></i> <span>Tutorial de HTML</span> </a> <a href="/es/css/" class="related-link"> <i class="fab fa-css3-alt text-blue-500"></i> <span>Guía Completa de CSS</span> </a> <a href="/es/javascript/" class="related-link"> <i class="fab fa-js-square text-yellow-500"></i> <span>Fundamentos de JavaScript</span> </a> </div> </div> </div> </div> </div> <!-- Coming Soon Modal --> <div id="coming-soon-modal" class="coming-soon-modal"> <div class="coming-soon-backdrop"></div> <div class="coming-soon-content"> <div class="coming-soon-header"> <div class="coming-soon-icon"> <i class="fas fa-clock"></i> </div> <h3 class="coming-soon-title">Coming Soon</h3> <button class="coming-soon-close" id="close-coming-soon"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="coming-soon-body"> <div class="course-info-section"> <h4 class="course-name" id="modal-course-name">Course Name</h4> <div class="course-status"> <span class="status-badge"> <i class="fas fa-hammer mr-1"></i> En Desarrollo </span> </div> <p class="course-description" id="modal-course-description"> This course is currently under development. We're working hard to bring you high-quality content. </p> </div> <div class="estimated-release"> <div class="flex items-center space-x-2 mb-2"> <i class="fas fa-calendar-alt text-blue-600"></i> <span class="font-semibold text-blue-600">Estimated Release</span> </div> <p class="text-sm text-blue-700" id="modal-release-date">Q2 2025</p> </div> </div> </div> </div> <!-- Include Footer --> <footer class="bg-gray-900 text-white"> <div class=""> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 grid grid-cols-2 md:grid-cols-6 gap-8"> <!-- Frontend Development --> <div> <h3 class="text-sm font-semibold text-gray-300 uppercase tracking-wide mb-4">Frontend</h3> <ul class="space-y-1"> <li><a href="/es/html/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">HTML Tutorial</a></li> <li><a href="/es/css/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">CSS Complete Guide</a></li> <li><a href="/es/javascript/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">JavaScript Fundamentals</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="react">React Development</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="vue">Vue.js Framework</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="angular">Angular Framework</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="typescript">TypeScript Guide</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="bootstrap">Bootstrap Framework</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="tailwind">Tailwind CSS</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="sass">Sass & SCSS</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="jquery">jQuery Library</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="webcomponents">Web Components</a></li> </ul> </div> <!-- Backend Development --> <div> <h3 class="text-sm font-semibold text-gray-300 uppercase tracking-wide mb-4">Backend</h3> <ul class="space-y-1"> <li><a href="/es/python/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">Python Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="django">Django Framework</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="flask">Flask Framework</a></li> <li><a href="/es/nodejs/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">Node.js Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="express">Express.js Framework</a></li> <li><a href="/es/php/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">PHP Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="laravel">Laravel Framework</a></li> <li><a href="/es/java/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">Java Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="spring">Spring Boot</a></li> <li><a href="/es/c-sharp/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">C# Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="dotnet">ASP.NET Core</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="ruby">Ruby on Rails</a></li> </ul> </div> <!-- Database Programming --> <div> <h3 class="text-sm font-semibold text-gray-300 uppercase tracking-wide mb-4">Base de Datos</h3> <ul class="space-y-1"> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="sql">SQL Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="mysql">MySQL Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="postgresql">PostgreSQL Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="mongodb">MongoDB Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="redis">Redis Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="sqlite">SQLite Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="database-design">Database Design</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="sqlserver">SQL Server Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="oracle">Oracle Database</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="mariadb">MariaDB Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="firebase">Firebase Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="elasticsearch">Elasticsearch Tutorial</a></li> </ul> </div> <!-- Mobile Development --> <div> <h3 class="text-sm font-semibold text-gray-300 uppercase tracking-wide mb-4">Móvil</h3> <ul class="space-y-1"> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="react-native">React Native Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="flutter">Flutter Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="dart">Dart Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="swift">iOS Swift Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="swiftui">SwiftUI Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="kotlin">Android Kotlin</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="android-java">Android Java</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="xamarin">Xamarin Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="ionic">Ionic Framework</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="phonegap">PhoneGap Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="pwa">Progressive Web Apps</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="mobile-ui">Mobile UI Design</a></li> </ul> </div> <!-- Advanced Topics --> <div> <h3 class="text-sm font-semibold text-gray-300 uppercase tracking-wide mb-4">Avanzado</h3> <ul class="space-y-1"> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="data-structures">Data Structures</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="algorithms">Algorithms Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="oop">Object Oriented Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="design-patterns">Design Patterns</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="api-development">API Development</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="rest-api">REST API Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="graphql">GraphQL Tutorial</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="microservices">Microservices</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="machine-learning">Machine Learning</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="ai">Artificial Intelligence</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="blockchain">Blockchain Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="game-dev">Game Development</a></li> </ul> </div> <!-- Programming Languages --> <div> <h3 class="text-sm font-semibold text-gray-300 uppercase tracking-wide mb-4">Lenguajes de Programación</h3> <ul class="space-y-1"> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="c">C Programming</a></li> <li><a href="/es/c-plus-plus/" class="text-xs text-gray-400 hover:text-teal-400 transition-colors">C++ Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="go">Go Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="rust">Rust Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="ruby">Ruby Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="scala">Scala Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="kotlin">Kotlin Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="r">R Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="matlab">MATLAB Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="perl">Perl Programming</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="assembly">Assembly Language</a></li> <li><a href="#" class="coming-soon-link text-xs text-gray-400 hover:text-teal-400 transition-colors" data-course="lua">Lua Programming</a></li> </ul> </div> </div> <!-- Brand Section --> <div class="border-t border-gray-800 mt-12 pt-8"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col md:flex-row justify-between items-center"> <div class="flex flex-col items-center text-center mb-6 md:mb-0"> <img src="/static/images/logo.6fecbe0a2cbf.png" alt="Mrebi Logo" class="h-12 w-auto object-contain mb-2"> <div> <p class="text-sm text-gray-400 mt-1">Aprende, Practica, Domina</p> </div> </div> <div class="text-center md:text-right"> <div class="flex flex-wrap justify-center md:justify-end gap-6 mb-4"> <a href="#" class="text-sm text-gray-400 hover:text-teal-400 transition-colors">Acerca de Nosotros</a> <a href="#" class="text-sm text-gray-400 hover:text-teal-400 transition-colors">Contacto</a> <a href="#" class="text-sm text-gray-400 hover:text-teal-400 transition-colors">Política de Privacidad</a> <a href="#" class="text-sm text-gray-400 hover:text-teal-400 transition-colors">Términos de Servicio</a> <a href="#" class="text-sm text-gray-400 hover:text-teal-400 transition-colors">Blog</a> </div> <div class="text-gray-400"> <p class="text-sm mb-2"> Domina la programación con tutoriales interactivos y práctica práctica </p> <p class="text-xs"> © 2025 Mrebi. Todos los derechos reservados. </p> </div> </div> </div> <!-- Social Links --> <div class="mt-8 pt-6 border-t border-gray-800 text-center"> <div class="flex justify-center gap-6 flex-wrap"> <a href="https://www.linkedin.com/in/mr-ebi/" class="text-gray-400 hover:text-teal-400 transition-colors duration-200" aria-label="LinkedIn" target="_blank" rel="noopener noreferrer"> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/> </svg> </a> <a href="https://www.youtube.com/@mrebi-com" class="text-gray-400 hover:text-teal-400 transition-colors duration-200" aria-label="YouTube" target="_blank" rel="noopener noreferrer"> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> <path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/> </svg> </a> <a href="https://www.instagram.com/mrebicom/" class="text-gray-400 hover:text-teal-400 transition-colors duration-200" aria-label="Instagram" target="_blank" rel="noopener noreferrer"> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.148 3.227-1.691 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.148-4.771-1.691-4.919-4.919-.058-1.265-.069-1.645-.069-4.849 0-3.205.012-3.584.069-4.849.149-3.227 1.691-4.771 4.919-4.919 1.266-.058 1.644-.07 4.849-.07zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.667.072 4.947.2 4.36 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.667-.014 4.947-.072 4.358-.2 6.78-2.618 6.98-6.98.059-1.281.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.2-4.36-2.618-6.78-6.98-6.98-1.281-.058-1.689-.072-4.948-.072zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/> </svg> </a> <a href="#" class="text-gray-400 hover:text-teal-400 transition-colors duration-200" aria-label="TikTok" target="_blank" rel="noopener noreferrer"> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> <path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-5.2 1.74 2.89 2.89 0 0 1 2.31-4.55 2.89 2.89 0 0 1 .88.13V9.65a6.34 6.34 0 0 0-1-.09A6.34 6.34 0 0 0 3 16a6.34 6.34 0 0 0 11.13 4.13 6.34 6.34 0 0 0 1.81-4.55V8.52a8.28 8.28 0 0 0 4.85 1.56V6.69z"/> </svg> </a> <a href="https://x.com/mrebicom" class="text-gray-400 hover:text-teal-400 transition-colors duration-200" aria-label="X" target="_blank" rel="noopener noreferrer"> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/> </svg> </a> <a href="https://www.facebook.com/mrebicom/" class="text-gray-400 hover:text-teal-400 transition-colors duration-200" aria-label="Facebook" target="_blank" rel="noopener noreferrer"> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> <path d="M22.675 0H1.325C.593 0 0 .593 0 1.325v21.351C0 23.407.593 24 1.325 24H12.82v-9.294H9.692v-3.622h3.128V8.413c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.795.143v3.24l-1.918.001c-1.504 0-1.795.715-1.795 1.763v2.313h3.587l-.467 3.622h-3.12V24h6.116c.73 0 1.323-.593 1.323-1.325V1.325C24 .593 23.407 0 22.675 0z"/> </svg> </a> </div> <p class="text-xs text-gray-500 mt-4"> Join our community and start your programming journey today! </p> </div> </div> </div> </footer> <script> // Handle Coming Soon links in footer document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.coming-soon-link').forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); const courseName = this.getAttribute('data-course') || 'default'; if (typeof window.showComingSoonModal === 'function') { window.showComingSoonModal(courseName); } }); }); }); </script> <!-- Prism.js for Syntax Highlighting --> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-html.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-css.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-javascript.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-php.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-sql.min.js"></script> <!-- Theme Switcher --> <script src="/static/js/theme-switcher.6107c7dde403.js"></script> <!-- Custom JavaScript --> <script src="/static/js/code-editor.744452e3251a.js"></script> <script src="/static/js/code-runner.0ff7847dbd6e.js"></script> <script src="/static/js/mobile-menu.b685f211e4ca.js"></script> <script> // Mobile menu toggle function toggleMobileMenu() { const menu = document.getElementById('mobile-menu'); menu.classList.toggle('hidden'); } // Enhanced language switcher function changeLanguage(languageCode) { const changeUrl = `/es/change-language/?language=${languageCode}`; if (typeof htmx !== 'undefined') { htmx.ajax('GET', changeUrl, { headers: { 'HX-Request': 'true' } }).then(function(response) { if (response.redirect) { window.location.href = response.redirect; } }); } else { window.location.href = changeUrl; } } // HTMX event listeners document.body.addEventListener('htmx:beforeRequest', function(evt) { document.getElementById('loading-indicator').style.display = 'block'; }); document.body.addEventListener('htmx:afterRequest', function(evt) { document.getElementById('loading-indicator').style.display = 'none'; }); document.body.addEventListener('htmx:afterSwap', function(evt) { // Reinitialize Prism.js highlighting if (typeof Prism !== 'undefined') { Prism.highlightAll(); } // Close mobile menu const mobileMenu = document.getElementById('mobile-menu'); if (mobileMenu && !mobileMenu.classList.contains('hidden')) { mobileMenu.classList.add('hidden'); } // Scroll to top for new content window.scrollTo({ top: 0, behavior: 'smooth' }); }); // Smooth scroll for anchor links document.addEventListener('click', function(e) { if (e.target.matches('a[href^="#"]')) { const href = e.target.getAttribute('href'); // Skip if just # if (href === '#') { return; } e.preventDefault(); const target = document.querySelector(href); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } }); // Coming Soon Modal functionality function initComingSoonModal() { const modal = document.getElementById('coming-soon-modal'); const closeBtn = document.getElementById('close-coming-soon-modal'); const backdrop = modal.querySelector('.coming-soon-backdrop'); const notifyForm = document.getElementById('notify-form'); // Course mapping for dynamic content const courseInfo = { 'python': { name: 'Python Programming', description: 'Aprende Python desde los fundamentos hasta conceptos avanzados incluyendo desarrollo web, ciencia de datos y automatización.' }, 'java': { name: 'Java Programming', description: 'Domina la programación Java para aplicaciones empresariales, desarrollo Android y programación del lado del servidor.' }, 'nodejs': { name: 'Node.js Development', description: 'Construye aplicaciones escalables del lado del servidor con Node.js y el framework Express.' }, 'react': { name: 'React Development', description: 'Crea interfaces de usuario modernas con React, hooks y gestión de estado.' }, 'typescript': { name: 'TypeScript Guide', description: 'Escribe JavaScript más seguro con verificación de tipos estática y características modernas del lenguaje.' }, 'vue': { name: 'Vue.js Framework', description: 'Construye aplicaciones web progresivas con Vue.js y su ecosistema.' }, 'angular': { name: 'Angular Framework', description: 'Desarrolla aplicaciones de una sola página de nivel empresarial con Angular.' }, 'tailwind': { name: 'Tailwind CSS', description: 'Crea diseños modernos rápidamente con el framework CSS utility-first.' }, 'django': { name: 'Django Framework', description: 'Construye aplicaciones web robustas con el framework completo de Django.' }, 'express': { name: 'Express.js Framework', description: 'Crea aplicaciones web rápidas y minimalistas con Express.js.' }, 'spring': { name: 'Spring Boot', description: 'Desarrolla aplicaciones Java empresariales con el framework Spring Boot.' }, 'php': { name: 'PHP Programming', description: 'Aprende scripting del lado del servidor con PHP para desarrollo web dinámico.' }, 'laravel': { name: 'Laravel Framework', description: 'Construye aplicaciones web elegantes con la sintaxis expresiva de Laravel.' }, 'sql': { name: 'SQL Tutorial', description: 'Domina las consultas de base de datos y manipulación de datos con SQL.' }, 'mysql': { name: 'MySQL Tutorial', description: 'Aprende la base de datos relacional de código abierto más popular del mundo.' }, 'postgresql': { name: 'PostgreSQL Tutorial', description: 'Domina las características avanzadas del sistema de base de datos PostgreSQL.' }, 'mongodb': { name: 'MongoDB Tutorial', description: 'Trabaja con base de datos de documentos NoSQL flexible para aplicaciones modernas.' }, 'flutter': { name: 'Flutter Tutorial', description: 'Construye hermosas aplicaciones móviles nativas para iOS y Android con una sola base de código.' }, 'react-native': { name: 'React Native Tutorial', description: 'Crea aplicaciones móviles nativas usando React y JavaScript.' }, 'swift': { name: 'iOS Swift Tutorial', description: 'Desarrolla aplicaciones iOS nativas con el lenguaje de programación Swift.' }, 'kotlin': { name: 'Android Kotlin', description: 'Construye aplicaciones Android modernas con el lenguaje de programación Kotlin.' }, 'docker': { name: 'Docker', description: 'Conteneriza aplicaciones para despliegue consistente en diferentes entornos.' }, 'git': { name: 'Git', description: 'Domina el control de versiones y flujos de trabajo colaborativos con Git.' }, 'aws': { name: 'AWS', description: 'Despliega y escala aplicaciones en la plataforma en la nube Amazon Web Services.' }, 'kubernetes': { name: 'Kubernetes', description: 'Orquesta aplicaciones contenerizadas a escala con Kubernetes.' }, 'go': { name: 'Go Programming', description: 'Construye software rápido, confiable y eficiente con el lenguaje Go.' }, 'rust': { name: 'Rust Programming', description: 'Aprende programación de sistemas con seguridad de memoria y abstracciones de costo cero.' }, 'csharp': { name: 'C# Programming', description: 'Desarrolla aplicaciones modernas con C# y el ecosistema .NET.' }, 'cpp': { name: 'C++ Programming', description: 'Domina la programación de sistemas y aplicaciones de alto rendimiento con C++.' }, 'bootstrap': { name: 'Bootstrap Framework', description: 'Construye sitios web responsivos rápidamente con el framework CSS Bootstrap.' }, 'jquery': { name: 'jQuery Library', description: 'Simplifica la programación JavaScript con la librería jQuery para manipulación del DOM.' }, 'sass': { name: 'Sass & SCSS', description: 'Escribe CSS más mantenible con el preprocesador Sass y características avanzadas.' }, 'graphql': { name: 'GraphQL Tutorial', description: 'Construye APIs eficientes con el lenguaje de consultas GraphQL y definición de esquemas.' }, 'nextjs': { name: 'Next.js', description: 'Crea aplicaciones React full-stack con el framework Next.js.' }, 'nuxtjs': { name: 'Nuxt.js', description: 'Construye aplicaciones Vue.js universales con el framework Nuxt.js.' }, 'redis': { name: 'Redis Tutorial', description: 'Aprende almacenamiento de estructuras de datos en memoria para caché y aplicaciones en tiempo real.' }, 'firebase': { name: 'Firebase Tutorial', description: 'Construye aplicaciones web y móviles con los servicios backend de Google Firebase.' }, 'elasticsearch': { name: 'Elasticsearch Tutorial', description: 'Implementa búsqueda y análisis potentes con el motor Elasticsearch.' }, 'c': { name: 'C Programming', description: 'Aprende los fundamentos de la programación de sistemas con el lenguaje C.' }, 'ruby': { name: 'Ruby Programming', description: 'Escribe código elegante con el lenguaje de programación Ruby y el framework Rails.' }, 'scala': { name: 'Scala Programming', description: 'Combina programación orientada a objetos y funcional con Scala.' }, 'r': { name: 'R Programming', description: 'Realiza computación estadística y análisis de datos con el lenguaje R.' }, 'matlab': { name: 'MATLAB Programming', description: 'Resuelve problemas de ingeniería y científicos con programación MATLAB.' }, 'perl': { name: 'Perl Programming', description: 'Domina el procesamiento de texto y administración de sistemas con Perl.' }, 'assembly': { name: 'Assembly Language', description: 'Comprende la programación de bajo nivel y arquitectura de computadoras con Assembly.' }, 'lua': { name: 'Lua Programming', description: 'Aprende lenguaje de scripting ligero para sistemas embebidos y juegos.' }, 'xamarin': { name: 'Xamarin Tutorial', description: 'Construye aplicaciones móviles multiplataforma con Xamarin y C#.' }, 'ionic': { name: 'Ionic Framework', description: 'Crea aplicaciones móviles híbridas con Ionic y tecnologías web.' }, 'phonegap': { name: 'PhoneGap Tutorial', description: 'Construye aplicaciones móviles usando tecnologías web con la plataforma PhoneGap.' }, 'pwa': { name: 'Progressive Web Apps', description: 'Crea experiencias similares a aplicaciones en la web con tecnologías Progressive Web App.' }, 'mobile-ui': { name: 'Mobile UI Design', description: 'Diseña interfaces de usuario hermosas e intuitivas para aplicaciones móviles.' }, 'data-structures': { name: 'Data Structures', description: 'Domina las estructuras de datos fundamentales para implementación eficiente de algoritmos.' }, 'algorithms': { name: 'Algorithms Tutorial', description: 'Aprende pensamiento algorítmico y técnicas de resolución de problemas.' }, 'oop': { name: 'Object Oriented Programming', description: 'Comprende los conceptos de programación orientada a objetos y principios de diseño.' }, 'design-patterns': { name: 'Design Patterns', description: 'Aplica patrones de diseño de software probados para resolver problemas comunes de programación.' }, 'api-development': { name: 'API Development', description: 'Diseña y construye APIs robustas para aplicaciones web y móviles.' }, 'rest-api': { name: 'REST API Tutorial', description: 'Crea servicios web RESTful siguiendo las mejores prácticas y estándares.' }, 'microservices': { name: 'Microservices', description: 'Arquitectura aplicaciones escalables usando patrones de diseño de microservicios.' }, 'machine-learning': { name: 'Machine Learning', description: 'Construye sistemas inteligentes con algoritmos y técnicas de aprendizaje automático.' }, 'ai': { name: 'Artificial Intelligence', description: 'Explora conceptos de IA y construye aplicaciones inteligentes con frameworks modernos.' }, 'blockchain': { name: 'Blockchain Programming', description: 'Desarrolla aplicaciones descentralizadas y contratos inteligentes en plataformas blockchain.' }, 'game-dev': { name: 'Game Development', description: 'Crea juegos atractivos usando motores de juego modernos y técnicas de programación.' }, 'webcomponents': { name: 'Web Components', description: 'Construye elementos personalizados reutilizables con estándares Web Components.' }, 'database-design': { name: 'Database Design', description: 'Diseña esquemas de base de datos eficientes y escalables y relaciones.' }, 'sqlserver': { name: 'SQL Server Tutorial', description: 'Trabaja con el sistema de gestión de base de datos Microsoft SQL Server.' }, 'oracle': { name: 'Oracle Database', description: 'Domina las técnicas de administración y desarrollo de base de datos Oracle.' }, 'mariadb': { name: 'MariaDB Tutorial', description: 'Aprende las características y administración de la base de datos MariaDB.' }, 'dotnet': { name: 'ASP.NET Core', description: 'Construye aplicaciones web modernas con el framework ASP.NET Core.' }, 'flask': { name: 'Flask Framework', description: 'Crea aplicaciones web ligeras con el microframework Python Flask.' }, 'android-java': { name: 'Android Java', description: 'Desarrolla aplicaciones Android usando el lenguaje de programación Java.' }, 'swiftui': { name: 'SwiftUI Tutorial', description: 'Construye interfaces iOS modernas con el framework declarativo SwiftUI.' }, 'prompt-engineering': { name: 'AI Prompt Engineering', description: 'Domina el arte de comunicarse efectivamente con sistemas de IA y modelos de lenguaje.' }, 'default': { name: 'Nuevo Curso', description: 'Este curso completo está siendo desarrollado con los últimos estándares de la industria y mejores prácticas.' } }; // Show modal function function showModal(courseName = 'default') { const info = courseInfo[courseName] || courseInfo['default']; const courseNameElement = document.getElementById('course-name'); const courseDescElement = modal.querySelector('.course-description'); if (courseNameElement) courseNameElement.textContent = info.name; if (courseDescElement) courseDescElement.textContent = info.description; modal.classList.remove('hidden'); modal.classList.add('active'); document.body.style.overflow = 'hidden'; } // Hide modal function function hideModal() { modal.classList.remove('active'); modal.classList.add('hidden'); document.body.style.overflow = 'auto'; // Reset form if (notifyForm) { notifyForm.reset(); } } // Event listeners if (closeBtn) { closeBtn.addEventListener('click', hideModal); } if (backdrop) { backdrop.addEventListener('click', hideModal); } // Escape key document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && modal.classList.contains('active')) { hideModal(); } }); // Handle notify form submission if (notifyForm) { notifyForm.addEventListener('submit', function(e) { e.preventDefault(); const email = document.getElementById('notify-email').value; if (email) { // Here you would typically send the email to your backend console.log('Notify email:', email); // Show success message alert('Thank you! We will notify you when this course becomes available.'); hideModal(); } }); } // Detect clicks on # links and show modal document.addEventListener('click', function(e) { if (e.target.matches('a[href="#"]') || e.target.closest('a[href="#"]')) { e.preventDefault(); // Try to extract course name from link text or data attribute const link = e.target.matches('a') ? e.target : e.target.closest('a'); const linkText = link.textContent.toLowerCase(); let courseName = 'default'; if (linkText.includes('python')) courseName = 'python'; else if (linkText.includes('java') && !linkText.includes('javascript')) courseName = 'java'; else if (linkText.includes('node')) courseName = 'nodejs'; else if (linkText.includes('react')) courseName = 'react'; else if (linkText.includes('typescript')) courseName = 'typescript'; else if (linkText.includes('vue')) courseName = 'vue'; else if (linkText.includes('angular')) courseName = 'angular'; else if (linkText.includes('tailwind')) courseName = 'tailwind'; else if (linkText.includes('django')) courseName = 'django'; else if (linkText.includes('express')) courseName = 'express'; else if (linkText.includes('spring')) courseName = 'spring'; else if (linkText.includes('php')) courseName = 'php'; else if (linkText.includes('laravel')) courseName = 'laravel'; else if (linkText.includes('sql') && !linkText.includes('mysql') && !linkText.includes('postgresql')) courseName = 'sql'; else if (linkText.includes('mysql')) courseName = 'mysql'; else if (linkText.includes('postgresql')) courseName = 'postgresql'; else if (linkText.includes('mongodb')) courseName = 'mongodb'; else if (linkText.includes('flutter')) courseName = 'flutter'; else if (linkText.includes('react native')) courseName = 'react-native'; else if (linkText.includes('swift')) courseName = 'swift'; else if (linkText.includes('kotlin')) courseName = 'kotlin'; else if (linkText.includes('docker')) courseName = 'docker'; else if (linkText.includes('git')) courseName = 'git'; else if (linkText.includes('aws')) courseName = 'aws'; else if (linkText.includes('kubernetes')) courseName = 'kubernetes'; else if (linkText.includes('go')) courseName = 'go'; else if (linkText.includes('rust')) courseName = 'rust'; else if (linkText.includes('c#')) courseName = 'csharp'; else if (linkText.includes('c++')) courseName = 'cpp'; else if (linkText.includes('bootstrap')) courseName = 'bootstrap'; else if (linkText.includes('jquery')) courseName = 'jquery'; else if (linkText.includes('sass')) courseName = 'sass'; else if (linkText.includes('graphql')) courseName = 'graphql'; else if (linkText.includes('next')) courseName = 'nextjs'; else if (linkText.includes('nuxt')) courseName = 'nuxtjs'; else if (linkText.includes('redis')) courseName = 'redis'; else if (linkText.includes('firebase')) courseName = 'firebase'; else if (linkText.includes('elasticsearch')) courseName = 'elasticsearch'; else if (linkText.includes('c programming')) courseName = 'c'; else if (linkText.includes('ruby')) courseName = 'ruby'; else if (linkText.includes('scala')) courseName = 'scala'; else if (linkText.includes('r programming')) courseName = 'r'; else if (linkText.includes('matlab')) courseName = 'matlab'; else if (linkText.includes('perl')) courseName = 'perl'; else if (linkText.includes('assembly')) courseName = 'assembly'; else if (linkText.includes('lua')) courseName = 'lua'; else if (linkText.includes('xamarin')) courseName = 'xamarin'; else if (linkText.includes('ionic')) courseName = 'ionic'; else if (linkText.includes('phonegap')) courseName = 'phonegap'; else if (linkText.includes('progressive web')) courseName = 'pwa'; else if (linkText.includes('mobile ui')) courseName = 'mobile-ui'; else if (linkText.includes('data structures')) courseName = 'data-structures'; else if (linkText.includes('algorithms')) courseName = 'algorithms'; else if (linkText.includes('object oriented')) courseName = 'oop'; else if (linkText.includes('design patterns')) courseName = 'design-patterns'; else if (linkText.includes('api development')) courseName = 'api-development'; else if (linkText.includes('rest api')) courseName = 'rest-api'; else if (linkText.includes('microservices')) courseName = 'microservices'; else if (linkText.includes('machine learning')) courseName = 'machine-learning'; else if (linkText.includes('artificial intelligence')) courseName = 'ai'; else if (linkText.includes('blockchain')) courseName = 'blockchain'; else if (linkText.includes('game development')) courseName = 'game-dev'; else if (linkText.includes('web components')) courseName = 'webcomponents'; else if (linkText.includes('database design')) courseName = 'database-design'; else if (linkText.includes('sql server')) courseName = 'sqlserver'; else if (linkText.includes('oracle')) courseName = 'oracle'; else if (linkText.includes('mariadb')) courseName = 'mariadb'; else if (linkText.includes('asp.net') || linkText.includes('dotnet')) courseName = 'dotnet'; else if (linkText.includes('flask')) courseName = 'flask'; else if (linkText.includes('android java')) courseName = 'android-java'; else if (linkText.includes('swiftui')) courseName = 'swiftui'; else if (linkText.includes('prompt engineering') || linkText.includes('ai prompt')) courseName = 'prompt-engineering'; showModal(courseName); } }); // Make showModal globally available window.showComingSoonModal = showModal; } // Initialize on page load document.addEventListener('DOMContentLoaded', function() { // Initialize Prism.js if (typeof Prism !== 'undefined') { Prism.highlightAll(); } // Hide loading indicator document.getElementById('loading-indicator').style.display = 'none'; // RTL adjustments if (window.siteConfig.isRTL) { document.body.classList.add('rtl'); } // Initialize Coming Soon Modal initComingSoonModal(); }); </script> <!-- Block for additional JavaScript --> <!-- Analytics (add your tracking code here) --> <!-- Add Google Analytics, Plausible, or other analytics scripts here --> </body> </html>