feat: sidebar con buscador de módulos e icono de configuración
- Icono de engranaje (⚙) en cabecera del sidebar → lab_configuracion.php - Buscador de texto que filtra ítems del menú en tiempo real - Al borrar la búsqueda restaura el estado colapsado guardado - CSS integrado en el mismo componente Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
9c9acbed70
commit
892b01493a
@@ -103,8 +103,20 @@ $_base = defined('APP_URL') ? rtrim(APP_URL, '/') : '';
|
||||
<nav class="sidebar" id="erp-sidebar">
|
||||
|
||||
<div class="sidebar-header">
|
||||
<h4><i class="<?= htmlspecialchars($_sidebar_icon, ENT_QUOTES, 'UTF-8') ?>"></i>
|
||||
<?= htmlspecialchars($_sidebar_title, ENT_QUOTES, 'UTF-8') ?></h4>
|
||||
<h4 style="flex:1;min-width:0">
|
||||
<i class="<?= htmlspecialchars($_sidebar_icon, ENT_QUOTES, 'UTF-8') ?>"></i>
|
||||
<?= htmlspecialchars($_sidebar_title, ENT_QUOTES, 'UTF-8') ?>
|
||||
</h4>
|
||||
<a href="<?= $_base ?>/lab_configuracion.php" class="sb-config-btn" title="Configuración">
|
||||
<i class="fas fa-gear"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Buscador de menú -->
|
||||
<div class="sb-search-wrap">
|
||||
<i class="fas fa-search sb-search-icon"></i>
|
||||
<input type="text" id="sbSearch" class="sb-search" placeholder="Buscar módulo…"
|
||||
oninput="sbFilter(this.value)" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<ul class="sidebar-menu" id="sb-menu">
|
||||
@@ -211,6 +223,48 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
/* ── Botón config en header ─────────────────────────── */
|
||||
.sidebar-header { display:flex; align-items:center; gap:10px; }
|
||||
.sb-config-btn {
|
||||
color: rgba(255,255,255,.65);
|
||||
font-size: 1rem;
|
||||
padding: 4px 6px;
|
||||
border-radius: 6px;
|
||||
transition: color .15s, background .15s;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
.sb-config-btn:hover { color:#fff; background:rgba(255,255,255,.15); }
|
||||
|
||||
/* ── Buscador de menú ───────────────────────────────── */
|
||||
.sb-search-wrap {
|
||||
position: relative;
|
||||
padding: 10px 14px 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.sb-search-icon {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
top: 50%;
|
||||
transform: translateY(-30%);
|
||||
color: rgba(255,255,255,.45);
|
||||
font-size: .75rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
.sb-search {
|
||||
width: 100%;
|
||||
background: rgba(255,255,255,.12);
|
||||
border: 1px solid rgba(255,255,255,.18);
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
padding: 6px 10px 6px 28px;
|
||||
font-size: .8rem;
|
||||
outline: none;
|
||||
transition: background .2s, border-color .2s;
|
||||
}
|
||||
.sb-search::placeholder { color: rgba(255,255,255,.45); }
|
||||
.sb-search:focus { background: rgba(255,255,255,.2); border-color: rgba(255,255,255,.4); }
|
||||
|
||||
/* ── Acordeón de categorías ─────────────────────────── */
|
||||
.sidebar-section {
|
||||
display: flex;
|
||||
@@ -285,6 +339,54 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
setCollapsed(arr);
|
||||
};
|
||||
|
||||
// ── Buscador de menú ─────────────────────────────────────────
|
||||
window.sbFilter = function(q) {
|
||||
q = q.trim().toLowerCase();
|
||||
var menu = document.getElementById('sb-menu');
|
||||
if (!menu) return;
|
||||
|
||||
if (!q) {
|
||||
// Restaurar estado guardado
|
||||
menu.querySelectorAll('.sb-group').forEach(function(g) {
|
||||
g.style.display = '';
|
||||
});
|
||||
menu.querySelectorAll('.sidebar-section').forEach(function(s) {
|
||||
s.style.display = '';
|
||||
});
|
||||
// Re-aplicar estado colapsado
|
||||
var collapsed = getCollapsed();
|
||||
menu.querySelectorAll('.sb-group').forEach(function(group) {
|
||||
var section = document.querySelector('[data-cat="' + group.id + '"]');
|
||||
var hasActive = !!group.querySelector('.nav-link.active');
|
||||
var isCol = !hasActive && collapsed.indexOf(group.id) !== -1;
|
||||
if (section) applyState(group, section, isCol, false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostrar todos expandidos y filtrar por texto
|
||||
menu.querySelectorAll('.sb-group').forEach(function(g) {
|
||||
var links = g.querySelectorAll('.nav-link');
|
||||
var anyMatch = false;
|
||||
links.forEach(function(a) {
|
||||
var txt = a.textContent.toLowerCase();
|
||||
var show = txt.includes(q);
|
||||
a.parentElement.style.display = show ? '' : 'none';
|
||||
if (show) anyMatch = true;
|
||||
});
|
||||
// Mostrar/ocultar grupo completo
|
||||
g.style.display = anyMatch ? '' : 'none';
|
||||
g.style.maxHeight = '2000px';
|
||||
g.style.opacity = '1';
|
||||
g.classList.remove('collapsed');
|
||||
var section = document.querySelector('[data-cat="' + g.id + '"]');
|
||||
if (section) {
|
||||
section.style.display = anyMatch ? '' : 'none';
|
||||
section.classList.remove('collapsed');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Inicializar al cargar
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var collapsed = getCollapsed();
|
||||
|
||||
Reference in New Issue
Block a user