PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.44
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.44
51.1.87 51.1.86 51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 All 41 releases
king-addons / includes / admin / layouts / dashboard-v3 / dashboard-v3.php

dashboard-v3.php in King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder 51.1.44, at includes/admin/layouts/dashboard-v3/dashboard-v3.php

876 lines 38.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Dashboard V3 - Premium "Pro" UI with Apple-inspired design.
4 *
5 * Modern, premium redesign inspired by high-end product pages.
6 * Features glassmorphism, bento grids, iOS-style toggles, and Titanium aesthetic.
7 *
8 * @package King_Addons
9 */
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 // Handle AJAX requests for dashboard settings
16 if (wp_doing_ajax()) {
17 return;
18 }
19
20 // Load extensions list
21 require_once __DIR__ . '/extensions-list.php';
22
23 // Get dashboard UI settings (view mode is shared, theme is per-user)
24 $dashboard_settings = get_option('king_addons_dashboard_ui', [
25 'show_descriptions' => true,
26 ]);
27 $show_descriptions = !empty($dashboard_settings['show_descriptions']);
28
29 $theme_mode = get_user_meta(get_current_user_id(), 'king_addons_theme_mode', true);
30 $allowed_theme_modes = ['dark', 'light', 'auto'];
31 if (!in_array($theme_mode, $allowed_theme_modes, true)) {
32 $theme_mode = 'dark';
33 }
34
35 // Handle settings update
36 if (isset($_GET['settings-updated'])) {
37 add_settings_error('king_addons_messages', 'king_addons_message', esc_html__('Settings Saved', 'king-addons'), 'updated');
38 }
39 settings_errors('king_addons_messages');
40
41 $options = get_option('king_addons_options', []);
42 $modules_map = \King_Addons\ModulesMap::getModulesMapArray();
43 $widgets = $modules_map['widgets'] ?? [];
44 $features = $modules_map['features'] ?? [];
45
46 // Hide modules hard-disabled via constants (used to QA/rollout new widgets/features).
47 $ka_v3_is_hard_disabled = static function (string $prefix, string $id): bool {
48 $const = $prefix . strtoupper(str_replace('-', '_', $id));
49 return defined($const) && constant($const) === false;
50 };
51
52 if (!empty($widgets)) {
53 $widgets = array_filter(
54 $widgets,
55 static fn($widget, $widget_id) => !$ka_v3_is_hard_disabled('KING_ADDONS_WGT_', (string) $widget_id),
56 ARRAY_FILTER_USE_BOTH
57 );
58 }
59
60 if (!empty($features)) {
61 $features = array_filter(
62 $features,
63 static fn($feature, $feature_id) => !$ka_v3_is_hard_disabled('KING_ADDONS_FEAT_', (string) $feature_id),
64 ARRAY_FILTER_USE_BOTH
65 );
66 }
67
68 // Count enabled/disabled modules
69 $total_modules = count($widgets);
70 $enabled_count = 0;
71 foreach ($widgets as $widget_id => $widget) {
72 if (isset($options[$widget_id]) && $options[$widget_id] === 'enabled') {
73 $enabled_count++;
74 }
75 }
76 $disabled_count = $total_modules - $enabled_count;
77
78 // Features count (enabled by default)
79 $total_features = count($features);
80 $enabled_features = 0;
81 foreach ($features as $feature_id => $feature) {
82 $feature_enabled = !isset($options[$feature_id]) || $options[$feature_id] === 'enabled';
83 if ($feature_enabled) {
84 $enabled_features++;
85 }
86 }
87 $disabled_features = $total_features - $enabled_features;
88
89 // Get extensions list
90 $extensions = king_addons_get_extensions_list();
91
92 // Count enabled extensions (default is enabled)
93 $total_extensions = count($extensions);
94 $enabled_extensions = 0;
95 foreach ($extensions as $ext_id => $ext) {
96 $ext_enabled = !isset($options['ext_' . $ext_id]) || $options['ext_' . $ext_id] === 'enabled';
97 if ($ext_enabled) {
98 $enabled_extensions++;
99 }
100 }
101 $disabled_extensions = $total_extensions - $enabled_extensions;
102
103 // Group widgets by category
104 $categories = [
105 'content' => [
106 'title' => esc_html__('Content Elements', 'king-addons'),
107 'icon' => 'dashicons-text-page',
108 'widgets' => [],
109 ],
110 'media' => [
111 'title' => esc_html__('Media & Gallery', 'king-addons'),
112 'icon' => 'dashicons-format-gallery',
113 'widgets' => [],
114 ],
115 'woocommerce' => [
116 'title' => esc_html__('WooCommerce', 'king-addons'),
117 'icon' => 'dashicons-cart',
118 'widgets' => [],
119 ],
120 'navigation' => [
121 'title' => esc_html__('Navigation & Menus', 'king-addons'),
122 'icon' => 'dashicons-menu',
123 'widgets' => [],
124 ],
125 'creative' => [
126 'title' => esc_html__('Creative Effects', 'king-addons'),
127 'icon' => 'dashicons-art',
128 'widgets' => [],
129 ],
130 'forms' => [
131 'title' => esc_html__('Forms & Input', 'king-addons'),
132 'icon' => 'dashicons-feedback',
133 'widgets' => [],
134 ],
135 'theme-builder' => [
136 'title' => esc_html__('Theme Builder', 'king-addons'),
137 'icon' => 'dashicons-admin-appearance',
138 'widgets' => [],
139 ],
140 'other' => [
141 'title' => esc_html__('Other Widgets', 'king-addons'),
142 'icon' => 'dashicons-screenoptions',
143 'widgets' => [],
144 ],
145 ];
146
147 // Categorize widgets strictly by explicit 'category' field
148 foreach ($widgets as $widget_id => $widget) {
149 $category_id = isset($widget['category']) ? (string) $widget['category'] : '';
150 if ($category_id === '' || !isset($categories[$category_id])) {
151 $category_id = 'other';
152 }
153 $categories[$category_id]['widgets'][$widget_id] = $widget;
154 }
155
156 // Remove empty categories
157 $categories = array_filter($categories, function($cat) {
158 return !empty($cat['widgets']);
159 });
160
161 $is_pro = function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code();
162
163 // Enqueue the CSS file
164 $shared_css_url = KING_ADDONS_URL . 'includes/admin/layouts/shared/admin-v3-styles.css';
165 $shared_css_path = KING_ADDONS_PATH . 'includes/admin/layouts/shared/admin-v3-styles.css';
166 $shared_css_version = file_exists($shared_css_path) ? filemtime($shared_css_path) : KING_ADDONS_VERSION;
167
168 $css_url = KING_ADDONS_URL . 'includes/admin/layouts/dashboard-v3/dashboard-v3.css';
169 $css_path = KING_ADDONS_PATH . 'includes/admin/layouts/dashboard-v3/dashboard-v3.css';
170 $css_version = file_exists($css_path) ? filemtime($css_path) : KING_ADDONS_VERSION;
171 ?>
172
173 <link rel="stylesheet" href="<?php echo esc_url($shared_css_url); ?>?v=<?php echo esc_attr($shared_css_version); ?>">
174 <link rel="stylesheet" href="<?php echo esc_url($css_url); ?>?v=<?php echo esc_attr($css_version); ?>">
175
176 <script>
177 (function() {
178 const mode = '<?php echo esc_js($theme_mode); ?>';
179 const mql = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
180
181 function applyThemeClasses(isDark) {
182 document.documentElement.classList.toggle('ka-v3-dark', isDark);
183 if (document.body) {
184 document.body.classList.toggle('ka-v3-dark', isDark);
185 }
186 }
187
188 function ensureBodyReady(fn) {
189 if (document.body) {
190 fn();
191 return;
192 }
193 document.addEventListener('DOMContentLoaded', fn, { once: true });
194 }
195
196 if (mode === 'auto') {
197 const isDark = !!(mql && mql.matches);
198 applyThemeClasses(isDark);
199 ensureBodyReady(function() { applyThemeClasses(isDark); });
200 } else {
201 const isDark = mode === 'dark';
202 applyThemeClasses(isDark);
203 ensureBodyReady(function() { applyThemeClasses(isDark); });
204 }
205 })();
206 </script>
207
208 <div class="ka-v3-wrap">
209 <!-- Header -->
210 <div class="ka-v3-header">
211 <div>
212 <h1 class="ka-v3-title"><?php esc_html_e('King Addons', 'king-addons'); ?></h1>
213 <p class="ka-v3-subtitle"><?php esc_html_e('The ultimate toolkit for Elementor. Build faster, design better.', 'king-addons'); ?></p>
214 </div>
215 <div class="ka-v3-header-actions">
216 <div class="ka-v3-segmented" id="ka-v3-theme-segment" role="radiogroup" aria-label="<?php echo esc_attr(esc_html__('Theme', 'king-addons')); ?>" data-active="<?php echo esc_attr($theme_mode); ?>">
217 <span class="ka-v3-segmented-indicator" aria-hidden="true"></span>
218 <button type="button" class="ka-v3-segmented-btn" data-theme="light" aria-pressed="<?php echo $theme_mode === 'light' ? 'true' : 'false'; ?>">
219 <span class="ka-v3-segmented-icon" aria-hidden="true">☀︎</span>
220 <?php esc_html_e('Light', 'king-addons'); ?>
221 </button>
222 <button type="button" class="ka-v3-segmented-btn" data-theme="dark" aria-pressed="<?php echo $theme_mode === 'dark' ? 'true' : 'false'; ?>">
223 <span class="ka-v3-segmented-icon" aria-hidden="true">☾</span>
224 <?php esc_html_e('Dark', 'king-addons'); ?>
225 </button>
226 <button type="button" class="ka-v3-segmented-btn" data-theme="auto" aria-pressed="<?php echo $theme_mode === 'auto' ? 'true' : 'false'; ?>">
227 <?php esc_html_e('Auto', 'king-addons'); ?>
228 </button>
229 </div>
230 <a href="https://www.youtube.com/@kingaddons/videos" target="_blank" class="ka-v3-btn ka-v3-btn-secondary">
231 <span class="dashicons dashicons-book"></span>
232 <?php esc_html_e('Guides', 'king-addons'); ?>
233 </a>
234 <?php if (!$is_pro): ?>
235 <a href="https://kingaddons.com/pricing/?utm_source=king-addons-dashboard" target="_blank" class="ka-v3-btn ka-v3-btn-primary">
236 <span class="dashicons dashicons-star-filled"></span>
237 <?php esc_html_e('Upgrade to Pro', 'king-addons'); ?>
238 </a>
239 <?php endif; ?>
240 </div>
241 </div>
242
243 <!-- Bento Grid Stats -->
244 <div class="ka-v3-bento">
245 <div class="ka-v3-bento-card large">
246 <div class="ka-v3-bento-bg" style="background: #0071e3; width: 250px; height: 250px; top: -80px; right: -60px;"></div>
247 <span class="ka-v3-bento-label"><?php esc_html_e('Widget Library', 'king-addons'); ?></span>
248 <div>
249 <div class="ka-v3-bento-value"><?php echo esc_html($total_modules); ?></div>
250 <div class="ka-v3-bento-desc"><?php esc_html_e('Premium Widgets Available', 'king-addons'); ?></div>
251 </div>
252 </div>
253 <div class="ka-v3-bento-card">
254 <div class="ka-v3-bento-bg" style="background: #34c759; width: 150px; height: 150px; bottom: -40px; left: -40px;"></div>
255 <span class="ka-v3-bento-label"><?php esc_html_e('Enabled', 'king-addons'); ?></span>
256 <div>
257 <div class="ka-v3-bento-value"><?php echo esc_html($enabled_count); ?></div>
258 <div class="ka-v3-bento-desc"><?php esc_html_e('Widgets Enabled', 'king-addons'); ?></div>
259 </div>
260 </div>
261 <div class="ka-v3-bento-card">
262 <div class="ka-v3-bento-bg" style="background: #af52de; width: 150px; height: 150px; top: 0; right: -20px;"></div>
263 <span class="ka-v3-bento-label"><?php esc_html_e('Disabled', 'king-addons'); ?></span>
264 <div>
265 <div class="ka-v3-bento-value"><?php echo esc_html($disabled_count); ?></div>
266 <div class="ka-v3-bento-desc"><?php esc_html_e('Widgets Disabled', 'king-addons'); ?></div>
267 </div>
268 </div>
269 </div>
270
271 <!-- Navigation -->
272 <div class="ka-v3-nav">
273 <button type="button" class="ka-v3-nav-item active" data-tab="widgets">
274 <?php esc_html_e('Widgets', 'king-addons'); ?>
275 <span class="ka-v3-nav-badge"><?php echo esc_html($total_modules); ?></span>
276 </button>
277 <button type="button" class="ka-v3-nav-item" data-tab="features">
278 <?php esc_html_e('Features', 'king-addons'); ?>
279 <span class="ka-v3-nav-badge"><?php echo esc_html($total_features); ?></span>
280 </button>
281 <button type="button" class="ka-v3-nav-item" data-tab="extensions">
282 <?php esc_html_e('Extensions', 'king-addons'); ?>
283 <span class="ka-v3-nav-badge"><?php echo esc_html($total_extensions); ?></span>
284 </button>
285 </div>
286
287 <!-- Single Form for all tabs -->
288 <form action="options.php" method="post" id="ka-v3-dashboard-form">
289 <?php settings_fields('king_addons'); ?>
290
291 <!-- Widgets Tab Content -->
292 <div class="ka-v3-tab-content active" id="ka-v3-tab-widgets">
293
294 <!-- Quick Actions -->
295 <div class="ka-v3-quick-actions">
296 <?php if (defined('KING_ADDONS_EXT_HEADER_FOOTER_BUILDER') && KING_ADDONS_EXT_HEADER_FOOTER_BUILDER): ?>
297 <a href="<?php echo esc_url(admin_url('edit.php?post_type=king-addons-el-hf')); ?>" class="ka-v3-btn ka-v3-btn-secondary">
298 <span class="dashicons dashicons-welcome-widgets-menus"></span>
299 <?php esc_html_e('Header & Footer', 'king-addons'); ?>
300 </a>
301 <?php endif; ?>
302 <?php if (defined('KING_ADDONS_EXT_POPUP_BUILDER') && KING_ADDONS_EXT_POPUP_BUILDER): ?>
303 <a href="<?php echo esc_url(admin_url('admin.php?page=king-addons-popup-builder')); ?>" class="ka-v3-btn ka-v3-btn-secondary">
304 <span class="dashicons dashicons-external"></span>
305 <?php esc_html_e('Popup Builder', 'king-addons'); ?>
306 </a>
307 <?php endif; ?>
308 <?php if (defined('KING_ADDONS_EXT_TEMPLATES_CATALOG') && KING_ADDONS_EXT_TEMPLATES_CATALOG): ?>
309 <a href="<?php echo esc_url(admin_url('admin.php?page=king-addons-templates')); ?>" class="ka-v3-btn ka-v3-btn-secondary">
310 <span class="dashicons dashicons-layout"></span>
311 <?php esc_html_e('Templates', 'king-addons'); ?>
312 </a>
313 <?php endif; ?>
314 </div>
315
316 <!-- Controls Bar -->
317 <div class="ka-v3-controls">
318 <div class="ka-v3-search">
319 <span class="dashicons dashicons-search"></span>
320 <input type="text" id="ka-v3-search" placeholder="<?php esc_attr_e('Search widgets...', 'king-addons'); ?>">
321 </div>
322 <div class="ka-v3-filters">
323 <button type="button" class="ka-v3-filter-btn active" data-filter="all"><?php esc_html_e('All', 'king-addons'); ?></button>
324 <button type="button" class="ka-v3-filter-btn" data-filter="enabled"><?php esc_html_e('Enabled', 'king-addons'); ?></button>
325 <button type="button" class="ka-v3-filter-btn" data-filter="disabled"><?php esc_html_e('Disabled', 'king-addons'); ?></button>
326 </div>
327 <div class="ka-v3-collapse-all">
328 <button type="button" class="ka-v3-filter-btn" id="ka-v3-collapse-toggle" data-state="expanded">
329 <span class="dashicons dashicons-arrow-up-alt2" aria-hidden="true"></span>
330 <span class="ka-v3-collapse-text"><?php esc_html_e('Collapse categories', 'king-addons'); ?></span>
331 </button>
332 </div>
333 </div>
334
335 <!-- Module Categories -->
336 <?php foreach ($categories as $cat_id => $category):
337 $category_enabled_count = 0;
338 foreach ($category['widgets'] as $widget_id => $widget) {
339 if (isset($options[$widget_id]) && $options[$widget_id] === 'enabled') {
340 $category_enabled_count++;
341 }
342 }
343 $category_total = count($category['widgets']);
344 $category_all_enabled = $category_enabled_count === $category_total;
345 ?>
346 <div class="ka-v3-category" data-category="<?php echo esc_attr($cat_id); ?>">
347 <div class="ka-v3-category-header">
348 <div class="ka-v3-category-title">
349 <span class="dashicons <?php echo esc_attr($category['icon']); ?>"></span>
350 <h3><?php echo esc_html($category['title']); ?></h3>
351 <span class="ka-v3-category-count"><?php echo esc_html($category_total); ?></span>
352 </div>
353 <div class="ka-v3-category-toggle">
354 <button type="button" class="ka-v3-category-collapse" aria-expanded="true" aria-label="<?php echo esc_attr(esc_html__('Collapse category', 'king-addons')); ?>">
355 <span class="dashicons dashicons-arrow-up-alt2" aria-hidden="true"></span>
356 </button>
357 <label class="ka-v3-toggle">
358 <input type="checkbox" class="ka-v3-category-toggle-input" data-category="<?php echo esc_attr($cat_id); ?>" <?php checked($category_all_enabled); ?>>
359 <span class="ka-v3-toggle-slider"></span>
360 </label>
361 </div>
362 </div>
363 <div class="ka-v3-category-body">
364 <div class="ka-v3-grid">
365 <?php foreach ($category['widgets'] as $widget_id => $widget):
366 $is_enabled = isset($options[$widget_id]) && $options[$widget_id] === 'enabled';
367 ?>
368 <div class="ka-v3-card <?php echo $is_enabled ? '' : 'disabled'; ?>" data-widget="<?php echo esc_attr($widget_id); ?>" data-enabled="<?php echo $is_enabled ? '1' : '0'; ?>">
369 <div class="ka-v3-card-header">
370 <div class="ka-v3-card-icon">
371 <?php
372 $icon_url = KING_ADDONS_URL . 'includes/admin/img/' . $widget_id . '.svg';
373 $default_icon = KING_ADDONS_URL . 'includes/admin/img/default-widget.svg';
374 ?>
375 <img src="<?php echo esc_url($icon_url); ?>?v=<?php echo esc_attr(KING_ADDONS_VERSION); ?>"
376 alt="<?php echo esc_attr($widget['title']); ?>"
377 onerror="this.onerror=null; this.src='<?php echo esc_url($default_icon); ?>';">
378 </div>
379 <label class="ka-v3-toggle">
380 <input type="hidden" name="king_addons_options[<?php echo esc_attr($widget_id); ?>]" value="disabled">
381 <input type="checkbox" name="king_addons_options[<?php echo esc_attr($widget_id); ?>]" value="enabled" <?php checked($is_enabled); ?>>
382 <span class="ka-v3-toggle-slider"></span>
383 </label>
384 </div>
385 <h4 class="ka-v3-card-title"><?php echo esc_html($widget['title']); ?></h4>
386 <?php if (!empty($widget['description'])): ?>
387 <p class="ka-v3-card-desc"><?php echo esc_html($widget['description']); ?></p>
388 <?php endif; ?>
389 <?php if (!empty($widget['demo-link'])): ?>
390 <div class="ka-v3-card-footer">
391 <a href="<?php echo esc_url($widget['demo-link']); ?>?utm_source=ka-dashboard-v3" target="_blank" class="ka-v3-card-link">
392 <?php esc_html_e('View Demo', 'king-addons'); ?>
393 <span class="dashicons dashicons-external"></span>
394 </a>
395 </div>
396 <?php endif; ?>
397 </div>
398 <?php endforeach; ?>
399 </div>
400 </div>
401 </div>
402 <?php endforeach; ?>
403 </div>
404
405 <!-- Features Tab Content -->
406 <div class="ka-v3-tab-content" id="ka-v3-tab-features">
407 <div class="ka-v3-grid">
408 <?php foreach ($features as $feature_id => $feature):
409 $feature_enabled = !isset($options[$feature_id]) || $options[$feature_id] === 'enabled';
410 ?>
411 <div class="ka-v3-card <?php echo $feature_enabled ? '' : 'disabled'; ?>" data-feature="<?php echo esc_attr($feature_id); ?>" data-enabled="<?php echo $feature_enabled ? '1' : '0'; ?>">
412 <div class="ka-v3-card-header">
413 <div class="ka-v3-card-icon">
414 <span class="dashicons dashicons-admin-settings"></span>
415 </div>
416 <label class="ka-v3-toggle">
417 <input type="hidden" name="king_addons_options[<?php echo esc_attr($feature_id); ?>]" value="disabled">
418 <input type="checkbox" name="king_addons_options[<?php echo esc_attr($feature_id); ?>]" value="enabled" <?php checked($feature_enabled); ?>>
419 <span class="ka-v3-toggle-slider"></span>
420 </label>
421 </div>
422 <h4 class="ka-v3-card-title"><?php echo esc_html($feature['title'] ?? $feature_id); ?></h4>
423 <?php if (!empty($feature['description'])): ?>
424 <p class="ka-v3-card-desc"><?php echo esc_html($feature['description']); ?></p>
425 <?php endif; ?>
426 <?php if (!empty($feature['demo-link'])): ?>
427 <div class="ka-v3-card-footer">
428 <a href="<?php echo esc_url($feature['demo-link']); ?>" target="_blank" class="ka-v3-card-link">
429 <?php esc_html_e('Learn More', 'king-addons'); ?>
430 <span class="dashicons dashicons-external"></span>
431 </a>
432 </div>
433 <?php endif; ?>
434 </div>
435 <?php endforeach; ?>
436 </div>
437 </div>
438
439 <!-- Extensions Tab Content -->
440 <div class="ka-v3-tab-content" id="ka-v3-tab-extensions">
441 <div class="ka-v3-grid">
442 <?php foreach ($extensions as $ext_id => $ext):
443 $ext_enabled = !isset($options['ext_' . $ext_id]) || $options['ext_' . $ext_id] === 'enabled';
444 ?>
445 <div class="ka-v3-card <?php echo $ext_enabled ? '' : 'disabled'; ?>" data-ext="<?php echo esc_attr($ext_id); ?>" data-enabled="<?php echo $ext_enabled ? '1' : '0'; ?>">
446 <div class="ka-v3-card-header">
447 <div class="ka-v3-card-icon">
448 <span class="dashicons <?php echo esc_attr($ext['icon']); ?>"></span>
449 </div>
450 <label class="ka-v3-toggle">
451 <input type="hidden" name="king_addons_options[ext_<?php echo esc_attr($ext_id); ?>]" value="disabled">
452 <input type="checkbox" name="king_addons_options[ext_<?php echo esc_attr($ext_id); ?>]" value="enabled" <?php checked($ext_enabled); ?>>
453 <span class="ka-v3-toggle-slider"></span>
454 </label>
455 </div>
456 <h4 class="ka-v3-card-title"><?php echo esc_html($ext['title']); ?></h4>
457 <p class="ka-v3-card-desc"><?php echo esc_html($ext['description']); ?></p>
458 <div class="ka-v3-card-footer">
459 <a href="<?php echo esc_url($ext['link']); ?>" class="ka-v3-card-link <?php echo !$ext_enabled ? 'ka-v3-link-disabled' : ''; ?>">
460 <?php esc_html_e('Open Settings', 'king-addons'); ?>
461 <span class="dashicons dashicons-arrow-right-alt"></span>
462 </a>
463 </div>
464 </div>
465 <?php endforeach; ?>
466 </div>
467 </div>
468
469 <!-- Sticky Footer -->
470 <div class="ka-v3-footer">
471 <button type="button" class="ka-v3-btn ka-v3-btn-secondary" id="ka-v3-enable-all"><?php esc_html_e('Enable All', 'king-addons'); ?></button>
472 <button type="button" class="ka-v3-btn ka-v3-btn-secondary" id="ka-v3-disable-all"><?php esc_html_e('Disable All', 'king-addons'); ?></button>
473 <button type="submit" class="ka-v3-btn ka-v3-btn-primary"><?php esc_html_e('Save Changes', 'king-addons'); ?></button>
474 </div>
475 </form>
476 </div>
477
478 <script>
479 (function($) {
480 'use strict';
481
482 $(document).ready(function() {
483 let currentFilter = 'all';
484 let searchQuery = '';
485 let currentTab = 'widgets';
486
487 // Bento stats data per tab (total / enabled / disabled)
488 const kaBentoStats = {
489 widgets: [
490 {
491 label: '<?php echo esc_js(esc_html__('Widget Library', 'king-addons')); ?>',
492 value: <?php echo (int) $total_modules; ?>,
493 desc: '<?php echo esc_js(esc_html__('Premium Widgets Available', 'king-addons')); ?>'
494 },
495 {
496 label: '<?php echo esc_js(esc_html__('Enabled', 'king-addons')); ?>',
497 value: <?php echo (int) $enabled_count; ?>,
498 desc: '<?php echo esc_js(esc_html__('Widgets Enabled', 'king-addons')); ?>'
499 },
500 {
501 label: '<?php echo esc_js(esc_html__('Disabled', 'king-addons')); ?>',
502 value: <?php echo (int) $disabled_count; ?>,
503 desc: '<?php echo esc_js(esc_html__('Widgets Disabled', 'king-addons')); ?>'
504 }
505 ],
506 features: [
507 {
508 label: '<?php echo esc_js(esc_html__('Features', 'king-addons')); ?>',
509 value: <?php echo (int) $total_features; ?>,
510 desc: '<?php echo esc_js(esc_html__('Total Features', 'king-addons')); ?>'
511 },
512 {
513 label: '<?php echo esc_js(esc_html__('Enabled', 'king-addons')); ?>',
514 value: <?php echo (int) $enabled_features; ?>,
515 desc: '<?php echo esc_js(esc_html__('Enabled', 'king-addons')); ?>'
516 },
517 {
518 label: '<?php echo esc_js(esc_html__('Disabled', 'king-addons')); ?>',
519 value: <?php echo (int) $disabled_features; ?>,
520 desc: '<?php echo esc_js(esc_html__('Disabled', 'king-addons')); ?>'
521 }
522 ],
523 extensions: [
524 {
525 label: '<?php echo esc_js(esc_html__('Extensions', 'king-addons')); ?>',
526 value: <?php echo (int) $total_extensions; ?>,
527 desc: '<?php echo esc_js(esc_html__('Total Extensions', 'king-addons')); ?>'
528 },
529 {
530 label: '<?php echo esc_js(esc_html__('Enabled', 'king-addons')); ?>',
531 value: <?php echo (int) $enabled_extensions; ?>,
532 desc: '<?php echo esc_js(esc_html__('Enabled', 'king-addons')); ?>'
533 },
534 {
535 label: '<?php echo esc_js(esc_html__('Disabled', 'king-addons')); ?>',
536 value: <?php echo (int) $disabled_extensions; ?>,
537 desc: '<?php echo esc_js(esc_html__('Disabled', 'king-addons')); ?>'
538 }
539 ]
540 };
541
542 function easeInOutQuad(t) {
543 return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
544 }
545
546 function animateTextSwap($el, nextText) {
547 const currentText = $el.text();
548 if (currentText === nextText) {
549 return;
550 }
551
552 const el = $el.get(0);
553 if (!el || !el.animate) {
554 $el.text(nextText);
555 return;
556 }
557
558 const out = el.animate(
559 [
560 { opacity: 1, transform: 'translateY(0px)' },
561 { opacity: 0, transform: 'translateY(-4px)' }
562 ],
563 { duration: 140, easing: 'ease-out', fill: 'forwards' }
564 );
565
566 out.onfinish = function() {
567 $el.text(nextText);
568 el.animate(
569 [
570 { opacity: 0, transform: 'translateY(4px)' },
571 { opacity: 1, transform: 'translateY(0px)' }
572 ],
573 { duration: 180, easing: 'ease-out', fill: 'both' }
574 );
575 };
576 }
577
578 function updateBento(tabKey) {
579 const data = kaBentoStats[tabKey];
580 if (!data) {
581 return;
582 }
583
584 const $cards = $('.ka-v3-bento .ka-v3-bento-card');
585 if ($cards.length < 3) {
586 return;
587 }
588
589 $cards.each(function(index) {
590 const cardData = data[index];
591 if (!cardData) {
592 return;
593 }
594
595 const $card = $(this);
596 const $label = $card.find('.ka-v3-bento-label').first();
597 const $value = $card.find('.ka-v3-bento-value').first();
598 const $desc = $card.find('.ka-v3-bento-desc').first();
599
600 animateTextSwap($label, cardData.label);
601 animateTextSwap($value, String(cardData.value));
602 animateTextSwap($desc, cardData.desc);
603 });
604 }
605
606 const ajaxUrl = '<?php echo esc_url(admin_url('admin-ajax.php')); ?>';
607 const nonce = '<?php echo esc_js(wp_create_nonce('king_addons_dashboard_ui')); ?>';
608
609 // Save UI setting via AJAX
610 function saveUISetting(key, value) {
611 $.post(ajaxUrl, {
612 action: 'king_addons_save_dashboard_ui',
613 nonce: nonce,
614 key: key,
615 value: value
616 });
617 }
618
619 // Theme segmented control
620 const $themeSegment = $('#ka-v3-theme-segment');
621 const $themeSegmentButtons = $themeSegment.find('.ka-v3-segmented-btn');
622
623 const themeMql = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
624 let themeMode = ($themeSegment.attr('data-active') || 'dark').toString();
625 let themeMqlHandler = null;
626
627 function updateSegment(mode) {
628 $themeSegment.attr('data-active', mode);
629 $themeSegmentButtons.each(function() {
630 const theme = $(this).data('theme');
631 $(this).attr('aria-pressed', theme === mode ? 'true' : 'false');
632 });
633 }
634
635 function applyThemeClass(isDark) {
636 $('body').toggleClass('ka-v3-dark', isDark);
637 document.documentElement.classList.toggle('ka-v3-dark', isDark);
638 }
639
640 function setThemeMode(mode, save) {
641 themeMode = mode;
642 updateSegment(mode);
643
644 if (themeMqlHandler && themeMql) {
645 if (themeMql.removeEventListener) {
646 themeMql.removeEventListener('change', themeMqlHandler);
647 } else if (themeMql.removeListener) {
648 themeMql.removeListener(themeMqlHandler);
649 }
650 themeMqlHandler = null;
651 }
652
653 if (mode === 'auto') {
654 applyThemeClass(!!(themeMql && themeMql.matches));
655 themeMqlHandler = function(e) {
656 if (themeMode !== 'auto') {
657 return;
658 }
659 applyThemeClass(!!e.matches);
660 };
661 if (themeMql) {
662 if (themeMql.addEventListener) {
663 themeMql.addEventListener('change', themeMqlHandler);
664 } else if (themeMql.addListener) {
665 themeMql.addListener(themeMqlHandler);
666 }
667 }
668 } else {
669 applyThemeClass(mode === 'dark');
670 }
671
672 if (save) {
673 saveUISetting('theme_mode', mode);
674 }
675 }
676
677 $themeSegment.on('click', '.ka-v3-segmented-btn', function(e) {
678 e.preventDefault();
679 const mode = ($(this).data('theme') || 'dark').toString();
680 setThemeMode(mode, true);
681 });
682
683 // Ensure mode applies for Auto (listener + system state)
684 setThemeMode(themeMode, false);
685
686 // Tab Navigation
687 $('.ka-v3-nav-item').on('click', function() {
688 const tab = $(this).data('tab');
689 currentTab = tab;
690
691 $('.ka-v3-nav-item').removeClass('active');
692 $(this).addClass('active');
693
694 $('.ka-v3-tab-content').removeClass('active');
695 $('#ka-v3-tab-' + tab).addClass('active');
696
697 // Update top bento stats for the active tab
698 updateBento(tab);
699
700 // Scroll dashboard to the top on tab switch
701 const $wrap = $('.ka-v3-wrap');
702 const targetTop = $wrap.length ? Math.max(0, Math.round($wrap.offset().top) - 20) : 0;
703 try {
704 window.scrollTo({ top: targetTop, behavior: 'smooth' });
705 } catch (e) {
706 window.scrollTo(0, targetTop);
707 }
708 });
709
710 // Initialize bento for the default tab
711 updateBento(currentTab);
712
713 // Apply filters (search + filter)
714 function applyFilters() {
715 const $cards = $('#ka-v3-tab-widgets .ka-v3-card');
716
717 $cards.each(function() {
718 const $card = $(this);
719 const title = $card.find('.ka-v3-card-title').text().toLowerCase();
720 const widgetId = ($card.data('widget') || '').toString().toLowerCase();
721 const isEnabled = $card.data('enabled') == 1;
722
723 let matchesSearch = !searchQuery || title.indexOf(searchQuery) !== -1 || widgetId.indexOf(searchQuery) !== -1;
724 let matchesFilter = currentFilter === 'all' ||
725 (currentFilter === 'enabled' && isEnabled) ||
726 (currentFilter === 'disabled' && !isEnabled);
727
728 if (matchesSearch && matchesFilter) {
729 $card.removeClass('ka-v3-hidden');
730 } else {
731 $card.addClass('ka-v3-hidden');
732 }
733 });
734
735 // Hide empty categories
736 $('.ka-v3-category').each(function() {
737 const $category = $(this);
738 const hasVisible = $category.find('.ka-v3-card:not(.ka-v3-hidden)').length > 0;
739 $category.toggleClass('ka-v3-hidden', !hasVisible);
740 });
741 }
742
743 // Search
744 $('#ka-v3-search').on('input', function() {
745 searchQuery = $(this).val().toLowerCase().trim();
746 applyFilters();
747 });
748
749 // Filter buttons (widgets tab)
750 $('.ka-v3-filters .ka-v3-filter-btn').on('click', function() {
751 $('.ka-v3-filters .ka-v3-filter-btn').removeClass('active');
752 $(this).addClass('active');
753 currentFilter = $(this).data('filter');
754 applyFilters();
755 });
756
757 // Collapse / Expand categories
758 const $collapseAllBtn = $('#ka-v3-collapse-toggle');
759
760 function setCategoryCollapsed($category, collapsed) {
761 $category.toggleClass('ka-v3-collapsed', !!collapsed);
762 $category.find('.ka-v3-category-collapse').attr('aria-expanded', collapsed ? 'false' : 'true');
763 }
764
765 function updateCollapseAllButton() {
766 const $cats = $('#ka-v3-tab-widgets .ka-v3-category');
767 if (!$cats.length || !$collapseAllBtn.length) {
768 return;
769 }
770
771 const allCollapsed = $cats.filter(':not(.ka-v3-collapsed)').length === 0;
772 $collapseAllBtn.attr('data-state', allCollapsed ? 'collapsed' : 'expanded');
773 const nextText = allCollapsed ? '<?php echo esc_js(esc_html__('Expand categories', 'king-addons')); ?>' : '<?php echo esc_js(esc_html__('Collapse categories', 'king-addons')); ?>';
774 $collapseAllBtn.find('.ka-v3-collapse-text').text(nextText);
775 }
776
777 $(document).on('click', '.ka-v3-category-collapse', function(e) {
778 e.preventDefault();
779 e.stopPropagation();
780 const $category = $(this).closest('.ka-v3-category');
781 const isCollapsed = $category.hasClass('ka-v3-collapsed');
782 setCategoryCollapsed($category, !isCollapsed);
783 updateCollapseAllButton();
784 });
785
786 $collapseAllBtn.on('click', function(e) {
787 e.preventDefault();
788
789 const $cats = $('#ka-v3-tab-widgets .ka-v3-category');
790 if (!$cats.length) {
791 return;
792 }
793
794 const anyExpanded = $cats.filter(':not(.ka-v3-collapsed)').length > 0;
795 $cats.each(function() {
796 setCategoryCollapsed($(this), anyExpanded);
797 });
798 updateCollapseAllButton();
799 });
800
801 // Initialize collapse button state
802 updateCollapseAllButton();
803
804 // Center footer relative to dashboard container (WP admin menu offsets content)
805 function updateFooterCenter() {
806 const $footer = $('.ka-v3-footer');
807 const $wrap = $('.ka-v3-wrap');
808 if (!$footer.length || !$wrap.length) {
809 return;
810 }
811 const wrapRect = $wrap.get(0).getBoundingClientRect();
812 const centerX = Math.round(wrapRect.left + (wrapRect.width / 2));
813 $footer.get(0).style.left = centerX + 'px';
814 $footer.get(0).style.transform = 'translateX(-50%)';
815 }
816
817 updateFooterCenter();
818 $(window).on('resize', function() {
819 updateFooterCenter();
820 });
821
822 // Category toggle
823 $('.ka-v3-category-toggle-input').on('change', function() {
824 const isEnabled = $(this).is(':checked');
825 const $category = $(this).closest('.ka-v3-category');
826
827 $category.find('.ka-v3-card').each(function() {
828 const $card = $(this);
829 const $checkbox = $card.find('input[type="checkbox"]');
830
831 $checkbox.prop('checked', isEnabled);
832
833 if (isEnabled) {
834 $card.removeClass('disabled').data('enabled', 1);
835 } else {
836 $card.addClass('disabled').data('enabled', 0);
837 }
838 });
839 });
840
841 // Update category toggle state when individual widgets change
842 $(document).on('change', '.ka-v3-card input[type="checkbox"]', function() {
843 const $card = $(this).closest('.ka-v3-card');
844 const $category = $card.closest('.ka-v3-category');
845
846 if ($(this).is(':checked')) {
847 $card.removeClass('disabled').data('enabled', 1);
848 } else {
849 $card.addClass('disabled').data('enabled', 0);
850 }
851
852 if ($category.length) {
853 const total = $category.find('.ka-v3-card').length;
854 const enabled = $category.find('.ka-v3-card input[type="checkbox"]:checked').length;
855 $category.find('.ka-v3-category-toggle-input').prop('checked', enabled === total);
856 }
857 });
858
859 // Enable/Disable All
860 $('#ka-v3-enable-all').on('click', function() {
861 const $activeTab = $('.ka-v3-tab-content.active');
862 $activeTab.find('input[type="checkbox"]').prop('checked', true);
863 $activeTab.find('.ka-v3-card').removeClass('disabled').data('enabled', 1);
864 $activeTab.find('.ka-v3-category-toggle-input').prop('checked', true);
865 });
866
867 $('#ka-v3-disable-all').on('click', function() {
868 const $activeTab = $('.ka-v3-tab-content.active');
869 $activeTab.find('input[type="checkbox"]').prop('checked', false);
870 $activeTab.find('.ka-v3-card').addClass('disabled').data('enabled', 0);
871 $activeTab.find('.ka-v3-category-toggle-input').prop('checked', false);
872 });
873 });
874 })(jQuery);
875 </script>
876