<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<title>Presupuesto - Visualización</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Librería SheetJS desde CDN para leer Excel en el navegador -->
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
<style>
:root {
--primario: #267e3e;
--gris-borde: #a3a3a3;
--gris-fondo: #f9f9f9;
--gris-intercalado: #f2f2f2;
}
body { font-family: Arial, sans-serif; background: var(--gris-fondo); margin: 0; }
#container {
max-width: 1000px; margin: 30px auto; background: #fff; border-radius: 12px;
box-shadow: 0 2px 12px #0002; padding: 28px;
}
header { display: flex; align-items: center; gap: 10px; justify-content: center; }
h1 { color: var(--primario); margin: 0; }
#status { text-align: center; color: #555; margin-top: 8px; }
table { width: 100%; border-collapse: collapse; margin-top: 24px; }
th, td { border: 1px solid var(--gris-borde); padding: 8px 10px; text-align: left; }
th { background: var(--primario); color: #fff; position: sticky; top: 0; z-index: 1; }
tr:nth-child(even) { background: var(--gris-intercalado); }
.tabla-wrapper { overflow: auto; max-height: 70vh; border: 1px solid #ddd; border-radius: 8px; }
.badge { display: inline-block; background: #eef8f0; color: var(--primario); border: 1px solid #bfe3c9; padding: 2px 8px; border-radius: 999px; font-size: 12px; }
.error { color: #b00020; }
.hidden { display: none; }
footer { margin-top: 20px; color: #666; font-size: 12px; text-align: center; }
/* Estilos mínimos sobre el HTML generado por SheetJS */
.sheetjs { width: 100%; }
.sheetjs table { width: 100%; }
</style>
</head>
<body>
<div id="container">
<header>
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M4 4h10l6 6v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" stroke="#267e3e" stroke-width="1.5" fill="none"/>
<path d="M14 4v6h6" stroke="#267e3e" stroke-width="1.5"/>
</svg>
<h1>Presupuesto</h1>
<span id="sheet-badge" class="badge hidden"></span>
</header>
<div id="status">Cargando “Presupuesto.xlsx” automáticamente…</div>
<div class="tabla-wrapper">
<div id="tabla-excel" class="sheetjs"></div>
</div>
<footer>
Visualización generada en el navegador con SheetJS. No se suben datos a ningún servidor.
</footer>
</div>
<script>
// ================== CONFIGURACIÓN ==================
// Nombre del archivo Excel a cargar (debe estar junto a este HTML)
const NOMBRE_ARCHIVO = 'Presupuesto.xlsx';
// Nombre de la hoja a priorizar
const HOJA_POR_DEFECTO = 'Presupuesto';
// ================== UTILIDADES ==================
function setStatus(msg, isError = false) {
const el = document.getElementById('status');
el.textContent = msg;
el.classList.toggle('error', isError);
}
function setSheetBadge(sheetName) {
const badge = document.getElementById('sheet-badge');
badge.textContent = 'Hoja: ' + sheetName;
badge.classList.remove('hidden');
}
function renderSheetToHTML(sheet) {
// Genera HTML con SheetJS. Se envuelve en un contenedor para aplicar estilos.
const html = XLSX.utils.sheet_to_html(sheet, { header: '', footer: '' });
// Limpieza opcional: SheetJS agrega un <table> con estilos inline; lo aceptamos tal cual.
return html;
}
// ================== CARGA AUTOMÁTICA ==================
async function cargarPresupuesto() {
try {
setStatus('Cargando “' + NOMBRE_ARCHIVO + '”…');
// Nota: al abrir localmente como file://, algunos navegadores bloquean fetch.
// Chrome/Edge suelen permitirlo si se abre con un servidor local.
// Safari/Firefox normalmente permiten leer archivos locales con fetch si es mismo path.
const resp = await fetch(NOMBRE_ARCHIVO);
if (!resp.ok) throw new Error('No se pudo obtener el archivo (' + resp.status + ').');
const buf = await resp.arrayBuffer();
const wb = XLSX.read(new Uint8Array(buf), { type: 'array' });
let nombreHoja = HOJA_POR_DEFECTO;
if (!wb.SheetNames.includes(nombreHoja)) {
nombreHoja = wb.SheetNames[0];
console.warn('No se encontró la hoja "' + HOJA_POR_DEFECTO + '". Se mostrará: ' + nombreHoja);
}
const hoja = wb.Sheets[nombreHoja];
const html = renderSheetToHTML(hoja);
document.getElementById('tabla-excel').innerHTML = html;
setSheetBadge(nombreHoja);
setStatus('Listo.');
} catch (err) {
console.error(err);
// Fallback de ayuda si fetch local es bloqueado por el navegador
setStatus('No fue posible cargar el archivo automáticamente. ' +
'Asegúrate de que “' + NOMBRE_ARCHIVO + '” esté en la misma carpeta. ' +
'Si lo abres directamente como archivo local y tu navegador bloquea la lectura, ' +
'usa un servidor local (ver notas al final) o súbelo a Netlify.', true);
}
}
document.addEventListener('DOMContentLoaded', cargarPresupuesto);
</script>
<!--
====================== INSTRUCCIONES PARA EJECUTAR LOCAL ======================
1) Coloca este "index.html" y "Presupuesto.xlsx" en la MISMA CARPETA.
2) Intenta abrir "index.html" con doble clic.
- Si NO ves la tabla y aparece el aviso de bloqueo: tu navegador bloquea fetch con file://
Soluciones rápidas:
- Opción A (recomendada): Inicia un servidor local simple en esa carpeta.
• Python 3: abre una terminal en la carpeta y ejecuta:
python -m http.server 5500
Luego abre http://localhost:5500 en el navegador.
• Node (npx): npx serve . (o npx http-server)
• VS Code: extensión "Live Server".
- Opción B: Usa Firefox (suele permitir fetch local en muchos casos).
3) Al cargar la página, se mostrará automáticamente la hoja "Presupuesto"
(o la primera hoja existente si no se encuentra esa).
====================== PUBLICAR EN NETLIFY (SERVIDOR EXTERNO) ======================
PASOS MÍNIMOS (YA ESTÁ PREPARADO):
- Sube ambos archivos:
✔ index.html
✔ Presupuesto.xlsx
- No necesitas cambiar el código: el `fetch('Presupuesto.xlsx')` funciona en Netlify.
- Si deseas cambiar el nombre del archivo u hoja por defecto, modifica estas líneas ARRIBA:
const NOMBRE_ARCHIVO = 'Presupuesto.xlsx';
const HOJA_POR_DEFECTO = 'Presupuesto';
===========================================================================
-->
</body>
</html>