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">
|
<nav class="sidebar" id="erp-sidebar">
|
||||||
|
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h4><i class="<?= htmlspecialchars($_sidebar_icon, ENT_QUOTES, 'UTF-8') ?>"></i>
|
<h4 style="flex:1;min-width:0">
|
||||||
<?= htmlspecialchars($_sidebar_title, ENT_QUOTES, 'UTF-8') ?></h4>
|
<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>
|
</div>
|
||||||
|
|
||||||
<ul class="sidebar-menu" id="sb-menu">
|
<ul class="sidebar-menu" id="sb-menu">
|
||||||
@@ -211,6 +223,48 @@ if (class_exists('ModuleRegistry', false)) {
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<style>
|
<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 ─────────────────────────── */
|
/* ── Acordeón de categorías ─────────────────────────── */
|
||||||
.sidebar-section {
|
.sidebar-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -285,6 +339,54 @@ if (class_exists('ModuleRegistry', false)) {
|
|||||||
setCollapsed(arr);
|
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
|
// Inicializar al cargar
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
var collapsed = getCollapsed();
|
var collapsed = getCollapsed();
|
||||||
|
|||||||
Reference in New Issue
Block a user