macros / index.html
andyontrade's picture
Add 1 files
a9ec097 verified
raw
history blame
27.3 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calculadora de Macronutrientes</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.result-card {
transition: all 0.3s ease;
}
.result-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.nutri-circle {
width: 100px;
height: 100px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin: 0 auto;
}
input[type="range"] {
-webkit-appearance: none;
height: 8px;
border-radius: 5px;
background: #e0e0e0;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
}
.tab-btn {
transition: all 0.3s ease;
}
.tab-btn.active {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
</style>
</head>
<body class="min-h-screen bg-gray-50">
<div class="gradient-bg text-white py-12 px-4 shadow-lg">
<div class="max-w-4xl mx-auto text-center">
<h1 class="text-4xl font-bold mb-4">Calculadora de Macronutrientes</h1>
<p class="text-xl opacity-90">Calcula tus necesidades nutricionales personalizadas</p>
</div>
</div>
<div class="max-w-4xl mx-auto px-4 py-8">
<div class="bg-white rounded-xl shadow-md p-6 mb-8">
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Datos Personales</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-gray-700 mb-2">Género</label>
<div class="flex space-x-4">
<button id="maleBtn" class="gender-btn px-4 py-2 rounded-lg bg-blue-100 text-blue-700 font-medium">Hombre</button>
<button id="femaleBtn" class="gender-btn px-4 py-2 rounded-lg bg-pink-100 text-pink-700 font-medium">Mujer</button>
</div>
</div>
<div>
<label class="block text-gray-700 mb-2">Objetivo</label>
<select id="goal" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="loss">Pérdida de peso</option>
<option value="maintenance" selected>Mantenimiento</option>
<option value="gain">Aumento de peso</option>
</select>
</div>
<div>
<label class="block text-gray-700 mb-2">Edad (años)</label>
<input type="number" id="age" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" min="15" max="100" value="30">
</div>
<div>
<label class="block text-gray-700 mb-2">Nivel de actividad</label>
<select id="activity" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="1.2">Sedentario (poco o nada de ejercicio)</option>
<option value="1.375">Ligero (ejercicio 1-3 días/semana)</option>
<option value="1.55" selected>Moderado (ejercicio 3-5 días/semana)</option>
<option value="1.725">Activo (ejercicio 6-7 días/semana)</option>
<option value="1.9">Muy activo (ejercicio intenso diario)</option>
</select>
</div>
<div>
<label class="block text-gray-700 mb-2">Peso (kg)</label>
<input type="number" id="weight" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" min="40" max="200" value="70">
</div>
<div>
<label class="block text-gray-700 mb-2">Altura (cm)</label>
<input type="number" id="height" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" min="140" max="220" value="170">
</div>
</div>
<div class="mt-6">
<div class="flex mb-4">
<button id="manualTab" class="tab-btn px-4 py-2 rounded-l-lg border border-gray-300 font-medium active">Manual</button>
<button id="calculateTab" class="tab-btn px-4 py-2 rounded-r-lg border border-gray-300 font-medium">Calcular % Grasa</button>
</div>
<div id="manualBodyfatSection">
<label class="block text-gray-700 mb-2">% Grasa corporal</label>
<input type="range" id="bodyfat" class="w-full" min="5" max="50" value="20">
<div class="flex justify-between text-sm text-gray-600 mt-1">
<span>5%</span>
<span id="bodyfatValue">20%</span>
<span>50%</span>
</div>
</div>
<div id="calculateBodyfatSection" class="hidden">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<div>
<label class="block text-gray-700 mb-2">Cuello (cm)</label>
<input type="number" id="neck" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" min="20" max="50" value="38">
</div>
<div>
<label class="block text-gray-700 mb-2">Cintura (cm)</label>
<input type="number" id="waist" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" min="50" max="150" value="80">
</div>
<div id="hipSection">
<label class="block text-gray-700 mb-2">Cadera (cm)</label>
<input type="number" id="hip" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" min="60" max="150" value="95">
</div>
</div>
<button id="calculateBodyfatBtn" class="w-full bg-gray-200 text-gray-800 py-2 rounded-lg font-medium hover:bg-gray-300 transition duration-300">
Calcular % Grasa
</button>
</div>
</div>
<div class="mt-8">
<button id="calculateBtn" class="w-full gradient-bg text-white py-3 rounded-lg font-bold text-lg hover:opacity-90 transition duration-300">
Calcular mis macronutrientes
</button>
</div>
</div>
<div id="results" class="hidden bg-white rounded-xl shadow-md p-6 mb-8">
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Tus resultados nutricionales</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="result-card bg-blue-50 rounded-xl p-6 text-center">
<div class="nutri-circle bg-blue-100 text-blue-700 text-2xl mb-4" id="caloriesCircle">0</div>
<h3 class="text-xl font-semibold text-blue-800 mb-2">Calorías diarias</h3>
<p class="text-gray-600">Recomendación basada en tus datos</p>
</div>
<div class="result-card bg-green-50 rounded-xl p-6 text-center">
<div class="nutri-circle bg-green-100 text-green-700 text-2xl mb-4" id="proteinCircle">0g</div>
<h3 class="text-xl font-semibold text-green-800 mb-2">Proteína</h3>
<p class="text-gray-600">Esencial para músculos y recuperación</p>
</div>
<div class="result-card bg-yellow-50 rounded-xl p-6 text-center">
<div class="nutri-circle bg-yellow-100 text-yellow-700 text-2xl mb-4" id="carbsCircle">0g</div>
<h3 class="text-xl font-semibold text-yellow-800 mb-2">Carbohidratos</h3>
<p class="text-gray-600">Energía para tu día y entrenamientos</p>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="result-card bg-purple-50 rounded-xl p-6">
<h3 class="text-xl font-semibold text-purple-800 mb-4">Distribución de macronutrientes</h3>
<div class="h-64 flex items-center justify-center">
<canvas id="macrosChart"></canvas>
</div>
</div>
<div class="result-card bg-red-50 rounded-xl p-6">
<h3 class="text-xl font-semibold text-red-800 mb-4">Detalles nutricionales</h3>
<div class="space-y-4">
<div class="flex justify-between items-center">
<span class="text-gray-700">Grasas</span>
<span class="font-semibold text-red-700" id="fatValue">0g</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="fatBar" class="bg-red-500 h-2.5 rounded-full" style="width: 0%"></div>
</div>
<div class="flex justify-between items-center">
<span class="text-gray-700">Proteína</span>
<span class="font-semibold text-blue-700" id="proteinValue">0g</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="proteinBar" class="bg-blue-500 h-2.5 rounded-full" style="width: 0%"></div>
</div>
<div class="flex justify-between items-center">
<span class="text-gray-700">Carbohidratos</span>
<span class="font-semibold text-yellow-700" id="carbsValue">0g</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="carbsBar" class="bg-yellow-500 h-2.5 rounded-full" style="width: 0%"></div>
</div>
<div class="pt-4 border-t border-gray-200">
<div class="flex justify-between items-center">
<span class="text-gray-700 font-medium">Agua recomendada</span>
<span class="font-semibold text-blue-700" id="waterValue">0L</span>
</div>
</div>
</div>
</div>
</div>
<div class="mt-8 bg-gray-50 rounded-xl p-6">
<h3 class="text-xl font-semibold text-gray-800 mb-4">Recomendaciones personalizadas</h3>
<div id="recommendations" class="space-y-3 text-gray-700">
<!-- Las recomendaciones se generarán aquí -->
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Variables globales
let gender = 'male';
let macrosChart = null;
// Event listeners
document.getElementById('maleBtn').addEventListener('click', () => setGender('male'));
document.getElementById('femaleBtn').addEventListener('click', () => setGender('female'));
document.getElementById('bodyfat').addEventListener('input', updateBodyfatValue);
document.getElementById('calculateBtn').addEventListener('click', calculateNutrition);
document.getElementById('manualTab').addEventListener('click', () => switchBodyfatTab('manual'));
document.getElementById('calculateTab').addEventListener('click', () => switchBodyfatTab('calculate'));
document.getElementById('calculateBodyfatBtn').addEventListener('click', calculateBodyfatPercentage);
document.getElementById('gender').addEventListener('change', toggleHipInput);
// Funciones
function setGender(selectedGender) {
gender = selectedGender;
document.querySelectorAll('.gender-btn').forEach(btn => {
btn.classList.remove('gradient-bg', 'text-white');
btn.classList.add('bg-gray-100', 'text-gray-700');
});
if (selectedGender === 'male') {
document.getElementById('maleBtn').classList.remove('bg-blue-100', 'text-blue-700');
document.getElementById('maleBtn').classList.add('gradient-bg', 'text-white');
document.getElementById('hipSection').classList.add('hidden');
} else {
document.getElementById('femaleBtn').classList.remove('bg-pink-100', 'text-pink-700');
document.getElementById('femaleBtn').classList.add('gradient-bg', 'text-white');
document.getElementById('hipSection').classList.remove('hidden');
}
}
function switchBodyfatTab(tab) {
if (tab === 'manual') {
document.getElementById('manualTab').classList.add('active');
document.getElementById('calculateTab').classList.remove('active');
document.getElementById('manualBodyfatSection').classList.remove('hidden');
document.getElementById('calculateBodyfatSection').classList.add('hidden');
} else {
document.getElementById('manualTab').classList.remove('active');
document.getElementById('calculateTab').classList.add('active');
document.getElementById('manualBodyfatSection').classList.add('hidden');
document.getElementById('calculateBodyfatSection').classList.remove('hidden');
}
}
function updateBodyfatValue() {
const bodyfat = document.getElementById('bodyfat').value;
document.getElementById('bodyfatValue').textContent = `${bodyfat}%`;
}
function calculateBodyfatPercentage() {
const neck = parseFloat(document.getElementById('neck').value);
const waist = parseFloat(document.getElementById('waist').value);
const height = parseFloat(document.getElementById('height').value);
// Fórmula de la Marina de EE.UU. para calcular % de grasa corporal
let bodyfatPercentage;
if (gender === 'male') {
// Fórmula para hombres
bodyfatPercentage = 86.010 * Math.log10(waist - neck) - 70.041 * Math.log10(height) + 36.76;
} else {
// Fórmula para mujeres (necesita medida de cadera)
const hip = parseFloat(document.getElementById('hip').value);
bodyfatPercentage = 163.205 * Math.log10(waist + hip - neck) - 97.684 * Math.log10(height) - 78.387;
}
// Asegurarse que el porcentaje esté dentro de límites razonables
bodyfatPercentage = Math.max(5, Math.min(50, bodyfatPercentage));
// Actualizar el slider y el valor mostrado
document.getElementById('bodyfat').value = Math.round(bodyfatPercentage);
document.getElementById('bodyfatValue').textContent = `${Math.round(bodyfatPercentage)}%`;
// Mostrar notificación de éxito
alert(`Tu porcentaje de grasa corporal calculado es: ${Math.round(bodyfatPercentage)}%`);
// Cambiar a la pestaña manual para mostrar el resultado
switchBodyfatTab('manual');
}
function calculateNutrition() {
// Obtener valores del formulario
const age = parseInt(document.getElementById('age').value);
const weight = parseFloat(document.getElementById('weight').value);
const height = parseFloat(document.getElementById('height').value);
const activity = parseFloat(document.getElementById('activity').value);
const goal = document.getElementById('goal').value;
const bodyfat = parseInt(document.getElementById('bodyfat').value) || 20;
// Validaciones básicas
if (age < 15 || age > 100 || weight < 40 || weight > 200 || height < 140 || height > 220) {
alert('Por favor ingresa valores válidos en todos los campos');
return;
}
// Calcular calorías (Harris-Benedict revisada por Mifflin-St Jeor)
let bmr;
if (gender === 'male') {
bmr = 10 * weight + 6.25 * height - 5 * age + 5;
} else {
bmr = 10 * weight + 6.25 * height - 5 * age - 161;
}
let tdee = bmr * activity;
// Ajustar según objetivo
let calorieAdjustment = 0;
switch(goal) {
case 'loss':
calorieAdjustment = -500;
break;
case 'gain':
calorieAdjustment = 500;
break;
default:
calorieAdjustment = 0;
}
const dailyCalories = Math.round(tdee + calorieAdjustment);
// Calcular macronutrientes
// Proteína: 2.2g/kg para pérdida de peso, 1.8g/kg para mantenimiento, 1.6g/kg para aumento
let proteinPerKg;
if (goal === 'loss') {
proteinPerKg = 2.2;
} else if (goal === 'maintenance') {
proteinPerKg = 1.8;
} else {
proteinPerKg = 1.6;
}
// Ajustar proteína si hay % grasa alto (>25%)
if (bodyfat > 25) {
proteinPerKg = Math.min(proteinPerKg + 0.2, 2.5);
}
const proteinGrams = Math.round(weight * proteinPerKg);
const proteinCalories = proteinGrams * 4;
// Grasas: 25-35% de calorías
const fatPercentage = 0.3; // 30%
const fatCalories = Math.round(dailyCalories * fatPercentage);
const fatGrams = Math.round(fatCalories / 9);
// Carbohidratos: resto de calorías
const carbsCalories = dailyCalories - proteinCalories - fatCalories;
const carbsGrams = Math.round(carbsCalories / 4);
// Agua recomendada
const waterIntake = Math.round((weight * 0.035) * 10) / 10; // 35ml por kg
// Mostrar resultados
document.getElementById('caloriesCircle').textContent = dailyCalories;
document.getElementById('proteinCircle').textContent = `${proteinGrams}g`;
document.getElementById('carbsCircle').textContent = `${carbsGrams}g`;
document.getElementById('proteinValue').textContent = `${proteinGrams}g`;
document.getElementById('carbsValue').textContent = `${carbsGrams}g`;
document.getElementById('fatValue').textContent = `${fatGrams}g`;
document.getElementById('waterValue').textContent = `${waterIntake}L`;
// Actualizar barras de progreso
document.getElementById('proteinBar').style.width = `${Math.min(proteinGrams / weight * 50, 100)}%`;
document.getElementById('carbsBar').style.width = `${Math.min(carbsGrams / (weight * 3) * 100, 100)}%`;
document.getElementById('fatBar').style.width = `${Math.min(fatGrams / (weight * 1.2) * 100, 100)}%`;
// Generar recomendaciones
generateRecommendations(goal, dailyCalories, proteinGrams, carbsGrams, fatGrams, waterIntake);
// Crear/actualizar gráfico
updateChart(proteinGrams, carbsGrams, fatGrams);
// Mostrar resultados
document.getElementById('results').classList.remove('hidden');
// Scroll a resultados
document.getElementById('results').scrollIntoView({ behavior: 'smooth' });
}
function generateRecommendations(goal, calories, protein, carbs, fat, water) {
const recommendationsEl = document.getElementById('recommendations');
recommendationsEl.innerHTML = '';
// Recomendación general según objetivo
let goalRecommendation = '';
switch(goal) {
case 'loss':
goalRecommendation = 'Para pérdida de peso, mantén un déficit calórico constante y prioriza proteínas para preservar masa muscular.';
break;
case 'maintenance':
goalRecommendation = 'Para mantenimiento, sigue una dieta balanceada y mantén tus niveles de actividad.';
break;
case 'gain':
goalRecommendation = 'Para aumento de peso, asegúrate de consumir suficientes calorías y proteínas para apoyar el crecimiento muscular.';
break;
}
addRecommendation(goalRecommendation);
// Recomendación de proteína
addRecommendation(`Consume aproximadamente ${protein}g de proteína diarios. Buenas fuentes incluyen carnes magras, pescado, huevos y lácteos.`);
// Recomendación de carbohidratos
if (goal === 'loss') {
addRecommendation(`Prioriza carbohidratos complejos (${carbs}g/día) como vegetales, granos enteros y legumbres para energía sostenida.`);
} else {
addRecommendation(`Consume ${carbs}g de carbohidratos diarios, priorizando fuentes complejas como arroz integral, quinoa y avena.`);
}
// Recomendación de grasas
addRecommendation(`Incluye ${fat}g de grasas saludables diarias de fuentes como aguacate, frutos secos, aceite de oliva y pescados grasos.`);
// Recomendación de agua
addRecommendation(`Bebe al menos ${water} litros de agua al día para mantener una hidratación óptima.`);
// Recomendación de comidas
addRecommendation('Distribuye tus macronutrientes en 3-5 comidas al día para mejor digestión y absorción.');
function addRecommendation(text) {
const div = document.createElement('div');
div.className = 'flex items-start';
div.innerHTML = `
<span class="text-blue-500 mr-3 mt-1"><i class="fas fa-check-circle"></i></span>
<span>${text}</span>
`;
recommendationsEl.appendChild(div);
}
}
function updateChart(protein, carbs, fat) {
const ctx = document.getElementById('macrosChart').getContext('2d');
// Destruir gráfico anterior si existe
if (macrosChart) {
macrosChart.destroy();
}
macrosChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Proteína', 'Carbohidratos', 'Grasas'],
datasets: [{
data: [protein, carbs, fat],
backgroundColor: [
'#3b82f6',
'#f59e0b',
'#ef4444'
],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
font: {
size: 14
},
padding: 20
}
},
tooltip: {
callbacks: {
label: function(context) {
const label = context.label || '';
const value = context.raw || 0;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = Math.round((value / total) * 100);
return `${label}: ${value}g (${percentage}%)`;
}
}
}
},
cutout: '70%'
}
});
}
// Inicializar
setGender('male');
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=andyontrade/macros" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>