[WORK IN PROGRESS] Basic Admin UI Enhancements with toggle fixes

This commit is contained in:
2025-04-08 01:24:17 +01:00
parent a4c69999f6
commit b5aeeaf2c4
8 changed files with 466 additions and 408 deletions

View File

@ -109,25 +109,50 @@
}
}
/* Base Toggle Switch Component */
/* Setting notification */
.wp-setting-notification {
display: inline-flex;
align-items: center;
margin-left: 10px;
background: #00a32a;
color: white;
padding: 3px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
animation: fadeIn 0.3s ease-in-out;
height: 20px;
box-sizing: border-box;
position: relative;
transform: translateY(-3px);
white-space: nowrap;
min-width: 60px;
justify-content: center;
}
.wp-setting-notification.error {
background: #d63638;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Toggle Switch */
.wp-toggle-switch {
position: relative;
display: inline-block;
width: 36px;
width: 40px;
height: 20px;
flex-shrink: 0;
cursor: pointer;
pointer-events: all;
z-index: 2;
vertical-align: middle;
margin-right: 8px;
}
.wp-toggle-switch input {
opacity: 0;
width: 0;
height: 0;
margin: 0;
padding: 0;
position: absolute;
}
.wp-toggle-slider {
@ -139,7 +164,7 @@
bottom: 0;
background-color: #ccc;
transition: .3s;
border-radius: 20px;
border-radius: 34px;
}
.wp-toggle-slider:before {
@ -152,15 +177,55 @@
background-color: white;
transition: .3s;
border-radius: 50%;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
input:checked + .wp-toggle-slider {
background-color: #2271b1;
}
input:focus + .wp-toggle-slider {
box-shadow: 0 0 1px #2271b1;
}
input:checked + .wp-toggle-slider:before {
transform: translateX(16px);
transform: translateX(20px);
}
/* Settings layout */
.wp-setting-row {
background: #fff;
border: 1px solid #e5e5e5;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
padding: 20px;
margin-bottom: 20px;
border-radius: 3px;
}
.wp-setting-header {
position: relative;
}
.wp-setting-main {
display: flex;
justify-content: space-between;
align-items: center;
}
.wp-setting-left {
display: flex;
align-items: center;
}
.wp-setting-label {
font-weight: 600;
margin: 0;
font-size: 14px;
}
.wp-setting-description {
margin: 10px 0 0;
color: #666;
font-size: 13px;
}
/* Tab Content Area - GLOBAL SETTINGS - All tab spacing should inherit from here */
@ -717,28 +782,6 @@ input:checked + .wp-toggle-slider:before {
}
}
/* Settings Notification */
.wp-setting-notification {
display: inline-flex;
align-items: center;
margin-left: 10px;
background: #00a32a;
color: white;
padding: 3px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
animation: fadeIn 0.3s ease-in-out;
height: 20px;
box-sizing: border-box;
position: relative;
transform: translateY(-3px);
}
.wp-setting-notification.error {
background: #d63638;
}
/* Add space for notification to prevent layout shifts */
.wp-setting-left label,
.wp-allstars-toggle-left label,
@ -758,11 +801,6 @@ input:checked + .wp-toggle-slider:before {
line-height: 1.4;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.wpa-loading-overlay {
position: absolute;
top: 0;

View File

@ -109,6 +109,7 @@ class WP_Allstars_Admin_Manager {
$allowed_options = array(
'wp_allstars_simple_setting',
'wp_allstars_auto_upload_images',
'wp_allstars_admin_color_scheme',
'wp_allstars_max_width',
'wp_allstars_max_height',
'wp_allstars_exclude_urls',

View File

@ -29,6 +29,7 @@ class WP_Allstars_Settings_Manager {
public static function register_settings() {
// General settings
register_setting('wp_allstars_settings', 'wp_allstars_simple_setting');
register_setting('wp_allstars_settings', 'wp_allstars_admin_color_scheme');
// Advanced settings
register_setting('wp_allstars_settings', 'wp_allstars_auto_upload_images');
@ -71,6 +72,31 @@ class WP_Allstars_Settings_Manager {
?>
<div class="wp-allstars-settings-section">
<div class="wp-allstars-settings-grid">
<!-- Admin Color Scheme Setting -->
<div class="wp-setting-row">
<div class="wp-setting-header">
<div class="wp-setting-main">
<div class="wp-setting-left">
<div class="wp-toggle-switch">
<input type="checkbox"
id="wp_allstars_admin_color_scheme"
name="wp_allstars_admin_color_scheme"
value="1"
<?php checked(get_option('wp_allstars_admin_color_scheme', false)); ?>
/>
<span class="wp-toggle-slider"></span>
</div>
<label for="wp_allstars_admin_color_scheme" class="wp-setting-label">
<?php esc_html_e('Modern Admin Colors', 'wp-allstars'); ?>
</label>
</div>
</div>
<p class="wp-setting-description">
<?php esc_html_e('Switch to the Modern Admin colors, to remind that you\'re using WP Allstars.', 'wp-allstars'); ?>
</p>
</div>
</div>
<!-- Example of a simple toggle setting (no panel) -->
<div class="wp-setting-row">
<div class="wp-setting-header">
@ -158,6 +184,7 @@ class WP_Allstars_Settings_Manager {
// Save general settings
update_option('wp_allstars_simple_setting', isset($_POST['wp_allstars_simple_setting']) ? 1 : 0);
update_option('wp_allstars_admin_color_scheme', isset($_POST['wp_allstars_admin_color_scheme']) ? 1 : 0);
// Save advanced settings
update_option('wp_allstars_auto_upload_images', isset($_POST['wp_allstars_auto_upload_images']) ? 1 : 0);

View File

@ -0,0 +1,74 @@
/**
* WP Allstars Admin Colors Script
*
* Handles toggling the admin color scheme
*/
(function($) {
'use strict';
// Once the DOM is ready
$(document).ready(function() {
// Find the color scheme toggle
var $toggle = $('#wp_allstars_admin_color_scheme');
if (!$toggle.length) {
return;
}
// Listen for changes to the toggle
$toggle.on('change', function() {
var $this = $(this);
var enabled = $this.is(':checked');
var $notification = $this.closest('label').find('.wp-setting-notification');
// Show loading notification
if ($notification.length) {
$notification.text('Saving...').show();
} else {
$notification = $('<span class="wp-setting-notification">Saving...</span>');
$this.closest('label').append($notification);
}
// Send AJAX request
$.ajax({
url: wpAllstarsColors.ajax_url,
type: 'POST',
data: {
action: 'wp_allstars_update_color_scheme',
nonce: wpAllstarsColors.nonce,
enabled: enabled ? 1 : 0
},
success: function(response) {
if (response.success) {
// Show success notification
$notification.text('Saved!').removeClass('error');
// Reload page after a short delay to apply new color scheme
setTimeout(function() {
window.location.reload();
}, 1000);
} else {
// Show error notification
$notification.text('Error').addClass('error');
// Revert toggle
$this.prop('checked', !enabled);
// Log error
console.error('Error updating color scheme:', response.data);
}
},
error: function(xhr, status, error) {
// Show error notification
$notification.text('Error').addClass('error');
// Revert toggle
$this.prop('checked', !enabled);
// Log error
console.error('AJAX error:', error);
}
});
});
});
})(jQuery);

View File

@ -1,387 +1,72 @@
// Define loadTheme in the global scope so it can be called from inline scripts
var loadTheme;
/**
* WP Allstars Admin Script
*
* Handles UI interactions in the admin settings
*/
(function($) {
'use strict';
jQuery(document).ready(function($) {
// Function to show notification
function showNotification(message, $element, isError = false) {
// Remove any existing notifications
$('.wp-setting-notification').remove();
// Create notification element
var $notification = $('<span class="wp-setting-notification' + (isError ? ' error' : '') + '">' + message + '</span>');
// If element is provided, show notification next to it
if ($element && $element.length) {
$element.after($notification);
} else {
// Fallback to header if no element provided
$('.wp-allstars-header h1').after($notification);
}
// Fade out after delay
setTimeout(function() {
$notification.fadeOut(300, function() {
$(this).remove();
});
}, 2000);
}
// Handle option updates
function updateOption(option, value) {
return $.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'wp_allstars_update_option',
option: option,
value: value,
nonce: wpAllstars.nonce
// Document ready handler
$(document).ready(function() {
// Handle toggle switches
$('.wp-toggle-switch input[type="checkbox"]').on('change', function() {
var $this = $(this);
var option = $this.attr('id');
var value = $this.is(':checked') ? 1 : 0;
// Don't handle the admin color scheme toggle here - it has its own handler
if (option === 'wp_allstars_admin_color_scheme') {
return;
}
}).then(function(response) {
if (!response.success) {
throw new Error(response.data || 'Error saving setting');
// Show update notification
var $notification = $this.closest('label').find('.wp-setting-notification');
if ($notification.length === 0) {
$notification = $('<span class="wp-setting-notification">Saving...</span>');
$this.closest('label').append($notification);
} else {
$notification.text('Saving...').removeClass('error').show();
}
return response;
});
}
// Handle toggle switch clicks
$('.wp-toggle-switch').on('click', function(e) {
e.stopPropagation();
var $checkbox = $(this).find('input[type="checkbox"]');
var isChecked = $checkbox.is(':checked');
$checkbox.prop('checked', !isChecked).trigger('change');
});
// Prevent label clicks from toggling the checkbox directly
$('.wp-setting-label, .wp-allstars-toggle-left label').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
});
// Handle checkbox changes
$('.wp-toggle-switch input[type="checkbox"]').on('change', function(e) {
e.stopPropagation();
var $input = $(this);
var option = $input.attr('name');
var value = $input.is(':checked') ? 1 : 0;
var $label = $input.closest('.wp-setting-left, .wp-allstars-toggle-left').find('label');
updateOption(option, value)
.then(function() {
showNotification('Saved', $label);
})
.catch(function() {
showNotification('Error saving settings', $label, true);
});
});
// Handle text input changes
$('.wp-allstars-setting-row input[type="text"], .wp-allstars-setting-row input[type="number"], .wp-allstars-setting-row textarea').on('blur change', function() {
var $input = $(this);
var option = $input.attr('name');
var value = $input.val();
var $label = $input.closest('.wp-allstars-setting-row').find('label').first();
updateOption(option, value)
.then(function() {
showNotification('Saved', $label);
})
.catch(function(error) {
console.error('Error:', error);
showNotification('Error saving setting', $label, true);
});
});
// Toggle expandable panels
$('.wp-allstars-toggle-header').on('click', function(e) {
if (!$(e.target).closest('.wp-toggle-switch').length &&
!$(e.target).closest('label').length) {
var $settings = $(this).closest('.wp-allstars-toggle').find('.wp-allstars-toggle-settings');
var isExpanded = $(this).attr('aria-expanded') === 'true';
$(this).attr('aria-expanded', !isExpanded);
$settings.slideToggle(200);
}
});
// Set initial panel states
$('.wp-allstars-toggle-header').each(function() {
var $settings = $(this).closest('.wp-allstars-toggle').find('.wp-allstars-toggle-settings');
var isExpanded = $(this).attr('aria-expanded') === 'true';
if (!isExpanded) {
$settings.hide();
}
});
// Remove JavaScript-based tab switching - let the native WordPress tab links work
// Plugin category filters
if ($('#wpa-plugin-filters').length) {
$('#wpa-plugin-filters a').on('click', function(e) {
e.preventDefault();
var category = $(this).data('category');
// Update active filter
$('#wpa-plugin-filters a').removeClass('current');
$(this).addClass('current');
// Load plugins for the selected category
loadPlugins(category);
});
// Load initial plugins if we're on the recommended tab
if ($('#recommended').is(':visible') && $('#wpa-plugin-list').is(':empty')) {
loadPlugins('minimal');
}
}
// Load theme tab content if we're on the theme tab
if ($('#theme').is(':visible') && $('#wpa-theme-list').length && $('#wpa-theme-list').is(':empty')) {
loadTheme();
}
// Function to load plugins
function loadPlugins(category) {
var $container = $('#wpa-plugin-list');
var $loadingOverlay = $('<div class="wp-allstars-loading-overlay"><span class="spinner is-active"></span></div>');
// Show loading overlay
$container.css('position', 'relative').append($loadingOverlay);
// Clear existing plugins
$container.empty().append($loadingOverlay);
// AJAX request to get plugins
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'wp_allstars_get_plugins',
category: category,
_wpnonce: wpAllstars.nonce
},
success: function(response) {
// Remove loading overlay
$loadingOverlay.remove();
if (response.success) {
// Append plugins HTML
$container.html(response.data);
// Initialize plugin action buttons
initPluginActions();
// Individual plugin card spinners have been removed
} else {
// Show error message
$container.html('<div class="notice notice-error"><p>' + response.data + '</p></div>');
}
},
error: function(xhr, status, error) {
// Remove loading overlay
$loadingOverlay.remove();
// Show error message
$container.html('<div class="notice notice-error"><p>Failed to load plugins. Please try again. Error: ' + error + '</p></div>');
console.error('AJAX Error:', xhr.responseText);
}
});
}
// Theme handlers are initialized directly from the inline script
// We don't need a separate loadTheme function anymore
// Initialize plugin action buttons
function initPluginActions() {
// Remove any existing event handlers to prevent duplicates
$('.plugin-card .install-now').off('click');
$('.plugin-card .update-now').off('click');
$('.plugin-card .activate-now').off('click');
// Install plugin
$('.plugin-card .install-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var slug = $button.data('slug');
$button.addClass('updating-message').text('Installing...');
wp.updates.installPlugin({
slug: slug,
success: function(response) {
$button.removeClass('updating-message').addClass('updated-message').text('Installed!');
setTimeout(function() {
// Replace the button with an activate button
var $parent = $button.parent();
$button.remove();
$parent.html('<a class="button activate-now" href="' + response.activateUrl + '" data-slug="' + slug + '" aria-label="Activate ' + slug + '">Activate</a>');
// Re-initialize the event handlers
initPluginActions();
}, 1000);
},
error: function(response) {
$button.removeClass('updating-message').text('Install Now');
alert(response.errorMessage);
}
});
});
// Update plugin
$('.plugin-card .update-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var slug = $button.data('slug');
$button.addClass('updating-message').text('Updating...');
wp.updates.updatePlugin({
slug: slug,
success: function() {
$button.removeClass('updating-message').addClass('updated-message').text('Updated!');
setTimeout(function() {
$button.removeClass('update-now updated-message')
.addClass('button-disabled')
.text('Active');
}, 1000);
},
error: function(response) {
$button.removeClass('updating-message').text('Update Now');
alert(response.errorMessage);
}
});
});
// Activate plugin
$('.plugin-card .activate-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var url = $button.attr('href');
var slug = $button.data('slug');
$button.addClass('updating-message').text('Activating...');
// Save the option via AJAX
$.ajax({
url: url,
dataType: 'html',
success: function() {
$button.removeClass('updating-message').addClass('updated-message').text('Activated!');
setTimeout(function() {
// Replace the button with an active button
var $parent = $button.parent();
$button.remove();
$parent.html('<button type="button" class="button button-disabled" disabled="disabled">Active</button>');
}, 1000);
},
error: function() {
$button.removeClass('updating-message').text('Activate');
alert('Failed to activate plugin. Please try again or activate from the Plugins page.');
}
});
});
}
// Expose initPluginActions to global scope for use in other scripts
window.initPluginActions = initPluginActions;
// Initialize theme handlers
function initThemeHandlers() {
console.log('Initializing theme handlers');
// Remove any existing event handlers to prevent duplicates
$('.theme-actions .install-now').off('click');
$('.theme-actions .activate-now').off('click');
// Install theme - use wp.updates.installTheme AJAX method
$('.theme-actions .install-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var slug = $button.data('slug');
var buttonText = $button.text();
$button.addClass('updating-message').attr('aria-label', wp.updates.l10n.installing);
wp.updates.installTheme({
slug: slug,
success: function(response) {
$button.removeClass('updating-message').addClass('updated-message').attr('aria-label', wp.updates.l10n.installed);
setTimeout(function() {
// Replace the button with an activate button
var $parent = $button.parent();
$button.remove();
// Create activate URL with nonce
var activateUrl = ajaxurl + '?action=wp_allstars_activate_theme&theme=' + slug + '&_wpnonce=' + wpAllstars.nonce;
$parent.prepend('<a href="' + activateUrl + '" class="button button-primary activate-now" data-slug="' + slug + '" data-name="Kadence" data-nonce="' + wpAllstars.nonce + '">Activate</a>');
// Re-initialize the event handlers
initThemeHandlers();
}, 1000);
},
error: function(response) {
$button.removeClass('updating-message').text(buttonText);
alert(response.errorMessage || 'Error installing theme');
}
});
});
// Activate theme - use AJAX
$('.theme-actions .activate-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var slug = $button.data('slug');
var nonce = $button.data('nonce');
var buttonText = $button.text();
$button.addClass('updating-message').attr('aria-label', 'Activating...');
$.ajax({
url: ajaxurl,
url: wpAllstars.ajaxurl,
type: 'POST',
data: {
action: 'wp_allstars_activate_theme',
theme: slug,
_wpnonce: wpAllstars.nonce
action: 'wp_allstars_update_option',
nonce: wpAllstars.nonce,
option: option,
value: value
},
success: function(response) {
if (response.success) {
$button.removeClass('updating-message').addClass('updated-message').attr('aria-label', 'Activated');
$notification.text('Saved!');
setTimeout(function() {
// Replace the button with an active button
var $parent = $button.parent();
$button.remove();
$parent.prepend('<button type="button" class="button button-disabled" disabled="disabled">Active</button>');
// Optionally reload the page to show the activated theme
// window.location.reload();
}, 1000);
$notification.fadeOut(300);
}, 2000);
} else {
$button.removeClass('updating-message').text(buttonText);
alert(response.data || 'Error activating theme');
$notification.text('Error').addClass('error');
console.error('Error saving option:', response.data);
}
},
error: function(xhr, status, error) {
$button.removeClass('updating-message').text(buttonText);
alert('Failed to activate theme. Please try again or activate from the Themes page. Error: ' + error);
$notification.text('Error').addClass('error');
console.error('AJAX error:', error);
}
});
});
}
// Expose initThemeHandlers to global scope for use in other scripts
window.initThemeHandlers = initThemeHandlers;
});
// Toggle expandable panels
$('.wp-allstars-toggle-header').on('click', function() {
var $this = $(this);
var $settings = $this.next('.wp-allstars-toggle-settings');
var isExpanded = $this.attr('aria-expanded') === 'true';
// Toggle aria-expanded attribute
$this.attr('aria-expanded', !isExpanded);
// Toggle settings visibility
$settings.slideToggle(200);
});
});
})(jQuery);