Actualizar js/layout.js
This commit is contained in:
103
js/layout.js
103
js/layout.js
@@ -10,20 +10,19 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Cargar Componentes HTML
|
// 2. Generar Sidebar (Con los nuevos enlaces)
|
||||||
await loadComponent("sidebar-container", "sidebar.html");
|
renderSidebar();
|
||||||
|
|
||||||
|
// 3. Cargar Header (Mantenemos carga externa para la cabecera)
|
||||||
await loadComponent("header-container", "header.html");
|
await loadComponent("header-container", "header.html");
|
||||||
|
|
||||||
// 3. Inicializar Iconos
|
// 4. Inicializar Iconos
|
||||||
if (window.lucide) lucide.createIcons();
|
if (window.lucide) lucide.createIcons();
|
||||||
|
|
||||||
// 4. Lógica del Usuario (Header)
|
// 5. Lógica del Usuario (Header)
|
||||||
setupUserInfo(token);
|
setupUserInfo(token);
|
||||||
|
|
||||||
// 5. Marcar enlace activo (Sidebar)
|
// 6. Configurar Logout (Ahora manejado dentro de renderSidebar para asegurar que existe el botón)
|
||||||
highlightActiveLink();
|
|
||||||
|
|
||||||
// 6. Configurar Logout
|
|
||||||
const btnLogout = document.getElementById("globalBtnLogout");
|
const btnLogout = document.getElementById("globalBtnLogout");
|
||||||
if(btnLogout) {
|
if(btnLogout) {
|
||||||
btnLogout.addEventListener("click", () => {
|
btnLogout.addEventListener("click", () => {
|
||||||
@@ -33,7 +32,67 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Función para cargar HTML externo
|
// --- GENERADOR DE SIDEBAR (NUEVO) ---
|
||||||
|
function renderSidebar() {
|
||||||
|
const container = document.getElementById('sidebar-container');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
// Detectar página actual
|
||||||
|
const path = window.location.pathname.split("/").pop() || "index.html";
|
||||||
|
|
||||||
|
// DEFINICIÓN DE MENÚ (Aquí añadimos Calendario y Automatizaciones)
|
||||||
|
const menuItems = [
|
||||||
|
{ name: "Servicios", link: "servicios.html", icon: "briefcase" },
|
||||||
|
{ name: "Calendario", link: "calendario.html", icon: "calendar-days" }, // ✅ NUEVO
|
||||||
|
{ name: "Clientes", link: "clientes.html", icon: "users" },
|
||||||
|
{ name: "Automatizaciones", link: "automatizaciones.html", icon: "zap" }, // ✅ NUEVO (Icono rayo)
|
||||||
|
{ name: "Configuración", link: "configuracion.html", icon: "settings" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Construir HTML de los enlaces
|
||||||
|
const linksHtml = menuItems.map(item => {
|
||||||
|
const isActive = path === item.link;
|
||||||
|
// Estilos basados en tu diseño actual (Slate oscuro)
|
||||||
|
const baseClasses = "flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 font-medium mb-1 text-sm";
|
||||||
|
const activeClasses = "bg-blue-600 text-white shadow-lg shadow-blue-500/30";
|
||||||
|
const inactiveClasses = "text-slate-400 hover:text-white hover:bg-slate-800";
|
||||||
|
|
||||||
|
return `
|
||||||
|
<a href="${item.link}" class="${baseClasses} ${isActive ? activeClasses : inactiveClasses}">
|
||||||
|
<i data-lucide="${item.icon}" class="w-5 h-5"></i>
|
||||||
|
${item.name}
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
// Inyectar HTML completo del Sidebar
|
||||||
|
container.innerHTML = `
|
||||||
|
<aside class="w-64 bg-slate-900 h-full flex flex-col text-white shadow-xl">
|
||||||
|
<div class="p-6 border-b border-slate-800 flex items-center gap-3">
|
||||||
|
<div class="w-8 h-8 bg-gradient-to-br from-blue-500 to-blue-700 rounded-lg flex items-center justify-center font-bold text-white shadow-lg">I</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="font-bold text-lg tracking-tight leading-none">Integra</h1>
|
||||||
|
<span class="text-[10px] text-slate-400 uppercase tracking-widest font-semibold">Repara</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||||||
|
<p class="text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-4 px-2 mt-2">Principal</p>
|
||||||
|
${linksHtml}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="p-4 border-t border-slate-800 bg-slate-900/50">
|
||||||
|
<button id="globalBtnLogout" class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-slate-400 hover:text-red-400 hover:bg-red-500/10 transition-all w-full text-left text-sm font-medium">
|
||||||
|
<i data-lucide="log-out" class="w-5 h-5"></i>
|
||||||
|
Cerrar Sesión
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FUNCIONES AUXILIARES ---
|
||||||
|
|
||||||
async function loadComponent(elementId, filePath) {
|
async function loadComponent(elementId, filePath) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(filePath);
|
const response = await fetch(filePath);
|
||||||
@@ -41,14 +100,13 @@ async function loadComponent(elementId, filePath) {
|
|||||||
const html = await response.text();
|
const html = await response.text();
|
||||||
document.getElementById(elementId).innerHTML = html;
|
document.getElementById(elementId).innerHTML = html;
|
||||||
} else {
|
} else {
|
||||||
console.error(`Error cargando ${filePath}`);
|
console.warn(`No se pudo cargar ${filePath} (puede que no sea necesario si usas el sidebar generado)`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
// Ignoramos errores silenciosos para no molestar en consola
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Función para rellenar datos del usuario
|
|
||||||
function setupUserInfo(token) {
|
function setupUserInfo(token) {
|
||||||
try {
|
try {
|
||||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||||
@@ -61,30 +119,9 @@ function setupUserInfo(token) {
|
|||||||
if (nameEl) nameEl.innerText = payload.email || "Usuario";
|
if (nameEl) nameEl.innerText = payload.email || "Usuario";
|
||||||
if (roleEl) roleEl.innerText = (payload.role || "Operario").toUpperCase();
|
if (roleEl) roleEl.innerText = (payload.role || "Operario").toUpperCase();
|
||||||
if (avatarEl) avatarEl.innerText = (payload.email?.[0] || "U").toUpperCase();
|
if (avatarEl) avatarEl.innerText = (payload.email?.[0] || "U").toUpperCase();
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error decodificando token", e);
|
console.error("Error decodificando token", e);
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
window.location.href = "index.html";
|
window.location.href = "index.html";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Función para poner azul el enlace actual
|
|
||||||
function highlightActiveLink() {
|
|
||||||
// Obtenemos el nombre del archivo actual (ej: panel.html)
|
|
||||||
const path = window.location.pathname.split("/").pop() || "index.html";
|
|
||||||
|
|
||||||
const links = document.querySelectorAll(".nav-item");
|
|
||||||
|
|
||||||
links.forEach(link => {
|
|
||||||
// Quitamos estilos activos por defecto
|
|
||||||
link.classList.remove("bg-blue-600", "text-white", "shadow-lg", "shadow-blue-500/30");
|
|
||||||
link.classList.add("text-slate-400", "hover:text-white", "hover:bg-slate-800");
|
|
||||||
|
|
||||||
// Si coincide con la página actual, le ponemos el estilo "Activo"
|
|
||||||
if (link.getAttribute("data-page") === path) {
|
|
||||||
link.classList.remove("text-slate-400", "hover:text-white", "hover:bg-slate-800");
|
|
||||||
link.classList.add("bg-blue-600", "text-white", "shadow-lg", "shadow-blue-500/30");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user