diff --git a/admin-panel/admin/assets/css/admin-panel.css b/admin-panel/admin/assets/css/admin-panel.css new file mode 100644 index 00000000..6b335ff2 --- /dev/null +++ b/admin-panel/admin/assets/css/admin-panel.css @@ -0,0 +1,169 @@ +/** + * Admin Panel Styles + * + * Estilos base para el panel de administración + * + * @package Apus_Theme + * @since 2.0.0 + */ + +/* ======================================== + Container + ======================================== */ + +.apus-admin-panel { + max-width: 1400px; + margin: 20px auto; +} + +/* ======================================== + Header + ======================================== */ + +.apus-admin-panel h1 { + margin-bottom: 10px; +} + +.apus-admin-panel .description { + color: #666; + margin-bottom: 20px; +} + +/* ======================================== + Tabs + ======================================== */ + +.nav-tabs { + border-bottom: 2px solid #dee2e6; +} + +.nav-tabs .nav-link { + color: #666; + border: none; + border-bottom: 2px solid transparent; + margin-bottom: -2px; +} + +.nav-tabs .nav-link:hover { + color: #0073aa; + border-bottom-color: #0073aa; +} + +.nav-tabs .nav-link.active { + color: #0073aa; + font-weight: 600; + border-bottom-color: #0073aa; + background-color: transparent; +} + +/* ======================================== + Tab Content + ======================================== */ + +.tab-content { + background: #fff; + padding: 20px; + border: 1px solid #ddd; + border-radius: 4px; +} + +.tab-pane h3 { + margin-top: 0; + margin-bottom: 15px; + font-size: 18px; +} + +.tab-pane h4 { + margin-top: 25px; + margin-bottom: 10px; + font-size: 16px; + color: #333; +} + +/* ======================================== + Form Sections + ======================================== */ + +.form-section { + padding-bottom: 20px; + border-bottom: 1px solid #eee; +} + +.form-section:last-child { + border-bottom: none; +} + +.form-group { + margin-bottom: 15px; +} + +.form-group label { + display: block; + font-weight: 600; + margin-bottom: 5px; + color: #333; +} + +.form-group input[type="text"], +.form-group input[type="url"], +.form-group input[type="email"], +.form-group input[type="number"], +.form-group select, +.form-group textarea { + max-width: 600px; +} + +.form-group .form-text { + margin-top: 5px; + font-size: 13px; +} + +.form-group .form-text code { + background: #f5f5f5; + padding: 2px 5px; + border-radius: 3px; + font-size: 12px; +} + +/* ======================================== + Action Buttons + ======================================== */ + +.admin-actions { + padding: 20px; + background: #f9f9f9; + border-top: 1px solid #ddd; + border-radius: 4px; +} + +.admin-actions .button-primary { + font-size: 14px; + padding: 8px 20px; + height: auto; +} + +.admin-actions .button-primary i { + vertical-align: middle; +} + +/* ======================================== + Responsive + ======================================== */ + +@media (max-width: 782px) { + .apus-admin-panel { + margin: 10px; + } + + .tab-content { + padding: 15px; + } + + .form-group input[type="text"], + .form-group input[type="url"], + .form-group input[type="email"], + .form-group select, + .form-group textarea { + max-width: 100%; + } +} diff --git a/admin-panel/admin/assets/js/admin-app.js b/admin-panel/admin/assets/js/admin-app.js new file mode 100644 index 00000000..3a0535d1 --- /dev/null +++ b/admin-panel/admin/assets/js/admin-app.js @@ -0,0 +1,276 @@ +/** + * Admin Panel Application + * + * Gestión de configuraciones de componentes del tema + * + * @package Apus_Theme + * @since 2.0.0 + */ + +const AdminPanel = { + /** + * Estado de la aplicación + */ + STATE: { + settings: {}, + hasChanges: false, + isLoading: false + }, + + /** + * Inicializar aplicación + */ + init() { + this.bindEvents(); + this.loadSettings(); + }, + + /** + * Vincular eventos + */ + bindEvents() { + // Botón guardar + document.getElementById('saveSettings').addEventListener('click', () => { + this.saveSettings(); + }); + + // Detectar cambios en formularios + document.querySelectorAll('input, select, textarea').forEach(input => { + input.addEventListener('change', () => { + this.STATE.hasChanges = true; + document.getElementById('saveSettings').disabled = false; + }); + }); + + // Tabs + const tabs = document.querySelectorAll('.nav-tabs .nav-link'); + tabs.forEach(tab => { + tab.addEventListener('click', (e) => { + e.preventDefault(); + this.switchTab(tab); + }); + }); + }, + + /** + * Cambiar tab + */ + switchTab(tab) { + // Remover active de todos + document.querySelectorAll('.nav-tabs .nav-link').forEach(t => { + t.classList.remove('active'); + }); + document.querySelectorAll('.tab-pane').forEach(pane => { + pane.classList.remove('show', 'active'); + }); + + // Activar seleccionado + tab.classList.add('active'); + const targetId = tab.getAttribute('data-bs-target').substring(1); + const targetPane = document.getElementById(targetId); + if (targetPane) { + targetPane.classList.add('show', 'active'); + } + }, + + /** + * Cargar configuraciones desde servidor + */ + async loadSettings() { + this.STATE.isLoading = true; + this.showSpinner(true); + + try { + const response = await axios({ + method: 'POST', + url: apusAdminData.ajaxUrl, + data: new URLSearchParams({ + action: 'apus_get_settings', + nonce: apusAdminData.nonce + }) + }); + + if (response.data.success) { + this.STATE.settings = response.data.data; + this.renderAllComponents(); + } else { + this.showNotice('Error al cargar configuraciones', 'error'); + } + } catch (error) { + console.error('Error loading settings:', error); + this.showNotice('Error de conexión', 'error'); + } finally { + this.STATE.isLoading = false; + this.showSpinner(false); + } + }, + + /** + * Guardar configuraciones al servidor + */ + async saveSettings() { + if (!this.STATE.hasChanges) { + this.showNotice('No hay cambios para guardar', 'info'); + return; + } + + this.showSpinner(true); + + try { + const formData = this.collectFormData(); + + const response = await axios({ + method: 'POST', + url: apusAdminData.ajaxUrl, + headers: { + 'Content-Type': 'application/json' + }, + data: JSON.stringify({ + action: 'apus_save_settings', + nonce: apusAdminData.nonce, + ...formData + }) + }); + + if (response.data.success) { + this.STATE.hasChanges = false; + document.getElementById('saveSettings').disabled = true; + this.showNotice('Configuración guardada correctamente', 'success'); + } else { + this.showNotice(response.data.data.message || 'Error al guardar', 'error'); + } + } catch (error) { + console.error('Error saving settings:', error); + this.showNotice('Error de conexión', 'error'); + } finally { + this.showSpinner(false); + } + }, + + /** + * Recolectar datos del formulario + * Cada componente agregará su sección aquí + */ + collectFormData() { + return { + components: { + top_bar: { + enabled: document.getElementById('topBarEnabled').checked, + show_on_mobile: document.getElementById('topBarShowOnMobile').checked, + show_on_desktop: document.getElementById('topBarShowOnDesktop').checked, + icon_class: document.getElementById('topBarIconClass').value.trim(), + show_icon: document.getElementById('topBarShowIcon').checked, + highlight_text: document.getElementById('topBarHighlightText').value.trim(), + message_text: document.getElementById('topBarMessageText').value.trim(), + link_text: document.getElementById('topBarLinkText').value.trim(), + link_url: document.getElementById('topBarLinkUrl').value.trim(), + link_target: document.getElementById('topBarLinkTarget').value, + show_link: document.getElementById('topBarShowLink').checked, + custom_styles: { + background_color: this.getColorValue('topBarBgColor', ''), + text_color: this.getColorValue('topBarTextColor', ''), + highlight_color: this.getColorValue('topBarHighlightColor', ''), + link_hover_color: this.getColorValue('topBarLinkHoverColor', ''), + font_size: document.getElementById('topBarFontSize').value + } + } + // Navbar - Pendiente + // Hero - Pendiente + // Footer - Pendiente + } + }; + }, + + /** + * Renderizar todos los componentes + */ + renderAllComponents() { + const components = this.STATE.settings.components || {}; + + // Top Bar + if (components.top_bar) { + this.renderTopBar(components.top_bar); + } + // Navbar - Pendiente + // Hero - Pendiente + // Footer - Pendiente + }, + + /** + * Renderizar Top Bar + */ + renderTopBar(topBar) { + document.getElementById('topBarEnabled').checked = topBar.enabled !== undefined ? topBar.enabled : true; + document.getElementById('topBarShowOnMobile').checked = topBar.show_on_mobile !== undefined ? topBar.show_on_mobile : true; + document.getElementById('topBarShowOnDesktop').checked = topBar.show_on_desktop !== undefined ? topBar.show_on_desktop : true; + document.getElementById('topBarIconClass').value = topBar.icon_class || 'bi bi-megaphone-fill'; + document.getElementById('topBarShowIcon').checked = topBar.show_icon !== undefined ? topBar.show_icon : true; + document.getElementById('topBarHighlightText').value = topBar.highlight_text || 'Nuevo:'; + document.getElementById('topBarMessageText').value = topBar.message_text || 'Accede a más de 200,000 Análisis de Precios Unitarios actualizados para 2025.'; + document.getElementById('topBarLinkText').value = topBar.link_text || 'Ver Catálogo'; + document.getElementById('topBarLinkUrl').value = topBar.link_url || '/catalogo'; + document.getElementById('topBarLinkTarget').value = topBar.link_target || '_self'; + document.getElementById('topBarShowLink').checked = topBar.show_link !== undefined ? topBar.show_link : true; + + // Estilos personalizados + if (topBar.custom_styles) { + if (topBar.custom_styles.background_color) { + document.getElementById('topBarBgColor').value = topBar.custom_styles.background_color; + } + if (topBar.custom_styles.text_color) { + document.getElementById('topBarTextColor').value = topBar.custom_styles.text_color; + } + if (topBar.custom_styles.highlight_color) { + document.getElementById('topBarHighlightColor').value = topBar.custom_styles.highlight_color; + } + if (topBar.custom_styles.link_hover_color) { + document.getElementById('topBarLinkHoverColor').value = topBar.custom_styles.link_hover_color; + } + document.getElementById('topBarFontSize').value = topBar.custom_styles.font_size || 'normal'; + } + }, + + /** + * Utilidad: Obtener valor de color con fallback + */ + getColorValue(inputId, defaultValue) { + const input = document.getElementById(inputId); + const value = input ? input.value.trim() : ''; + return value || defaultValue; + }, + + /** + * Utilidad: Mostrar spinner + */ + showSpinner(show) { + const spinner = document.querySelector('.spinner'); + if (spinner) { + spinner.style.display = show ? 'inline-block' : 'none'; + } + }, + + /** + * Utilidad: Mostrar notificación + */ + showNotice(message, type = 'info') { + // WordPress admin notices + const noticeDiv = document.createElement('div'); + noticeDiv.className = `notice notice-${type} is-dismissible`; + noticeDiv.innerHTML = `
${message}
`; + + const container = document.querySelector('.apus-admin-panel'); + if (container) { + container.insertBefore(noticeDiv, container.firstChild); + + // Auto-dismiss después de 5 segundos + setTimeout(() => { + noticeDiv.remove(); + }, 5000); + } + } +}; + +// Inicializar cuando el DOM esté listo +document.addEventListener('DOMContentLoaded', () => { + AdminPanel.init(); +}); diff --git a/admin-panel/admin/includes/class-admin-menu.php b/admin-panel/admin/includes/class-admin-menu.php new file mode 100644 index 00000000..3378bb9f --- /dev/null +++ b/admin-panel/admin/includes/class-admin-menu.php @@ -0,0 +1,119 @@ + admin_url('admin-ajax.php'), + 'nonce' => wp_create_nonce('apus_admin_nonce') + )); + } +} + +// Instanciar clase +new APUS_Admin_Menu(); diff --git a/admin-panel/admin/pages/main.php b/admin-panel/admin/pages/main.php new file mode 100644 index 00000000..73ce46f1 --- /dev/null +++ b/admin-panel/admin/pages/main.php @@ -0,0 +1,177 @@ + + +Configure los componentes del tema Apus
+ + + + + +Personaliza la barra de notificación superior del sitio.
+ + +Si está desactivado, el Top Bar no se mostrará en el sitio.
+Usa clases de Bootstrap Icons
+Máximo 30 caracteres. Aparece en negritas.
+Máximo 250 caracteres. Campo obligatorio.
+Deja en blanco para usar los colores del tema por defecto.
+ +