Jake Vanderwerf
4 hours ago 56a9a1ccf764ff7a6af8f8a2292cb07443cb4aa7
inc/helpers/ui.php
@@ -1,5 +1,10 @@
<?php
use JVBase\managers\Cache;
use JVBase\meta\Form;
use JVBase\base\Site;
use JVBase\utility\Image;
if (!defined('ABSPATH')) {
   exit;
}
@@ -9,23 +14,22 @@
function jvbClientQueue():void
{
    if (!jvbSiteHasDashboard() || !is_user_logged_in()) {
    if (!Site::has('dashboard') || !is_user_logged_in()) {
        return;
    }
    ?>
    <aside id="queue" class="col start btw" aria-expanded="false" hidden>
        <div class="status-actions row start nowrap">
         <div class="refresh row btw">
                <span class="countdown row" title="Will refresh again...">5</span>
                <button class="refreshNow row" title="Check now">
                    <?= jvbIcon('refresh', ['title'=> 'Check now']) ?>
                </button>
            </div>
    <aside id="queue" class="left col top main" aria-expanded="false" >
        <div class="m-actions row left nowrap">
         <button class="refresh row" title="Check now">
            <?= jvbIcon('arrows-clockwise', ['title'=> 'Check now']) ?>
            <span class="countdown row indicator" title="Will refresh again...">5</span>
         </button>
            <div class="popup row"><span></span></div>
        </div>
      <div class="header col start">
         <h3>Queue Status</h3>
      <div class="header col top">
         <h2>Queue Status</h2>
         <nav class="filters">
            <?php
            $filters = [
@@ -42,7 +46,8 @@
            foreach($filters as $filter => $title) {
               $active = ($i === 0) ? ' active': '';
               ?>
               <button class="filter<?=$active?>" data-filter="<?=$filter?>" data-count="0"><span class="count row"></span><?=$title?></button>
               <input type="radio" id="qfilter-<?=$filter?>" name="qfilter" class="btn filter<?=$active?>" data-filter="<?=$filter?>">
               <label for="qfilter-<?=$filter?>" data-count="0"><span class="count indicator row"></span><?=$title?></label>
               <?php
               $i++;
            }
@@ -50,35 +55,39 @@
            ?>
         </nav>
      </div>
      <div class="qitems col">
         <!-- Operations will be listed here -->
      <div class="qitems item-grid col top left nowrap">
      </div>
      <div class="queue-actions row btw">
      <div class="queue-actions row x-btw nowrap">
         <button class="dismiss-all">Clear Completed</button>
         <button class="retry-all">Retry Failed</button>
      </div>
    </aside>
   <button class="qtoggle row" title="Show Queue" aria-controls="queue" hidden>
      <?= jvbIcon('save') ?>
   <button class="qtoggle sticky" title="Show Queue" aria-controls="queue" >
      <?= jvbIcon('floppy-disk') ?>
      <span class="screen-reader-text"></span>
      <span class="indicator"></span>
      <span class="count row"></span>
   </button>
   <template class="queueItem">
      <div class="item">
         <div class="header row btw">
         <div class="header row x-btw">
            <span class="type"></span>
            <span class="status row"><span class="screen-reader-text"></span></span>
            <span class="status row"><?= jvbIcon('arrows-clockwise') ?><span class="screen-reader-text"></span></span>
         </div>
         <?php jvbRenderProgressBar() ?>
         <?php jvbRenderProgressBar('',false,false) ?>
         <div class="info">
            <div class="details"></div>
            <div class="time row start">
            <div class="time row left">
               <?= jvbIcon('clock') ?>
               <span class="started">Started: <span class="time"></span>
               <span class="completed"></span>
               <span class="started">Started: <time></time></span>
               <span class="completed" hidden><span>Completed: </span><time></time></span>
            </div>
         </div>
         <div class="actions row end">
         <div class="actions row right">
            <button class="retry" data-action="retry"><span>Retry</span><?= jvbIcon('arrows-clockwise')?></button>
            <button class="cancel" data-action="cancel"><span>Cancel</span><?= jvbIcon('x-square')?></button>
            <button class="refresh" data-action="refresh" title="Refresh to see changes"><span>Refresh</span><?= jvbIcon('arrows-clockwise')?></button>
            <button class="dismiss" data-action="dismiss"><span>Dismiss</span><?= jvbIcon('eye-closed')?></button>
         </div>
      </div>
   </template>
@@ -90,7 +99,7 @@
      <button></button>
   </template>
   <template class="emptyQueue">
      <div class="empty-queue row">Everything is up to date.</div>
      <div class="empty queue row">Everything is up to date.</div>
   </template>
    <?php
}
@@ -101,25 +110,26 @@
 */
function jvbNotificationMenu():string
{
    if (jvbSiteHasNotifications() && is_user_logged_in()) {
   $membership = Site::membership();
    if ($membership && $membership->has('notifications') && is_user_logged_in()) {
        ob_start();
        ?>
        <li>
            <a href="<?=get_home_url(2, '/dash/')?>" title="Behind the Scenes">
                <?= jvbIcon('dashboard', ['title' => 'Behind the Scenes'])?>
            <a href="<?=get_home_url(null, '/dash/')?>" title="Behind the Scenes">
                <?= jvbIcon('door', ['title' => 'Behind the Scenes'])?>
                <span class="screen-reader-text">Go Behind the Scenes</span>
            </a>
        </li>
        <li class="notifications has-submenu">
            <button class="toggle notifications" type="button" title="Toggle Notifications" aria-expanded="false" aria-controls="notifications-dropdown">
            <button class="toggle notifications" type="button" data-action="toggle-submenu" title="Toggle Notifications" aria-expanded="false" aria-controls="notifications-dropdown">
                <?= jvbIcon('bell', ['title'=> 'No Notifications'])?>
                <?= jvbIcon('bell-ringing', ['title'=> 'New Notifications']) ?>
                <span class="notification-badge" aria-label="Notifications">
                </span>
            </button>
            <ul class="notifications-preview submenu">
                <li id="view-all"><a href="<?=get_home_url(2, '/dash/notifications/')?>" class="view-all">View All Notifications</a></li>
            <ul class="notifications-preview submenu" id="notifications-dropdown">
                <li id="view-all"><a href="<?=get_home_url(null, '/dash/notifications/')?>" class="view-all">View All Notifications</a></li>
            </ul>
            <template class="notificationItem">
                <li class="notification-preview">
@@ -148,46 +158,51 @@
 */
function jvbHelpMenu():string
{
    $out = get_option(BASE.'help_menu');
    if ($out === false) {
        $open = '<li><a href="';
        $mid = '">';
        $close = '</a></li>';
   if (!Site::has('help_menu')) {
      return '';
   }
        $titles = array(
            'About',
            'Contact',
            'Request a Feature',
            'Technical Issue',
        );
        $links = '';
        foreach ($titles as $t) {
            $page = new WP_Query(array(
                'post_type' => 'page',
                'title'     => $t,
                'fields'    => 'ids'
            ));
            if ($page->have_posts()) {
                $end = ($t == 'About') ? '<li><a href="'.get_home_url(2, '/directory/partners/').'" title="View our Partners">Partners</a></li>' : '';
                $links .= $open.get_the_permalink($page->posts[0]).'" title="'.$t.$mid.$t.$close.$end;
            }
            wp_reset_postdata();
        }
   $cache = Cache::for('help_menu');
   $out = $cache->remember(
      'help_menu',
      function () {
         $open = '<li><a href="';
         $mid = '">';
         $close = '</a></li>';
        $out = '<li class="has-submenu">
                <button class="toggle quick-help" type="button" title="Toggle Quick Help Menu" aria-expanded="false" aria-controls="quick-help" aria-label="Toggle Quick Help Menu">'.jvbIcon('help', ['title'=> 'Quick Help']).'</button>
                <ul class="submenu">
         $titles = array(
            'About',
            'Contact',
            'Request a Feature',
            'Technical Issue',
         );
         $links = '';
         foreach ($titles as $t) {
            $page = new WP_Query(array(
               'post_type' => 'page',
               'title'     => $t,
               'fields'    => 'ids'
            ));
            if ($page->have_posts()) {
               $end = ($t == 'About') ? '<li><a href="'.get_home_url(null, '/directory/partners/').'" title="View our Partners">Partners</a></li>' : '';
               $links .= $open.get_the_permalink($page->posts[0]).'" title="'.$t.$mid.$t.$close.$end;
            }
            wp_reset_postdata();
         }
         return '<li class="has-submenu">
                <button class="toggle quick-help" data-action="toggle-submenu" type="button" title="Toggle Quick Help Menu" aria-expanded="false" aria-controls="quick-help" aria-label="Toggle Quick Help Menu">'.jvbIcon('question', ['title'=> 'Quick Help']).'</button>
                <ul class="submenu" id="quick-help">
                    '.$links.'
                </ul>
            </li>';
        update_option(BASE.'help_menu', $out);
    }
      }
   );
    if (is_user_logged_in()) {
        $out .= '<li><a href="'.wp_logout_url(get_home_url()).'" title="Logout">'.jvbIcon('logout').'<span class="screen-reader-text">Logout</span></a></li>';
        $out .= '<li><a href="'.wp_logout_url(get_home_url()).'" title="Logout">'.jvbIcon('sign-out').'<span class="screen-reader-text">Logout</span></a></li>';
    } else {
        $out .= '<li><a href="'.wp_login_url(null, true).'" title="Login">'.jvbIcon('login').'<span class="screen-reader-text">Login</span></a></li>';
        $out .= '<li><a href="'.wp_login_url(null, true).'" title="Login">'.jvbIcon('sign-in').'<span class="screen-reader-text">Login</span></a></li>';
    }
    return $out;
}
@@ -197,19 +212,9 @@
 * Outputs the search bar (likely don't need anymore)
 * @return string
 */
function jvbSearch(string $placeholder = 'Search...'):string
function jvbSearch(string $placeholder = 'Search...', string $id = 'search', string $label = '', string $buttonText = '', bool $buttonInside = false, bool $hideSearch = false):string
{
    return '<div class="search-container row start nowrap">
  <input type="search" id="search" placeholder="'.$placeholder.'">
  <button
    title="Clear Search"
    type="button"
    class="clear-search"
    aria-label="Clear search"
    onclick="this.previousElementSibling.value = \'\'; this.previousElementSibling.focus();"
  >'.jvbIcon('x', ['title'=> 'Clear Search']).'</button>
  <button type="button" title="Search" class="toggle search" aria-label="Toggles search input visually" onclick="this.parentNode.classList.toggle(\'open\');this.previousElementSibling.previousElementSibling.focus();">'.jvbIcon('search').'</button>
</div>';
   return Form::search($placeholder, $id, $label, $buttonText, $buttonInside, $hideSearch);
}
@@ -217,8 +222,8 @@
function jvbModalActions()
{
    return '<div class="m-actions row">
        <button type="button" class="cancel">'.jvbIcon('close').'<span class="screen-reader-text">Cancel</span></button>
        <button type="submit" class="save">'.jvbIcon('save').'<span class="screen-reader-text">Save</span></button>
        <button type="button" class="cancel">'.jvbIcon('x').'<span class="screen-reader-text">Cancel</span></button>
        <button type="submit" class="save">'.jvbIcon('floppy-disk').'<span class="screen-reader-text">Save</span></button>
    </div>';
}
@@ -240,19 +245,17 @@
 *
 * @return string
 */
function jvbFormatImage(int|string $imgID, string $start = 'tiny', string $end = 'large'):string
function jvbFormatImage(int $imgID, string $start = 'tiny', string $end = 'large', bool $addLink = true, ?string $postSlug = null):string
{
    $block = new \JVBase\blocks\CustomBlocks();
    if ($imgID === '' || $imgID === 0) {
        $imgID = $block->imageID($imgID);
    }
    if ($imgID === '' || $imgID === 0 || $imgID === false) {
        return '';
    }
    $image = new Image();
    return $image->formatImage($imgID, $start, $end, $addLink, $postSlug);
}
   $imgID = (int)$imgID;
    return $block->formatImage($imgID, $start, $end);
function jvbImageCaption(int $imgID, string $start = 'tiny', string $end = 'large', bool $addLink = true, ?string $postSlug = null):string
{
   $caption = wp_get_attachment_caption($imgID);
   $caption = ($caption && $caption !== '') ? '<figcaption>'.jvb_filter_content( $caption).'</figcaption>' : '';
   return '<figure>'.jvbFormatImage($imgID, $start, $end, $addLink, $postSlug).$caption.'</figure>';
}
/**
@@ -260,8 +263,6 @@
 * @return void
 */
add_action('wp_footer', 'jvbToastContainer');
function jvbToastContainer():void
{
    ?>
@@ -270,10 +271,10 @@
    </aside>
    <template class="notificationPopup">
        <div class="toast" role="status" aria-live="polite">
            <div class="toast-content row btw">
            <div class="toast-content row x-btw">
                <p></p>
                <button type="button" class="close-toast" aria-label="Close">
                    <?= jvbIcon('close') ?>
                    <?= jvbIcon('x') ?>
                </button>
            </div>
        </div>
@@ -297,17 +298,11 @@
    ?>
    <nav id="<?=$id?>" class="on-this-page index">
        <label>Jump to:
            <button type="button" aria-label="Show Index" title="Show Index" class="toggle" aria-expanded="false">
                <?= jvbIcon('add') ?>
            </button>
        </label>
      <button type="button" aria-label="Show Index" title="Show Index" class="toggle main" aria-expanded="false">
         <span>Jump To:</span><?= jvbIcon('plus-square') ?>
      </button>
        <ul>
            <li>
                <a href="#top" title="Back to Top">
                    <?= jvbIcon('up') ?>
                </a>
            </li>
            <?php
            foreach ($ids as $slug) {
                ?>
@@ -324,13 +319,15 @@
    return ob_get_clean();
}
add_action('wp_footer', 'jvbLoadingScreen');
function jvbLoadingScreen():string
{
   $icon = apply_filters('jvbLoadingIcon', 'drop-simple');
   return '<dialog class="loading">
      <div class="col">
         <div class="spinner"></div>
         <div class="status col">
            <div class="icon">'.apply_filters('jvbLoadingIcon', jvbIcon('tattoo')).'</div>
            <div class="icon">'.jvbIcon($icon).'</div>
            <h3>Loading</h3>
            <p class="typeText">Please wait...</p>
         </div>
@@ -361,20 +358,24 @@
      echo '';
      return '';
   }
   $header = '<nav class="tabs row start" role="tablist">';
   $header = '<nav class="tabs row left" role="tablist">';
   $content = '';
   $i = 0;
   foreach ($tabs as $slug => $config) {
      if (!array_key_exists('content', $config) || empty($config['content'])) {
         error_log('No content for tab: '.$slug);
         continue;
      }
      //Header
      $active = ($i === 0) ? ' active' : '';
      $selected = ($i === 0) ? 'true' : 'false';
      $hidden = (array_key_exists('hidden', $config)) ? ' hidden' : '';
      $header .= '<button type="button" class="button tab'.$active.'" data-tab="'.$slug.'" role="tab" aria-selected="'.$selected.'"'.$hidden.'>
         <h2 class="row">';
      $header .= '<button type="button" class="button tab'.$active.'" data-tab="'.$slug.'" role="tab" aria-selected="'.$selected.'"'.$hidden.'>';
         if (array_key_exists('icon', $config)) {
            $header .= jvbIcon($config['icon']);
         }
         $header .= $config['title'].'</h2>
         $header .= $config['title'].'
      </button>';
      //Content
@@ -383,11 +384,28 @@
      if ($i !== 0) {
         $content .= ' hidden';
      }
      $content .= '>
         <h2>'.$config['title'].'</h2>';
         if ( $config['description']) {
            $content .= apply_filters('the_content', $config['description']);
      $content .= '>';
      if (array_key_exists('header', $config)) {
         $content .= $config['header'];
      } else {
         $content .= '<h2>'.$config['title'].'</h2>';
         if ( array_key_exists('description', $config)) {
            if (!is_array($config['description'])) {
               $content .= jvb_filter_content( $config['description']);
            } else {
//             foreach ($config['description'] as $desc) {
//                $content .= jvb_filter_content( $desc);
//             }
               $content .= implode('',array_map(function ($paragraph) {
                  return jvb_filter_content( $paragraph);
               }, $config['description']));
            }
         }
      }
      $content .= $config['content'].'
      </div>';
@@ -403,17 +421,79 @@
   return $out;
}
function jvbRenderProgressBar(string $inside ='')
function jvbRenderProgressBar(string $inside ='', $top = false, $icon = true, $return = false):string
{
   ?>
   <div class="progress">
   $top = $top ? ' abs top' : '';
   $bar = sprintf(
      '<div class="progress%s">
      <div class="bar">
         <div class="fill"></div>
      </div>
      <div class="details row btw">
         <?=$inside?>
      <div class="row x-btw">
         %s
         <div class="details">
            %s
         </div>
      </div>
   </div>
   <?php
   </div>',
      $top,
      ($icon) ? '<i class="icon"></i>': '',
      $inside
   );
   if (!$return) {
      echo $bar;
   }
   return $bar;
}
function jvbFormStatus(string $message = ''):string
{
   return sprintf(
      '%s
      <div class="fstatus row" hidden>
         <div class="spinner"></div>
         <i class="icon"></i>
         <p class="message">%s</p>
      </div>',
      jvbFormRestore(),
      $message
   );
}
function jvbFormRestore():string
{
   return sprintf(
      '<div class="restore-form col" hidden>
         <h3>Looks like we left things hanging...</h3>
         <p>Would you like to continue where you left off?</p>
         <div class="actions">
            <button class="restore" type="button" data-action="restore">%s<span>Restore</span></button>
            <button type="button" class="discard" data-action="clear">
               %s
               <span>Discard</span>
            </button>
         </div>
      </div>',
      jvbFormIcon('clock-clockwise'),
      jvbFormIcon('x'),
   );
}
function jvbDarkModeToggle():string
{
   $checked = (is_user_logged_in() && current_user_can('prefers_dark_theme', true)) ? ' checked' : '';
   $title = ($checked == '') ? 'Toggle Dark Mode' : 'Toggle Light Mode';
   $showThemeSwitch = (bool)apply_filters('jvb_show_theme_switch', true);
   $themeSwitch = sprintf(
'<label title="%s" id="theme-switch" class="switch" for="theme-switcher">
         <input class="theme-switch row" id="theme-switcher" name="theme-switcher" type="checkbox"%s data-setting="theme" data-theme role="switch" name="dark-mode" aria-label="Toggle dark mode">
         <span class="slider">%s%s</span>
      </label>',
      $title,
      $checked,
      jvbIcon('sun-dim', ['title'=> 'Light Mode']),
      jvbIcon('moon', ['title'=>'Dark Mode'])
   );
   return ($showThemeSwitch) ? $themeSwitch : '';
}