Spaces:
Running
Running
<html lang="es"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Calculadora de Costos Textiles</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> | |
.input-error { | |
border-color: #f87171; | |
background-color: #fee2e2; | |
} | |
.result-card { | |
transition: all 0.3s ease; | |
} | |
.result-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 min-h-screen"> | |
<div class="container mx-auto px-4 py-8 max-w-4xl"> | |
<div class="text-center mb-10"> | |
<h1 class="text-3xl md:text-4xl font-bold text-indigo-700 mb-2">Calculadora Textil</h1> | |
<p class="text-gray-600">Calcula el costo total de tela y sublimación para tus proyectos</p> | |
</div> | |
<div class="bg-white rounded-xl shadow-md p-6 mb-8"> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div> | |
<label for="fabricPrice" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-ruler-combined text-indigo-500 mr-2"></i>Precio por m² de tela ($) | |
</label> | |
<div class="relative"> | |
<input type="number" id="fabricPrice" min="0" step="0.01" value="25" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-2.5 text-gray-500">$/m²</span> | |
</div> | |
<p id="fabricError" class="text-red-500 text-xs mt-1 hidden">Ingrese un valor válido</p> | |
</div> | |
<div> | |
<label for="sublimationPrice" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-fire text-indigo-500 mr-2"></i>Precio por m² de sublimación ($) | |
</label> | |
<div class="relative"> | |
<input type="number" id="sublimationPrice" min="0" step="0.01" value="25" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-2.5 text-gray-500">$/m²</span> | |
</div> | |
<p id="sublimationError" class="text-red-500 text-xs mt-1 hidden">Ingrese un valor válido</p> | |
</div> | |
<div> | |
<label for="fabricArea" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-square text-indigo-500 mr-2"></i>Metros cuadrados de tela por unidad | |
</label> | |
<div class="relative"> | |
<input type="number" id="fabricArea" min="0" step="0.01" value="0.80" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-2.5 text-gray-500">m²</span> | |
</div> | |
<p id="areaError" class="text-red-500 text-xs mt-1 hidden">Ingrese un valor válido</p> | |
</div> | |
<div> | |
<label for="sublimationArea" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-square text-indigo-500 mr-2"></i>Metros cuadrados de sublimación por unidad | |
</label> | |
<div class="relative"> | |
<input type="number" id="sublimationArea" min="0" step="0.01" value="0.85" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-2.5 text-gray-500">m²</span> | |
</div> | |
<p id="sublimationAreaError" class="text-red-500 text-xs mt-1 hidden">Ingrese un valor válido</p> | |
</div> | |
<div class="relative"> | |
<label for="quantity" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-boxes text-indigo-500 mr-2"></i>Cantidad de unidades | |
</label> | |
<input type="number" id="quantity" min="1" value="10" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-8 text-gray-500">unidades</span> | |
</div> | |
<div> | |
<label for="sewingPrice" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-needle text-indigo-500 mr-2"></i>Precio de costura por unidad ($) | |
</label> | |
<div class="relative"> | |
<input type="number" id="sewingPrice" min="0" step="0.01" value="12" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-2.5 text-gray-500">$/unidad</span> | |
</div> | |
<p id="sewingError" class="text-red-500 text-xs mt-1 hidden">Ingrese un valor válido</p> | |
</div> | |
<div> | |
<label for="orderName" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-tag text-indigo-500 mr-2"></i>Nombre del pedido | |
</label> | |
<input type="text" id="orderName" value="Pedido 1" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
</div> | |
<div> | |
<label for="extraCosts" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-plus-circle text-indigo-500 mr-2"></i>Costos extras por unidad ($) | |
</label> | |
<div class="relative"> | |
<input type="number" id="extraCosts" min="0" step="0.01" value="0" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> | |
<span class="absolute right-3 top-2.5 text-gray-500">$/unidad</span> | |
</div> | |
<p id="extraCostsError" class="text-red-500 text-xs mt-1 hidden">Ingrese un valor válido</p> | |
</div> | |
</div> | |
<div class="mt-6 flex justify-center"> | |
<button id="calculateBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2 px-6 rounded-lg transition duration-300 flex items-center"> | |
<i class="fas fa-calculator mr-2"></i> Calcular Costos | |
</button> | |
</div> | |
</div> | |
<div id="resultsContainer" class="hidden w-full"> | |
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> | |
<i class="fas fa-chart-line text-indigo-500 mr-2"></i> Resultados | |
</h2> | |
<div class="grid grid-cols-1"> | |
<div class="result-card bg-white rounded-xl shadow-md p-6 border-l-4 border-indigo-500 w-full"> | |
<h3 class="font-medium text-gray-700 mb-4 flex items-center"> | |
<i class="fas fa-tshirt text-indigo-500 mr-2"></i> Costo por 1 unidad | |
</h3> | |
<div class="space-y-3"> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costo tela (1 unidad):</span> | |
<span id="fabricCostSingle" class="font-medium">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costo sublimación (1 unidad):</span> | |
<span id="sublimationCostSingle" class="font-medium">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costo costura (1 unidad):</span> | |
<span id="sewingCostSingle" class="font-medium">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costos extras (1 unidad):</span> | |
<span id="extraCostsSingle" class="font-medium">$0.00</span> | |
</div> | |
<div class="border-t border-gray-200 my-2"></div> | |
<div class="flex justify-between"> | |
<span class="text-gray-800 font-semibold">Total por 1 unidad:</span> | |
<span id="totalCostSingle" class="text-indigo-600 font-bold">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costo tela:</span> | |
<span id="fabricCostQuantity" class="font-medium">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costo sublimación:</span> | |
<span id="sublimationCostQuantity" class="font-medium">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costos extras:</span> | |
<span id="extraCostsQuantity" class="font-medium">$0.00</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-600">Costo costura:</span> | |
<span id="sewingCostQuantity" class="font-medium">$0.00</span> | |
</div> | |
<div class="border-t border-gray-200 my-2"></div> | |
<div class="flex justify-between"> | |
<span class="text-gray-800 font-semibold">Total por <span id="quantityDisplay">1</span> unidad(es):</span> | |
<span id="totalCostQuantity" class="text-indigo-600 font-bold text-lg">$0.00</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="mt-6 bg-white rounded-xl shadow-md p-6 w-full"> | |
<h3 class="font-medium text-gray-700 mb-4 flex items-center"> | |
<i class="fas fa-history text-indigo-500 mr-2"></i> Historial (últimos 10) | |
</h3> | |
<div id="historyList" class="space-y-3"> | |
<!-- History items will be added here --> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// Load history from localStorage | |
let calculationHistory = JSON.parse(localStorage.getItem('textileCalcHistory')) || []; | |
renderHistory(); | |
const calculateBtn = document.getElementById('calculateBtn'); | |
const resultsContainer = document.getElementById('resultsContainer'); | |
// Input fields | |
const fabricPriceInput = document.getElementById('fabricPrice'); | |
const sublimationPriceInput = document.getElementById('sublimationPrice'); | |
const fabricAreaInput = document.getElementById('fabricArea'); | |
const sublimationAreaInput = document.getElementById('sublimationArea'); | |
const sewingPriceInput = document.getElementById('sewingPrice'); | |
// Error messages | |
const fabricError = document.getElementById('fabricError'); | |
const sublimationError = document.getElementById('sublimationError'); | |
const areaError = document.getElementById('areaError'); | |
const sublimationAreaError = document.getElementById('sublimationAreaError'); | |
const sewingError = document.getElementById('sewingError'); | |
// Result fields | |
const fabricCostSingle = document.getElementById('fabricCostSingle'); | |
const sublimationCostSingle = document.getElementById('sublimationCostSingle'); | |
const totalCostSingle = document.getElementById('totalCostSingle'); | |
const fabricCostBulk = document.getElementById('fabricCostBulk'); | |
const sublimationCostBulk = document.getElementById('sublimationCostBulk'); | |
const totalCostBulk = document.getElementById('totalCostBulk'); | |
calculateBtn.addEventListener('click', calculateCosts); | |
// Also calculate when pressing Enter in any input | |
[fabricPriceInput, sublimationPriceInput, fabricAreaInput, sublimationAreaInput].forEach(input => { | |
input.addEventListener('keypress', function(e) { | |
if (e.key === 'Enter') { | |
calculateCosts(); | |
} | |
}); | |
}); | |
function calculateCosts() { | |
// Reset error states | |
resetErrors(); | |
// Get values | |
const fabricPrice = parseFloat(fabricPriceInput.value); | |
const sublimationPrice = parseFloat(sublimationPriceInput.value); | |
const fabricArea = parseFloat(fabricAreaInput.value); | |
const sublimationArea = parseFloat(sublimationAreaInput.value); | |
const sewingPrice = parseFloat(sewingPriceInput.value); | |
const extraCosts = parseFloat(document.getElementById('extraCosts').value) || 0; | |
// Validate inputs | |
let isValid = true; | |
if (isNaN(fabricPrice) || fabricPrice < 0) { | |
fabricError.classList.remove('hidden'); | |
fabricPriceInput.classList.add('input-error'); | |
isValid = false; | |
} | |
if (isNaN(sublimationPrice) || sublimationPrice < 0) { | |
sublimationError.classList.remove('hidden'); | |
sublimationPriceInput.classList.add('input-error'); | |
isValid = false; | |
} | |
if (isNaN(fabricArea) || fabricArea <= 0) { | |
areaError.classList.remove('hidden'); | |
fabricAreaInput.classList.add('input-error'); | |
isValid = false; | |
} | |
if (isNaN(sublimationArea) || sublimationArea < 0) { | |
sublimationAreaError.classList.remove('hidden'); | |
sublimationAreaInput.classList.add('input-error'); | |
isValid = false; | |
} | |
if (isNaN(sewingPrice) || sewingPrice < 0) { | |
sewingError.classList.remove('hidden'); | |
sewingPriceInput.classList.add('input-error'); | |
isValid = false; | |
} | |
if (!isValid) return; | |
// Calculate costs | |
const fabricCostPerUnit = fabricPrice * fabricArea; | |
const sublimationCostPerUnit = sublimationPrice * sublimationArea; | |
const totalCostPerUnit = fabricCostPerUnit + sublimationCostPerUnit + sewingPrice + extraCosts; | |
const quantity = parseInt(document.getElementById('quantity').value) || 1; | |
document.getElementById('quantityDisplay').textContent = quantity; | |
const fabricCostForQuantity = fabricCostPerUnit * quantity; | |
const sublimationCostForQuantity = sublimationCostPerUnit * quantity; | |
const sewingCostForQuantity = sewingPrice * quantity; | |
const extraCostsForQuantity = extraCosts * quantity; | |
const totalCostForQuantity = totalCostPerUnit * quantity; | |
// Update UI with results | |
fabricCostSingle.textContent = `${fabricCostPerUnit.toFixed(2)}`; | |
sublimationCostSingle.textContent = `${sublimationCostPerUnit.toFixed(2)}`; | |
totalCostSingle.textContent = `${totalCostPerUnit.toFixed(2)}`; | |
document.getElementById('sewingCostSingle').textContent = `${sewingPrice.toFixed(2)}`; | |
document.getElementById('extraCostsSingle').textContent = `${extraCosts.toFixed(2)}`; | |
document.getElementById('fabricCostQuantity').textContent = `${fabricCostForQuantity.toFixed(2)}`; | |
document.getElementById('sublimationCostQuantity').textContent = `${sublimationCostForQuantity.toFixed(2)}`; | |
document.getElementById('sewingCostQuantity').textContent = `${sewingCostForQuantity.toFixed(2)}`; | |
document.getElementById('extraCostsQuantity').textContent = `${extraCostsForQuantity.toFixed(2)}`; | |
document.getElementById('totalCostQuantity').textContent = `${totalCostForQuantity.toFixed(2)}`; | |
// Add to history | |
const orderName = document.getElementById('orderName').value || 'Pedido sin nombre'; | |
const calculation = { | |
date: new Date().toLocaleString(), | |
fabricPrice, | |
sublimationPrice, | |
fabricArea, | |
sublimationArea, | |
sewingPrice, | |
extraCosts, | |
quantity, | |
orderName, | |
totalCostPerUnit, | |
totalCostForQuantity | |
}; | |
calculationHistory.unshift(calculation); | |
if (calculationHistory.length > 10) { | |
calculationHistory = calculationHistory.slice(0, 10); | |
} | |
localStorage.setItem('textileCalcHistory', JSON.stringify(calculationHistory)); | |
renderHistory(); | |
// Show results | |
resultsContainer.classList.remove('hidden'); | |
// Smooth scroll to results | |
resultsContainer.scrollIntoView({ behavior: 'smooth' }); | |
} | |
function renderHistory() { | |
const historyList = document.getElementById('historyList'); | |
historyList.innerHTML = ''; | |
if (calculationHistory.length === 0) { | |
historyList.innerHTML = '<p class="text-gray-500 text-center py-4">No hay cálculos recientes</p>'; | |
return; | |
} | |
calculationHistory.forEach(item => { | |
const historyItem = document.createElement('div'); | |
historyItem.className = 'bg-gray-50 rounded-lg p-3 border border-gray-200'; | |
historyItem.innerHTML = ` | |
<div class="flex justify-between items-start"> | |
<div> | |
<span class="text-xs text-gray-500">${item.date}</span> | |
<div class="text-sm mt-1"> | |
<span class="font-medium">${item.orderName}</span> | |
<span class="mx-2">•</span> | |
<span>${item.quantity} unidad(es)</span> | |
<span class="mx-2">•</span> | |
<span>${item.fabricArea}m² tela</span> | |
<span class="mx-2">•</span> | |
<span>${item.sublimationArea}m² sublim</span> | |
${item.extraCosts > 0 ? `<span class="mx-2">•</span><span>Extras: ${item.extraCosts.toFixed(2)}</span>` : ''} | |
</div> | |
</div> | |
<div class="text-right"> | |
<div class="text-sm">Unidad: <span class="font-medium">${item.totalCostPerUnit.toFixed(2)}</span></div> | |
<div class="text-sm">Total: <span class="font-medium text-indigo-600">${item.totalCostForQuantity.toFixed(2)}</span></div> | |
</div> | |
</div> | |
`; | |
historyList.appendChild(historyItem); | |
}); | |
} | |
function resetErrors() { | |
[fabricError, sublimationError, areaError, sublimationAreaError, sewingError].forEach(error => { | |
error.classList.add('hidden'); | |
}); | |
[fabricPriceInput, sublimationPriceInput, fabricAreaInput, sublimationAreaInput, sewingPriceInput].forEach(input => { | |
input.classList.remove('input-error'); | |
}); | |
} | |
}); | |
</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 Logo2" 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=JymNils/calculadora-textil" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p><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=JymNils/calculadora-textil" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p><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=JymNils/calculadora-textil2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |