Files
roi-theme/_planificacion/01-design-system/13-PANEL-ADMINISTRACION.md
FrankZamora 0f6387ab46 refactor: reorganizar openspec y planificacion con spec recaptcha
- renombrar openspec/ a _openspec/ (carpeta auxiliar)
- mover specs de features a changes/
- crear specs base: arquitectura-limpia, estandares-codigo, nomenclatura
- migrar _planificacion/ con design-system y roi-theme-template
- agregar especificacion recaptcha anti-spam (proposal, tasks, spec)
- corregir rutas y referencias en todas las specs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 15:30:45 -06:00

13 KiB

🎛️ PANEL DE ADMINISTRACIÓN PRINCIPAL

Arquitectura del Sistema

El panel de administración utiliza un sistema de tabs (pestañas) de Bootstrap 5, donde todos los componentes existen en una sola página y se alternan mediante JavaScript.

Características Principales

  • Single Page: Todos los componentes en un solo archivo main.php
  • Bootstrap Tabs: Navegación mediante nav-tabs y tab-pane
  • Carga Modular: Cada componente se incluye con require_once
  • Botones Globales: Save/Cancel compartidos para todos los componentes
  • Sin Recargas: Cambio de tabs sin reload de página

Estructura del main.php

<?php
/**
 * Admin Panel - Main Page
 */
if (!defined('ABSPATH')) {
    exit;
}
?>

<div class="wrap apus-admin">
    <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
    <p class="description">Configure los componentes del tema</p>

    <!-- Navigation Tabs -->
    <ul class="nav nav-tabs" role="tablist">
        <!-- Tabs aquí -->
    </ul>

    <!-- Tab Content -->
    <div class="tab-content mt-3">
        <?php
        // Componentes incluidos aquí
        ?>
    </div>

    <!-- Action Buttons (Global) -->
    <div class="d-flex justify-content-end gap-2 p-3 rounded border mt-4"
         style="background-color: #f8f9fa;">
        <button type="button" class="btn btn-outline-secondary" id="cancelChanges">
            <i class="bi bi-x-circle me-1"></i>
            Cancelar
        </button>
        <button type="button" id="saveSettings"
                class="btn fw-semibold text-white"
                style="background-color: #FF8600; border-color: #FF8600;">
            <i class="bi bi-check-circle me-1"></i>
            Guardar Cambios
        </button>
    </div>
</div>

Agregar un Nuevo Tab

Paso 1: Agregar el Tab en la Navegación

<ul class="nav nav-tabs" role="tablist">
    <li class="nav-item">
        <a class="nav-link active"
           data-bs-toggle="tab"
           data-bs-target="#[tabId]"
           href="#[tabId]"
           role="tab">
            <i class="bi bi-[icon-class] me-2"></i>
            [Nombre del Componente]
        </a>
    </li>
    <!-- Más tabs... -->
</ul>

Reemplazar:

  • [tabId]: ID único del tab (ej: notificationBarTab, siteFooterTab)
  • [icon-class]: Clase del icono de Bootstrap Icons (ej: megaphone-fill)
  • [Nombre del Componente]: Nombre visible del tab (ej: "Barra de Notificaciones")

Paso 2: Incluir el Componente en Tab Content

<div class="tab-content mt-3">
    <?php
    /**
     * [Component Name] Component
     * Archivo: Admin/Components/component-[name].php
     */
    require_once APUS_ADMIN_PANEL_PATH . 'Admin/Components/component-[name].php';
    ?>

    <!-- Más componentes... -->
</div>

Reemplazar:

  • [Component Name]: Nombre descriptivo del componente
  • [name]: Nombre del archivo (ej: notification-bar, site-footer)

Paso 3: Crear el Archivo del Componente

Crear Admin/Components/component-[name].php:

<!-- Tab Pane: [Component Name] -->
<div class="tab-pane fade show active" id="[tabId]" role="tabpanel">

    <!-- Header del Tab -->
    <div class="rounded p-4 mb-4 shadow text-white"
         style="background: linear-gradient(135deg, #0E2337 0%, #1e3a5f 100%);
                border-left: 4px solid #FF8600;">
        <div class="d-flex align-items-center justify-content-between flex-wrap gap-3">
            <div>
                <h3 class="h4 mb-1 fw-bold">
                    <i class="bi bi-[icon-class] me-2" style="color: #FF8600;"></i>
                    [Título del Componente]
                </h3>
                <p class="mb-0 small" style="opacity: 0.85;">
                    [Descripción breve del componente]
                </p>
            </div>
            <button type="button" class="btn btn-sm btn-outline-light" id="reset[Component]Defaults">
                <i class="bi bi-arrow-counterclockwise me-1"></i>
                Restaurar valores por defecto
            </button>
        </div>
    </div>

    <!-- Grid de Configuración -->
    <div class="row g-3">
        <!-- Columna izquierda: Configuración -->
        <div class="col-lg-6">
            <!-- Cards de configuración -->
        </div>

        <!-- Columna derecha: Preview -->
        <div class="col-lg-6">
            <!-- Card de vista previa -->
        </div>
    </div>

</div><!-- /tab-pane -->

Iconos Sugeridos por Tipo de Componente

Tipo de Componente Icono Clase Bootstrap Icons
Notificaciones/Anuncios 📢 bi-megaphone-fill
Navegación/Menú 📋 bi-layout-text-window
Sección Hero 🖼️ bi-image
Footer ⬇️ bi-box-arrow-down
Formularios 📝 bi-clipboard-check
Call-to-Action 👆 bi-cursor-fill
Testimonios 💬 bi-chat-quote
Configuración ⚙️ bi-gear-fill

Ejemplo Completo: Agregar Componente de Navegación

1. Agregar Tab en main.php

<ul class="nav nav-tabs" role="tablist">
    <!-- Tab existente -->
    <li class="nav-item">
        <a class="nav-link active"
           data-bs-toggle="tab"
           data-bs-target="#topBarTab"
           href="#topBarTab"
           role="tab">
            <i class="bi bi-megaphone-fill me-2"></i>
            Top Bar
        </a>
    </li>

    <!-- NUEVO TAB -->
    <li class="nav-item">
        <a class="nav-link"
           data-bs-toggle="tab"
           data-bs-target="#navbarTab"
           href="#navbarTab"
           role="tab">
            <i class="bi bi-layout-text-window me-2"></i>
            Navbar
        </a>
    </li>
</ul>

Notas:

  • El primer tab tiene class="nav-link active"
  • Los demás tabs solo tienen class="nav-link"

2. Incluir Componente en Tab Content

<div class="tab-content mt-3">
    <?php
    // Componente existente
    require_once APUS_ADMIN_PANEL_PATH . 'Admin/Components/component-top-bar.php';

    // NUEVO COMPONENTE
    require_once APUS_ADMIN_PANEL_PATH . 'Admin/Components/component-navbar.php';
    ?>
</div>

3. Crear component-navbar.php

Crear archivo: Admin/Components/component-navbar.php

<!-- Tab Pane: Navbar -->
<div class="tab-pane fade" id="navbarTab" role="tabpanel">

    <!-- Header del Tab -->
    <div class="rounded p-4 mb-4 shadow text-white"
         style="background: linear-gradient(135deg, #0E2337 0%, #1e3a5f 100%);
                border-left: 4px solid #FF8600;">
        <div class="d-flex align-items-center justify-content-between flex-wrap gap-3">
            <div>
                <h3 class="h4 mb-1 fw-bold">
                    <i class="bi bi-layout-text-window me-2" style="color: #FF8600;"></i>
                    Configuración del Navbar
                </h3>
                <p class="mb-0 small" style="opacity: 0.85;">
                    Gestiona los colores, estilo y comportamiento del menú de navegación
                </p>
            </div>
            <button type="button" class="btn btn-sm btn-outline-light" id="resetNavbarDefaults">
                <i class="bi bi-arrow-counterclockwise me-1"></i>
                Restaurar valores por defecto
            </button>
        </div>
    </div>

    <!-- Grid de Configuración -->
    <div class="row g-3">
        <!-- Configuración -->
        <div class="col-lg-6">
            <div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">
                <div class="card-body">
                    <h5 class="fw-bold mb-3" style="color: #1e3a5f;">
                        <i class="bi bi-palette me-2" style="color: #FF8600;"></i>
                        Colores
                    </h5>
                    <!-- Campos de configuración aquí -->
                </div>
            </div>
        </div>

        <!-- Vista Previa -->
        <div class="col-lg-6">
            <div class="card shadow-sm mb-3" style="border-left: 4px solid #FF8600;">
                <div class="card-body">
                    <h5 class="fw-bold mb-3" style="color: #1e3a5f;">
                        <i class="bi bi-eye me-2" style="color: #FF8600;"></i>
                        Vista Previa
                    </h5>
                    <!-- Preview del componente aquí -->
                    <div id="navbarPreview">
                        <!-- HTML idéntico al front-end -->
                    </div>
                </div>
            </div>
        </div>
    </div>

</div><!-- /tab-pane -->

Notas:

  • El primer tab-pane tiene class="tab-pane fade show active"
  • Los demás tab-panes tienen class="tab-pane fade"

Orden de los Tabs

Por Prioridad

Organizar los tabs de más importante a menos importante:

  1. Componentes críticos/visibles (Header, Navbar, Hero)
  2. Componentes de contenido (Secciones, CTAs)
  3. Componentes complementarios (Footer, Forms)
  4. Configuraciones generales

Ejemplo de Orden

<ul class="nav nav-tabs" role="tablist">
    <li class="nav-item"><!-- Barra de Notificaciones --></li>
    <li class="nav-item"><!-- Navbar --></li>
    <li class="nav-item"><!-- Hero Section --></li>
    <li class="nav-item"><!-- Call-to-Action --></li>
    <li class="nav-item"><!-- Footer --></li>
    <li class="nav-item"><!-- Configuración General --></li>
</ul>

Botones Globales Save/Cancel

Los botones de guardar y cancelar son globales para todos los tabs:

<div class="d-flex justify-content-end gap-2 p-3 rounded border mt-4"
     style="background-color: #f8f9fa; border-color: #e9ecef !important;">

    <!-- Cancelar -->
    <button type="button" class="btn btn-outline-secondary" id="cancelChanges">
        <i class="bi bi-x-circle me-1"></i>
        Cancelar
    </button>

    <!-- Guardar -->
    <button type="button" id="saveSettings"
            class="btn fw-semibold text-white"
            style="background-color: #FF8600; border-color: #FF8600;"
            disabled>
        <i class="bi bi-check-circle me-1"></i>
        Guardar Cambios
    </button>
</div>

JavaScript para Activar/Desactivar Guardar

// Detectar cambios en cualquier campo
document.querySelectorAll('input, select, textarea').forEach(field => {
    field.addEventListener('change', function() {
        // Activar botón de guardar
        document.getElementById('saveSettings').disabled = false;
    });
});

// Guardar cambios
document.getElementById('saveSettings').addEventListener('click', function() {
    // Guardar configuración de todos los componentes
    saveAllConfigs();

    // Desactivar botón de guardar
    this.disabled = true;
});

// Cancelar cambios
document.getElementById('cancelChanges').addEventListener('click', function() {
    if (confirm('¿Descartar todos los cambios sin guardar?')) {
        // Recargar configuraciones originales
        loadAllConfigs();

        // Desactivar botón de guardar
        document.getElementById('saveSettings').disabled = true;
    }
});

Responsive Behavior

Desktop (≥992px)

  • Tabs en una sola línea horizontal
  • Grid de 2 columnas (configuración + preview)
  • Espaciado completo

Tablet (768px - 991px)

  • Tabs pueden hacer wrap a 2 líneas
  • Grid de 2 columnas (se mantiene)
  • Espaciado reducido

Mobile (<768px)

  • Tabs en scroll horizontal o stacked vertical
  • Grid stacked (1 columna)
  • Botones Save/Cancel pueden hacer stack
@media (max-width: 991px) {
    .nav-tabs {
        flex-wrap: wrap;
    }

    .nav-tabs .nav-link {
        font-size: 0.9rem;
        padding: 0.5rem 0.75rem;
    }
}

@media (max-width: 767px) {
    .nav-tabs {
        overflow-x: auto;
        flex-wrap: nowrap;
    }

    .nav-tabs .nav-item {
        white-space: nowrap;
    }
}

Funcionalidad Adicional (Opcional)

Badges de Estado en Tabs

<li class="nav-item">
    <a class="nav-link" data-bs-toggle="tab" data-bs-target="#[tabId]" role="tab">
        <i class="bi bi-[icon-class] me-2"></i>
        [Nombre del Componente]
        <span class="badge bg-success ms-2" style="font-size: 0.65rem;">Activo</span>
    </a>
</li>

Estados posibles:

  • bg-success: Activo
  • bg-secondary: Inactivo
  • bg-warning text-dark: Requiere atención

Indicador de Cambios Sin Guardar

// Agregar asterisco al tab si tiene cambios sin guardar
function markTabAsModified(tabId) {
    const tabLink = document.querySelector(`a[data-bs-target="#${tabId}"]`);
    if (!tabLink.querySelector('.modified-indicator')) {
        tabLink.innerHTML += ' <span class="modified-indicator" style="color: #FF8600;">*</span>';
    }
}

Checklist de Implementación

Cuando agregues un nuevo componente al panel, asegúrate de:

  • Agregar el tab en la navegación (<ul class="nav nav-tabs">)
  • Crear el archivo PHP del componente (component-[name].php)
  • Incluir el componente en tab-content con require_once
  • Crear archivo CSS del componente (component-[name].css)
  • Crear archivo JS del componente (component-[name].js)
  • Crear archivo de configuración JSON ([name]-config.json)
  • Agregar estilos específicos del componente
  • Implementar vista previa en tiempo real
  • Conectar con sistema de guardar/cancelar global
  • Probar responsive behavior
  • Verificar que el tab-pane tenga el ID correcto
  • Verificar que el primer tab y tab-pane tengan active y show

Volver al Índice

← Volver al README