484 lines
17 KiB
PHP
484 lines
17 KiB
PHP
<?php include __DIR__ . "/../../layouts/header.php"; ?>
|
|
|
|
<style>
|
|
/* --- Diseño adaptable (Responsive) y estilos de juego --- */
|
|
body {
|
|
background-color: #f0f2f5;
|
|
}
|
|
|
|
.game-container {
|
|
background-color: #f5f5f5;
|
|
border-radius: 15px;
|
|
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
|
padding: 20px;
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.card {
|
|
border: none;
|
|
border-radius: 10px;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
transition: transform 0.3s ease-in-out;
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.achievement {
|
|
transition: transform 0.3s ease-in-out;
|
|
}
|
|
|
|
.achievement:hover {
|
|
transform: scale(1.05);
|
|
}
|
|
|
|
.progress {
|
|
height: 25px;
|
|
font-size: 0.8rem;
|
|
background-color: #e9ecef;
|
|
border-radius: 1rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #007bff;
|
|
color: white;
|
|
transition: width 0.6s ease;
|
|
}
|
|
|
|
.btn-primary {
|
|
background-color: #4e73df;
|
|
border-color: #4e73df;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background-color: #2e59d9;
|
|
border-color: #2653d4;
|
|
}
|
|
|
|
.list-group-item {
|
|
border-left: 5px solid #4e73df;
|
|
margin-bottom: 10px;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.badge {
|
|
font-size: 0.8rem;
|
|
padding: 0.4em 0.6em;
|
|
}
|
|
|
|
.text-primary {
|
|
color: #4e73df !important;
|
|
}
|
|
|
|
/* Animaciones */
|
|
@keyframes pulse {
|
|
0% {
|
|
transform: scale(1);
|
|
}
|
|
|
|
50% {
|
|
transform: scale(1.075);
|
|
}
|
|
|
|
100% {
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
.pulse {
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
/* Breakpoint para tablets y pantallas medianas (≥ 768px) */
|
|
@media (max-width: 767.98px) {
|
|
.achievement-card {
|
|
margin-bottom: 1rem;
|
|
}
|
|
}
|
|
|
|
/* Breakpoint para teléfonos y pantallas pequeñas (≤ 576px) */
|
|
@media (max-width: 576px) {
|
|
.card-title {
|
|
font-size: 1.25rem;
|
|
}
|
|
}
|
|
|
|
/* Block: profile-card */
|
|
.profile-card {
|
|
background: linear-gradient(145deg, #ffffff, #f5f5f5);
|
|
border-radius: 16px;
|
|
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
|
padding: 1.5rem;
|
|
font-family: 'Segoe UI', system-ui, sans-serif;
|
|
}
|
|
|
|
/* Elements */
|
|
.profile-card__header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.profile-card__icon {
|
|
background: linear-gradient(45deg, #4e73df, #2e59d9);
|
|
color: white;
|
|
width: 48px;
|
|
height: 48px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 1rem;
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.profile-card__title {
|
|
color: #1a1a1a;
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
margin: 0;
|
|
}
|
|
|
|
.profile-card__stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.profile-card__stat-item {
|
|
background: rgba(78, 115, 223, 0.1);
|
|
padding: 1rem;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
}
|
|
|
|
.profile-card__stat-label {
|
|
color: #666;
|
|
font-size: 0.875rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.profile-card__stat-value {
|
|
color: #1a1a1a;
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.profile-card__progress {
|
|
background: #e0e0e0;
|
|
border-radius: 8px;
|
|
height: 12px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
.profile-card__progress-bar {
|
|
background: linear-gradient(90deg, #4e73df, #2e59d9); /* Colores ajustados */
|
|
height: 100%;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
/* Modifiers */
|
|
.profile-card__progress-bar--low {
|
|
background: linear-gradient(90deg, #FFA726, #F57C00);
|
|
}
|
|
|
|
.profile-card__progress-bar--high {
|
|
background: linear-gradient(90deg, #66BB6A, #388E3C);
|
|
}
|
|
</style>
|
|
|
|
<div class="container-fluid px-3 px-md-4 mt-4">
|
|
<div class="game-container">
|
|
<div class="row mt-3">
|
|
<div class="col-12">
|
|
<h1 class="text-center fw-bold h2 text-dark">
|
|
<i class="fas fa-dumbbell mr-2"></i> Rutinas Personalizadas
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-4">
|
|
<div class="col-12 col-md-4">
|
|
<div class="profile-card">
|
|
<div class="profile-card__header">
|
|
<div class="profile-card__icon">
|
|
<i class="fas fa-user-circle"></i>
|
|
</div>
|
|
<h2 class="profile-card__title">Perfil de Gymbro</h2>
|
|
</div>
|
|
|
|
<div class="profile-card__stats">
|
|
<div class="profile-card__stat-item">
|
|
<div class="profile-card__stat-label">Nivel</div>
|
|
<div class="profile-card__stat-value" id="userLevel">1</div>
|
|
</div>
|
|
<div class="profile-card__stat-item">
|
|
<div class="profile-card__stat-label">Puntos XP</div>
|
|
<div class="profile-card__stat-value" id="userPoints">0</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-card__progress">
|
|
<div class="profile-card__progress-bar" id="expProgress" role="progressbar" aria-valuenow="0"
|
|
aria-valuemin="0" aria-valuemax="100"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-md-8">
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
<h5 class="card-title"><i class="fas fa-tasks mr-2"></i> Misión Diaria</h5>
|
|
<select id="routineType" class="form-select mb-3">
|
|
<option value="fullBody">Full Body</option>
|
|
<option value="upperLower">Torso/Pierna</option>
|
|
</select>
|
|
<ul id="exerciseList" class="list-group mb-3">
|
|
<!-- Los ejercicios se agregarán dinámicamente aquí -->
|
|
</ul>
|
|
<button id="completeRoutine" class="btn btn-primary btn-lg btn-block">
|
|
<i class="fas fa-check-circle mr-2"></i> Completar Misión
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-4">
|
|
<div class="col-12">
|
|
<h3 class="text-center mb-3 text-primary"><i class="fas fa-trophy mr-2"></i> Logros Desbloqueados</h3>
|
|
<div id="achievements" class="row">
|
|
<!-- Los logros se agregarán dinámicamente aquí -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SweetAlert2 -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const exercisesByType = {
|
|
fullBody: [
|
|
{ name: 'Sentadillas', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Flexiones', points: 10, icon: 'fa-child' },
|
|
{ name: 'Peso muerto', points: 20, icon: 'fa-dumbbell' },
|
|
{ name: 'Dominadas', points: 15, icon: 'fa-child' },
|
|
{ name: 'Burpees', points: 20, icon: 'fa-running' }
|
|
],
|
|
upperLower: {
|
|
upper: [
|
|
{ name: 'Press de banca', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Remo con barra', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Press militar', points: 12, icon: 'fa-dumbbell' },
|
|
{ name: 'Curl de bíceps', points: 10, icon: 'fa-dumbbell' },
|
|
{ name: 'Tríceps en polea', points: 10, icon: 'fa-dumbbell' }
|
|
],
|
|
lower: [
|
|
{ name: 'Sentadillas', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Peso muerto', points: 20, icon: 'fa-dumbbell' },
|
|
{ name: 'Prensa de piernas', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Elevaciones de pantorrilla', points: 10, icon: 'fa-dumbbell' },
|
|
{ name: 'Hip thrust', points: 12, icon: 'fa-dumbbell' }
|
|
]
|
|
},
|
|
pushPullLegs: {
|
|
push: [
|
|
{ name: 'Press de banca', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Press militar', points: 12, icon: 'fa-dumbbell' },
|
|
{ name: 'Fondos en paralelas', points: 15, icon: 'fa-child' },
|
|
{ name: 'Elevaciones laterales', points: 10, icon: 'fa-dumbbell' },
|
|
{ name: 'Extensiones de tríceps', points: 10, icon: 'fa-dumbbell' }
|
|
],
|
|
pull: [
|
|
{ name: 'Dominadas', points: 15, icon: 'fa-child' },
|
|
{ name: 'Remo con barra', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Curl de bíceps', points: 10, icon: 'fa-dumbbell' },
|
|
{ name: 'Face pull', points: 12, icon: 'fa-dumbbell' },
|
|
{ name: 'Remo en T', points: 12, icon: 'fa-dumbbell' }
|
|
],
|
|
legs: [
|
|
{ name: 'Sentadillas', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Peso muerto', points: 20, icon: 'fa-dumbbell' },
|
|
{ name: 'Prensa de piernas', points: 15, icon: 'fa-dumbbell' },
|
|
{ name: 'Extensiones de cuádriceps', points: 10, icon: 'fa-dumbbell' },
|
|
{ name: 'Curl de isquiotibiales', points: 10, icon: 'fa-dumbbell' }
|
|
]
|
|
}
|
|
};
|
|
|
|
const achievements = [
|
|
{ name: 'Principiante', description: 'Completa tu primera misión', icon: 'fa-star', unlocked: false },
|
|
{ name: 'Constante', description: 'Completa 5 misiones', icon: 'fa-fire', unlocked: false },
|
|
{ name: 'Maestro del Fitness', description: 'Alcanza el nivel 5', icon: 'fa-fist-raised', unlocked: false },
|
|
{ name: 'Imparable', description: 'Acumula 1000 puntos', icon: 'fa-trophy', unlocked: false }
|
|
];
|
|
|
|
let userPoints = 0;
|
|
let userLevel = 1;
|
|
let routinesCompleted = 0;
|
|
|
|
function updateUserInterface() {
|
|
document.getElementById('userPoints').textContent = userPoints;
|
|
document.getElementById('userLevel').textContent = userLevel;
|
|
const expProgress = (userPoints % 100) / 100 * 100;
|
|
const progressBar = document.getElementById('expProgress');
|
|
progressBar.style.width = `${expProgress}%`;
|
|
progressBar.setAttribute('aria-valuenow', expProgress);
|
|
// Eliminado: progressBar.textContent
|
|
}
|
|
|
|
function populateExerciseList() {
|
|
const exerciseList = document.getElementById('exerciseList');
|
|
exerciseList.innerHTML = '';
|
|
const routineType = document.getElementById('routineType').value;
|
|
let exercises;
|
|
|
|
if (routineType === 'fullBody') {
|
|
exercises = exercisesByType.fullBody;
|
|
} else if (routineType === 'upperLower') {
|
|
exercises = Math.random() < 0.5 ? exercisesByType.upperLower.upper : exercisesByType.upperLower.lower;
|
|
} else {
|
|
const pplTypes = ['push', 'pull', 'legs'];
|
|
const randomType = pplTypes[Math.floor(Math.random() * pplTypes.length)];
|
|
exercises = exercisesByType.pushPullLegs[randomType];
|
|
}
|
|
|
|
exercises.forEach((exercise, index) => {
|
|
const li = document.createElement('li');
|
|
li.className = 'list-group-item d-flex justify-content-between align-items-center';
|
|
li.innerHTML = `
|
|
<span><i class="fas ${exercise.icon} mr-2"></i> ${exercise.name}</span>
|
|
<span class="badge bg-primary rounded-pill">${exercise.points} XP</span>
|
|
`;
|
|
exerciseList.appendChild(li);
|
|
});
|
|
}
|
|
|
|
function completeRoutine() {
|
|
const routineType = document.getElementById('routineType').value;
|
|
let exercises;
|
|
|
|
if (routineType === 'fullBody') {
|
|
exercises = exercisesByType.fullBody;
|
|
} else if (routineType === 'upperLower') {
|
|
exercises = Math.random() < 0.5 ? exercisesByType.upperLower.upper : exercisesByType.upperLower.lower;
|
|
} else {
|
|
const pplTypes = ['push', 'pull', 'legs'];
|
|
const randomType = pplTypes[Math.floor(Math.random() * pplTypes.length)];
|
|
exercises = exercisesByType.pushPullLegs[randomType];
|
|
}
|
|
|
|
const earnedPoints = exercises.reduce((sum, exercise) => sum + exercise.points, 0);
|
|
userPoints += earnedPoints;
|
|
routinesCompleted++;
|
|
|
|
while (userPoints >= userLevel * 100) {
|
|
userPoints -= userLevel * 100;
|
|
userLevel++;
|
|
showLevelUpMessage(userLevel);
|
|
}
|
|
|
|
updateUserInterface();
|
|
checkAchievements();
|
|
|
|
showMessageToast(`¡Misión cumplida! Has ganado ${earnedPoints} puntos de experiencia.`);
|
|
}
|
|
|
|
function showLevelUpMessage(newLevel) {
|
|
Swal.fire({
|
|
title: '¡Subiste de nivel!',
|
|
text: `Has alcanzado el nivel ${newLevel}. ¡Sigue así, campeón!`,
|
|
icon: 'success',
|
|
confirmButtonText: '¡Genial!'
|
|
});
|
|
}
|
|
|
|
function checkAchievements() {
|
|
achievements.forEach((achievement, index) => {
|
|
if (!achievement.unlocked) {
|
|
if (
|
|
(achievement.name === 'Principiante' && routinesCompleted >= 1) ||
|
|
(achievement.name === 'Constante' && routinesCompleted >= 5) ||
|
|
(achievement.name === 'Maestro del Fitness' && userLevel >= 5) ||
|
|
(achievement.name === 'Imparable' && userPoints + (userLevel - 1) * 100 >= 1000)
|
|
) {
|
|
achievement.unlocked = true;
|
|
updateAchievementDisplay(index);
|
|
showAchievementUnlockedMessage(achievement);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateAchievementDisplay(index) {
|
|
const achievementElement = document.getElementById(`achievement-${index}`);
|
|
if (achievementElement) {
|
|
achievementElement.classList.remove('bg-secondary');
|
|
achievementElement.classList.add('bg-success', 'pulse');
|
|
}
|
|
}
|
|
|
|
function showAchievementUnlockedMessage(achievement) {
|
|
Swal.fire({
|
|
title: '¡Logro Desbloqueado!',
|
|
text: `Has conseguido el logro "${achievement.name}": ${achievement.description}`,
|
|
icon: 'success',
|
|
confirmButtonText: '¡Increíble!'
|
|
});
|
|
}
|
|
|
|
function populateAchievements() {
|
|
const achievementsContainer = document.getElementById('achievements');
|
|
achievements.forEach((achievement, index) => {
|
|
const achievementElement = document.createElement('div');
|
|
achievementElement.className = 'col-md-3 mb-3';
|
|
achievementElement.innerHTML = `
|
|
<div id="achievement-${index}" class="card text-white ${achievement.unlocked ? 'bg-success' : 'bg-secondary'} achievement">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title"><i class="fas ${achievement.icon} mr-2"></i> ${achievement.name}</h5>
|
|
<p class="card-text">${achievement.description}</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
achievementsContainer.appendChild(achievementElement);
|
|
});
|
|
}
|
|
|
|
function showMessageToast(message, type = 'success') {
|
|
Swal.fire({
|
|
text: message,
|
|
icon: type,
|
|
showConfirmButton: false,
|
|
timer: 2000,
|
|
toast: true,
|
|
position: 'top-end',
|
|
background: '#f8f9fa',
|
|
color: '#000',
|
|
iconColor: type === 'error' ? '#dc3545' : type === 'warning' ? '#ffc107' : '#28a745',
|
|
customClass: {
|
|
popup: 'shadow-sm'
|
|
}
|
|
});
|
|
}
|
|
|
|
document.getElementById('routineType').addEventListener('change', populateExerciseList);
|
|
document.getElementById('completeRoutine').addEventListener('click', completeRoutine);
|
|
|
|
populateExerciseList();
|
|
populateAchievements();
|
|
updateUserInterface();
|
|
});
|
|
</script>
|
|
|
|
<?php include __DIR__ . "/../../layouts/footer.php"; ?>
|