From 56a9a1ccf764ff7a6af8f8a2292cb07443cb4aa7 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 28 May 2026 18:19:57 +0000
Subject: [PATCH] =New Gitbit setpu

---
 inc/helpers/ui.php |  312 +++++++++++++++++++++++++++++----------------------
 1 files changed, 175 insertions(+), 137 deletions(-)

diff --git a/inc/helpers/ui.php b/inc/helpers/ui.php
index a9e310d..d0f5f4e 100644
--- a/inc/helpers/ui.php
+++ b/inc/helpers/ui.php
@@ -1,6 +1,9 @@
 <?php
 
-use JVBase\utility\Features;
+use JVBase\managers\Cache;
+use JVBase\meta\Form;
+use JVBase\base\Site;
+use JVBase\utility\Image;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -11,24 +14,22 @@
 
 function jvbClientQueue():void
 {
-    if (!Features::forSite()->has('dashboard') || !is_user_logged_in()) {
+    if (!Site::has('dashboard') || !is_user_logged_in()) {
         return;
     }
 
     ?>
-    <aside id="queue" class="left 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 = [
@@ -45,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++;
 				}
@@ -53,36 +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>
@@ -94,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
 }
@@ -105,24 +110,25 @@
  */
 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(null, '/dash/')?>" title="Behind the Scenes">
-                <?= jvbIcon('dashboard', ['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">
+            <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">
@@ -152,47 +158,51 @@
  */
 function jvbHelpMenu():string
 {
-    $out = get_option(BASE.'help_menu');
+	if (!Site::has('help_menu')) {
+		return '';
+	}
 
-    if ($out === false) {
-        $open = '<li><a href="';
-        $mid = '">';
-        $close = '</a></li>';
+	$cache = Cache::for('help_menu');
+	$out = $cache->remember(
+		'help_menu',
+		function () {
+			$open = '<li><a href="';
+			$mid = '">';
+			$close = '</a></li>';
 
-        $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();
-        }
+			$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();
+			}
 
-        $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">
+			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;
 }
@@ -202,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);
 }
 
 
@@ -222,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>';
 }
 
@@ -245,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>';
 }
 
 /**
@@ -265,8 +263,6 @@
  * @return void
  */
 add_action('wp_footer', 'jvbToastContainer');
-
-
 function jvbToastContainer():void
 {
     ?>
@@ -275,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>
@@ -302,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) {
                 ?>
@@ -332,11 +322,12 @@
 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>
@@ -367,7 +358,7 @@
 		echo '';
 		return '';
 	}
-	$header = '<nav class="tabs row start" role="tablist">';
+	$header = '<nav class="tabs row left" role="tablist">';
 	$content = '';
 	$i = 0;
 
@@ -380,12 +371,11 @@
 		$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
@@ -394,21 +384,28 @@
 		if ($i !== 0) {
 			$content .= ' hidden';
 		}
-		$content .= '>
-			<h2>'.$config['title'].'</h2>';
-			if ( $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 .= apply_filters('the_content', $config['description']);
+					$content .= jvb_filter_content( $config['description']);
 				} else {
 //					foreach ($config['description'] as $desc) {
-//						$content .= apply_filters('the_content', $desc);
+//						$content .= jvb_filter_content( $desc);
 //					}
 					$content .= implode('',array_map(function ($paragraph) {
-						return apply_filters('the_content', $paragraph);
+						return jvb_filter_content( $paragraph);
 					}, $config['description']));
 				}
 
 			}
+		}
+
+
 
 		$content .= $config['content'].'
 		</div>';
@@ -424,38 +421,79 @@
 	return $out;
 }
 
-function jvbRenderProgressBar(string $inside ='', $top = false)
+function jvbRenderProgressBar(string $inside ='', $top = false, $icon = true, $return = false):string
 {
+
 	$top = $top ? ' abs top' : '';
-	?>
-	<div class="progress<?=$top?>">
+	$bar = sprintf(
+		'<div class="progress%s">
 		<div class="bar">
 			<div class="fill"></div>
 		</div>
-		<div class="details row btw">
-			<?=$inside?>
-		</div>
-	</div>
-	<?php
-}
-
-function jvbFormStatus(string $message = '') {
-	return '<div class="restore-form col" hidden>
-			<h3>Looks like we left things hanging...</h3>
-			<p>We\'ve filled in the fields with what you put last time.</p>
-			<div class="actions">
-				<button type="button" data-action="clear-form">
-					'.jvbIcon('arrows-clockwise').'
-					<span>Start Over</span>
-				</button>
-				<button type="button" data-action="dismiss-restore">
-					'.jvbIcon('close').'
-					<span>Dismiss</span>
-				</button>
+		<div class="row x-btw">
+			%s
+			<div class="details">
+				%s
 			</div>
 		</div>
+	</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>
-			<p class="message">'.$message.'</p>
-		</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 : '';
 }

--
Gitblit v1.10.0