|
|
<!DOCTYPE html> |
|
|
<html lang="en" class="dark"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Matrix Calculators - Modern & Dark</title> |
|
|
|
|
|
|
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> |
|
|
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com"> |
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet"> |
|
|
|
|
|
<style> |
|
|
body { |
|
|
font-family: 'Poppins', sans-serif; |
|
|
-webkit-font-smoothing: antialiased; |
|
|
-moz-osx-font-smoothing: grayscale; |
|
|
} |
|
|
::-webkit-scrollbar { width: 8px; } |
|
|
::-webkit-scrollbar-track { background: #1e293b; } |
|
|
::-webkit-scrollbar-thumb { background: #475569; border-radius: 10px; } |
|
|
::-webkit-scrollbar-thumb:hover { background: #64748b; } |
|
|
|
|
|
.fade-in { animation: fadeInAnimation 0.5s ease-in-out; } |
|
|
@keyframes fadeInAnimation { |
|
|
from { opacity: 0; transform: translateY(15px); } |
|
|
to { opacity: 1; transform: translateY(0); } |
|
|
} |
|
|
|
|
|
input[type="date"]::-webkit-calendar-picker-indicator { |
|
|
filter: invert(0.8); |
|
|
cursor: pointer; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-slate-900 text-slate-200 flex justify-center items-start min-h-screen p-4 sm:p-8"> |
|
|
|
|
|
<div class="w-full max-w-6xl"> |
|
|
|
|
|
|
|
|
<div id="dashboard" class="fade-in"> |
|
|
<header class="text-center mb-10"> |
|
|
<h1 class="text-4xl md:text-5xl font-bold text-white">Matrix Calculators</h1> |
|
|
<p class="text-lg text-slate-400 mt-2">Your ultimate suite of calculators and converters for everyday life</p> |
|
|
</header> |
|
|
|
|
|
<main class="grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-8"> |
|
|
|
|
|
<div class="bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border-t-4 border-green-500 transition-transform duration-300 hover:-translate-y-2"> |
|
|
<div class="flex items-center gap-4 mb-5"> |
|
|
<i class="fa-solid fa-coins text-3xl text-green-400"></i> |
|
|
<h2 class="font-semibold text-2xl text-white">Finance Calculators</h2> |
|
|
</div> |
|
|
<div class="space-y-3"> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('emi')"> |
|
|
<strong class="font-semibold text-slate-100">EMI Calculator</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Calculate loan EMIs with sliders</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('gst')"> |
|
|
<strong class="font-semibold text-slate-100">GST/VAT Calculator</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Add or remove tax from amounts</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('split')"> |
|
|
<strong class="font-semibold text-slate-100">Bill Splitter</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Split restaurant bills with friends</small> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border-t-4 border-red-500 transition-transform duration-300 hover:-translate-y-2"> |
|
|
<div class="flex items-center gap-4 mb-5"> |
|
|
<i class="fa-solid fa-heart-pulse text-3xl text-red-400"></i> |
|
|
<h2 class="font-semibold text-2xl text-white">Health & Fitness</h2> |
|
|
</div> |
|
|
<div class="space-y-3"> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('bmi')"> |
|
|
<strong class="font-semibold text-slate-100">BMI Calculator</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Body Mass Index with visual gauge</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('calorie')"> |
|
|
<strong class="font-semibold text-slate-100">Calorie Calculator</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">BMR & TDEE needs</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('bodyfat')"> |
|
|
<strong class="font-semibold text-slate-100">Body Fat Calculator</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Estimate your body fat percentage</small> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border-t-4 border-blue-500 transition-transform duration-300 hover:-translate-y-2"> |
|
|
<div class="flex items-center gap-4 mb-5"> |
|
|
<i class="fa-solid fa-arrows-rotate text-3xl text-blue-400"></i> |
|
|
<h2 class="font-semibold text-2xl text-white">Unit Converters</h2> |
|
|
</div> |
|
|
<div class="space-y-3"> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('converter', 'length')"> |
|
|
<strong class="font-semibold text-slate-100">Length Converter</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Meters, Feet, Inches, Miles...</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('converter', 'weight')"> |
|
|
<strong class="font-semibold text-slate-100">Weight Converter</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Kilograms, Pounds, Ounces...</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('converter', 'temperature')"> |
|
|
<strong class="font-semibold text-slate-100">Temperature Converter</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Celsius, Fahrenheit, Kelvin</small> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border-t-4 border-purple-500 transition-transform duration-300 hover:-translate-y-2"> |
|
|
<div class="flex items-center gap-4 mb-5"> |
|
|
<i class="fa-solid fa-calendar-days text-3xl text-purple-400"></i> |
|
|
<h2 class="font-semibold text-2xl text-white">Date & Time Tools</h2> |
|
|
</div> |
|
|
<div class="space-y-3"> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('age')"> |
|
|
<strong class="font-semibold text-slate-100">Age Calculator</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Calculate exact age from birth date</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('dateDiff')"> |
|
|
<strong class="font-semibold text-slate-100">Date Difference</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Days, weeks, months between dates</small> |
|
|
</div> |
|
|
<div class="bg-slate-700/50 p-4 rounded-lg cursor-pointer hover:bg-slate-700 transition" onclick="showCalculator('dateAdd')"> |
|
|
<strong class="font-semibold text-slate-100">Add/Subtract Dates</strong> |
|
|
<small class="text-sm text-slate-400 block mt-1">Calculate a future or past date</small> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="calculator-container" class="w-full"></div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<script> |
|
|
// --- JAVASCRIPT LOGIC --- |
|
|
|
|
|
const dashboard = document.getElementById('dashboard'); |
|
|
const calculatorContainer = document.getElementById('calculator-container'); |
|
|
const formatCurrency = (num, digits = 2) => `₹ ${num.toLocaleString('en-IN', { minimumFractionDigits: digits, maximumFractionDigits: digits })}`; |
|
|
|
|
|
// Generic back button for all calculators |
|
|
const backButton = `<button onclick="showDashboard()" class="absolute top-4 left-4 bg-slate-700 hover:bg-slate-600 text-white font-bold py-2 px-4 rounded-full transition duration-300"><i class="fas fa-arrow-left"></i></button>`; |
|
|
|
|
|
const calculators = { |
|
|
// --- Finance Calculators --- |
|
|
emi: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-green-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-green-400">EMI Calculator</h2> |
|
|
<div class="space-y-6"> |
|
|
<div> |
|
|
<label class="text-slate-300 font-semibold">Loan Amount: <span id="amount-val" class="font-bold text-green-400"></span></label> |
|
|
<input type="range" id="amount" min="10000" max="10000000" value="500000" class="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer"> |
|
|
</div> |
|
|
<div> |
|
|
<label class="text-slate-300 font-semibold">Interest Rate (% p.a.): <span id="rate-val" class="font-bold text-green-400"></span></label> |
|
|
<input type="range" id="rate" min="1" max="20" value="8.5" step="0.1" class="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer"> |
|
|
</div> |
|
|
<div> |
|
|
<label class="text-slate-300 font-semibold">Tenure (Months): <span id="tenure-val" class="font-bold text-green-400"></span></label> |
|
|
<input type="range" id="tenure" min="6" max="360" value="120" class="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer"> |
|
|
</div> |
|
|
</div> |
|
|
<div id="emi-result" class="text-center mt-8 bg-slate-900 p-6 rounded-lg"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const amountSlider = document.getElementById('amount'); |
|
|
const rateSlider = document.getElementById('rate'); |
|
|
const tenureSlider = document.getElementById('tenure'); |
|
|
const calculateEMI = () => { |
|
|
const p = parseFloat(amountSlider.value); |
|
|
const r = parseFloat(rateSlider.value) / 12 / 100; |
|
|
const n = parseFloat(tenureSlider.value); |
|
|
document.getElementById('amount-val').textContent = formatCurrency(p, 0); |
|
|
document.getElementById('rate-val').textContent = `${rateSlider.value}%`; |
|
|
document.getElementById('tenure-val').textContent = `${n} months`; |
|
|
if (r === 0) { |
|
|
document.getElementById('emi-result').innerHTML = `<p class="text-lg text-slate-400">Monthly EMI:</p><p class="text-4xl font-bold text-white">${formatCurrency(p/n)}</p>`; |
|
|
return; |
|
|
} |
|
|
const emi = p * r * (Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1); |
|
|
const totalPayable = emi * n; |
|
|
const totalInterest = totalPayable - p; |
|
|
|
|
|
document.getElementById('emi-result').innerHTML = ` |
|
|
<p class="text-lg text-slate-400">Monthly EMI:</p> |
|
|
<p class="text-4xl font-bold text-white mb-4">${formatCurrency(emi)}</p> |
|
|
<div class="flex justify-around text-center"> |
|
|
<div> |
|
|
<p class="text-slate-400 text-sm">Total Interest</p> |
|
|
<p class="text-lg font-semibold text-red-400">${formatCurrency(totalInterest)}</p> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-slate-400 text-sm">Total Payment</p> |
|
|
<p class="text-lg font-semibold text-green-400">${formatCurrency(totalPayable)}</p> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
}; |
|
|
[amountSlider, rateSlider, tenureSlider].forEach(el => el.addEventListener('input', calculateEMI)); |
|
|
calculateEMI(); |
|
|
} |
|
|
}, |
|
|
gst: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-green-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-green-400">GST/VAT Calculator</h2> |
|
|
<div class="space-y-4"> |
|
|
<div> |
|
|
<label for="gst-amount" class="text-slate-300 font-semibold block mb-2">Amount</label> |
|
|
<input type="number" id="gst-amount" placeholder="Enter amount" class="w-full bg-slate-700 border-2 border-slate-600 rounded-lg p-3 text-white focus:outline-none focus:border-green-500"> |
|
|
</div> |
|
|
<div> |
|
|
<label for="gst-rate" class="text-slate-300 font-semibold block mb-2">GST/VAT Rate (%)</label> |
|
|
<input type="number" id="gst-rate" value="18" class="w-full bg-slate-700 border-2 border-slate-600 rounded-lg p-3 text-white focus:outline-none focus:border-green-500"> |
|
|
</div> |
|
|
<div class="flex gap-4"> |
|
|
<button id="add-gst" class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 rounded-lg transition">Add GST</button> |
|
|
<button id="remove-gst" class="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-3 rounded-lg transition">Remove GST</button> |
|
|
</div> |
|
|
</div> |
|
|
<div id="gst-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg min-h-[100px] flex flex-col justify-center"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const amountInput = document.getElementById('gst-amount'); |
|
|
const rateInput = document.getElementById('gst-rate'); |
|
|
const resultDiv = document.getElementById('gst-result'); |
|
|
document.getElementById('add-gst').addEventListener('click', () => { |
|
|
const amount = parseFloat(amountInput.value); |
|
|
const rate = parseFloat(rateInput.value); |
|
|
if (isNaN(amount) || isNaN(rate)) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please enter valid amount and rate.</p>`; |
|
|
return; |
|
|
} |
|
|
const tax = amount * (rate / 100); |
|
|
const total = amount + tax; |
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Tax Amount: <span class="font-semibold text-white">${formatCurrency(tax)}</span></p> |
|
|
<p class="text-slate-400">Total Amount (incl. GST): <span class="font-semibold text-2xl text-green-400">${formatCurrency(total)}</span></p> |
|
|
`; |
|
|
}); |
|
|
document.getElementById('remove-gst').addEventListener('click', () => { |
|
|
const amount = parseFloat(amountInput.value); |
|
|
const rate = parseFloat(rateInput.value); |
|
|
if (isNaN(amount) || isNaN(rate)) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please enter valid amount and rate.</p>`; |
|
|
return; |
|
|
} |
|
|
const originalAmount = amount / (1 + rate / 100); |
|
|
const tax = amount - originalAmount; |
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Base Amount: <span class="font-semibold text-2xl text-green-400">${formatCurrency(originalAmount)}</span></p> |
|
|
<p class="text-slate-400">Tax Amount (GST): <span class="font-semibold text-white">${formatCurrency(tax)}</span></p> |
|
|
`; |
|
|
}); |
|
|
} |
|
|
}, |
|
|
split: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-green-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-green-400">Bill Splitter</h2> |
|
|
<div class="space-y-4"> |
|
|
<input type="number" id="bill-total" placeholder="Total Bill Amount" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-green-500"> |
|
|
<input type="number" id="bill-people" placeholder="Number of People" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-green-500"> |
|
|
<div> |
|
|
<label class="text-slate-300 font-semibold">Tip: <span id="bill-tip-val" class="font-bold text-green-400">10%</span></label> |
|
|
<input type="range" id="bill-tip" min="0" max="50" value="10" class="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer"> |
|
|
</div> |
|
|
<button id="split-bill-btn" class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 rounded-lg transition">Calculate</button> |
|
|
</div> |
|
|
<div id="split-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg min-h-[100px] flex flex-col justify-center"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const totalInput = document.getElementById('bill-total'); |
|
|
const peopleInput = document.getElementById('bill-people'); |
|
|
const tipSlider = document.getElementById('bill-tip'); |
|
|
const tipVal = document.getElementById('bill-tip-val'); |
|
|
const resultDiv = document.getElementById('split-result'); |
|
|
|
|
|
tipSlider.addEventListener('input', () => tipVal.textContent = `${tipSlider.value}%`); |
|
|
|
|
|
document.getElementById('split-bill-btn').addEventListener('click', () => { |
|
|
const total = parseFloat(totalInput.value); |
|
|
const people = parseInt(peopleInput.value); |
|
|
const tipPercent = parseFloat(tipSlider.value); |
|
|
|
|
|
if (isNaN(total) || isNaN(people) || total <= 0 || people <= 0) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please enter a valid bill amount and number of people.</p>`; |
|
|
return; |
|
|
} |
|
|
|
|
|
const tipAmount = total * (tipPercent / 100); |
|
|
const finalTotal = total + tipAmount; |
|
|
const perPerson = finalTotal / people; |
|
|
|
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Total Bill (incl. tip): <span class="font-semibold text-white">${formatCurrency(finalTotal)}</span></p> |
|
|
<p class="text-slate-400">Each person pays:</p> |
|
|
<p class="text-3xl font-bold text-green-400">${formatCurrency(perPerson)}</p> |
|
|
`; |
|
|
}); |
|
|
} |
|
|
}, |
|
|
|
|
|
// --- Health Calculators --- |
|
|
bmi: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-red-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-red-400">BMI Calculator</h2> |
|
|
<div class="flex justify-center mb-4"> |
|
|
<div class="bg-slate-700 p-1 rounded-full flex gap-1"> |
|
|
<button id="bmi-metric" class="px-4 py-2 rounded-full font-semibold bg-red-500 text-white">Metric</button> |
|
|
<button id="bmi-imperial" class="px-4 py-2 rounded-full font-semibold text-slate-300">Imperial</button> |
|
|
</div> |
|
|
</div> |
|
|
<div id="bmi-inputs" class="space-y-4"></div> |
|
|
<div id="bmi-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg min-h-[100px]"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const metricBtn = document.getElementById('bmi-metric'); |
|
|
const imperialBtn = document.getElementById('bmi-imperial'); |
|
|
const inputsDiv = document.getElementById('bmi-inputs'); |
|
|
const resultDiv = document.getElementById('bmi-result'); |
|
|
let unit = 'metric'; |
|
|
|
|
|
const metricTemplate = ` |
|
|
<input type="number" id="cm" placeholder="Height (cm)" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-red-500"> |
|
|
<input type="number" id="kg" placeholder="Weight (kg)" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-red-500"> |
|
|
`; |
|
|
const imperialTemplate = ` |
|
|
<div class="flex gap-4"> |
|
|
<input type="number" id="ft" placeholder="Height (ft)" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-red-500"> |
|
|
<input type="number" id="in" placeholder="Height (in)" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-red-500"> |
|
|
</div> |
|
|
<input type="number" id="lbs" placeholder="Weight (lbs)" class="w-full bg-slate-700 p-3 rounded-lg text-white focus:outline-none focus:border-red-500"> |
|
|
`; |
|
|
|
|
|
const calculateBMI = () => { |
|
|
let bmi; |
|
|
if (unit === 'metric') { |
|
|
const cm = parseFloat(document.getElementById('cm').value); |
|
|
const kg = parseFloat(document.getElementById('kg').value); |
|
|
if (!cm || !kg || cm <= 0 || kg <= 0) return; |
|
|
bmi = kg / Math.pow(cm / 100, 2); |
|
|
} else { |
|
|
const ft = parseFloat(document.getElementById('ft').value) || 0; |
|
|
const inches = parseFloat(document.getElementById('in').value) || 0; |
|
|
const lbs = parseFloat(document.getElementById('lbs').value); |
|
|
const totalInches = (ft * 12) + inches; |
|
|
if (!totalInches || !lbs || totalInches <= 0 || lbs <= 0) return; |
|
|
bmi = (lbs / Math.pow(totalInches, 2)) * 703; |
|
|
} |
|
|
|
|
|
if (isNaN(bmi)) return; |
|
|
|
|
|
let category = ''; |
|
|
let color = ''; |
|
|
if (bmi < 18.5) { category = 'Underweight'; color = 'text-blue-400'; } |
|
|
else if (bmi < 25) { category = 'Normal weight'; color = 'text-green-400'; } |
|
|
else if (bmi < 30) { category = 'Overweight'; color = 'text-yellow-400'; } |
|
|
else { category = 'Obese'; color = 'text-red-400'; } |
|
|
|
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Your BMI:</p> |
|
|
<p class="text-4xl font-bold text-white">${bmi.toFixed(1)}</p> |
|
|
<p class="text-xl font-semibold ${color}">${category}</p> |
|
|
`; |
|
|
}; |
|
|
|
|
|
const setupInputs = () => { |
|
|
inputsDiv.innerHTML = unit === 'metric' ? metricTemplate : imperialTemplate; |
|
|
resultDiv.innerHTML = ''; |
|
|
inputsDiv.querySelectorAll('input').forEach(el => el.addEventListener('input', calculateBMI)); |
|
|
}; |
|
|
|
|
|
metricBtn.addEventListener('click', () => { |
|
|
unit = 'metric'; |
|
|
metricBtn.classList.add('bg-red-500', 'text-white'); |
|
|
imperialBtn.classList.remove('bg-red-500', 'text-white'); |
|
|
setupInputs(); |
|
|
}); |
|
|
|
|
|
imperialBtn.addEventListener('click', () => { |
|
|
unit = 'imperial'; |
|
|
imperialBtn.classList.add('bg-red-500', 'text-white'); |
|
|
metricBtn.classList.remove('bg-red-500', 'text-white'); |
|
|
setupInputs(); |
|
|
}); |
|
|
|
|
|
setupInputs(); |
|
|
} |
|
|
}, |
|
|
calorie: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-red-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-red-400">Calorie Calculator (BMR & TDEE)</h2> |
|
|
<div class="grid md:grid-cols-2 gap-4"> |
|
|
<input type="number" id="cal-age" placeholder="Age" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<select id="cal-gender" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<option value="male">Male</option> |
|
|
<option value="female">Female</option> |
|
|
</select> |
|
|
<input type="number" id="cal-height" placeholder="Height (cm)" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<input type="number" id="cal-weight" placeholder="Weight (kg)" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<select id="cal-activity" class="w-full bg-slate-700 p-3 rounded-lg text-white md:col-span-2"> |
|
|
<option value="1.2">Sedentary (little or no exercise)</option> |
|
|
<option value="1.375">Lightly active (light exercise/sports 1-3 days/week)</option> |
|
|
<option value="1.55">Moderately active (moderate exercise/sports 3-5 days/week)</option> |
|
|
<option value="1.725">Very active (hard exercise/sports 6-7 days a week)</option> |
|
|
<option value="1.9">Extra active (very hard exercise/sports & physical job)</option> |
|
|
</select> |
|
|
<button id="cal-calculate" class="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-3 rounded-lg transition md:col-span-2">Calculate</button> |
|
|
</div> |
|
|
<div id="cal-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg"></div> |
|
|
</div>`, |
|
|
init: function() { |
|
|
document.getElementById('cal-calculate').addEventListener('click', () => { |
|
|
const age = parseFloat(document.getElementById('cal-age').value); |
|
|
const gender = document.getElementById('cal-gender').value; |
|
|
const height = parseFloat(document.getElementById('cal-height').value); |
|
|
const weight = parseFloat(document.getElementById('cal-weight').value); |
|
|
const activity = parseFloat(document.getElementById('cal-activity').value); |
|
|
const resultDiv = document.getElementById('cal-result'); |
|
|
|
|
|
if (!age || !height || !weight) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please fill all fields.</p>`; |
|
|
return; |
|
|
} |
|
|
|
|
|
let bmr; |
|
|
if (gender === 'male') { |
|
|
bmr = 10 * weight + 6.25 * height - 5 * age + 5; |
|
|
} else { |
|
|
bmr = 10 * weight + 6.25 * height - 5 * age - 161; |
|
|
} |
|
|
const tdee = bmr * activity; |
|
|
|
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Your Basal Metabolic Rate (BMR) is:</p> |
|
|
<p class="text-2xl font-bold text-white">${bmr.toFixed(0)} Calories/day</p> |
|
|
<p class="text-slate-400 mt-4">Your Total Daily Energy Expenditure (TDEE) is:</p> |
|
|
<p class="text-3xl font-bold text-red-400">${tdee.toFixed(0)} Calories/day</p> |
|
|
`; |
|
|
}); |
|
|
} |
|
|
}, |
|
|
bodyfat: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-red-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-red-400">Body Fat Calculator (Navy Method)</h2> |
|
|
<div class="grid md:grid-cols-2 gap-4"> |
|
|
<select id="bf-gender" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<option value="male">Male</option> |
|
|
<option value="female">Female</option> |
|
|
</select> |
|
|
<input type="number" id="bf-height" placeholder="Height (cm)" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<input type="number" id="bf-neck" placeholder="Neck (cm)" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<input type="number" id="bf-waist" placeholder="Waist (cm)" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<div id="bf-female-only" class="md:col-span-2 hidden"> |
|
|
<input type="number" id="bf-hip" placeholder="Hip (cm)" class="w-full bg-slate-700 p-3 rounded-lg text-white mt-4"> |
|
|
</div> |
|
|
<button id="bf-calculate" class="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-3 rounded-lg transition md:col-span-2">Calculate</button> |
|
|
</div> |
|
|
<div id="bf-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg"></div> |
|
|
</div>`, |
|
|
init: function() { |
|
|
const genderSelect = document.getElementById('bf-gender'); |
|
|
const femaleOnlyDiv = document.getElementById('bf-female-only'); |
|
|
|
|
|
genderSelect.addEventListener('change', () => { |
|
|
femaleOnlyDiv.classList.toggle('hidden', genderSelect.value === 'male'); |
|
|
}); |
|
|
|
|
|
document.getElementById('bf-calculate').addEventListener('click', () => { |
|
|
const gender = genderSelect.value; |
|
|
const height = parseFloat(document.getElementById('bf-height').value); |
|
|
const neck = parseFloat(document.getElementById('bf-neck').value); |
|
|
const waist = parseFloat(document.getElementById('bf-waist').value); |
|
|
const resultDiv = document.getElementById('bf-result'); |
|
|
let bfp; |
|
|
|
|
|
if (!height || !neck || !waist) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please fill all required fields.</p>`; |
|
|
return; |
|
|
} |
|
|
|
|
|
if (gender === 'male') { |
|
|
bfp = 495 / (1.0324 - 0.19077 * Math.log10(waist - neck) + 0.15456 * Math.log10(height)) - 450; |
|
|
} else { |
|
|
const hip = parseFloat(document.getElementById('bf-hip').value); |
|
|
if (!hip) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please fill all required fields.</p>`; |
|
|
return; |
|
|
} |
|
|
bfp = 495 / (1.29579 - 0.35004 * Math.log10(waist + hip - neck) + 0.22100 * Math.log10(height)) - 450; |
|
|
} |
|
|
|
|
|
if (isNaN(bfp) || bfp < 0) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Could not calculate. Please check your measurements.</p>`; |
|
|
} else { |
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Estimated Body Fat:</p> |
|
|
<p class="text-4xl font-bold text-red-400">${bfp.toFixed(1)}%</p> |
|
|
`; |
|
|
} |
|
|
}); |
|
|
} |
|
|
}, |
|
|
|
|
|
// --- Converters --- |
|
|
converter: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-blue-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 id="converter-title" class="text-2xl font-bold text-center mb-6 text-blue-400"></h2> |
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 items-center"> |
|
|
<div> |
|
|
<select id="from-unit" class="w-full bg-slate-700 p-3 rounded-lg text-white"></select> |
|
|
<input type="number" id="from-value" placeholder="Enter value" class="w-full bg-slate-700 p-3 rounded-lg text-white mt-2"> |
|
|
</div> |
|
|
<div> |
|
|
<select id="to-unit" class="w-full bg-slate-700 p-3 rounded-lg text-white"></select> |
|
|
<input type="text" id="to-value" readonly class="w-full bg-slate-900 p-3 rounded-lg text-white mt-2 font-bold text-xl"> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
`, |
|
|
init: function(type) { |
|
|
const units = { |
|
|
length: { name: 'Length Converter', base: 'meter', list: { meter: 1, kilometer: 1000, centimeter: 0.01, millimeter: 0.001, mile: 1609.34, yard: 0.9144, foot: 0.3048, inch: 0.0254 } }, |
|
|
weight: { name: 'Weight Converter', base: 'kilogram', list: { kilogram: 1, gram: 0.001, milligram: 1e-6, ton: 1000, pound: 0.453592, ounce: 0.0283495 } }, |
|
|
temperature: { name: 'Temperature Converter', base: 'celsius', list: { celsius: 'C', fahrenheit: 'F', kelvin: 'K' } } |
|
|
}; |
|
|
|
|
|
const config = units[type]; |
|
|
document.getElementById('converter-title').textContent = config.name; |
|
|
|
|
|
const fromUnit = document.getElementById('from-unit'); |
|
|
const toUnit = document.getElementById('to-unit'); |
|
|
const fromValue = document.getElementById('from-value'); |
|
|
|
|
|
Object.keys(config.list).forEach(unit => { |
|
|
fromUnit.innerHTML += `<option value="${unit}">${unit}</option>`; |
|
|
toUnit.innerHTML += `<option value="${unit}">${unit}</option>`; |
|
|
}); |
|
|
|
|
|
fromUnit.value = Object.keys(config.list)[0]; |
|
|
toUnit.value = Object.keys(config.list)[1]; |
|
|
|
|
|
const convert = () => { |
|
|
const from = fromValue.value; |
|
|
if (from === '' || isNaN(from)) { |
|
|
document.getElementById('to-value').value = ''; |
|
|
return; |
|
|
} |
|
|
|
|
|
let result; |
|
|
if (type === 'temperature') { |
|
|
const fromU = fromUnit.value; |
|
|
const toU = toUnit.value; |
|
|
const val = parseFloat(from); |
|
|
if (fromU === toU) { result = val; } |
|
|
else if (fromU === 'celsius' && toU === 'fahrenheit') { result = (val * 9/5) + 32; } |
|
|
else if (fromU === 'celsius' && toU === 'kelvin') { result = val + 273.15; } |
|
|
else if (fromU === 'fahrenheit' && toU === 'celsius') { result = (val - 32) * 5/9; } |
|
|
else if (fromU === 'fahrenheit' && toU === 'kelvin') { result = (val - 32) * 5/9 + 273.15; } |
|
|
else if (fromU === 'kelvin' && toU === 'celsius') { result = val - 273.15; } |
|
|
else if (fromU === 'kelvin' && toU === 'fahrenheit') { result = (val - 273.15) * 9/5 + 32; } |
|
|
} else { |
|
|
const inBase = from * config.list[fromUnit.value]; |
|
|
result = inBase / config.list[toUnit.value]; |
|
|
} |
|
|
|
|
|
document.getElementById('to-value').value = result.toFixed(type === 'temperature' ? 2 : 4); |
|
|
}; |
|
|
|
|
|
[fromUnit, toUnit, fromValue].forEach(el => el.addEventListener('change', convert)); |
|
|
fromValue.addEventListener('input', convert); |
|
|
} |
|
|
}, |
|
|
|
|
|
// --- Date & Time --- |
|
|
age: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-purple-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-purple-400">Age Calculator</h2> |
|
|
<div class="grid md:grid-cols-2 gap-4"> |
|
|
<div> |
|
|
<label for="birth-date" class="text-slate-300 font-semibold block mb-2">Your Date of Birth</label> |
|
|
<input type="date" id="birth-date" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
</div> |
|
|
<div> |
|
|
<label for="current-date" class="text-slate-300 font-semibold block mb-2">Age at the Date of</label> |
|
|
<input type="date" id="current-date" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
</div> |
|
|
<button id="age-calculate" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 rounded-lg transition md:col-span-2">Calculate Age</button> |
|
|
</div> |
|
|
<div id="age-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const today = new Date().toISOString().split('T')[0]; |
|
|
document.getElementById('current-date').value = today; |
|
|
document.getElementById('age-calculate').addEventListener('click', () => { |
|
|
const birthDate = new Date(document.getElementById('birth-date').value); |
|
|
const currentDate = new Date(document.getElementById('current-date').value); |
|
|
const resultDiv = document.getElementById('age-result'); |
|
|
|
|
|
if (isNaN(birthDate.getTime()) || isNaN(currentDate.getTime())) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please select valid dates.</p>`; |
|
|
return; |
|
|
} |
|
|
|
|
|
if (birthDate > currentDate) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Birth date cannot be in the future.</p>`; |
|
|
return; |
|
|
} |
|
|
|
|
|
let years = currentDate.getFullYear() - birthDate.getFullYear(); |
|
|
let months = currentDate.getMonth() - birthDate.getMonth(); |
|
|
let days = currentDate.getDate() - birthDate.getDate(); |
|
|
|
|
|
if (days < 0) { |
|
|
months--; |
|
|
days += new Date(currentDate.getFullYear(), currentDate.getMonth(), 0).getDate(); |
|
|
} |
|
|
if (months < 0) { |
|
|
years--; |
|
|
months += 12; |
|
|
} |
|
|
|
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Your Age is</p> |
|
|
<p class="text-3xl font-bold text-purple-400">${years} <span class="text-xl">years</span> ${months} <span class="text-xl">months</span> ${days} <span class="text-xl">days</span></p> |
|
|
`; |
|
|
}); |
|
|
} |
|
|
}, |
|
|
dateDiff: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-purple-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-purple-400">Date Difference</h2> |
|
|
<div class="grid md:grid-cols-2 gap-4"> |
|
|
<div> |
|
|
<label for="start-date" class="text-slate-300 font-semibold block mb-2">Start Date</label> |
|
|
<input type="date" id="start-date" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
</div> |
|
|
<div> |
|
|
<label for="end-date" class="text-slate-300 font-semibold block mb-2">End Date</label> |
|
|
<input type="date" id="end-date" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
</div> |
|
|
</div> |
|
|
<div id="date-diff-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const startDateInput = document.getElementById('start-date'); |
|
|
const endDateInput = document.getElementById('end-date'); |
|
|
const resultDiv = document.getElementById('date-diff-result'); |
|
|
|
|
|
const calculateDiff = () => { |
|
|
const startDate = new Date(startDateInput.value); |
|
|
const endDate = new Date(endDateInput.value); |
|
|
|
|
|
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { |
|
|
resultDiv.innerHTML = ''; |
|
|
return; |
|
|
} |
|
|
|
|
|
const diffTime = Math.abs(endDate - startDate); |
|
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); |
|
|
|
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Difference:</p> |
|
|
<p class="text-3xl font-bold text-purple-400">${diffDays} days</p> |
|
|
<p class="text-lg text-white">~${(diffDays/7).toFixed(1)} weeks | ~${(diffDays/30.44).toFixed(1)} months</p> |
|
|
`; |
|
|
}; |
|
|
|
|
|
startDateInput.addEventListener('change', calculateDiff); |
|
|
endDateInput.addEventListener('change', calculateDiff); |
|
|
} |
|
|
}, |
|
|
dateAdd: { |
|
|
template: ` |
|
|
<div class="fade-in bg-slate-800/70 backdrop-blur-sm rounded-xl shadow-lg p-6 lg:p-8 border-t-4 border-purple-500 relative max-w-2xl mx-auto"> |
|
|
${backButton} |
|
|
<h2 class="text-2xl font-bold text-center mb-6 text-purple-400">Add / Subtract Dates</h2> |
|
|
<div> |
|
|
<label for="start-date-add" class="text-slate-300 font-semibold block mb-2">Start Date</label> |
|
|
<input type="date" id="start-date-add" class="w-full bg-slate-700 p-3 rounded-lg text-white mb-4"> |
|
|
</div> |
|
|
<div class="grid grid-cols-3 gap-2"> |
|
|
<input type="number" id="add-years" placeholder="Years" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<input type="number" id="add-months" placeholder="Months" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
<input type="number" id="add-days" placeholder="Days" class="w-full bg-slate-700 p-3 rounded-lg text-white"> |
|
|
</div> |
|
|
<div class="flex gap-4 mt-4"> |
|
|
<button id="add-date-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 rounded-lg transition">Add</button> |
|
|
<button id="sub-date-btn" class="w-full bg-purple-800 hover:bg-purple-900 text-white font-bold py-3 rounded-lg transition">Subtract</button> |
|
|
</div> |
|
|
<div id="date-add-result" class="text-center mt-6 bg-slate-900 p-4 rounded-lg"></div> |
|
|
</div> |
|
|
`, |
|
|
init: function() { |
|
|
const startDateInput = document.getElementById('start-date-add'); |
|
|
startDateInput.value = new Date().toISOString().split('T')[0]; |
|
|
const resultDiv = document.getElementById('date-add-result'); |
|
|
|
|
|
const calculate = (multiplier) => { |
|
|
const startDate = new Date(startDateInput.value); |
|
|
if(isNaN(startDate.getTime())) { |
|
|
resultDiv.innerHTML = `<p class="text-red-400">Please select a valid start date.</p>`; |
|
|
return; |
|
|
} |
|
|
|
|
|
const years = parseInt(document.getElementById('add-years').value) || 0; |
|
|
const months = parseInt(document.getElementById('add-months').value) || 0; |
|
|
const days = parseInt(document.getElementById('add-days').value) || 0; |
|
|
|
|
|
startDate.setFullYear(startDate.getFullYear() + years * multiplier); |
|
|
startDate.setMonth(startDate.getMonth() + months * multiplier); |
|
|
startDate.setDate(startDate.getDate() + days * multiplier); |
|
|
|
|
|
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; |
|
|
|
|
|
resultDiv.innerHTML = ` |
|
|
<p class="text-slate-400">Resulting Date:</p> |
|
|
<p class="text-3xl font-bold text-purple-400">${startDate.toLocaleDateString('en-US', options)}</p> |
|
|
`; |
|
|
}; |
|
|
|
|
|
document.getElementById('add-date-btn').addEventListener('click', () => calculate(1)); |
|
|
document.getElementById('sub-date-btn').addEventListener('click', () => calculate(-1)); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
function showDashboard() { |
|
|
calculatorContainer.innerHTML = ''; |
|
|
dashboard.classList.remove('hidden'); |
|
|
dashboard.classList.add('fade-in'); |
|
|
} |
|
|
|
|
|
function showCalculator(calcName, subType = null) { |
|
|
dashboard.classList.add('hidden'); |
|
|
const calc = calculators[calcName]; |
|
|
if (calc) { |
|
|
calculatorContainer.innerHTML = calc.template; |
|
|
calc.init(subType); |
|
|
} |
|
|
} |
|
|
</script> |
|
|
|
|
|
</body> |
|
|
</html> |