Traduccion para paginas de atleta

This commit is contained in:
JorgeLuisOZ 2025-06-10 17:35:34 -06:00
parent 56cba7f7ab
commit e6a45a0369
4 changed files with 278 additions and 69 deletions

View File

@ -4,45 +4,65 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Panel del Atleta</title> <title>Panel del Atleta</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" />
<link href="css/estiloAtletaSimulador.css" rel="stylesheet" />
<link rel="stylesheet" href="css/estiloAtletaSimulador.css"/>
<link rel="stylesheet" href="css/navbar.css">
</head> </head>
<body class="bg-light"> <body class="bg-light">
<!-- NAV -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top shadow-sm px-4 py-3"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top shadow-sm px-4 py-3">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand fw-bold text-white">SwimmingArt</a> <a class="navbar-brand fw-bold text-white">SwimmingArt</a>
<div class="ms-auto d-flex gap-4 align-items-center"> <div class="ms-auto d-flex gap-4 align-items-center">
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-outline-light dropdown-toggle d-flex align-items-center gap-2 px-3 py-1" type="button" id="userDropdown" data-bs-toggle="dropdown"> <button class="btn btn-outline-light dropdown-toggle d-flex align-items-center gap-2 px-3 py-1" type="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<svg width="20" height="20" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
<path d="M11 10a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/> <path d="M11 10a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-4.546 12.174c.03-.256.071-.512.124-.767C4.28 10.798 5.94 10 8 10s3.72.798 4.422 2.407c.053.255.094.511.124.767A7 7 0 0 0 8 1z"/> <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-4.546 12.174c.03-.256.071-.512.124-.767C4.28 10.798 5.94 10 8 10s3.72.798 4.422 2.407c.053.255.094.511.124.767A7 7 0 0 0 8 1z"/>
</svg> </svg>
<span id="nombreUsuarioHeader" class="fw-semibold">Usuario</span> <span id="nombreUsuarioHeader" class="fw-semibold">Usuario</span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end text-center p-3" <ul class="dropdown-menu dropdown-menu-end text-center p-3"
style="background-color: #0d6efd; color: white; border-radius: 0 0 8px 8px;"> aria-labelledby="userDropdown"
<li> style="background-color: #0d6efd; color: white; border-radius: 0 0 8px 8px; min-width: 100%; max-width: 250px;">
<select id="langSelector" class="form-select form-select-sm mb-3 bg-white text-dark border-0 rounded"> <!-- Mostrar rol -->
<li class="mb-2">
<span id="nombreUsuarioDropdown" class="fw-semibold text-white d-block" data-i18n="role">Atleta</span>
</li>
<!-- Selector de idioma -->
<li class="mb-1">
<div class="d-flex align-items-center justify-content-center gap-2 w-100">
<i class="bi bi-globe" style="color: white; font-size: 1rem;"></i>
<select id="langSelector" class="form-select form-select-sm" style="border: none; border-radius: 6px; max-width: 140px;">
<option value="es">Español</option> <option value="es">Español</option>
<option value="en">English</option> <option value="en">English</option>
<option value="fr">Français</option> <option value="fr">Français</option>
</select> </select>
</div>
</li>
<!-- Botón salir -->
<li>
<button class="btn btn-danger btn-sm w-100" onclick="logout()" data-i18n="logout">Salir</button>
</li> </li>
<li><button class="btn btn-danger btn-sm w-100" onclick="logout()">Salir</button></li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
</nav> </nav>
<!-- CONTENIDO PRINCIPAL -->
<div class="container py-5"> <div class="container py-5">
<h2 class="fw-bold fs-3 mb-2 text-center text-primary">Equipos Disponibles</h2> <h2 class="fw-bold fs-3 mb-2 text-center text-primary" data-i18n="titulo">Equipos Disponibles</h2>
<p class="text-muted text-center mb-4">Consulta las competencias en las que estás asignado</p> <p class="text-muted text-center mb-4" data-i18n="subtitulo">Consulta las competencias en las que estás asignado</p>
<div id="rutinas-list" class="row justify-content-center"></div> <div id="rutinas-list" class="row justify-content-center"></div>
</div> </div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="js/atleta.js"></script> <script src="js/atleta.js"></script>
</body> </body>

View File

@ -1,9 +1,99 @@
document.addEventListener("DOMContentLoaded", async () => { const traducciones = {
es: {
logout: "Salir",
role: "Atleta",
titulo: "Equipos Disponibles",
subtitulo: "Consulta las competencias en las que estás asignado",
sinSesion: "No se encontró tu sesión. Inicia sesión nuevamente.",
sinAsignacion: "No estás asignado a ninguna formación aún.",
errorCarga: "Error al cargar tus asignaciones.",
rutinaSinNombre: "Rutina sin nombre",
formacion: "Formación",
duracion: "Duración",
notas: "Notas",
rol: "Rol",
id: "ID",
figura: "Figura",
verSimulacion: "Ver simulación"
},
en: {
logout: "Logout",
role: "Athlete",
titulo: "Available Teams",
subtitulo: "Check the competitions you are assigned to",
sinSesion: "Session not found. Please log in again.",
sinAsignacion: "You are not assigned to any formation yet.",
errorCarga: "Error loading your assignments.",
rutinaSinNombre: "Unnamed routine",
formacion: "Formation",
duracion: "Duration",
notas: "Notes",
rol: "Role",
id: "ID",
figura: "Figure",
verSimulacion: "View simulation"
},
fr: {
logout: "Se déconnecter",
role: "Athlète",
titulo: "Équipes disponibles",
subtitulo: "Consultez les compétitions auxquelles vous êtes affecté",
sinSesion: "Session introuvable. Veuillez vous reconnecter.",
sinAsignacion: "Vous n'êtes affecté à aucune formation pour le moment.",
errorCarga: "Erreur lors du chargement de vos affectations.",
rutinaSinNombre: "Routine sans nom",
formacion: "Formation",
duracion: "Durée",
notas: "Remarques",
rol: "Rôle",
id: "ID",
figura: "Figure",
verSimulacion: "Voir la simulation"
}
};
let langActual = 'es';
function translateStatic() {
document.querySelector('[data-i18n="logout"]').textContent = traducciones[langActual].logout;
document.querySelector('h2').textContent = traducciones[langActual].titulo;
document.querySelector('p.text-muted').textContent = traducciones[langActual].subtitulo;
const rolEl = document.querySelector('[data-i18n="role"]');
if (rolEl) rolEl.textContent = traducciones[langActual].role;
}
document.getElementById('langSelector')?.addEventListener('change', async (e) => {
langActual = e.target.value;
translateStatic();
cargarAsignaciones();
const userId = sessionStorage.getItem("userId");
if (userId) {
await fetch(`/api/users/${userId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ language: langActual })
});
}
});
function logout() {
sessionStorage.clear();
alert("Sesión cerrada");
window.location.href = "../index.html";
}
function verSimulador(rutinaId, index) {
window.location.href = `simulador.html?routineId=${rutinaId}&formationIndex=${index}`;
}
async function cargarAsignaciones() {
const atletaId = sessionStorage.getItem("userId"); const atletaId = sessionStorage.getItem("userId");
const contenedor = document.getElementById("rutinas-list"); const contenedor = document.getElementById("rutinas-list");
if (!atletaId) { if (!atletaId) {
contenedor.innerHTML = "<p>No se encontró tu sesión. Inicia sesión nuevamente.</p>"; contenedor.innerHTML = `<p>${traducciones[langActual].sinSesion}</p>`;
return; return;
} }
@ -13,27 +103,28 @@ document.addEventListener("DOMContentLoaded", async () => {
const formaciones = await res.json(); const formaciones = await res.json();
if (formaciones.length === 0) { if (formaciones.length === 0) {
contenedor.innerHTML = "<p>No estás asignado a ninguna formación aún.</p>"; contenedor.innerHTML = `<p>${traducciones[langActual].sinAsignacion}</p>`;
return; return;
} }
contenedor.innerHTML = '';
formaciones.forEach(f => { formaciones.forEach(f => {
const card = document.createElement("div"); const card = document.createElement("div");
card.className = "card text-start my-3 shadow-sm"; card.className = "card text-start my-3 shadow-sm";
card.innerHTML = ` card.innerHTML = `
<div class="card-body"> <div class="card-body">
<h5 class="card-title text-primary fw-bold">${f.rutinaNombre || "Rutina sin nombre"}</h5> <h5 class="card-title text-primary fw-bold">${f.rutinaNombre || traducciones[langActual].rutinaSinNombre}</h5>
<h6 class="card-subtitle mb-2 text-muted">Formación: ${f.nombreColoquial || "(sin nombre)"}</h6> <h6 class="card-subtitle mb-2 text-muted">${traducciones[langActual].formacion}: ${f.nombreColoquial || "(sin nombre)"}</h6>
<p class="card-text small mb-1"> <p class="card-text small mb-1">
<strong>Duración:</strong> ${f.duracion || "?"}s<br> <strong>${traducciones[langActual].duracion}:</strong> ${f.duracion || "?"}s<br>
<strong>Notas:</strong> ${f.notasTacticas || "Sin notas"}<br> <strong>${traducciones[langActual].notas}:</strong> ${f.notasTacticas || ""}<br>
<strong>Rol:</strong> ${f.atleta.rol || "N/A"} | <strong>${traducciones[langActual].rol}:</strong> ${f.atleta.rol || "N/A"} |
<strong>ID:</strong> ${f.atleta.idPersonalizado || "N/A"} | <strong>${traducciones[langActual].id}:</strong> ${f.atleta.idPersonalizado || "N/A"} |
<strong>Figura:</strong> ${f.atleta.figura || ""} <strong>${traducciones[langActual].figura}:</strong> ${f.atleta.figura || ""}
</p> </p>
<button class="btn btn-sm btn-outline-success" onclick="verSimulador('${f.rutinaId}', ${f.index})"> <button class="btn btn-sm btn-outline-success" onclick="verSimulador('${f.rutinaId}', ${f.index})">
Ver simulación ${traducciones[langActual].verSimulacion}
</button> </button>
</div> </div>
`; `;
@ -41,24 +132,12 @@ document.addEventListener("DOMContentLoaded", async () => {
}); });
} catch (err) { } catch (err) {
console.error("❌ Error al obtener formaciones:", err); console.error("❌ Error al obtener formaciones:", err);
contenedor.innerHTML = "<p>Error al cargar tus asignaciones.</p>"; contenedor.innerHTML = `<p>${traducciones[langActual].errorCarga}</p>`;
} }
});
function verSimulador(rutinaId, index) {
window.location.href = `simulador.html?routineId=${rutinaId}&formationIndex=${index}`;
} }
function logout() { async function loadUserInfoYIdioma() {
sessionStorage.clear();
alert("Sesión cerrada");
window.location.href = "../index.html";
}
// Mostrar nombre de usuario
window.addEventListener("DOMContentLoaded", async () => {
const userId = sessionStorage.getItem("userId"); const userId = sessionStorage.getItem("userId");
if (!userId) return; if (!userId) return;
try { try {
@ -68,7 +147,18 @@ window.addEventListener("DOMContentLoaded", async () => {
if (user?.name) { if (user?.name) {
document.getElementById("nombreUsuarioHeader").textContent = user.name; document.getElementById("nombreUsuarioHeader").textContent = user.name;
} }
if (user?.language && traducciones[user.language]) {
langActual = user.language;
const selector = document.getElementById('langSelector');
if (selector) selector.value = langActual;
}
translateStatic();
cargarAsignaciones();
} catch (err) { } catch (err) {
console.error("❌ Error al obtener usuario:", err); console.error("❌ Error al obtener usuario:", err);
} }
}); }
document.addEventListener("DOMContentLoaded", loadUserInfoYIdioma);

View File

@ -1,7 +1,92 @@
const traducciones = {
es: {
"nav.init": "Panel Atleta",
logout: "Salir",
role: "Atleta",
"sim.title": "Cargando rutina...",
"sim.play": "▶ Reproducir",
"sim.pause": "⏸ Pausar",
"sim.timeline": "Línea de Tiempo"
},
en: {
"nav.init": "Athlete Panel",
logout: "Logout",
role: "Athlete",
"sim.title": "Loading routine...",
"sim.play": "▶ Play",
"sim.pause": "⏸ Pause",
"sim.timeline": "Timeline"
},
fr: {
"nav.init": "Panneau Athlète",
logout: "Se déconnecter",
role: "Athlète",
"sim.title": "Chargement de la routine...",
"sim.play": "▶ Lecture",
"sim.pause": "⏸ Pause",
"sim.timeline": "Ligne du Temps"
}
};
let langActual = 'es';
function t(clave) {
return traducciones[langActual]?.[clave] || clave;
}
function translateStatic() {
const mapping = {
'nav.init': '[data-i18n="nav.init"]',
'logout': '[data-i18n="logout"]',
'sim.title': '#tituloRutina',
'sim.timeline': '[data-i18n="sim.timeline"]',
'sim.play': '#playPauseBtn',
'role': '[data-i18n="role"]'
};
for (const [clave, selector] of Object.entries(mapping)) {
const el = document.querySelector(selector);
if (el) el.textContent = t(clave);
}
}
document.getElementById('langSelector')?.addEventListener('change', async (e) => {
langActual = e.target.value;
translateStatic();
const userId = sessionStorage.getItem("userId");
if (userId) {
await fetch(`/api/users/${userId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ language: langActual })
});
}
});
document.addEventListener("DOMContentLoaded", async () => { document.addEventListener("DOMContentLoaded", async () => {
const rutinaId = new URLSearchParams(window.location.search).get("routineId"); const rutinaId = new URLSearchParams(window.location.search).get("routineId");
const formationIndex = parseInt(new URLSearchParams(window.location.search).get("formationIndex")); const formationIndex = parseInt(new URLSearchParams(window.location.search).get("formationIndex"));
const userId = sessionStorage.getItem("userId");
if (userId) {
try {
const user = await fetch(`/api/users/${userId}`).then(res => res.json());
if (user?.language && traducciones[user.language]) {
langActual = user.language;
const selector = document.getElementById("langSelector");
if (selector) selector.value = langActual;
}
if (user?.name) {
document.getElementById("nombreUsuarioHeader").textContent = user.name;
}
} catch (err) {
console.error("❌ Error al obtener usuario:", err);
}
}
translateStatic();
if (!rutinaId || isNaN(formationIndex)) { if (!rutinaId || isNaN(formationIndex)) {
return alert("No se proporcionó ID de rutina o índice de formación."); return alert("No se proporcionó ID de rutina o índice de formación.");
} }
@ -22,13 +107,14 @@ document.addEventListener("DOMContentLoaded", async () => {
if (rutina.musicUrl) { if (rutina.musicUrl) {
audioPlayer.src = rutina.musicUrl; audioPlayer.src = rutina.musicUrl;
playBtn.textContent = t("sim.play");
playBtn.onclick = () => { playBtn.onclick = () => {
if (audioPlayer.paused) { if (audioPlayer.paused) {
audioPlayer.play(); audioPlayer.play();
playBtn.textContent = "⏸ Pausar"; playBtn.textContent = t("sim.pause");
} else { } else {
audioPlayer.pause(); audioPlayer.pause();
playBtn.textContent = "▶ Reproducir"; playBtn.textContent = t("sim.play");
} }
}; };
} else { } else {
@ -58,7 +144,7 @@ document.addEventListener("DOMContentLoaded", async () => {
const divPiscina = document.getElementById("piscina"); const divPiscina = document.getElementById("piscina");
divPiscina.style.width = `${piscinaWidth}px`; divPiscina.style.width = `${piscinaWidth}px`;
divPiscina.style.height = `${piscinaHeight}px`; divPiscina.style.height = `${piscinaHeight}px`;
divPiscina.style.background = "#d4f0ff"; // Azul claro divPiscina.style.background = "#d4f0ff";
document.getElementById("piscinaContainer").style.width = `${piscinaWidth + 20}px`; document.getElementById("piscinaContainer").style.width = `${piscinaWidth + 20}px`;
function dibujarCuadricula(layer, ancho, alto, tamano = 45) { function dibujarCuadricula(layer, ancho, alto, tamano = 45) {
@ -126,9 +212,7 @@ document.addEventListener("DOMContentLoaded", async () => {
points: [atleta.direccion.x1, atleta.direccion.y1, atleta.direccion.x2, atleta.direccion.y2], points: [atleta.direccion.x1, atleta.direccion.y1, atleta.direccion.x2, atleta.direccion.y2],
stroke: 'black', stroke: 'black',
strokeWidth: 2, strokeWidth: 2,
dash: [4, 4], dash: [4, 4]
pointerLength: 10,
pointerWidth: 10
}); });
layer.add(dir); layer.add(dir);
} }
@ -144,10 +228,8 @@ document.addEventListener("DOMContentLoaded", async () => {
return; return;
} }
// Pintar solo esta formación
formacion.atletas.forEach(dibujarAtleta); formacion.atletas.forEach(dibujarAtleta);
// Mostrar título visual
const block = document.createElement("button"); const block = document.createElement("button");
block.className = "btn btn-outline-primary btn-sm me-2 step"; block.className = "btn btn-outline-primary btn-sm me-2 step";
block.textContent = `${formacion.nombreColoquial || `Formación ${formationIndex + 1}`} (${formacion.duracion || '?'}s)`; block.textContent = `${formacion.nombreColoquial || `Formación ${formationIndex + 1}`} (${formacion.duracion || '?'}s)`;

View File

@ -3,37 +3,52 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Simulador de Rutina</title> <title>Simulador de Rutina</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet"/>
<link href="css/estiloAtletaSimulador.css" rel="stylesheet" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link href="css/estiloAtletaSimulador.css" rel="stylesheet" />
<link rel="stylesheet" href="css/navbar.css">
</head> </head>
<body class="bg-light"> <body class="bg-light">
<!-- NAV -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top shadow-sm px-4 py-3"> <nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top shadow-sm px-4 py-3">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand fw-bold text-white">SwimmingArt</a> <a class="navbar-brand fw-bold text-white">SwimmingArt</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="ms-auto d-flex gap-4 align-items-center"> <div class="ms-auto d-flex gap-4 align-items-center">
<a href="atleta.html" class="nav-link text-white">Volver al Panel</a> <a href="atleta.html" class="nav-link text-white" data-i18n="nav.init">Panel Atleta</a>
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-outline-light dropdown-toggle d-flex align-items-center gap-2 px-3 py-1" type="button" id="userDropdown" data-bs-toggle="dropdown"> <button class="btn btn-outline-light dropdown-toggle d-flex align-items-center gap-2 px-3 py-1" type="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<svg width="20" height="20" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
<path d="M11 10a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/> <path d="M11 10a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-4.546 12.174c.03-.256.071-.512.124-.767C4.28 10.798 5.94 10 8 10s3.72.798 4.422 2.407c.053.255.094.511.124.767A7 7 0 0 0 8 1z"/> <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-4.546 12.174c.03-.256.071-.512.124-.767C4.28 10.798 5.94 10 8 10s3.72.798 4.422 2.407c.053.255.094.511.124.767A7 7 0 0 0 8 1z"/>
</svg> </svg>
<span id="nombreUsuarioHeader" class="fw-semibold">Usuario</span> <span id="nombreUsuarioHeader" class="fw-semibold">Usuario</span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end text-center p-3" style="background-color: #0d6efd; color: white; border-radius: 0 0 8px 8px;"> <ul class="dropdown-menu dropdown-menu-end text-center p-3"
<li> aria-labelledby="userDropdown"
<select id="langSelector" class="form-select form-select-sm mb-3 bg-white text-dark border-0 rounded"> style="background-color: #0d6efd; color: white; border-radius: 0 0 8px 8px; min-width: 100%; max-width: 250px;">
<!-- Mostrar rol -->
<li class="mb-2">
<span id="nombreUsuarioDropdown" class="fw-semibold text-white d-block" data-i18n="role">Atleta</span>
</li>
<!-- Selector de idioma -->
<li class="mb-1">
<div class="d-flex align-items-center justify-content-center gap-2 w-100">
<i class="bi bi-globe" style="color: white; font-size: 1rem;"></i>
<select id="langSelector" class="form-select form-select-sm" style="border: none; border-radius: 6px; max-width: 140px;">
<option value="es">Español</option> <option value="es">Español</option>
<option value="en">English</option> <option value="en">English</option>
<option value="fr">Français</option> <option value="fr">Français</option>
</select> </select>
</div>
</li>
<!-- Botón salir -->
<li>
<button class="btn btn-danger btn-sm w-100" onclick="logout()" data-i18n="logout">Salir</button>
</li> </li>
<li><button class="btn btn-danger btn-sm w-100" onclick="logout()">Salir</button></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -41,7 +56,7 @@
</nav> </nav>
<div class="container py-5"> <div class="container py-5">
<h2 id="tituloRutina" class="text-center fw-bold text-primary mb-2">Cargando rutina...</h2> <h2 id="tituloRutina" class="text-center fw-bold text-primary mb-2" data-i18n="sim.title">Cargando rutina...</h2>
<p class="text-center fs-6"> <p class="text-center fs-6">
<span id="tipoRutina" class="badge bg-info"></span> <span id="tipoRutina" class="badge bg-info"></span>
<span id="modalidadRutina" class="badge bg-secondary ms-2"></span> <span id="modalidadRutina" class="badge bg-secondary ms-2"></span>
@ -49,7 +64,7 @@
<div class="text-center my-4"> <div class="text-center my-4">
<audio id="audioPlayer" controls class="mb-2 w-100" style="max-width: 500px;"></audio> <audio id="audioPlayer" controls class="mb-2 w-100" style="max-width: 500px;"></audio>
<button id="playPauseBtn" class="btn btn-outline-primary btn-sm">▶ Reproducir</button> <button id="playPauseBtn" class="btn btn-outline-primary btn-sm" data-i18n="sim.play">▶ Reproducir</button>
</div> </div>
<div id="piscinaContainer" class="border rounded p-2 shadow-sm mx-auto mb-4 bg-white" style="max-width: fit-content;"> <div id="piscinaContainer" class="border rounded p-2 shadow-sm mx-auto mb-4 bg-white" style="max-width: fit-content;">
@ -57,11 +72,13 @@
</div> </div>
<div class="text-start mt-4"> <div class="text-start mt-4">
<h5 class="fw-semibold">Línea de Tiempo</h5> <h5 class="fw-semibold" data-i18n="sim.timeline">Línea de Tiempo</h5>
<div id="lineaTiempo" class="d-flex flex-wrap gap-2"></div> <div id="lineaTiempo" class="d-flex flex-wrap gap-2"></div>
</div> </div>
</div> </div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/konva@8.3.12/konva.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/konva@8.3.12/konva.min.js"></script>
<script src="js/simulador.js"></script> <script src="js/simulador.js"></script>