| @@ -1,5 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 3 | + exit; | |
| 4 | +} | |
| 2 | 5 | $current_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : 'easy-invoice'; |
| 3 | 6 | |
| 4 | 7 | // Function to check if current page is a subpage of a main menu |
| 5 | 8 | function is_subpage_of($current_page, $main_page) { |
| @@ -13,9 +16,9 @@ | ||
| 13 | 16 | function get_menu_class($current_page, $menu_page, $is_active = false) { |
| 14 | 17 | if ($is_active) { |
| 15 | 18 | return 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600'; |
| 16 | 19 | } |
| 17 | - return 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; | |
| 20 | + return 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; | |
| 18 | 21 | } |
| 19 | 22 | |
| 20 | 23 | // Function to get the active icon class |
| 21 | 24 | function get_icon_class($current_page, $menu_page, $is_active = false) { |
| @@ -21,9 +24,9 @@ | ||
| 21 | 24 | function get_icon_class($current_page, $menu_page, $is_active = false) { |
| 22 | 25 | if ($is_active) { |
| 23 | 26 | return 'text-indigo-600'; |
| 24 | 27 | } |
| 25 | - return 'text-gray-400 group-hover:text-gray-500'; | |
| 28 | + return 'text-gray-400 group-hover:text-indigo-500'; | |
| 26 | 29 | } |
| 27 | 30 | |
| 28 | 31 | // Determine which menu should be active |
| 29 | 32 | $is_dashboard_active = $current_page === 'easy-invoice'; |
| @@ -65,28 +68,63 @@ | ||
| 65 | 68 | 'easy-invoice-email-settings-payment-reminder', |
| 66 | 69 | 'easy-invoice-pro-settings', // Pro settings |
| 67 | 70 | 'easy-invoice-pro-translations' // Pro translations |
| 68 | 71 | ]); |
| 72 | +// The "Addons" sidebar entry is only active on the Addons grid itself. | |
| 73 | +// Per-addon settings pages (Time Tracking / Smart Reminders / White-Label / | |
| 74 | +// Team & Audit / Webhooks) are now top-level sidebar entries — each highlights | |
| 75 | +// itself; the parent Addons row should NOT also light up. | |
| 76 | +$is_addons_active = ($current_page === 'easy-invoice-addons'); | |
| 69 | 77 | ?> |
| 70 | 78 | |
| 71 | -<!-- Sidebar --> | |
| 72 | -<div class="fixed inset-y-0 left-0 w-64 bg-white shadow-lg border-r border-gray-200"> | |
| 73 | - <!-- Logo and Back Button --> | |
| 74 | - <div class="ei-app-sidebar-top flex flex-col items-center justify-center px-4 py-2 border-b border-gray-200 box-border"> | |
| 75 | - <div class="flex items-center space-x-2 mb-1"> | |
| 76 | - <div class="flex items-center justify-center w-8 h-8 bg-indigo-600 rounded"> | |
| 77 | - <!-- Invoice Logo SVG --> | |
| 78 | - <svg class="h-5 w-5 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 79 | - <path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 80 | - <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 81 | - <path d="M16 13H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 82 | - <path d="M16 17H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 83 | - <path d="M10 9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 84 | - </svg> | |
| 85 | - </div> | |
| 86 | - <span class="text-lg font-semibold text-gray-900"><?php esc_html_e('Easy Invoice', 'easy-invoice'); ?></span> | |
| 87 | - </div> | |
| 88 | - <a href="<?php echo admin_url(); ?>" target="_blank" class="inline-flex items-center text-xs text-gray-500 hover:text-gray-700 transition-colors duration-200"> | |
| 79 | +<?php | |
| 80 | +/* | |
| 81 | + * The sidebar is 256px wide and fixed. It used to carry no responsive classes at | |
| 82 | + * all, and the content wrapper below was an unconditional `pl-64` — so on a 390px | |
| 83 | + * phone the sidebar ate 256px and left ~134px for the actual page. Stat cards | |
| 84 | + * became unreadable slivers, tables collapsed to a column of checkboxes, and every | |
| 85 | + * screen overflowed horizontally. | |
| 86 | + * | |
| 87 | + * It is now an off-canvas drawer under `lg` (slid out by default, toggled by the | |
| 88 | + * button below) and pinned open from `lg` up, which is the behaviour it always had | |
| 89 | + * on desktop. The toggle script near the bottom of this file adds and removes | |
| 90 | + * `-translate-x-full` on the sidebar to slide it; `lg:translate-x-0` overrides that | |
| 91 | + * from 1024px up, so the drawer state is irrelevant on desktop. | |
| 92 | + */ | |
| 93 | +?> | |
| 94 | +<button type="button" id="ei-sidebar-toggle" | |
| 95 | + class="lg:hidden fixed top-3 left-3 z-[60] inline-flex items-center justify-center w-11 h-11 rounded-md bg-white border border-gray-300 shadow-sm text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" | |
| 96 | + aria-controls="ei-app-sidebar" aria-expanded="false"> | |
| 97 | + <span class="sr-only"><?php esc_html_e('Toggle Easy Invoice navigation', 'easy-invoice'); ?></span> | |
| 98 | + <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"> | |
| 99 | + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path> | |
| 100 | + </svg> | |
| 101 | +</button> | |
| 102 | + | |
| 103 | +<div id="ei-sidebar-backdrop" class="lg:hidden fixed inset-0 bg-gray-900 bg-opacity-50 z-40 hidden" aria-hidden="true"></div> | |
| 104 | + | |
| 105 | +<div id="ei-app-sidebar" class="fixed inset-y-0 left-0 w-64 bg-white shadow-lg border-r border-gray-200 ei-app-sidebar flex flex-col z-50 transform -translate-x-full transition-transform duration-200 ease-in-out lg:translate-x-0"> | |
| 106 | + | |
| 107 | + <div class="ei-app-sidebar-top flex flex-col items-center justify-center px-4 py-2 border-b border-gray-200 box-border flex-shrink-0"> | |
| 108 | + <?php | |
| 109 | + /** | |
| 110 | + * Default logo HTML. Addons (White-Label) can short-circuit this to | |
| 111 | + * inject a custom image/label without touching this template. | |
| 112 | + * | |
| 113 | + * Filter: easy_invoice_admin_logo_html | |
| 114 | + * Args: ($default_html) | |
| 115 | + */ | |
| 116 | + $default_logo_html = '<div class="flex items-center space-x-2 mb-1">' | |
| 117 | + . '<div class="flex items-center justify-center w-8 h-8 rounded ei-app-logo-mark">' | |
| 118 | + . easy_invoice_logo_mark_svg(32) | |
| 119 | + . '</div>' | |
| 120 | + . '<span class="text-lg font-semibold text-gray-900 ei-app-logo-label">' . esc_html__('Easy Invoice', 'easy-invoice') . '</span>' | |
| 121 | + . '</div>'; | |
| 122 | + // wp_kses_post() drops <svg>; the logo list keeps the mark intact. | |
| 123 | + echo easy_invoice_kses_logo(apply_filters('easy_invoice_admin_logo_html', $default_logo_html)); | |
| 124 | + ?> | |
| 125 | + <?php if (apply_filters('easy_invoice_admin_show_back_to_wp', true)): ?> | |
| 126 | + <a href="<?php echo esc_url(admin_url()); ?>" target="_blank" class="inline-flex items-center text-xs text-gray-500 hover:text-gray-700 transition-colors duration-200"> | |
| 89 | 127 | <svg class="w-3 h-3 mr-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 90 | 128 | <path d="M19 12H5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 91 | 129 | <path d="M12 19L5 12L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 92 | 130 | </svg> |
| @@ -91,12 +129,14 @@ | ||
| 91 | 129 | <path d="M12 19L5 12L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 92 | 130 | </svg> |
| 93 | 131 | <?php esc_html_e( 'Back to WordPress', 'easy-invoice' ); ?> |
| 94 | 132 | </a> |
| 133 | + <?php endif; ?> | |
| 95 | 134 | |
| 96 | - <!-- Version Information --> | |
| 135 | + | |
| 136 | + <?php if (apply_filters('easy_invoice_admin_show_version_badges', true)): ?> | |
| 97 | 137 | <div class="mt-1 flex flex-wrap items-center justify-center gap-1.5"> |
| 98 | - <!-- Free Version Badge --> | |
| 138 | + | |
| 99 | 139 | <span class="inline-flex items-center px-1.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-700 border border-gray-200"> |
| 100 | 140 | <svg class="w-2.5 h-2.5 mr-1 text-gray-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 101 | 141 | <path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 102 | 142 | <path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| @@ -105,26 +145,27 @@ | ||
| 105 | 145 | v<?php echo esc_html(EASY_INVOICE_VERSION); ?> |
| 106 | 146 | </span> |
| 107 | 147 | |
| 108 | 148 | <?php if (defined('EASY_INVOICE_PRO_VERSION') && function_exists('is_plugin_active') && is_plugin_active('easy-invoice-pro/easy-invoice-pro.php')): ?> |
| 109 | - <!-- Pro Version Badge --> | |
| 149 | + | |
| 110 | 150 | <span class="inline-flex items-center px-1.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-700 border border-green-200"> |
| 111 | 151 | <svg class="w-2.5 h-2.5 mr-1 text-green-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 112 | 152 | <path d="M9 12L11 14L15 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 113 | 153 | <path d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 114 | 154 | </svg> |
| 115 | - <?php echo esc_html( sprintf( __( 'Pro v%s', 'easy-invoice' ), EASY_INVOICE_PRO_VERSION ) ); ?> | |
| 155 | + <?php /* translators: %s: Pro plugin version. */ echo esc_html( sprintf( __( 'Pro v%s', 'easy-invoice' ), EASY_INVOICE_PRO_VERSION ) ); ?> | |
| 116 | 156 | </span> |
| 117 | 157 | <?php endif; ?> |
| 118 | 158 | </div> |
| 159 | + <?php endif; // easy_invoice_admin_show_version_badges ?> | |
| 119 | 160 | </div> |
| 120 | 161 | |
| 121 | - <!-- Navigation Links --> | |
| 122 | - <nav class="mt-6 px-3 space-y-2"> | |
| 123 | - <!-- Dashboard --> | |
| 124 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice'); ?>" | |
| 125 | - class="<?php echo $is_dashboard_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 126 | - <svg class="<?php echo $is_dashboard_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 162 | + | |
| 163 | + <nav class="ei-app-sidebar-nav flex-1 min-h-0 overflow-y-auto mt-6 px-3 pb-4 space-y-2"> | |
| 164 | + | |
| 165 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice')); ?>" | |
| 166 | + class="<?php echo esc_attr($is_dashboard_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 167 | + <svg class="<?php echo $is_dashboard_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 127 | 168 | <path d="M3 13H9V19H3V13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 128 | 169 | <path d="M9 13H15V19H9V13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 129 | 170 | <path d="M15 13H21V19H15V13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 130 | 171 | <path d="M3 5H9V11H3V5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| @@ -133,48 +174,58 @@ | ||
| 133 | 174 | </svg> |
| 134 | 175 | <?php esc_html_e( 'Dashboard', 'easy-invoice' ); ?> |
| 135 | 176 | </a> |
| 136 | 177 | |
| 137 | - <!-- Invoices --> | |
| 138 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-all'); ?>" | |
| 139 | - class="<?php echo $is_invoices_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 140 | - <svg class="<?php echo $is_invoices_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 178 | + | |
| 179 | + <?php | |
| 180 | +// A sidebar entry is drawn only when the current user can open the page it | |
| 181 | +// leads to: administrators can open everything; a team member with an EI role | |
| 182 | +// (Pro Team Roles) is mapped through the same filter the menu uses. | |
| 183 | +$ei_can_open = static function ($slug) { | |
| 184 | + return current_user_can((string) apply_filters('easy_invoice_menu_capability', 'manage_options', $slug)); | |
| 185 | +}; | |
| 186 | +?> | |
| 187 | +<a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-all')); ?>" | |
| 188 | + class="<?php echo esc_attr($is_invoices_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 189 | + <svg class="<?php echo $is_invoices_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 141 | 190 | <path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 142 | 191 | <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 143 | - <path d="M16 13H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 144 | - <path d="M16 17H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 145 | - <path d="M10 9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 192 | + <path d="M12 11V19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 193 | + <path d="M14.5 13H10.75a1.75 1.75 0 0 0 0 3.5h2.5a1.75 1.75 0 0 1 0 3.5H9.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 146 | 194 | </svg> |
| 147 | 195 | <?php esc_html_e( 'Invoices', 'easy-invoice' ); ?> |
| 148 | 196 | </a> |
| 149 | 197 | |
| 150 | - <!-- Quotes --> | |
| 151 | - <a href="<?php echo admin_url('admin.php?page=easy-quote-all'); ?>" | |
| 152 | - class="<?php echo $is_quotes_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 153 | - <svg class="<?php echo $is_quotes_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 198 | + | |
| 199 | + <?php if ($ei_can_open('easy-quote-all')) : ?> | |
| 200 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-quote-all')); ?>" | |
| 201 | + class="<?php echo esc_attr($is_quotes_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 202 | + <svg class="<?php echo $is_quotes_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 154 | 203 | <path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 155 | 204 | <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 156 | - <path d="M9 9H15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 157 | - <path d="M9 13H15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 158 | - <path d="M9 17H13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 205 | + <path d="M8.5 15.5L11 18L16 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 159 | 206 | </svg> |
| 160 | 207 | <?php esc_html_e( 'Quotes', 'easy-invoice' ); ?> |
| 161 | 208 | </a> |
| 209 | + <?php endif; ?> | |
| 162 | 210 | |
| 163 | - <!-- Payments --> | |
| 164 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-payments'); ?>" | |
| 165 | - class="<?php echo $is_payments_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 166 | - <svg class="<?php echo $is_payments_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 211 | + | |
| 212 | + <?php if ($ei_can_open('easy-invoice-payments')) : ?> | |
| 213 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-payments')); ?>" | |
| 214 | + class="<?php echo esc_attr($is_payments_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 215 | + <svg class="<?php echo $is_payments_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 167 | 216 | <rect x="1" y="4" width="22" height="16" rx="2" ry="2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 168 | 217 | <line x1="1" y1="10" x2="23" y2="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 169 | 218 | </svg> |
| 170 | 219 | <?php esc_html_e( 'Payments', 'easy-invoice' ); ?> |
| 171 | 220 | </a> |
| 221 | + <?php endif; ?> | |
| 172 | 222 | |
| 173 | - <!-- Clients --> | |
| 174 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-clients'); ?>" | |
| 175 | - class="<?php echo $is_clients_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 176 | - <svg class="<?php echo $is_clients_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 223 | + | |
| 224 | + <?php if ($ei_can_open('easy-invoice-clients')) : ?> | |
| 225 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-clients')); ?>" | |
| 226 | + class="<?php echo esc_attr($is_clients_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 227 | + <svg class="<?php echo $is_clients_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 177 | 228 | <path d="M17 21V19C17 17.9391 16.5786 16.9217 15.8284 16.1716C15.0783 15.4214 14.0609 15 13 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 178 | 229 | <circle cx="9" cy="7" r="4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 179 | 230 | <path d="M23 21V19C23 18.1137 22.6485 17.2628 22.0237 16.6425C21.3989 16.0221 20.5471 15.6722 19.66 15.6722C18.7729 15.6722 17.9211 16.0221 17.2963 16.6425C16.6715 17.2628 16.32 18.1137 16.32 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 180 | 231 | <path d="M16.32 11.6722C18.36 11.6722 20 10.0322 20 7.99219C20 5.95219 18.36 4.31219 16.32 4.31219" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| @@ -180,39 +231,34 @@ | ||
| 180 | 231 | <path d="M16.32 11.6722C18.36 11.6722 20 10.0322 20 7.99219C20 5.95219 18.36 4.31219 16.32 4.31219" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 181 | 232 | </svg> |
| 182 | 233 | <?php esc_html_e( 'Clients', 'easy-invoice' ); ?> |
| 183 | 234 | </a> |
| 235 | + <?php endif; ?> | |
| 184 | 236 | |
| 185 | - <?php if (easy_invoice_has_pro()): ?> | |
| 186 | - <!-- Item Library --> | |
| 187 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-pro-item-library'); ?>" | |
| 188 | - class="<?php echo $is_item_library_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 189 | - <svg class="<?php echo $is_item_library_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 190 | - <path d="M20 7H4C2.9 7 2 7.9 2 9V19C2 20.1 2.9 21 4 21H20C21.1 21 22 20.1 22 19V9C22 7.9 21.1 7 20 7Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 191 | - <path d="M16 3H8C7.4 3 7 3.4 7 4V7H17V4C17 3.4 16.6 3 16 3Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 192 | - <path d="M8 11H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 193 | - <path d="M8 15H13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 194 | - </svg> | |
| 195 | - <?php esc_html_e( 'Item Library', 'easy-invoice' ); ?> | |
| 196 | - </a> | |
| 197 | - | |
| 198 | - <!-- Template Builder --> | |
| 199 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-templates'); ?>" | |
| 200 | - class="<?php echo $is_templates_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 201 | - <svg class="<?php echo $is_templates_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 202 | - <path d="M4 4h7v2H9.5L7.5 7.5H4V4zm7 4h7v2h2.5L17.5 7.5H11V4zm7 4h7v2h2.5L27.5 7.5H18V4z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 203 | - <path d="M4 11h7v2H9.5L7.5 14.5H4V11zm7 0h7v2h2.5L17.5 14.5H11V11zm7 0h7v2h2.5L27.5 14.5H18V11z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 204 | - <path d="M4 18h7v2H9.5L7.5 21.5H4V18zm7 0h7v2h2.5L17.5 21.5H11V18zm7 0h7v2h2.5L27.5 21.5H18V18z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 205 | - </svg> | |
| 206 | - <?php esc_html_e( 'Template Builder', 'easy-invoice' ); ?> | |
| 207 | - </a> | |
| 208 | - <?php endif; ?> | |
| 237 | + <?php | |
| 238 | + // Item Library + Template Builder sidebar entries were here. | |
| 239 | + // They've been moved BELOW the Addons menu — see the per-addon | |
| 240 | + // sidebar loop further down in this file (lines ~365). The loop | |
| 241 | + // automatically renders a sidebar entry for every enabled addon | |
| 242 | + // whose registry entry has a non-empty settings_url, so the two | |
| 243 | + // explicit blocks are no longer needed (and were creating | |
| 244 | + // visual duplication with the loop). | |
| 245 | + ?> | |
| 209 | 246 | |
| 210 | - <!-- Reports --> | |
| 247 | + <?php | |
| 248 | + // Reports — addon-gated (PERSONAL tier). | |
| 249 | + // | |
| 250 | + // When the addon is loaded, the per-addon sidebar loop further | |
| 251 | + // down in this file (after the Addons menu entry) renders the | |
| 252 | + // Reports link automatically — so this block only handles the | |
| 253 | + // Free-user upsell state. Showing it twice (here AND via the | |
| 254 | + // loop) was the cause of the "2 Reports pages" duplicate. | |
| 255 | + ?> | |
| 211 | 256 | <?php if (!easy_invoice_has_pro()): ?> |
| 257 | + | |
| 212 | 258 | <a href="#" id="reports-menu-link" |
| 213 | - class="text-gray-600 hover:bg-gray-50 hover:text-gray-900 group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 214 | - <svg class="text-gray-400 group-hover:text-gray-500 mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 259 | + class="text-gray-600 hover:bg-indigo-50 hover:text-indigo-700 group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 260 | + <svg class="text-gray-400 group-hover:text-indigo-500 mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 215 | 261 | <path d="M18 20V10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 216 | 262 | <path d="M12 20V4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 217 | 263 | <path d="M6 20V14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 218 | 264 | </svg> |
| @@ -223,31 +269,34 @@ | ||
| 223 | 269 | </svg> |
| 224 | 270 | <?php esc_html_e( 'Pro', 'easy-invoice' ); ?> |
| 225 | 271 | </span> |
| 226 | 272 | </a> |
| 227 | - <?php else: ?> | |
| 228 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-reports'); ?>" | |
| 229 | - class="<?php echo $is_reports_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 230 | - <svg class="<?php echo $is_reports_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 231 | - <path d="M18 20V10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 232 | - <path d="M12 20V4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 233 | - <path d="M6 20V14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 273 | + <?php endif; ?> | |
| 274 | + | |
| 275 | + | |
| 276 | + <?php if ($ei_can_open('easy-invoice-settings')) : ?> | |
| 277 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-settings')); ?>" | |
| 278 | + class="<?php echo esc_attr($is_settings_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 279 | + <svg class="<?php echo $is_settings_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 280 | + <circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 281 | + <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 234 | 282 | </svg> |
| 235 | - <?php esc_html_e( 'Reports', 'easy-invoice' ); ?> | |
| 283 | + <?php esc_html_e( 'Settings', 'easy-invoice' ); ?> | |
| 236 | 284 | </a> |
| 237 | 285 | <?php endif; ?> |
| 238 | 286 | |
| 239 | - <!-- Settings --> | |
| 240 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-settings'); ?>" | |
| 241 | - class="<?php echo $is_settings_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 242 | - <svg class="<?php echo $is_settings_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 243 | - <circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 244 | - <path d="M19.4 15A1.65 1.65 0 0 0 18 14A6 6 0 0 0 6 14A1.65 1.65 0 0 0 4.6 15A2 2 0 0 0 6 19H18A2 2 0 0 0 19.4 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 287 | + <?php $is_import_active = ( 'easy-invoice-import' === $current_page ); ?> | |
| 288 | + <?php if ($ei_can_open('easy-invoice-import')) : ?> | |
| 289 | + <a href="<?php echo esc_url( admin_url( 'admin.php?page=easy-invoice-import' ) ); ?>" | |
| 290 | + class="<?php echo esc_attr( $is_import_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700' ); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 291 | + <svg class="<?php echo $is_import_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" aria-hidden="true"> | |
| 292 | + <path d="M12 3v12m0 0l-4-4m4 4l4-4M4 17v2a2 2 0 002 2h12a2 2 0 002-2v-2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 245 | 293 | </svg> |
| 246 | - <?php esc_html_e( 'Settings', 'easy-invoice' ); ?> | |
| 294 | + <?php esc_html_e( 'Import', 'easy-invoice' ); ?> | |
| 247 | 295 | </a> |
| 296 | + <?php endif; ?> | |
| 248 | 297 | |
| 249 | - <!-- License --> | |
| 298 | + | |
| 250 | 299 | <?php |
| 251 | 300 | // Check if Pro plugin is active and get license status |
| 252 | 301 | $show_license_badge = false; |
| 253 | 302 | $license_status = 'inactive'; |
| @@ -283,31 +332,36 @@ | ||
| 283 | 332 | $license_status = 'free'; |
| 284 | 333 | $license_text = __( 'Free', 'easy-invoice' ); |
| 285 | 334 | } |
| 286 | 335 | ?> |
| 287 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-license'); ?>" | |
| 288 | - class="<?php echo ($current_page === 'easy-invoice-license') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 289 | - <svg class="<?php echo ($current_page === 'easy-invoice-license') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 290 | - <path d="M12 2L13.09 8.26L20 9L13.09 9.74L12 16L10.91 9.74L4 9L10.91 8.26L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 336 | + <?php if ($ei_can_open('easy-invoice-license')) : ?> | |
| 337 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-license')); ?>" | |
| 338 | + class="<?php echo esc_attr(($current_page === 'easy-invoice-license') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 339 | + | |
| 340 | + <svg class="<?php echo ($current_page === 'easy-invoice-license') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 341 | + <circle cx="7.5" cy="15.5" r="5.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 342 | + <path d="M21 2L11.5 11.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 343 | + <path d="M15.5 7.5L18.5 10.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 291 | 344 | </svg> |
| 292 | 345 | <span class="flex-1"><?php esc_html_e( 'License', 'easy-invoice' ); ?></span> |
| 293 | 346 | <?php if ($show_license_badge): ?> |
| 294 | - <span class="license-status-badge <?php echo $license_status; ?>"> | |
| 347 | + <span class="license-status-badge <?php echo esc_attr($license_status); ?>"> | |
| 295 | 348 | <span class="status-dot"></span> |
| 296 | 349 | <?php echo esc_html( $license_text ); ?> |
| 297 | 350 | </span> |
| 298 | 351 | <?php endif; ?> |
| 299 | 352 | </a> |
| 353 | + <?php endif; ?> | |
| 300 | 354 | |
| 301 | - <!-- Free vs Pro - only show in free version --> | |
| 355 | + | |
| 302 | 356 | <?php |
| 303 | 357 | $show_free_vs_pro = !easy_invoice_has_pro(); |
| 304 | 358 | |
| 305 | 359 | if ($show_free_vs_pro): |
| 306 | 360 | ?> |
| 307 | - <a href="<?php echo admin_url('admin.php?page=easy-invoice-free-vs-pro'); ?>" | |
| 308 | - class="<?php echo ($current_page === 'easy-invoice-free-vs-pro') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 309 | - <svg class="<?php echo ($current_page === 'easy-invoice-free-vs-pro') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 361 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-free-vs-pro')); ?>" | |
| 362 | + class="<?php echo esc_attr(($current_page === 'easy-invoice-free-vs-pro') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 363 | + <svg class="<?php echo ($current_page === 'easy-invoice-free-vs-pro') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 310 | 364 | <path d="M3 6L21 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 311 | 365 | <path d="M3 12L21 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 312 | 366 | <path d="M3 18L21 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 313 | 367 | <path d="M9 3L9 21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| @@ -319,14 +373,76 @@ | ||
| 319 | 373 | </span> |
| 320 | 374 | </a> |
| 321 | 375 | <?php endif; ?> |
| 322 | 376 | |
| 323 | - <!-- Join Community --> | |
| 377 | + <?php | |
| 378 | + // Per-addon sidebar entries. Show every enabled addon that has | |
| 379 | + // its own dedicated page (Smart Reminders, Time Tracking, | |
| 380 | + // White Label, etc. — anything whose settings_url is NOT a | |
| 381 | + // deep-link into the main Settings page). Addons whose settings | |
| 382 | + // live inside Settings → <section> (Secure Links → Advanced, | |
| 383 | + // Partial Payments → Invoice, etc.) are intentionally excluded: | |
| 384 | + // the main Settings page's section nav is already the | |
| 385 | + // navigation aid for those, and a sidebar entry would be a | |
| 386 | + // duplicate path to the same place. Users still reach those | |
| 387 | + // via the "Settings →" link on the addon card. | |
| 388 | + if (class_exists('\\EasyInvoice\\Addons\\AddonRegistry') && class_exists('\\EasyInvoice\\Addons\\AddonManager')): | |
| 389 | + foreach (\EasyInvoice\Addons\AddonRegistry::all() as $ei_addon): | |
| 390 | + if (empty($ei_addon['settings_url'])) continue; | |
| 391 | + if (!\EasyInvoice\Addons\AddonManager::isEnabled($ei_addon['id'])) continue; | |
| 392 | + if (!\EasyInvoice\Addons\AddonManager::userCanAccess($ei_addon['id'])) continue; | |
| 393 | + | |
| 394 | + // Skip addons whose settings_url deep-links into the | |
| 395 | + // main Settings page (easy-invoice-settings). Those | |
| 396 | + // are accessed via the card's "Settings →" link only. | |
| 397 | + $ei_addon_parsed = wp_parse_url($ei_addon['settings_url']); | |
| 398 | + $ei_addon_query = []; | |
| 399 | + if (!empty($ei_addon_parsed['query'])) { | |
| 400 | + parse_str($ei_addon_parsed['query'], $ei_addon_query); | |
| 401 | + } | |
| 402 | + $ei_addon_slug = $ei_addon_query['page'] ?? ''; | |
| 403 | + if ($ei_addon_slug === 'easy-invoice-settings') continue; | |
| 404 | + if (!$ei_can_open($ei_addon_slug)) continue; | |
| 405 | + | |
| 406 | + $ei_addon_active = ($current_page === $ei_addon_slug); | |
| 407 | + $ei_addon_icon = !empty($ei_addon['icon']) ? $ei_addon['icon'] : 'dashicons-admin-plugins'; | |
| 408 | + $ei_addon_label = !empty($ei_addon['short_name']) ? $ei_addon['short_name'] : $ei_addon['name']; | |
| 409 | + ?> | |
| 410 | + <a href="<?php echo esc_url($ei_addon['settings_url']); ?>" | |
| 411 | + class="<?php echo $ei_addon_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200" | |
| 412 | + title="<?php echo esc_attr($ei_addon['name']); ?>"> | |
| 413 | + <span class="dashicons <?php echo esc_attr($ei_addon_icon); ?> mr-3 flex-shrink-0 h-5 w-5 <?php echo $ei_addon_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?>" style="font-size:20px;width:20px;height:20px;line-height:20px;"></span> | |
| 414 | + <span class="flex-1 truncate"><?php echo esc_html($ei_addon_label); ?></span> | |
| 415 | + </a> | |
| 416 | + <?php | |
| 417 | + endforeach; | |
| 418 | + endif; | |
| 419 | + ?> | |
| 420 | + | |
| 421 | + | |
| 422 | + <?php if ($ei_can_open('easy-invoice-addons')) : ?> | |
| 423 | + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-addons')); ?>" | |
| 424 | + class="<?php echo esc_attr($is_addons_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'); ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 425 | + <svg class="<?php echo $is_addons_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 426 | + <rect x="3" y="3" width="7" height="7" rx="1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 427 | + <rect x="14" y="3" width="7" height="7" rx="1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 428 | + <rect x="3" y="14" width="7" height="7" rx="1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 429 | + <path d="M17.5 14V21M14 17.5H21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
| 430 | + </svg> | |
| 431 | + <span class="flex-1"><?php esc_html_e('Addons', 'easy-invoice'); ?></span> | |
| 432 | + <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-700"> | |
| 433 | + <?php esc_html_e('New', 'easy-invoice'); ?> | |
| 434 | + </span> | |
| 435 | + </a> | |
| 436 | + <?php endif; ?> | |
| 437 | + | |
| 438 | + | |
| 439 | + <?php if (apply_filters('easy_invoice_show_upgrade_prompts', true)) : ?> | |
| 324 | 440 | <a href="<?php echo esc_url('https://www.facebook.com/groups/mantrabraincommunity'); ?>" |
| 325 | 441 | target="_blank" |
| 326 | 442 | rel="noopener noreferrer" |
| 327 | - class="<?php echo ($current_page === 'easy-invoice-join-community') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 328 | - <svg class="<?php echo ($current_page === 'easy-invoice-join-community') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 443 | + class="<?php echo ($current_page === 'easy-invoice-join-community') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 444 | + <svg class="<?php echo ($current_page === 'easy-invoice-join-community') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 329 | 445 | <path d="M18 2H15C13.6739 2 12.4021 2.52678 11.4645 3.46447C10.5268 4.40215 10 5.67392 10 7V10H7V14H10V22H14V14H17L18 10H14V7C14 6.73478 14.1054 6.48043 14.2929 6.29289C14.4804 6.10536 14.7348 6 15 6H18V2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 330 | 446 | </svg> |
| 331 | 447 | <span class="flex-1"><?php esc_html_e('Join Community', 'easy-invoice'); ?></span> |
| 332 | 448 | <svg class="flex-shrink-0 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| @@ -332,15 +448,25 @@ | ||
| 332 | 448 | <svg class="flex-shrink-0 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 333 | 449 | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/> |
| 334 | 450 | </svg> |
| 335 | 451 | </a> |
| 452 | + <?php endif; ?> | |
| 336 | 453 | |
| 337 | - <!-- Documentation --> | |
| 338 | - <a href="<?php echo esc_url('https://easy-invoice.matrixaddons.com/docs/'); ?>" | |
| 454 | + | |
| 455 | + <?php | |
| 456 | + /** | |
| 457 | + * Filter the sidebar help link. Pro's White Label addon points it at | |
| 458 | + * the agency's own support page. | |
| 459 | + * | |
| 460 | + * @param string $url | |
| 461 | + */ | |
| 462 | + $ei_help_url = apply_filters('easy_invoice_help_link_url', 'https://easy-invoice.matrixaddons.com/docs/'); | |
| 463 | + ?> | |
| 464 | + <a href="<?php echo esc_url($ei_help_url); ?>" | |
| 339 | 465 | target="_blank" |
| 340 | 466 | rel="noopener noreferrer" |
| 341 | - class="text-gray-600 hover:bg-gray-50 hover:text-gray-900 group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 342 | - <svg class="text-gray-400 group-hover:text-gray-500 mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 467 | + class="text-gray-600 hover:bg-indigo-50 hover:text-indigo-700 group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"> | |
| 468 | + <svg class="text-gray-400 group-hover:text-indigo-500 mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| 343 | 469 | <path d="M4 19.5V4.5C4 3.4 4.9 2.5 6 2.5H19C19.5 2.5 20 3 20 3.5V20.5C20 21 19.5 21.5 19 21.5H6C4.9 21.5 4 20.6 4 19.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 344 | 470 | <path d="M8 7H16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> |
| 345 | 471 | <path d="M8 11H16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> |
| 346 | 472 | <path d="M8 15H13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> |
| @@ -352,15 +478,15 @@ | ||
| 352 | 478 | </a> |
| 353 | 479 | |
| 354 | 480 | </nav> |
| 355 | 481 | |
| 356 | - <!-- User Profile --> | |
| 357 | - <div class="absolute bottom-0 w-full border-t border-gray-200 p-4"> | |
| 482 | + | |
| 483 | + <div class="ei-app-sidebar-foot border-t border-gray-200 p-4 flex-shrink-0 bg-white"> | |
| 358 | 484 | <div class="relative"> |
| 359 | 485 | <button type="button" id="user-dropdown-button" class="flex items-center w-full text-left hover:bg-gray-50 rounded-lg p-2 transition-colors duration-200"> |
| 360 | 486 | <div class="flex-shrink-0"> |
| 361 | 487 | <div class="h-8 w-8 rounded-full bg-gray-200 flex items-center justify-center"> |
| 362 | - <span class="text-gray-600 font-medium text-sm"><?php echo substr(wp_get_current_user()->display_name, 0, 1); ?></span> | |
| 488 | + <span class="text-gray-600 font-medium text-sm"><?php echo esc_html(substr(wp_get_current_user()->display_name, 0, 1)); ?></span> | |
| 363 | 489 | </div> |
| 364 | 490 | </div> |
| 365 | 491 | <div class="ml-3 flex-1"> |
| 366 | 492 | <p class="text-sm font-medium text-gray-700"><?php echo esc_html(wp_get_current_user()->display_name); ?></p> |
| @@ -372,22 +498,22 @@ | ||
| 372 | 498 | </svg> |
| 373 | 499 | </div> |
| 374 | 500 | </button> |
| 375 | 501 | |
| 376 | - <!-- Dropdown Menu --> | |
| 502 | + | |
| 377 | 503 | <div id="user-dropdown-menu" class="hidden absolute bottom-full left-0 right-0 mb-2 bg-white border border-gray-200 rounded-lg shadow-lg z-50"> |
| 378 | 504 | <div class="py-1"> |
| 379 | - <a href="<?php echo admin_url(); ?>" target="_blank" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors duration-200"> | |
| 505 | + <a href="<?php echo esc_url(admin_url()); ?>" target="_blank" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors duration-200"> | |
| 380 | 506 | <svg class="mr-3 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 381 | 507 | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path> |
| 382 | 508 | </svg> |
| 383 | - <?php _e('Back to WordPress', 'easy-invoice'); ?> | |
| 509 | + <?php esc_html_e('Back to WordPress', 'easy-invoice'); ?> | |
| 384 | 510 | </a> |
| 385 | - <a href="<?php echo wp_logout_url(); ?>" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors duration-200"> | |
| 511 | + <a href="<?php echo esc_url(wp_logout_url()); ?>" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors duration-200"> | |
| 386 | 512 | <svg class="mr-3 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| 387 | 513 | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path> |
| 388 | 514 | </svg> |
| 389 | - <?php _e('Logout', 'easy-invoice'); ?> | |
| 515 | + <?php esc_html_e('Logout', 'easy-invoice'); ?> | |
| 390 | 516 | </a> |
| 391 | 517 | </div> |
| 392 | 518 | </div> |
| 393 | 519 | </div> |
| @@ -393,30 +519,28 @@ | ||
| 393 | 519 | </div> |
| 394 | 520 | </div> |
| 395 | 521 | </div> |
| 396 | 522 | |
| 397 | -<!-- Mobile menu button --> | |
| 398 | -<div class="fixed top-0 left-0 z-50 p-4 sm:hidden"> | |
| 399 | - <button type="button" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" aria-expanded="false" aria-label="<?php echo esc_attr__( 'Open menu', 'easy-invoice' ); ?>"> | |
| 400 | - <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"> | |
| 401 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path> | |
| 402 | - </svg> | |
| 403 | - </button> | |
| 404 | -</div> | |
| 523 | +<?php | |
| 524 | +/* | |
| 525 | + * The old mobile menu button lived here. Removed in favour of #ei-sidebar-toggle | |
| 526 | + * at the top of this file, because this one could not work: | |
| 527 | + * | |
| 528 | + * - Its handler bound to `document.querySelector('button[aria-expanded="false"]')`, | |
| 529 | + * i.e. the first such button anywhere in the document — not reliably this one. | |
| 530 | + * - It toggled a `hidden` class the sidebar never had. The sidebar had no | |
| 531 | + * responsive rules at all, so it was always open; toggling `hidden` removed it | |
| 532 | + * outright while the content kept its unconditional `pl-64`, leaving a 256px | |
| 533 | + * empty gutter. | |
| 534 | + * - It was `sm:hidden`, so it only appeared below 640px, while the layout | |
| 535 | + * actually breaks below 1024px. | |
| 536 | + */ | |
| 537 | +?> | |
| 405 | 538 | |
| 406 | 539 | <script> |
| 407 | 540 | document.addEventListener('DOMContentLoaded', function() { |
| 408 | - const mobileMenuButton = document.querySelector('button[aria-expanded="false"]'); | |
| 409 | - const sidebar = document.querySelector('.fixed.inset-y-0.left-0'); | |
| 541 | + /* Sidebar drawer is handled by the #ei-sidebar-toggle script above. */ | |
| 410 | 542 | |
| 411 | - if (mobileMenuButton && sidebar) { | |
| 412 | - mobileMenuButton.addEventListener('click', function() { | |
| 413 | - const expanded = this.getAttribute('aria-expanded') === 'true'; | |
| 414 | - this.setAttribute('aria-expanded', !expanded); | |
| 415 | - sidebar.classList.toggle('hidden'); | |
| 416 | - }); | |
| 417 | - } | |
| 418 | - | |
| 419 | 543 | // Handle Reports menu click for premium feature |
| 420 | 544 | const reportsMenuLink = document.getElementById('reports-menu-link'); |
| 421 | 545 | if (reportsMenuLink) { |
| 422 | 546 | reportsMenuLink.addEventListener('click', function(e) { |
| @@ -474,8 +598,65 @@ | ||
| 474 | 598 | body.easy-invoice-admin-body.admin-bar #wpbody-content { |
| 475 | 599 | padding-top: 0 !important; |
| 476 | 600 | } |
| 477 | 601 | |
| 602 | +/* Keep any admin notice clear of the fixed sidebar. | |
| 603 | + * | |
| 604 | + * WordPress prints `admin_notices` output into #wpbody-content BEFORE this | |
| 605 | + * template's markup, so a notice sits outside the `.lg:pl-64` content column and | |
| 606 | + * runs edge to edge underneath the 16rem fixed sidebar — the first words of every | |
| 607 | + * line get covered. disableAdminNoticesOnEasyInvoicePages() suppresses most | |
| 608 | + * notices on our screens, but not all of them: WordPress core prints some | |
| 609 | + * (php_update_notice, update-nag) outside that hook, and any notice we | |
| 610 | + * deliberately keep would be clipped the same way. Indenting them costs nothing | |
| 611 | + * when there are none to show. */ | |
| 612 | +@media (min-width: 1024px) { | |
| 613 | + body.easy-invoice-admin-body #wpbody-content > .notice, | |
| 614 | + body.easy-invoice-admin-body #wpbody-content > .updated, | |
| 615 | + body.easy-invoice-admin-body #wpbody-content > .update-nag, | |
| 616 | + body.easy-invoice-admin-body #wpbody-content > .error { | |
| 617 | + margin-left: 17rem; | |
| 618 | + margin-right: 1rem; | |
| 619 | + } | |
| 620 | +} | |
| 621 | + | |
| 622 | +/* Full-height app shell — works WITH the global | |
| 623 | + `#wpbody-content { display: flex; flex-direction: column; min-height: 100vh }` | |
| 624 | + rule defined in easy-invoice.css. Because the parent is a flex | |
| 625 | + column, the wrapper can't rely on `height: 100%` alone (flex | |
| 626 | + children stay at content height unless given `flex-grow`). We give | |
| 627 | + the wrapper `flex: 1` so it expands to fill whatever vertical space | |
| 628 | + the flex column offers, and a `min-height: 100vh` floor so short | |
| 629 | + pages still paint the bg-gray-50 all the way down to the viewport | |
| 630 | + bottom. Removing the previous html → body → wpwrap → wpcontent | |
| 631 | + chain that wasn't doing anything useful in the flex-column world. */ | |
| 632 | +.easy-invoice-admin { | |
| 633 | + flex: 1; | |
| 634 | + min-height: 100vh; | |
| 635 | +} | |
| 636 | + | |
| 637 | +/* | |
| 638 | + * Below `lg` the sidebar collapses to a drawer and #ei-sidebar-toggle is pinned at | |
| 639 | + * top-left. Every page header starts hard against the left edge, so without this | |
| 640 | + * the toggle sat on top of the page title ("Invoices" rendered as "voices") and on | |
| 641 | + * top of the builders' "Back to invoices" link. | |
| 642 | + * | |
| 643 | + * Reserve the toggle's width (44px) plus its offset so headers start clear of it. | |
| 644 | + * Both header variants are covered: `.ei-app-page-header` is used by the eight | |
| 645 | + * list/settings screens, `.ei-app-header-sync` by the invoice and quote builders. | |
| 646 | + */ | |
| 647 | +@media (max-width: 1023px) { | |
| 648 | + /* !important is needed here, not for weight games: five of these headers | |
| 649 | + (invoice/quote listings, payments, clients, reports) set `padding-left` | |
| 650 | + in an inline style attribute, which a stylesheet rule cannot otherwise | |
| 651 | + beat. Those inline paddings pair with a negative margin to bleed the | |
| 652 | + header full-width, so they cannot simply be removed. */ | |
| 653 | + .ei-app-page-header, | |
| 654 | + .ei-app-header-sync { | |
| 655 | + padding-left: 3.75rem !important; | |
| 656 | + } | |
| 657 | +} | |
| 658 | + | |
| 478 | 659 | /* Custom color for active icons */ |
| 479 | 660 | .group:hover svg { |
| 480 | 661 | color: rgb(79 70 229) !important; |
| 481 | 662 | } |
| @@ -488,14 +669,46 @@ | ||
| 488 | 669 | /* Hover state for non-active items */ |
| 489 | 670 | .group:hover:not(.bg-indigo-50) svg { |
| 490 | 671 | color: rgb(79 70 229) !important; |
| 491 | 672 | } |
| 673 | + | |
| 674 | +/* Sidebar scrollbar — slim, only visible on hover/scroll. Firefox uses scrollbar-* */ | |
| 675 | +.ei-app-sidebar-nav { | |
| 676 | + scrollbar-width: thin; | |
| 677 | + scrollbar-color: rgba(156, 163, 175, 0) transparent; | |
| 678 | + transition: scrollbar-color 0.2s ease; | |
| 679 | +} | |
| 680 | +.ei-app-sidebar-nav:hover { | |
| 681 | + scrollbar-color: rgba(156, 163, 175, 0.5) transparent; | |
| 682 | +} | |
| 683 | +/* WebKit (Chrome / Safari / Edge) */ | |
| 684 | +.ei-app-sidebar-nav::-webkit-scrollbar { | |
| 685 | + width: 8px; | |
| 686 | +} | |
| 687 | +.ei-app-sidebar-nav::-webkit-scrollbar-track { | |
| 688 | + background: transparent; | |
| 689 | +} | |
| 690 | +.ei-app-sidebar-nav::-webkit-scrollbar-thumb { | |
| 691 | + background-color: transparent; | |
| 692 | + border-radius: 4px; | |
| 693 | + border: 2px solid transparent; | |
| 694 | + background-clip: content-box; | |
| 695 | + transition: background-color 0.2s ease; | |
| 696 | +} | |
| 697 | +.ei-app-sidebar-nav:hover::-webkit-scrollbar-thumb { | |
| 698 | + background-color: rgba(156, 163, 175, 0.45); | |
| 699 | +} | |
| 700 | +.ei-app-sidebar-nav::-webkit-scrollbar-thumb:hover { | |
| 701 | + background-color: rgba(107, 114, 128, 0.7); | |
| 702 | +} | |
| 492 | 703 | </style> |
| 493 | 704 | |
| 494 | -<div class="min-h-screen bg-gray-50 easy-invoice-admin"> | |
| 705 | +<div class="min-h-screen bg-white easy-invoice-admin"> | |
| 495 | 706 | <a href="#easy-invoice-main" class="easy-invoice-skip-link screen-reader-text"><?php esc_html_e( 'Skip to main content', 'easy-invoice' ); ?></a> |
| 496 | - <!-- Main Content --> | |
| 497 | - <div id="easy-invoice-main" class="pl-64" tabindex="-1"> | |
| 707 | + | |
| 708 | + <?php // pl-64 only from `lg` up — under that the sidebar is an off-canvas drawer | |
| 709 | + // and reserving 256px of padding left phones with ~134px of usable width. ?> | |
| 710 | + <div id="easy-invoice-main" class="lg:pl-64" tabindex="-1"> | |
| 498 | 711 | <?php |
| 499 | 712 | |
| 500 | 713 | $page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : 'easy-invoice'; |
| 501 | 714 | // Content will be inserted here |
| @@ -507,11 +720,51 @@ | ||
| 507 | 720 | |
| 508 | 721 | ?> |
| 509 | 722 | </div> |
| 510 | 723 | |
| 511 | - <!-- Add ajaxurl for custom notice JavaScript --> | |
| 724 | + | |
| 512 | 725 | <script> |
| 726 | + /* Off-canvas sidebar for viewports below Tailwind's `lg` (1024px). | |
| 727 | + Kept dependency-free and inline so it works on every Easy Invoice screen | |
| 728 | + without touching the 13 individual page templates. */ | |
| 729 | + (function () { | |
| 730 | + var toggle = document.getElementById('ei-sidebar-toggle'); | |
| 731 | + var sidebar = document.getElementById('ei-app-sidebar'); | |
| 732 | + var backdrop = document.getElementById('ei-sidebar-backdrop'); | |
| 733 | + if (!toggle || !sidebar || !backdrop) { return; } | |
| 734 | + | |
| 735 | + function setOpen(open) { | |
| 736 | + sidebar.classList.toggle('-translate-x-full', !open); | |
| 737 | + backdrop.classList.toggle('hidden', !open); | |
| 738 | + toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); | |
| 739 | + /* Stop the page scrolling behind the drawer while it is open. */ | |
| 740 | + document.body.style.overflow = open ? 'hidden' : ''; | |
| 741 | + } | |
| 742 | + | |
| 743 | + toggle.addEventListener('click', function () { | |
| 744 | + setOpen(sidebar.classList.contains('-translate-x-full')); | |
| 745 | + }); | |
| 746 | + backdrop.addEventListener('click', function () { setOpen(false); }); | |
| 747 | + | |
| 748 | + document.addEventListener('keydown', function (e) { | |
| 749 | + if (e.key === 'Escape' && !sidebar.classList.contains('-translate-x-full')) { | |
| 750 | + setOpen(false); | |
| 751 | + toggle.focus(); | |
| 752 | + } | |
| 753 | + }); | |
| 754 | + | |
| 755 | + /* Closing on navigation keeps the drawer from being stuck open after a | |
| 756 | + click-through, and resizing up to desktop must clear the inline | |
| 757 | + overflow lock the drawer set. */ | |
| 758 | + sidebar.addEventListener('click', function (e) { | |
| 759 | + if (e.target.closest('a') && window.matchMedia('(max-width: 1023px)').matches) { setOpen(false); } | |
| 760 | + }); | |
| 761 | + window.matchMedia('(min-width: 1024px)').addEventListener('change', function (ev) { | |
| 762 | + if (ev.matches) { setOpen(false); document.body.style.overflow = ''; } | |
| 763 | + }); | |
| 764 | + })(); | |
| 765 | + | |
| 513 | 766 | if (typeof ajaxurl === 'undefined') { |
| 514 | - var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>'; | |
| 767 | + var ajaxurl = '<?php echo esc_url(admin_url('admin-ajax.php')); ?>'; | |
| 515 | 768 | } |
| 516 | 769 | </script> |
| 517 | 770 | </div> |