initial commit

This commit is contained in:
2025-10-26 23:39:49 -05:00
commit 5fb0909e8d
120 changed files with 11279 additions and 0 deletions

318
templates/base.html Normal file
View File

@@ -0,0 +1,318 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Balotario Licencia Clase A - Categoría I{% endblock %}</title>
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.svg') }}">
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}">
<meta name="theme-color" content="#3498db">
<link href="{{ url_for('static', filename='css/bootstrap/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/fontawesome-local.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet">
<style>
:root {
--primary-color: #2c3e50;
--secondary-color: #3498db;
--success-color: #27ae60;
--danger-color: #e74c3c;
--warning-color: #f39c12;
--light-bg: #ecf0f1;
}
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.navbar {
background: rgba(44, 62, 80, 0.95) !important;
backdrop-filter: blur(10px);
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
}
.navbar-brand {
font-weight: bold;
color: white !important;
}
.nav-link {
color: rgba(255, 255, 255, 0.8) !important;
transition: color 0.3s ease;
}
.nav-link:hover {
color: white !important;
}
.container-main {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
margin-top: 2rem;
margin-bottom: 2rem;
padding: 2rem;
}
.card {
border: none;
border-radius: 15px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
}
.btn-primary {
background: linear-gradient(45deg, var(--secondary-color), #5dade2);
border: none;
border-radius: 25px;
padding: 12px 30px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-primary:hover {
background: linear-gradient(45deg, #2980b9, var(--secondary-color));
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(52, 152, 219, 0.3);
}
.btn-success {
background: linear-gradient(45deg, var(--success-color), #58d68d);
border: none;
border-radius: 25px;
padding: 12px 30px;
font-weight: 600;
}
.btn-danger {
background: linear-gradient(45deg, var(--danger-color), #ec7063);
border: none;
border-radius: 25px;
padding: 12px 30px;
font-weight: 600;
}
.btn-warning {
background: linear-gradient(45deg, var(--warning-color), #f7dc6f);
border: none;
border-radius: 25px;
padding: 12px 30px;
font-weight: 600;
color: white;
}
.question-card {
background: white;
border-radius: 15px;
padding: 2rem;
margin-bottom: 2rem;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.option-btn {
width: 100%;
text-align: left;
margin-bottom: 10px;
padding: 15px 20px;
border-radius: 10px;
border: 2px solid #e9ecef;
background: white;
transition: all 0.3s ease;
}
.option-btn:hover {
border-color: var(--secondary-color);
background: rgba(52, 152, 219, 0.1);
}
.option-btn.selected {
border-color: var(--secondary-color);
background: rgba(52, 152, 219, 0.2);
}
.option-btn.correct {
border-color: var(--success-color);
background: rgba(39, 174, 96, 0.2);
}
.option-btn.incorrect {
border-color: var(--danger-color);
background: rgba(231, 76, 60, 0.2);
}
.stats-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 15px;
padding: 1.5rem;
}
.progress {
height: 10px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.2);
}
.progress-bar {
border-radius: 10px;
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.question-image {
max-width: 100%;
height: auto;
border-radius: 10px;
margin: 1rem 0;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid var(--secondary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container">
<a class="navbar-brand" href="/">
<i class="fas fa-car me-2"></i>
Balotario Licencia A-I
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="/">
<i class="fas fa-home me-1"></i>Inicio
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/study">
<i class="fas fa-book me-1"></i>Estudiar
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/practice">
<i class="fas fa-dumbbell me-1"></i>Practicar
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/exam">
<i class="fas fa-clipboard-check me-1"></i>Examen
</a>
</li>
<li class="nav-item">
<button class="btn btn-outline-light btn-sm ms-2" id="theme-toggle"
title="Cambiar tema (Ctrl+D)">
<i class="fas fa-moon" id="theme-icon"></i>
</button>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="container-main">
{% block content %}{% endblock %}
</div>
</div>
<script src="{{ url_for('static', filename='js/modules/bootstrap/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<!-- Modular JavaScript -->
<script src="{{ url_for('static', filename='js/modules/base.js') }}"></script>
<script src="{{ url_for('static', filename='js/modules/question-navigator.js') }}"></script>
<script src="{{ url_for('static', filename='js/modules/study-mode.js') }}"></script>
<script src="{{ url_for('static', filename='js/modules/practice-mode.js') }}"></script>
<script src="{{ url_for('static', filename='js/modules/exam-mode.js') }}"></script>
<script src="{{ url_for('static', filename='js/modules/stats-display.js') }}"></script>
<script>
// Script para el botón de tema
document.addEventListener('DOMContentLoaded', function () {
const themeToggle = document.getElementById('theme-toggle');
const themeIcon = document.getElementById('theme-icon');
if (themeToggle) {
themeToggle.addEventListener('click', function () {
window.themeManager.toggleTheme();
updateThemeIcon();
Utils.playSound('click');
});
}
function updateThemeIcon() {
if (themeIcon && window.themeManager) {
const isDark = window.themeManager.currentTheme === 'dark';
themeIcon.className = isDark ? 'fas fa-sun' : 'fas fa-moon';
}
}
// Inicializar icono después de que se cargue el themeManager
setTimeout(() => {
updateThemeIcon();
// Asegurar que el tema se aplique al cargar la página
if (window.themeManager) {
window.themeManager.applyTheme();
}
}, 100);
});
</script>
{% block scripts %}{% endblock %}
</body>
</html>

329
templates/exam.html Normal file
View File

@@ -0,0 +1,329 @@
{% extends "base.html" %}
{% block title %}Examen Simulado - Balotario Licencia A-I{% endblock %}
{% block content %}
<div class="text-center mb-4">
<h2 class="fw-bold text-warning">
<i class="fas fa-clipboard-check me-2"></i>
Examen Simulado
</h2>
<p class="text-muted">Simula el examen real con tiempo limitado y obtén tu calificación final</p>
</div>
<div id="exam-setup" class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<h5 class="card-title text-center mb-4">
<i class="fas fa-cog me-2"></i>Configuración del Examen
</h5>
<div class="row g-4">
<div class="col-md-6">
<label class="form-label">Número de preguntas:</label>
<select class="form-select" id="exam-questions">
<option value="20">20 preguntas (Rápido)</option>
<option value="30" selected>30 preguntas (Estándar)</option>
<option value="40">40 preguntas (Completo)</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Tiempo límite:</label>
<select class="form-select" id="exam-time">
<option value="15">15 minutos</option>
<option value="30" selected>30 minutos</option>
<option value="45">45 minutos</option>
<option value="60">60 minutos</option>
</select>
</div>
</div>
<div class="alert alert-info mt-4">
<i class="fas fa-info-circle me-2"></i>
<strong>Instrucciones:</strong>
<ul class="mb-0 mt-2">
<li>Responde todas las preguntas antes de que se acabe el tiempo</li>
<li>Puedes navegar entre preguntas usando los botones</li>
<li>Las preguntas no respondidas se marcarán como incorrectas</li>
<li>Al finalizar verás tu calificación y las respuestas correctas</li>
</ul>
</div>
<div class="text-center mt-4">
<button class="btn btn-warning btn-lg" id="start-exam">
<i class="fas fa-play me-2"></i>Comenzar Examen
</button>
</div>
</div>
</div>
</div>
</div>
<div id="exam-content" style="display: none;">
<div class="row mb-4">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<h6 class="mb-0">
<i class="fas fa-clock me-2"></i>
Tiempo restante: <span id="timer" class="text-warning fw-bold">30:00</span>
</h6>
<div>
<span class="badge bg-warning" id="question-progress">1 de 30</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body text-center">
<h6 class="mb-2">Progreso</h6>
<div class="row">
<div class="col-6">
<h5 class="text-success" id="answered-count">0</h5>
<small>Respondidas</small>
</div>
<div class="col-6">
<h5 class="text-muted" id="remaining-count">30</h5>
<small>Restantes</small>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="question-card fade-in" id="exam-question-container">
<!-- Question content is loaded here -->
</div>
<div class="row mt-4">
<div class="col-md-8">
<div class="d-flex justify-content-between">
<button class="btn btn-outline-secondary" id="prev-exam-btn" disabled>
<i class="fas fa-chevron-left me-2"></i>Anterior
</button>
<button class="btn btn-warning" id="next-exam-btn">
Siguiente<i class="fas fa-chevron-right ms-2"></i>
</button>
</div>
</div>
<div class="col-md-4">
<button class="btn btn-danger w-100" id="finish-exam">
<i class="fas fa-flag-checkered me-2"></i>Finalizar Examen
</button>
</div>
</div>
<!-- Question Navigator -->
<div class="card mt-4">
<div class="card-body">
<h6 class="card-title">Navegador de Preguntas</h6>
<div id="question-navigator" class="d-flex flex-wrap gap-2">
<!-- Navigation buttons are generated here -->
</div>
</div>
</div>
</div>
<div id="exam-results" class="text-center" style="display: none;">
<div class="card">
<div class="card-body">
<div id="result-icon" class="mb-4">
<!-- Icon is generated based on result -->
</div>
<h3 class="mb-3" id="result-title">Examen Completado</h3>
<div class="row justify-content-center mb-4">
<div class="col-md-8">
<div class="row text-center">
<div class="col-3">
<h4 class="text-success" id="exam-correct">0</h4>
<p class="mb-0">Correctas</p>
</div>
<div class="col-3">
<h4 class="text-danger" id="exam-incorrect">0</h4>
<p class="mb-0">Incorrectas</p>
</div>
<div class="col-3">
<h4 class="text-muted" id="exam-unanswered">0</h4>
<p class="mb-0">Sin responder</p>
</div>
<div class="col-3">
<h4 class="text-primary" id="exam-score">0%</h4>
<p class="mb-0">Calificación</p>
</div>
</div>
<div class="progress mb-4" style="height: 25px;">
<div class="progress-bar" id="exam-progress-bar" style="width: 0%"></div>
</div>
<div id="pass-message" class="alert" style="display: none;">
<!-- Pass/fail message -->
</div>
</div>
</div>
<div class="d-flex gap-2 justify-content-center">
<button class="btn btn-warning" id="retake-exam">
<i class="fas fa-redo me-2"></i>Repetir Examen
</button>
<button class="btn btn-outline-primary" id="review-answers">
<i class="fas fa-eye me-2"></i>Revisar Respuestas
</button>
<a href="/" class="btn btn-outline-secondary">
<i class="fas fa-home me-2"></i>Volver al Inicio
</a>
</div>
</div>
</div>
</div>
<div id="exam-review" style="display: none;">
<div class="text-center mb-4">
<h3 class="fw-bold text-primary">
<i class="fas fa-eye me-2"></i>
Revisión de Respuestas
</h3>
<p class="text-muted">Revisa tus respuestas y las correctas</p>
</div>
<div class="row mb-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<h6 class="mb-0">
<span class="badge bg-success me-2" id="review-correct-count">0</span>Correctas
<span class="badge bg-danger me-2 ms-3" id="review-incorrect-count">0</span>Incorrectas
<span class="badge bg-secondary me-2 ms-3" id="review-unanswered-count">0</span>Sin responder
</h6>
<div>
<span class="badge bg-primary" id="review-progress">1 de 30</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="question-card fade-in" id="review-question-container">
<!-- Review question content is loaded here -->
</div>
<div class="row mt-4">
<div class="col-md-8">
<div class="d-flex justify-content-between">
<button class="btn btn-outline-secondary" id="prev-review-btn" disabled>
<i class="fas fa-chevron-left me-2"></i>Anterior
</button>
<button class="btn btn-primary" id="next-review-btn">
Siguiente<i class="fas fa-chevron-right ms-2"></i>
</button>
</div>
</div>
<div class="col-md-4">
<button class="btn btn-outline-secondary w-100" id="back-to-results">
<i class="fas fa-arrow-left me-2"></i>Volver a Resultados
</button>
</div>
</div>
<!-- Question Navigator for Review -->
<div class="card mt-4">
<div class="card-body">
<h6 class="card-title">Navegador de Preguntas</h6>
<div class="d-flex flex-wrap gap-2 mb-3">
<span class="badge bg-success me-2">
<i class="fas fa-check me-1"></i>Correcta
</span>
<span class="badge bg-danger me-2">
<i class="fas fa-times me-1"></i>Incorrecta
</span>
<span class="badge bg-secondary me-2">
<i class="fas fa-question me-1"></i>Sin responder
</span>
</div>
<div id="review-navigator" class="d-flex flex-wrap gap-2">
<!-- Navigation buttons are generated here -->
</div>
</div>
</div>
</div>
<!-- Custom confirmation modal -->
<div id="confirmModal" style="display: none;">
<div id="confirmBackdrop" style="
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1050;
"></div>
<div id="confirmDialog" style="
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1055;
background: white;
border-radius: 15px;
box-shadow: 0 15px 35px rgba(0,0,0,0.3);
min-width: 400px;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
">
<div style="
padding: 20px 25px 15px 25px;
border-bottom: 1px solid #dee2e6;
display: flex;
justify-content: space-between;
align-items: center;
">
<h5 style="margin: 0; color: #333;">Confirmar acción</h5>
<button id="confirmModalClose" style="
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
">&times;</button>
</div>
<div style="padding: 20px 25px;">
<p id="confirm-message" style="margin: 0 0 10px 0; color: #333;">¿Estás seguro de que quieres finalizar el examen?</p>
<p style="margin: 0; color: #666; font-size: 14px;">Tienes <span id="unanswered-warning"></span> preguntas sin responder.</p>
</div>
<div style="
padding: 15px 25px 20px 25px;
border-top: 1px solid #dee2e6;
display: flex;
gap: 10px;
justify-content: flex-end;
">
<button id="confirmModalCancel" class="btn btn-secondary">Cancelar</button>
<button id="confirm-finish" class="btn btn-danger">Finalizar</button>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
// Exam mode is now handled by the ExamMode module
// The module auto-initializes when the DOM is ready
console.log('Exam mode template loaded - using modular JavaScript');
</script>
{% endblock %}

269
templates/index.html Normal file
View File

@@ -0,0 +1,269 @@
{% extends "base.html" %}
{% block content %}
<div class="text-center mb-5">
<h1 class="display-4 fw-bold text-primary mb-3">
<i class="fas fa-graduation-cap me-3"></i>
Balotario Licencia Clase A - Categoría I
</h1>
<p class="lead text-muted">Prepárate para tu examen de manejo con {{ total_questions }} preguntas oficiales del MTC
</p>
</div>
<div class="row g-4">
<div class="col-md-6 col-lg-3">
<div class="card h-100 text-center">
<div class="card-body d-flex flex-column">
<div class="mb-3">
<i class="fas fa-book fa-3x text-primary"></i>
</div>
<h5 class="card-title">Modo Estudio</h5>
<p class="card-text flex-grow-1">
Revisa todas las preguntas con sus respuestas correctas. Perfecto para aprender.
</p>
<a href="/study" class="btn btn-primary">
<i class="fas fa-play me-2"></i>Comenzar a Estudiar
</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card h-100 text-center">
<div class="card-body d-flex flex-column">
<div class="mb-3">
<i class="fas fa-dumbbell fa-3x text-success"></i>
</div>
<h5 class="card-title">Modo Práctica</h5>
<p class="card-text flex-grow-1">
Practica con preguntas aleatorias y recibe retroalimentación inmediata.
</p>
<a href="/practice" class="btn btn-success">
<i class="fas fa-play me-2"></i>Practicar Ahora
</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card h-100 text-center">
<div class="card-body d-flex flex-column">
<div class="mb-3">
<i class="fas fa-clipboard-check fa-3x text-warning"></i>
</div>
<h5 class="card-title">Examen Simulado</h5>
<p class="card-text flex-grow-1">
Simula el examen real con tiempo limitado y obtén tu calificación final.
</p>
<a href="/exam" class="btn btn-warning">
<i class="fas fa-clock me-2"></i>Tomar Examen
</a>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card h-100 text-center stats-card">
<div class="card-body d-flex flex-column">
<div class="mb-3">
<i class="fas fa-chart-line fa-3x text-white"></i>
</div>
<h5 class="card-title text-white">Estadísticas</h5>
<div class="flex-grow-1">
<div id="stats-content">
<div class="row text-center">
<div class="col-6">
<h4 id="total-answered">0</h4>
<small>Respondidas</small>
</div>
<div class="col-6">
<h4 id="accuracy">0%</h4>
<small>Precisión</small>
</div>
</div>
<div class="mt-3">
<div class="progress">
<div class="progress-bar bg-success" id="accuracy-bar" style="width: 0%"></div>
</div>
</div>
<div class="mt-3">
<button class="btn btn-outline-light btn-sm" id="reset-stats-btn"
title="Restablecer estadísticas">
<i class="fas fa-redo me-1"></i>Restablecer
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-info-circle me-2"></i>
Información del Balotario
</h5>
<div class="row">
<div class="col-md-6">
<ul class="list-unstyled">
<li><i class="fas fa-check text-success me-2"></i>{{ total_questions }} preguntas oficiales
</li>
<li><i class="fas fa-check text-success me-2"></i>Respuestas correctas marcadas</li>
<li><i class="fas fa-check text-success me-2"></i>Imágenes de señales de tránsito</li>
<li><i class="fas fa-check text-success me-2"></i>Seguimiento de progreso</li>
</ul>
</div>
<div class="col-md-6">
<ul class="list-unstyled">
<li><i class="fas fa-check text-success me-2"></i>Interfaz intuitiva y moderna</li>
<li><i class="fas fa-check text-success me-2"></i>Modo examen con cronómetro</li>
<li><i class="fas fa-check text-success me-2"></i>Estadísticas detalladas</li>
<li><i class="fas fa-check text-success me-2"></i>Responsive para móviles</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Statistics reset confirmation modal -->
<div id="resetStatsModal" style="display: none;">
<div id="resetStatsBackdrop" style="
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.6);
z-index: 1050;
backdrop-filter: blur(3px);
"></div>
<div id="resetStatsDialog" style="
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1055;
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
min-width: 400px;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
animation: modalSlideIn 0.3s ease-out;
">
<div style="
padding: 25px 30px 20px 30px;
border-bottom: 1px solid #dee2e6;
display: flex;
justify-content: space-between;
align-items: center;
">
<div style="display: flex; align-items: center;">
<i class="fas fa-exclamation-triangle text-warning me-3" style="font-size: 24px;"></i>
<h5 style="margin: 0; color: #333; font-weight: 600;">Restablecer Estadísticas</h5>
</div>
<button id="resetStatsModalClose" style="
background: none;
border: none;
font-size: 28px;
cursor: pointer;
color: #666;
padding: 0;
width: 35px;
height: 35px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.2s ease;
" onmouseover="this.style.background='#f8f9fa'" onmouseout="this.style.background='none'">&times;</button>
</div>
<div style="padding: 25px 30px;">
<div style="text-align: center; margin-bottom: 20px;">
<i class="fas fa-chart-line text-primary" style="font-size: 48px; opacity: 0.7;"></i>
</div>
<p style="margin: 0 0 15px 0; color: #333; font-size: 16px; text-align: center;">
¿Estás seguro de que quieres restablecer todas tus estadísticas?
</p>
<div
style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 10px; padding: 15px; margin-bottom: 20px;">
<div style="display: flex; align-items: flex-start;">
<i class="fas fa-info-circle text-warning me-2" style="margin-top: 2px;"></i>
<div style="font-size: 14px; color: #856404;">
<strong>Esta acción eliminará:</strong>
<ul style="margin: 8px 0 0 0; padding-left: 20px;">
<li>Preguntas respondidas</li>
<li>Porcentaje de precisión</li>
<li>Racha de respuestas correctas</li>
<li>Tiempo de estudio</li>
<li>Historial de exámenes</li>
</ul>
</div>
</div>
</div>
<p style="margin: 0; color: #666; font-size: 14px; text-align: center;">
<strong>Esta acción no se puede deshacer.</strong>
</p>
</div>
<div style="
padding: 20px 30px 25px 30px;
border-top: 1px solid #dee2e6;
display: flex;
gap: 12px;
justify-content: flex-end;
">
<button id="resetStatsModalCancel" class="btn btn-secondary" style="min-width: 100px;">
<i class="fas fa-times me-1"></i>Cancelar
</button>
<button id="confirmResetStats" class="btn btn-danger" style="min-width: 120px;">
<i class="fas fa-trash-alt me-1"></i>Restablecer
</button>
</div>
</div>
</div>
<style>
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translate(-50%, -60%);
}
to {
opacity: 1;
transform: translate(-50%, -50%);
}
}
@keyframes modalSlideOut {
from {
opacity: 1;
transform: translate(-50%, -50%);
}
to {
opacity: 0;
transform: translate(-50%, -40%);
}
}
.modal-closing {
animation: modalSlideOut 0.2s ease-in forwards;
}
</style>
{% endblock %}
{% block scripts %}
<script>
// Index page stats are now handled by the StatsDisplay module
// The module auto-initializes when the DOM is ready
console.log('Index page template loaded - using modular JavaScript');
</script>
{% endblock %}

217
templates/practice.html Normal file
View File

@@ -0,0 +1,217 @@
{% extends "base.html" %}
{% block title %}Modo Práctica - Balotario Licencia A-I{% endblock %}
{% block content %}
<div class="text-center mb-4">
<h2 class="fw-bold text-success">
<i class="fas fa-dumbbell me-2"></i>
Modo Práctica
</h2>
<p class="text-muted">Practica con preguntas aleatorias y recibe retroalimentación inmediata</p>
</div>
<div class="row mb-4">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0">Configuración de Práctica</h6>
<button class="btn btn-sm btn-outline-success" id="new-session">
<i class="fas fa-refresh me-1"></i>Nueva Sesión
</button>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Número de preguntas:</label>
<select class="form-select" id="question-count">
<option value="10">10 preguntas</option>
<option value="20" selected>20 preguntas</option>
<option value="30">30 preguntas</option>
<option value="50">50 preguntas</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">&nbsp;</label>
<button class="btn btn-success w-100" id="start-practice">
<i class="fas fa-play me-1"></i>Comenzar Práctica
</button>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card stats-enhanced">
<div class="card-body text-center position-relative">
<h6 class="text-white mb-3">Estadísticas de Sesión</h6>
<div class="row g-2">
<div class="col-6 col-sm-4">
<div class="stats-number" id="session-correct">0</div>
<small class="d-block">Correctas</small>
</div>
<div class="col-6 col-sm-4">
<div class="stats-number" id="session-incorrect">0</div>
<small class="d-block">Incorrectas</small>
</div>
<div class="col-12 col-sm-4">
<div class="stats-number" id="session-accuracy">0%</div>
<small class="d-block">Precisión</small>
</div>
</div>
<div class="mt-3">
<div class="progress" style="height: 8px;">
<div class="progress-bar bg-light" id="session-progress" style="width: 0%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="loading" class="loading">
<div class="spinner"></div>
</div>
<div id="practice-content" style="display: none;">
<div class="question-card fade-in" id="question-container">
<!-- Question content is loaded here -->
</div>
<div class="d-flex justify-content-between mt-4">
<div>
<span class="badge bg-primary fs-6" id="question-counter">1 de 20</span>
</div>
<div class="d-flex gap-2">
<button class="btn btn-outline-secondary" id="skip-question">
<i class="fas fa-forward me-2"></i>Saltar
</button>
<button class="btn btn-success" id="next-question" style="display: none;">
Siguiente<i class="fas fa-chevron-right ms-2"></i>
</button>
</div>
</div>
</div>
<div id="practice-complete" class="text-center" style="display: none;">
<div class="card">
<div class="card-body">
<i class="fas fa-trophy fa-4x text-warning mb-4"></i>
<h3 class="mb-3">¡Práctica Completada!</h3>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="row text-center mb-4">
<div class="col-4">
<h4 class="text-success" id="final-correct">0</h4>
<p class="mb-0">Correctas</p>
</div>
<div class="col-4">
<h4 class="text-danger" id="final-incorrect">0</h4>
<p class="mb-0">Incorrectas</p>
</div>
<div class="col-4">
<h4 class="text-primary" id="final-accuracy">0%</h4>
<p class="mb-0">Precisión</p>
</div>
</div>
<div class="progress mb-4" style="height: 20px;">
<div class="progress-bar bg-success" id="final-progress" style="width: 0%"></div>
</div>
<div class="d-flex gap-2 justify-content-center">
<button class="btn btn-success" id="practice-again">
<i class="fas fa-redo me-2"></i>Practicar de Nuevo
</button>
<a href="/" class="btn btn-outline-primary">
<i class="fas fa-home me-2"></i>Volver al Inicio
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="welcome-message" class="text-center">
<div class="card">
<div class="card-body">
<i class="fas fa-play-circle fa-4x text-success mb-4"></i>
<h4>¡Listo para Practicar!</h4>
<p class="text-muted">Configura tu sesión de práctica y comienza a responder preguntas aleatorias.</p>
<p class="small text-muted">
<i class="fas fa-lightbulb me-1"></i>
Tip: Recibirás retroalimentación inmediata después de cada respuesta.
</p>
</div>
</div>
</div>
<style>
/* Mobile-specific improvements for session statistics */
@media (max-width: 576px) {
.stats-enhanced .card-body {
padding: 1rem 0.75rem;
}
.stats-enhanced h6 {
font-size: 0.9rem;
margin-bottom: 1rem !important;
}
.stats-number {
font-size: 1.5rem !important;
font-weight: bold;
line-height: 1.2;
margin-bottom: 0.25rem;
}
.stats-enhanced small {
font-size: 0.75rem;
opacity: 0.9;
line-height: 1.1;
}
.stats-enhanced .row {
margin: 0 -0.25rem;
}
.stats-enhanced .row > div {
padding: 0.5rem 0.25rem;
}
/* Better spacing for the accuracy stat when it's full width */
.stats-enhanced .col-12 {
margin-top: 0.5rem;
padding-top: 0.75rem;
border-top: 1px solid rgba(255,255,255,0.2);
}
}
/* Tablet improvements */
@media (min-width: 577px) and (max-width: 768px) {
.stats-enhanced .stats-number {
font-size: 1.75rem;
font-weight: bold;
}
.stats-enhanced small {
font-size: 0.8rem;
}
}
/* General stats number styling */
.stats-number {
font-size: 2rem;
font-weight: bold;
color: white;
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
</style>
{% endblock %}
{% block scripts %}
<script>
// Practice mode is now handled by the PracticeMode module
// The module auto-initializes when the DOM is ready
console.log('Practice mode template loaded - using modular JavaScript');
</script>
{% endblock %}

287
templates/study.html Normal file
View File

@@ -0,0 +1,287 @@
{% extends "base.html" %}
{% block title %}Modo Estudio - Balotario Licencia A-I{% endblock %}
{% block content %}
<div class="text-center mb-4">
<h2 class="fw-bold text-primary">
<i class="fas fa-book me-2"></i>
Modo Estudio
</h2>
<p class="text-muted">Revisa todas las preguntas con sus respuestas correctas</p>
</div>
<div class="row mb-4">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0">Filtros de Estudio</h6>
<button class="btn btn-sm btn-outline-primary" id="reset-filters">
<i class="fas fa-refresh me-1"></i>Resetear
</button>
</div>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Desde pregunta:</label>
<input type="number" class="form-control" id="start-question" min="1" max="200" value="1">
</div>
<div class="col-md-4">
<label class="form-label">Hasta pregunta:</label>
<input type="number" class="form-control" id="end-question" min="1" max="200" value="200">
</div>
<div class="col-md-4">
<label class="form-label">&nbsp;</label>
<button class="btn btn-primary w-100" id="apply-filters">
<i class="fas fa-filter me-1"></i>Aplicar Filtros
</button>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card stats-card">
<div class="card-body text-center">
<h6 class="text-white mb-3">Progreso de Estudio</h6>
<div class="row">
<div class="col-6">
<h4 class="text-white" id="current-question">1</h4>
<small>Pregunta Actual</small>
</div>
<div class="col-6">
<h4 class="text-white" id="total-questions">0</h4>
<small>Total</small>
</div>
</div>
<div class="progress mt-3">
<div class="progress-bar bg-light" id="study-progress" style="width: 0%"></div>
</div>
</div>
</div>
</div>
</div>
<div id="loading" class="loading">
<div class="spinner"></div>
</div>
<div id="study-content" style="display: none;">
<div class="question-card fade-in" id="question-container">
<!-- Question content is loaded here -->
</div>
<div class="d-flex justify-content-between mt-4">
<button class="btn btn-outline-secondary" id="prev-btn" disabled>
<i class="fas fa-chevron-left me-2"></i>Anterior
</button>
<div class="d-flex gap-2">
<button class="btn btn-outline-primary" id="show-answer">
<i class="fas fa-eye me-2"></i>Mostrar Respuesta
</button>
<button class="btn btn-outline-primary" id="hide-answer" style="display: none;">
<i class="fas fa-eye-slash me-2"></i>Ocultar Respuesta
</button>
</div>
<button class="btn btn-primary" id="next-btn">
Siguiente<i class="fas fa-chevron-right ms-2"></i>
</button>
</div>
<!-- Question Navigator -->
<div class="card mt-4">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="card-title mb-0">
<i class="fas fa-map me-2"></i>Navegador de Preguntas
</h6>
<div class="d-flex gap-2 align-items-center">
<small class="text-muted">Ir a:</small>
<input type="number" class="form-control form-control-sm" id="jump-to-question"
min="1" max="200" placeholder="#" style="width: 60px;">
<button class="btn btn-sm btn-outline-primary" id="jump-btn" title="Ir a pregunta">
<i class="fas fa-arrow-right"></i>
</button>
<button class="btn btn-sm btn-outline-warning" id="reset-visited-btn" title="Limpiar preguntas visitadas">
<i class="fas fa-redo"></i>
</button>
</div>
</div>
<div id="question-navigator" class="question-navigator">
<!-- Question navigation buttons will be generated here -->
</div>
<div class="mt-2 d-flex justify-content-between align-items-center">
<div class="navigator-legend">
<small class="text-muted">
<span class="badge bg-primary me-2"></span>Actual
<span class="badge bg-success me-2 ms-2"></span>Visitada
<span class="badge bg-outline-secondary me-2 ms-2"></span>Pendiente
</small>
</div>
<small class="text-muted" id="navigator-progress">0 de 0 visitadas</small>
</div>
</div>
</div>
</div>
<div id="no-questions" class="text-center" style="display: none;">
<div class="card">
<div class="card-body">
<i class="fas fa-exclamation-triangle fa-3x text-warning mb-3"></i>
<h5>No se encontraron preguntas</h5>
<p class="text-muted">Ajusta los filtros para ver las preguntas disponibles.</p>
</div>
</div>
</div>
<style>
/* Question Navigator Styles */
.question-navigator {
display: flex;
flex-wrap: wrap;
gap: 4px;
max-height: 200px;
overflow-y: auto;
padding: 8px;
background: #f8f9fa;
border-radius: 8px;
border: 1px solid #dee2e6;
}
.question-nav-btn {
width: 35px;
height: 35px;
border: 1px solid #dee2e6;
background: white;
color: #6c757d;
border-radius: 6px;
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.question-nav-btn:hover {
border-color: #3498db;
background: #e3f2fd;
transform: translateY(-1px);
}
.question-nav-btn.current {
background: #3498db;
color: white;
border-color: #2980b9;
font-weight: bold;
box-shadow: 0 2px 4px rgba(52, 152, 219, 0.3);
}
.question-nav-btn.visited {
background: #27ae60;
color: white;
border-color: #229954;
}
.question-nav-btn.visited:hover {
background: #2ecc71;
border-color: #27ae60;
}
.navigator-legend .badge {
font-size: 0.7rem;
padding: 0.25em 0.4em;
}
/* Mobile responsive */
@media (max-width: 576px) {
.question-navigator {
max-height: 150px;
gap: 3px;
padding: 6px;
}
.question-nav-btn {
width: 30px;
height: 30px;
font-size: 0.75rem;
}
.navigator-legend {
display: none;
}
#jump-to-question {
width: 50px !important;
}
}
/* Tablet responsive */
@media (min-width: 577px) and (max-width: 768px) {
.question-navigator {
max-height: 180px;
}
.question-nav-btn {
width: 32px;
height: 32px;
}
}
/* Smooth scrolling for navigator */
.question-navigator {
scroll-behavior: smooth;
}
/* Jump to question input styling */
#jump-to-question {
text-align: center;
font-weight: bold;
}
#jump-to-question:focus {
border-color: #3498db;
box-shadow: 0 0 0 0.2rem rgba(52, 152, 219, 0.25);
}
/* Reset visited button styling */
#reset-visited-btn {
transition: all 0.2s ease;
}
#reset-visited-btn:hover {
background: #ffc107;
border-color: #ffc107;
color: #000;
transform: translateY(-1px);
}
#reset-visited-btn:active {
transform: scale(0.95);
}
/* Mobile adjustments for navigator controls */
@media (max-width: 576px) {
.card-title {
font-size: 0.9rem;
}
#reset-visited-btn, #jump-btn {
padding: 0.25rem 0.5rem;
}
#reset-visited-btn i, #jump-btn i {
font-size: 0.8rem;
}
}
</style>
{% endblock %}
{% block scripts %}
<script>
// Study mode is now handled by the StudyMode module
// The module auto-initializes when the DOM is ready
console.log('Study mode template loaded - using modular JavaScript');
</script>
{% endblock %}