Davidal07 commited on
Commit
fc67011
verified
1 Parent(s): 194cfaf

un formulario para calcular el indicie de masa corporal - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +141 -519
index.html CHANGED
@@ -3,564 +3,186 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Sistema de Gesti贸n de N煤meros de Parte</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- .fade-in {
11
- animation: fadeIn 0.3s ease-in-out;
12
  }
13
-
14
- @keyframes fadeIn {
15
- from { opacity: 0; transform: translateY(10px); }
16
- to { opacity: 1; transform: translateY(0); }
17
  }
18
-
19
- .feature-item:hover .delete-feature {
20
- opacity: 1;
21
- }
22
-
23
- .delete-feature {
24
- opacity: 0;
25
- transition: opacity 0.2s ease;
 
26
  }
27
  </style>
28
  </head>
29
- <body class="bg-gray-100 min-h-screen">
30
- <div class="container mx-auto px-4 py-8">
31
- <div class="max-w-4xl mx-auto">
32
- <!-- Header -->
33
- <div class="bg-blue-600 text-white rounded-lg shadow-md p-6 mb-8">
34
- <h1 class="text-3xl font-bold">Sistema de Gesti贸n de N煤meros de Parte</h1>
35
- <p class="mt-2">Registro y administraci贸n de n煤meros de parte para la empresa</p>
36
- </div>
37
-
38
- <!-- Main Form -->
39
- <div class="bg-white rounded-lg shadow-md p-6 mb-8">
40
- <h2 class="text-2xl font-semibold text-gray-800 mb-6">Nuevo N煤mero de Parte</h2>
41
-
42
- <form id="partForm" class="space-y-6">
43
- <!-- Basic Information -->
44
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
45
- <div>
46
- <label for="partNumber" class="block text-sm font-medium text-gray-700 mb-1">N煤mero de Parte*</label>
47
- <input type="text" id="partNumber" name="partNumber" required
48
- class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
49
  </div>
50
-
51
- <div>
52
- <label for="partType" class="block text-sm font-medium text-gray-700 mb-1">Tipo de Parte*</label>
53
- <select id="partType" name="partType" required
54
- class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
55
- <option value="">Seleccione un tipo</option>
56
- <option value="MGG">MGG</option>
57
- <option value="Iniciador">Iniciador</option>
58
- <option value="Naked">Naked</option>
59
- </select>
 
60
  </div>
61
  </div>
62
-
63
- <!-- Description -->
64
- <div>
65
- <label for="description" class="block text-sm font-medium text-gray-700 mb-1">Descripci贸n</label>
66
- <textarea id="description" name="description" rows="3"
67
- class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"></textarea>
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </div>
69
 
70
- <!-- Dynamic Features Section -->
71
- <div id="featuresSection" class="hidden fade-in">
72
- <h3 class="text-lg font-medium text-gray-800 mb-4">Caracter铆sticas</h3>
73
- <div id="defaultFeatures" class="space-y-4 mb-6"></div>
74
-
75
- <!-- Add Custom Feature -->
76
- <div class="flex items-center space-x-4">
77
- <input type="text" id="newFeatureName" placeholder="Nombre de caracter铆stica"
78
- class="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
79
- <input type="text" id="newFeatureValue" placeholder="Valor"
80
- class="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
81
- <button type="button" id="addFeatureBtn"
82
- class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition">
83
- <i class="fas fa-plus mr-2"></i>Agregar
84
- </button>
85
- </div>
86
  </div>
87
 
88
- <!-- Form Actions -->
89
- <div class="flex justify-end space-x-4 pt-6 border-t border-gray-200">
90
- <button type="reset"
91
- class="px-6 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition">
92
- <i class="fas fa-times mr-2"></i>Cancelar
93
- </button>
94
- <button type="submit"
95
- class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition">
96
- <i class="fas fa-save mr-2"></i>Guardar
97
- </button>
98
  </div>
99
- </form>
100
- </div>
101
-
102
- <!-- Parts List -->
103
- <div class="bg-white rounded-lg shadow-md p-6">
104
- <div class="flex justify-between items-center mb-6">
105
- <h2 class="text-2xl font-semibold text-gray-800">N煤meros de Parte Registrados</h2>
106
- <button id="exportExcelBtn" class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition">
107
- <i class="fas fa-file-excel mr-2"></i>Exportar a Excel
108
- </button>
109
- </div>
110
-
111
- <div class="overflow-x-auto">
112
- <table class="min-w-full divide-y divide-gray-200">
113
- <thead class="bg-gray-50">
114
- <tr>
115
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">N煤mero</th>
116
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipo</th>
117
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Descripci贸n</th>
118
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th>
119
- </tr>
120
- </thead>
121
- <tbody id="partsList" class="bg-white divide-y divide-gray-200">
122
- <!-- Parts will be loaded here -->
123
- <tr>
124
- <td colspan="4" class="px-6 py-4 text-center text-gray-500">No hay n煤meros de parte registrados</td>
125
- </tr>
126
- </tbody>
127
- </table>
128
  </div>
129
  </div>
130
  </div>
131
- </div>
132
 
133
- <!-- Part Details Modal -->
134
- <div id="partDetailsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
135
- <div class="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
136
- <div class="p-6">
137
- <div class="flex justify-between items-center mb-4">
138
- <h3 id="modalTitle" class="text-xl font-semibold text-gray-800">Detalles del N煤mero de Parte</h3>
139
- <button id="closeModalBtn" class="text-gray-500 hover:text-gray-700">
140
- <i class="fas fa-times"></i>
141
- </button>
142
- </div>
143
-
144
- <div id="modalContent" class="space-y-4">
145
- <!-- Content will be loaded here -->
146
- </div>
147
-
148
- <div class="flex justify-end space-x-4 pt-6 mt-6 border-t border-gray-200">
149
- <button id="editPartBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition">
150
- <i class="fas fa-edit mr-2"></i>Editar
151
- </button>
152
- <button id="deletePartBtn" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition">
153
- <i class="fas fa-trash mr-2"></i>Eliminar
154
- </button>
155
- </div>
156
- </div>
157
  </div>
158
  </div>
159
 
160
  <script>
161
- // Default features for each part type
162
- const defaultFeatures = {
163
- 'MGG': [
164
- { name: 'Material', value: '', required: true },
165
- { name: 'Espesor', value: '', required: true },
166
- { name: 'Color', value: '', required: true },
167
- { name: 'Acabado', value: '', required: false }
168
- ],
169
- 'Iniciador': [
170
- { name: 'Potencia', value: '', required: true },
171
- { name: 'Voltaje', value: '', required: true },
172
- { name: 'Temperatura', value: '', required: false }
173
- ],
174
- 'Naked': [
175
- { name: 'Di谩metro', value: '', required: true },
176
- { name: 'Longitud', value: '', required: true },
177
- { name: 'Peso', value: '', required: false }
178
- ]
179
- };
180
-
181
- // Sample data storage (in a real scenario, this would be a database)
182
- let partsDatabase = [];
183
-
184
- // DOM Elements
185
- const partForm = document.getElementById('partForm');
186
- const partTypeSelect = document.getElementById('partType');
187
- const featuresSection = document.getElementById('featuresSection');
188
- const defaultFeaturesContainer = document.getElementById('defaultFeatures');
189
- const newFeatureName = document.getElementById('newFeatureName');
190
- const newFeatureValue = document.getElementById('newFeatureValue');
191
- const addFeatureBtn = document.getElementById('addFeatureBtn');
192
- const partsList = document.getElementById('partsList');
193
- const partDetailsModal = document.getElementById('partDetailsModal');
194
- const closeModalBtn = document.getElementById('closeModalBtn');
195
- const modalContent = document.getElementById('modalContent');
196
- const editPartBtn = document.getElementById('editPartBtn');
197
- const deletePartBtn = document.getElementById('deletePartBtn');
198
-
199
- // Event Listeners
200
- partTypeSelect.addEventListener('change', updateFeatures);
201
- addFeatureBtn.addEventListener('click', addCustomFeature);
202
- partForm.addEventListener('submit', savePart);
203
- closeModalBtn.addEventListener('click', () => partDetailsModal.classList.add('hidden'));
204
- editPartBtn.addEventListener('click', editPart);
205
- deletePartBtn.addEventListener('click', deletePart);
206
-
207
- // Initialize the app
208
- function init() {
209
- // Load parts from localStorage (simulating database)
210
- const savedParts = localStorage.getItem('partsDatabase');
211
- if (savedParts) {
212
- partsDatabase = JSON.parse(savedParts);
213
- updatePartsList();
214
- }
215
- }
216
-
217
- // Update features based on selected part type
218
- function updateFeatures() {
219
- const selectedType = partTypeSelect.value;
220
-
221
- if (!selectedType) {
222
- featuresSection.classList.add('hidden');
223
- return;
224
- }
225
-
226
- // Clear previous features
227
- defaultFeaturesContainer.innerHTML = '';
228
-
229
- // Add default features for selected type
230
- defaultFeatures[selectedType].forEach(feature => {
231
- const featureItem = document.createElement('div');
232
- featureItem.className = 'feature-item bg-gray-50 p-4 rounded-md relative';
233
-
234
- featureItem.innerHTML = `
235
- <div class="flex items-center space-x-4">
236
- <div class="flex-1">
237
- <label class="block text-sm font-medium text-gray-700 mb-1">${feature.name}${feature.required ? '*' : ''}</label>
238
- <input type="text" name="feature_${feature.name}" value="${feature.value}"
239
- ${feature.required ? 'required' : ''}
240
- class="w-full px-3 py-1 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
241
- </div>
242
- ${!feature.required ? `
243
- <button type="button" class="delete-feature px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition"
244
- onclick="this.closest('.feature-item').remove()">
245
- <i class="fas fa-trash"></i>
246
- </button>
247
- ` : ''}
248
- </div>
249
- `;
250
-
251
- defaultFeaturesContainer.appendChild(featureItem);
252
- });
253
-
254
- // Show features section
255
- featuresSection.classList.remove('hidden');
256
- }
257
-
258
- // Add custom feature
259
- function addCustomFeature() {
260
- const name = newFeatureName.value.trim();
261
- const value = newFeatureValue.value.trim();
262
-
263
- if (!name) {
264
- alert('Por favor ingrese un nombre para la caracter铆stica');
265
- return;
266
- }
267
-
268
- const featureItem = document.createElement('div');
269
- featureItem.className = 'feature-item bg-gray-50 p-4 rounded-md relative fade-in';
270
-
271
- featureItem.innerHTML = `
272
- <div class="flex items-center space-x-4">
273
- <div class="flex-1">
274
- <label class="block text-sm font-medium text-gray-700 mb-1">${name}</label>
275
- <input type="text" name="feature_${name}" value="${value}"
276
- class="w-full px-3 py-1 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
277
- </div>
278
- <button type="button" class="delete-feature px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition"
279
- onclick="this.closest('.feature-item').remove()">
280
- <i class="fas fa-trash"></i>
281
- </button>
282
- </div>
283
- `;
284
-
285
- defaultFeaturesContainer.appendChild(featureItem);
286
-
287
- // Clear inputs
288
- newFeatureName.value = '';
289
- newFeatureValue.value = '';
290
- }
291
-
292
- // Save part to database
293
- function savePart(e) {
294
  e.preventDefault();
295
 
296
- const formData = new FormData(partForm);
297
- const partNumber = formData.get('partNumber');
298
- const partType = formData.get('partType');
299
- const description = formData.get('description');
300
-
301
- // Collect features
302
- const features = [];
303
- const featureItems = defaultFeaturesContainer.querySelectorAll('.feature-item');
304
-
305
- featureItems.forEach(item => {
306
- const label = item.querySelector('label').textContent.replace('*', '');
307
- const input = item.querySelector('input');
308
- const value = input.value.trim();
309
-
310
- if (value) {
311
- features.push({
312
- name: label,
313
- value: value,
314
- required: input.required
315
- });
316
- } else if (input.required) {
317
- alert(`Por favor complete el campo requerido: ${label}`);
318
- input.focus();
319
- throw new Error('Required field missing');
320
- }
321
- });
322
-
323
- // Create part object
324
- const part = {
325
- id: Date.now().toString(),
326
- partNumber,
327
- partType,
328
- description,
329
- features,
330
- createdAt: new Date().toISOString(),
331
- createdBy: 'Usuario Actual' // In a real app, this would be the logged in user
332
- };
333
-
334
- // Add to database
335
- partsDatabase.push(part);
336
- localStorage.setItem('partsDatabase', JSON.stringify(partsDatabase));
337
 
338
- // Update UI
339
- updatePartsList();
340
- partForm.reset();
341
- featuresSection.classList.add('hidden');
342
-
343
- // Show success message
344
- alert('N煤mero de parte guardado exitosamente!');
345
- }
346
-
347
- // Update parts list in UI
348
- function updatePartsList() {
349
- if (partsDatabase.length === 0) {
350
- partsList.innerHTML = `
351
- <tr>
352
- <td colspan="4" class="px-6 py-4 text-center text-gray-500">No hay n煤meros de parte registrados</td>
353
- </tr>
354
- `;
355
  return;
356
  }
357
 
358
- partsList.innerHTML = '';
359
-
360
- partsDatabase.forEach(part => {
361
- const row = document.createElement('tr');
362
- row.className = 'hover:bg-gray-50';
363
- row.innerHTML = `
364
- <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${part.partNumber}</td>
365
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
366
- <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
367
- ${part.partType === 'MGG' ? 'bg-blue-100 text-blue-800' :
368
- part.partType === 'Iniciador' ? 'bg-green-100 text-green-800' :
369
- 'bg-purple-100 text-purple-800'}">
370
- ${part.partType}
371
- </span>
372
- </td>
373
- <td class="px-6 py-4 text-sm text-gray-500">${part.description || 'Sin descripci贸n'}</td>
374
- <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
375
- <button onclick="showPartDetails('${part.id}')" class="text-blue-600 hover:text-blue-900 mr-4">
376
- <i class="fas fa-eye"></i> Ver
377
- </button>
378
- <button onclick="editPartFromList('${part.id}')" class="text-yellow-600 hover:text-yellow-900">
379
- <i class="fas fa-edit"></i> Editar
380
- </button>
381
- </td>
382
- `;
383
- partsList.appendChild(row);
384
- });
385
- }
386
-
387
- // Show part details in modal
388
- function showPartDetails(partId) {
389
- const part = partsDatabase.find(p => p.id === partId);
390
- if (!part) return;
391
-
392
- document.getElementById('modalTitle').textContent = `Detalles: ${part.partNumber}`;
393
-
394
- let content = `
395
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
396
- <div>
397
- <h4 class="text-sm font-medium text-gray-500">N煤mero de Parte</h4>
398
- <p class="mt-1 text-sm text-gray-900">${part.partNumber}</p>
399
- </div>
400
- <div>
401
- <h4 class="text-sm font-medium text-gray-500">Tipo</h4>
402
- <p class="mt-1 text-sm text-gray-900">${part.partType}</p>
403
- </div>
404
- <div>
405
- <h4 class="text-sm font-medium text-gray-500">Fecha de Creaci贸n</h4>
406
- <p class="mt-1 text-sm text-gray-900">${new Date(part.createdAt).toLocaleString()}</p>
407
- </div>
408
- <div>
409
- <h4 class="text-sm font-medium text-gray-500">Creado por</h4>
410
- <p class="mt-1 text-sm text-gray-900">${part.createdBy}</p>
411
- </div>
412
- </div>
413
-
414
- <div class="mb-6">
415
- <h4 class="text-sm font-medium text-gray-500">Descripci贸n</h4>
416
- <p class="mt-1 text-sm text-gray-900">${part.description || 'Sin descripci贸n'}</p>
417
- </div>
418
-
419
- <div>
420
- <h4 class="text-sm font-medium text-gray-500 mb-2">Caracter铆sticas</h4>
421
- <div class="bg-gray-50 rounded-md p-4">
422
- `;
423
-
424
- if (part.features.length === 0) {
425
- content += `<p class="text-sm text-gray-500">No hay caracter铆sticas definidas</p>`;
426
  } else {
427
- content += `<div class="grid grid-cols-1 md:grid-cols-2 gap-4">`;
428
- part.features.forEach(feat => {
429
- content += `
430
- <div>
431
- <h5 class="text-xs font-medium text-gray-500">${feat.name}</h5>
432
- <p class="text-sm text-gray-900">${feat.value}</p>
433
- </div>
434
- `;
435
- });
436
- content += `</div>`;
437
  }
438
 
439
- content += `</div></div>`;
440
-
441
- modalContent.innerHTML = content;
442
- editPartBtn.setAttribute('data-part-id', partId);
443
- deletePartBtn.setAttribute('data-part-id', partId);
444
- partDetailsModal.classList.remove('hidden');
445
- }
446
-
447
- // Edit part from list
448
- function editPartFromList(partId) {
449
- const part = partsDatabase.find(p => p.id === partId);
450
- if (!part) return;
451
-
452
- // Fill form with part data
453
- document.getElementById('partNumber').value = part.partNumber;
454
- document.getElementById('partType').value = part.partType;
455
- document.getElementById('description').value = part.description || '';
456
-
457
- // Trigger change event to load features
458
- const event = new Event('change');
459
- partTypeSelect.dispatchEvent(event);
460
 
461
- // Wait for features to load
462
- setTimeout(() => {
463
- // Clear existing features
464
- defaultFeaturesContainer.innerHTML = '';
465
-
466
- // Add part features
467
- part.features.forEach(feature => {
468
- const isDefault = defaultFeatures[part.partType].some(f => f.name === feature.name);
469
-
470
- const featureItem = document.createElement('div');
471
- featureItem.className = 'feature-item bg-gray-50 p-4 rounded-md relative fade-in';
472
-
473
- featureItem.innerHTML = `
474
- <div class="flex items-center space-x-4">
475
- <div class="flex-1">
476
- <label class="block text-sm font-medium text-gray-700 mb-1">${feature.name}${feature.required ? '*' : ''}</label>
477
- <input type="text" name="feature_${feature.name}" value="${feature.value}"
478
- ${feature.required ? 'required' : ''}
479
- class="w-full px-3 py-1 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
480
- </div>
481
- ${!feature.required ? `
482
- <button type="button" class="delete-feature px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition"
483
- onclick="this.closest('.feature-item').remove()">
484
- <i class="fas fa-trash"></i>
485
- </button>
486
- ` : ''}
487
- </div>
488
- `;
489
-
490
- defaultFeaturesContainer.appendChild(featureItem);
491
- });
492
-
493
- // Show features section
494
- featuresSection.classList.remove('hidden');
495
-
496
- // Scroll to form
497
- document.querySelector('form').scrollIntoView({ behavior: 'smooth' });
498
- }, 100);
499
- }
500
-
501
- // Edit part (from modal)
502
- function editPart() {
503
- const partId = this.getAttribute('data-part-id');
504
- partDetailsModal.classList.add('hidden');
505
- editPartFromList(partId);
506
- }
507
-
508
- // Delete part
509
- function deletePart() {
510
- if (!confirm('驴Est谩 seguro que desea eliminar este n煤mero de parte?')) return;
511
 
512
- const partId = this.getAttribute('data-part-id');
513
- partsDatabase = partsDatabase.filter(p => p.id !== partId);
514
- localStorage.setItem('partsDatabase', JSON.stringify(partsDatabase));
515
 
516
- partDetailsModal.classList.add('hidden');
517
- updatePartsList();
518
- }
519
-
520
- // Export to Excel function
521
- function exportToExcel() {
522
- if (partsDatabase.length === 0) {
523
- alert('No hay datos para exportar');
524
- return;
525
- }
526
 
527
- // Create CSV content
528
- let csvContent = "N煤mero de Parte,Tipo,Descripci贸n,Fecha de Creaci贸n,Creado por\n";
 
 
 
 
 
 
 
 
529
 
530
- partsDatabase.forEach(part => {
531
- const row = [
532
- `"${part.partNumber}"`,
533
- `"${part.partType}"`,
534
- `"${part.description || ''}"`,
535
- `"${new Date(part.createdAt).toLocaleString()}"`,
536
- `"${part.createdBy}"`
537
- ];
538
-
539
- // Add features to the row
540
- part.features.forEach(feat => {
541
- row.push(`"${feat.name}: ${feat.value}"`);
542
- });
543
-
544
- csvContent += row.join(',') + '\n';
545
  });
546
-
547
- // Create download link
548
- const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
549
- const url = URL.createObjectURL(blob);
550
- const link = document.createElement('a');
551
- link.setAttribute('href', url);
552
- link.setAttribute('download', `numeros_de_parte_${new Date().toISOString().slice(0,10)}.csv`);
553
- link.style.visibility = 'hidden';
554
- document.body.appendChild(link);
555
- link.click();
556
- document.body.removeChild(link);
557
- }
558
-
559
- // Add event listener for export button
560
- document.getElementById('exportExcelBtn').addEventListener('click', exportToExcel);
561
-
562
- // Initialize the app
563
- init();
564
  </script>
565
  <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=Davidal07/test" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
566
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Calculadora de IMC</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ .bmi-scale {
11
+ background: linear-gradient(90deg, #3b82f6 0%, #10b981 25%, #f59e0b 50%, #ef4444 75%);
12
  }
13
+ .tooltip {
14
+ position: absolute;
15
+ transform: translateX(-50%);
16
+ transition: all 0.3s ease;
17
  }
18
+ .tooltip::after {
19
+ content: '';
20
+ position: absolute;
21
+ top: 100%;
22
+ left: 50%;
23
+ transform: translateX(-50%);
24
+ border-width: 8px;
25
+ border-style: solid;
26
+ border-color: #1f2937 transparent transparent transparent;
27
  }
28
  </style>
29
  </head>
30
+ <body class="bg-gray-100 min-h-screen flex items-center justify-center p-4">
31
+ <div class="bg-white rounded-2xl shadow-xl overflow-hidden w-full max-w-md">
32
+ <div class="bg-gradient-to-r from-blue-500 to-purple-600 p-6 text-white">
33
+ <h1 class="text-2xl font-bold flex items-center">
34
+ <i class="fas fa-weight-scale mr-3"></i>
35
+ Calculadora de IMC
36
+ </h1>
37
+ <p class="text-blue-100 mt-2">脥ndice de Masa Corporal</p>
38
+ </div>
39
+
40
+ <div class="p-6">
41
+ <form id="bmiForm" class="space-y-4">
42
+ <div>
43
+ <label for="height" class="block text-sm font-medium text-gray-700 mb-1">Estatura (cm)</label>
44
+ <div class="relative">
45
+ <input type="number" id="height" min="100" max="250" step="0.1"
46
+ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
47
+ placeholder="Ej. 175" required>
48
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
49
+ <i class="fas fa-ruler-vertical text-gray-400"></i>
50
  </div>
51
+ </div>
52
+ </div>
53
+
54
+ <div>
55
+ <label for="weight" class="block text-sm font-medium text-gray-700 mb-1">Peso (kg)</label>
56
+ <div class="relative">
57
+ <input type="number" id="weight" min="30" max="300" step="0.1"
58
+ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
59
+ placeholder="Ej. 70" required>
60
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
61
+ <i class="fas fa-weight-hanging text-gray-400"></i>
62
  </div>
63
  </div>
64
+ </div>
65
+
66
+ <div class="pt-2">
67
+ <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200 flex items-center justify-center">
68
+ <i class="fas fa-calculator mr-2"></i>
69
+ Calcular IMC
70
+ </button>
71
+ </div>
72
+ </form>
73
+
74
+ <div id="result" class="mt-6 hidden">
75
+ <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
76
+ <h3 class="font-semibold text-lg text-gray-800 mb-2">Tu resultado:</h3>
77
+ <div class="flex items-center justify-between">
78
+ <div>
79
+ <p class="text-sm text-gray-600">脥ndice de Masa Corporal</p>
80
+ <p id="bmiValue" class="text-3xl font-bold text-gray-900">--</p>
81
+ </div>
82
+ <div id="bmiCategory" class="px-3 py-1 rounded-full text-sm font-medium"></div>
83
  </div>
84
 
85
+ <div class="mt-4 relative h-8 bmi-scale rounded-full overflow-hidden">
86
+ <div id="bmiIndicator" class="tooltip bg-white w-4 h-4 rounded-full border-2 border-gray-800 absolute -top-1" style="left: 0%"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  </div>
88
 
89
+ <div class="mt-6">
90
+ <p id="bmiMessage" class="text-sm text-gray-600"></p>
 
 
 
 
 
 
 
 
91
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  </div>
93
  </div>
94
  </div>
 
95
 
96
+ <div class="bg-gray-50 p-6 border-t border-gray-200">
97
+ <h3 class="font-medium text-gray-800 mb-2 flex items-center">
98
+ <i class="fas fa-info-circle text-blue-500 mr-2"></i>
99
+ Escala de IMC
100
+ </h3>
101
+ <ul class="space-y-2 text-sm text-gray-600">
102
+ <li class="flex items-center"><span class="w-3 h-3 bg-blue-500 rounded-full mr-2"></span> Bajo peso: menos de 18.5</li>
103
+ <li class="flex items-center"><span class="w-3 h-3 bg-green-500 rounded-full mr-2"></span> Normal: 18.5 - 24.9</li>
104
+ <li class="flex items-center"><span class="w-3 h-3 bg-yellow-500 rounded-full mr-2"></span> Sobrepeso: 25 - 29.9</li>
105
+ <li class="flex items-center"><span class="w-3 h-3 bg-red-500 rounded-full mr-2"></span> Obesidad: 30 o m谩s</li>
106
+ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  </div>
108
  </div>
109
 
110
  <script>
111
+ document.getElementById('bmiForm').addEventListener('submit', function(e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  e.preventDefault();
113
 
114
+ const height = parseFloat(document.getElementById('height').value) / 100; // Convert cm to m
115
+ const weight = parseFloat(document.getElementById('weight').value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
+ if (isNaN(height) || isNaN(weight) || height <= 0 || weight <= 0) {
118
+ alert('Por favor ingresa valores v谩lidos');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  return;
120
  }
121
 
122
+ const bmi = weight / (height * height);
123
+ const roundedBMI = bmi.toFixed(1);
124
+
125
+ document.getElementById('bmiValue').textContent = roundedBMI;
126
+
127
+ let category = '';
128
+ let categoryClass = '';
129
+ let message = '';
130
+ let position = 0;
131
+
132
+ if (bmi < 18.5) {
133
+ category = 'Bajo peso';
134
+ categoryClass = 'bg-blue-100 text-blue-800';
135
+ message = 'Tu peso es inferior al normal. Considera consultar con un nutricionista para un plan de alimentaci贸n adecuado.';
136
+ position = (bmi / 18.5) * 25;
137
+ } else if (bmi >= 18.5 && bmi < 25) {
138
+ category = 'Normal';
139
+ categoryClass = 'bg-green-100 text-green-800';
140
+ message = '隆Felicidades! Tu peso es saludable. Mant茅n una dieta balanceada y ejercicio regular.';
141
+ position = 25 + ((bmi - 18.5) / (25 - 18.5)) * 25;
142
+ } else if (bmi >= 25 && bmi < 30) {
143
+ category = 'Sobrepeso';
144
+ categoryClass = 'bg-yellow-100 text-yellow-800';
145
+ message = 'Tienes sobrepeso. Considera aumentar tu actividad f铆sica y mejorar tus h谩bitos alimenticios.';
146
+ position = 50 + ((bmi - 25) / (30 - 25)) * 25;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  } else {
148
+ category = 'Obesidad';
149
+ categoryClass = 'bg-red-100 text-red-800';
150
+ message = 'Tienes obesidad. Es recomendable consultar con un m茅dico o nutricionista para un plan de salud adecuado.';
151
+ position = 75 + ((Math.min(bmi, 40) - 30) / (40 - 30)) * 25;
 
 
 
 
 
 
152
  }
153
 
154
+ document.getElementById('bmiCategory').textContent = category;
155
+ document.getElementById('bmiCategory').className = `px-3 py-1 rounded-full text-sm font-medium ${categoryClass}`;
156
+ document.getElementById('bmiMessage').textContent = message;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
+ const indicator = document.getElementById('bmiIndicator');
159
+ indicator.style.left = `${Math.min(Math.max(position, 2), 98)}%`;
160
+ indicator.setAttribute('data-tooltip', `IMC: ${roundedBMI} (${category})`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
+ document.getElementById('result').classList.remove('hidden');
 
 
163
 
164
+ // Smooth scroll to results
165
+ document.getElementById('result').scrollIntoView({ behavior: 'smooth' });
166
+ });
 
 
 
 
 
 
 
167
 
168
+ // Tooltip functionality
169
+ document.addEventListener('DOMContentLoaded', function() {
170
+ const indicator = document.getElementById('bmiIndicator');
171
+
172
+ indicator.addEventListener('mouseover', function() {
173
+ const tooltip = document.createElement('div');
174
+ tooltip.className = 'tooltip bg-gray-800 text-white text-xs px-2 py-1 rounded absolute -top-8 whitespace-nowrap';
175
+ tooltip.textContent = this.getAttribute('data-tooltip') || '';
176
+ this.appendChild(tooltip);
177
+ });
178
 
179
+ indicator.addEventListener('mouseout', function() {
180
+ const tooltip = this.querySelector('.tooltip');
181
+ if (tooltip) {
182
+ tooltip.remove();
183
+ }
 
 
 
 
 
 
 
 
 
 
184
  });
185
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  </script>
187
  <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=Davidal07/test" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
188
  </html>