feat: nano-style footer bar, missing utility classes, CSS semantic vars
- layout_footer.php: add lt-footer with context-sensitive keyboard hint bar
([ ~ ] HOME | [ / ] SEARCH | [ + ] NEW | [ * ] CFG | [ ? ] HELP)
Context adapts for dashboard, ticket, and admin pages
- layout_footer.php: wire show-keyboard-help and open-settings for all pages
- base.css: body { display:flex; flex-direction:column } + lt-main { flex:1 }
so footer sticks to bottom of viewport on short pages
- base.css: add lt-flex-gap-xs/sm/md/lg and lt-flex-align-start/center/end
(were used across all views but never defined — causing broken layouts)
- base.css: add --lt-danger/amber/cyan/success/text-primary CSS variables
(referenced in ticket.css and dashboard.css fallbacks but never declared)
- base.css: add lt-text-danger/warning/success/info/primary utility classes
(used in TicketView, DashboardView, admin views but not defined in base.css)
- DashboardView.php: remove ascii-banner.js (loaded but never called)
- TemplatesView.php: fix priority badge from lt-p* to lt-chip component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+71
-1
@@ -79,6 +79,13 @@
|
||||
--accent-purple: #BF5FFF;
|
||||
--accent-purple-dim: rgba(191,95,255,0.10);
|
||||
|
||||
/* ── App semantic aliases (used in ticket.css, dashboard.css) ── */
|
||||
--lt-danger: var(--accent-red);
|
||||
--lt-amber: var(--accent-amber);
|
||||
--lt-cyan: var(--accent-cyan);
|
||||
--lt-success: var(--accent-green);
|
||||
--lt-text-primary: var(--accent-green);
|
||||
|
||||
/* Legacy aliases — keeps all existing component HTML working */
|
||||
--terminal-green: var(--accent-green);
|
||||
--terminal-green-dim: var(--accent-green-dim);
|
||||
@@ -216,6 +223,8 @@ body {
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -349,6 +358,7 @@ hr {
|
||||
|
||||
.lt-main {
|
||||
padding-top: calc(var(--header-height) + var(--space-lg));
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.lt-layout {
|
||||
@@ -369,6 +379,17 @@ hr {
|
||||
.lt-flex-col { display: flex; flex-direction: column; }
|
||||
.lt-flex-wrap { flex-wrap: wrap; }
|
||||
|
||||
/* Flex gap modifiers (used with lt-flex) */
|
||||
.lt-flex-gap-xs { gap: var(--space-xs); }
|
||||
.lt-flex-gap-sm { gap: var(--space-sm); }
|
||||
.lt-flex-gap-md { gap: var(--space-md); }
|
||||
.lt-flex-gap-lg { gap: var(--space-lg); }
|
||||
|
||||
/* Flex align modifiers */
|
||||
.lt-flex-align-start { align-items: flex-start; }
|
||||
.lt-flex-align-center { align-items: center; }
|
||||
.lt-flex-align-end { align-items: flex-end; }
|
||||
|
||||
.lt-gap-sm { gap: var(--space-sm); }
|
||||
.lt-gap-md { gap: var(--space-md); }
|
||||
.lt-gap-lg { gap: var(--space-lg); }
|
||||
@@ -2294,6 +2315,12 @@ select option:checked {
|
||||
.lt-text-red { color: var(--accent-red); text-shadow: var(--glow-red); }
|
||||
.lt-text-muted { color: var(--text-muted); }
|
||||
.lt-text-dim { color: var(--text-dim); }
|
||||
/* Semantic aliases */
|
||||
.lt-text-danger { color: var(--accent-red); text-shadow: var(--glow-red); }
|
||||
.lt-text-warning { color: var(--accent-amber); text-shadow: var(--glow-amber); }
|
||||
.lt-text-success { color: var(--accent-green); text-shadow: var(--glow-green); }
|
||||
.lt-text-info { color: var(--accent-cyan); text-shadow: var(--glow-cyan); }
|
||||
.lt-text-primary { color: var(--accent-green); text-shadow: var(--glow-green); }
|
||||
|
||||
.lt-text-xs { font-size: 0.63rem; }
|
||||
.lt-text-sm { font-size: 0.78rem; }
|
||||
@@ -5477,7 +5504,7 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-md) var(--space-lg);
|
||||
padding: var(--space-sm) var(--space-lg);
|
||||
border-top: 1px solid var(--border-dim);
|
||||
margin-top: auto;
|
||||
background: var(--bg-secondary);
|
||||
@@ -5485,6 +5512,49 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
|
||||
font-size: 0.7rem;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
/* Keyboard hint bar */
|
||||
.lt-footer-hints {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.lt-footer-hint {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.68rem;
|
||||
letter-spacing: 0.03em;
|
||||
text-decoration: none;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
font-family: inherit;
|
||||
cursor: default;
|
||||
transition: color 0.12s;
|
||||
}
|
||||
a.lt-footer-hint,
|
||||
button.lt-footer-hint {
|
||||
cursor: pointer;
|
||||
}
|
||||
a.lt-footer-hint:hover,
|
||||
button.lt-footer-hint:hover {
|
||||
color: var(--accent-green);
|
||||
text-shadow: var(--glow-green);
|
||||
}
|
||||
.lt-footer-key {
|
||||
color: var(--accent-green);
|
||||
opacity: 0.75;
|
||||
font-weight: 700;
|
||||
}
|
||||
.lt-footer-sep {
|
||||
opacity: 0.25;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@media (max-width: 479px) {
|
||||
.lt-footer { flex-direction: column; align-items: flex-start; gap: 0.25rem; }
|
||||
.lt-footer-hints { gap: 0.5rem; }
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ $pageTitle = 'Dashboard';
|
||||
$activeNav = 'dashboard';
|
||||
$pageStyles = ['/assets/css/dashboard.css?v=20260327'];
|
||||
$pageScripts = [
|
||||
'/assets/js/ascii-banner.js?v=20260327',
|
||||
'/assets/js/markdown.js?v=20260327',
|
||||
'/assets/js/dashboard.js?v=20260327',
|
||||
'/assets/js/advanced-search.js?v=20260327',
|
||||
|
||||
@@ -45,7 +45,8 @@ include __DIR__ . '/../../views/layout_header.php';
|
||||
<td data-label="Name"><strong><?= htmlspecialchars($tpl['template_name']) ?></strong></td>
|
||||
<td data-label="Category" class="lt-text-xs"><?= htmlspecialchars($tpl['category'] ?? 'Any') ?></td>
|
||||
<td data-label="Type" class="lt-text-xs"><?= htmlspecialchars($tpl['type'] ?? 'Any') ?></td>
|
||||
<td data-label="Priority" class="lt-text-xs"><span class="lt-p<?= $tpl['default_priority'] ?? 4 ?>">P<?= $tpl['default_priority'] ?? 4 ?></span></td>
|
||||
<?php $tp = (int)($tpl['default_priority'] ?? 4); $tChip = match($tp) { 1 => 'lt-chip-critical', 2 => 'lt-chip-warn', 3 => 'lt-chip-info', default => 'lt-chip-ok' }; ?>
|
||||
<td data-label="Priority"><span class="lt-chip <?= $tChip ?>">P<?= $tp ?></span></td>
|
||||
<td data-label="Status">
|
||||
<span class="lt-status <?= ($tpl['is_active'] ?? 1) ? 'lt-status-open' : 'lt-status-closed' ?>">
|
||||
<?= ($tpl['is_active'] ?? 1) ? 'Active' : 'Inactive' ?>
|
||||
|
||||
+61
-2
@@ -18,6 +18,43 @@
|
||||
|
||||
</main><!-- /#main-content / .lt-main -->
|
||||
|
||||
<!-- ================================================================
|
||||
FOOTER — keyboard hint bar + version
|
||||
================================================================ -->
|
||||
<?php
|
||||
// Context-sensitive keyboard hints based on active nav
|
||||
$_ltf_nav = $activeNav ?? 'dashboard';
|
||||
$_ltf_isTicket = str_starts_with($pageTitle ?? '', 'Ticket #');
|
||||
?>
|
||||
<footer class="lt-footer" role="contentinfo" aria-label="Keyboard shortcuts and app info">
|
||||
<nav class="lt-footer-hints" aria-label="Keyboard shortcuts">
|
||||
<?php if ($_ltf_isTicket): ?>
|
||||
<a href="/" class="lt-footer-hint" title="Go to dashboard"><span class="lt-footer-key">[ ← ]</span> BACK</a>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<span class="lt-footer-hint" title="Press 1–4 to change status"><span class="lt-footer-key">[ 1-4 ]</span> STATUS</span>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<span class="lt-footer-hint" title="Press C to jump to comment box"><span class="lt-footer-key">[ C ]</span> COMMENT</span>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<button type="button" class="lt-footer-hint" data-action="open-settings" title="Open settings"><span class="lt-footer-key">[ * ]</span> CFG</button>
|
||||
<?php elseif (str_starts_with($_ltf_nav, 'admin')): ?>
|
||||
<a href="/" class="lt-footer-hint" title="Go to dashboard"><span class="lt-footer-key">[ ~ ]</span> HOME</a>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<button type="button" class="lt-footer-hint" data-action="open-settings" title="Open settings"><span class="lt-footer-key">[ * ]</span> CFG</button>
|
||||
<?php else: ?>
|
||||
<a href="/" class="lt-footer-hint" title="Go to dashboard (G then D)"><span class="lt-footer-key">[ ~ ]</span> HOME</a>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<span class="lt-footer-hint" title="Press / or Ctrl+K to search"><span class="lt-footer-key">[ / ]</span> SEARCH</span>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<a href="/ticket/create" class="lt-footer-hint" title="Create new ticket (N)"><span class="lt-footer-key">[ + ]</span> NEW</a>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<button type="button" class="lt-footer-hint" data-action="open-settings" title="Open settings"><span class="lt-footer-key">[ * ]</span> CFG</button>
|
||||
<?php endif ?>
|
||||
<span class="lt-footer-sep">|</span>
|
||||
<button type="button" class="lt-footer-hint" data-action="show-keyboard-help" title="Show keyboard shortcuts (?)"><span class="lt-footer-key">[ ? ]</span> HELP</button>
|
||||
</nav>
|
||||
<span aria-label="Application version">TINKER TICKETS — TDS v1.2</span>
|
||||
</footer>
|
||||
|
||||
<!-- base.js + utils.js + globals already loaded in <head> via layout_header.php -->
|
||||
|
||||
<?php if (!empty($pageScripts)): ?>
|
||||
@@ -34,11 +71,33 @@
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- LT INIT — runs boot animation once per session, then sets up UI handlers -->
|
||||
<!-- LT INIT — boot animation + global UI init (base.js handles keys/nav automatically) -->
|
||||
<script nonce="<?= htmlspecialchars($nonce, ENT_QUOTES, 'UTF-8') ?>">
|
||||
if (window.lt) {
|
||||
lt.init({ bootName: 'TINKER TICKETS', skipBoot: false });
|
||||
lt.init({ bootName: 'TINKER TICKETS' });
|
||||
}
|
||||
|
||||
// Footer hint bar actions (keyboard help + settings — work on all pages)
|
||||
document.addEventListener('click', function(e) {
|
||||
var btn = e.target.closest('[data-action]');
|
||||
if (!btn) return;
|
||||
var action = btn.getAttribute('data-action');
|
||||
if (action === 'show-keyboard-help') {
|
||||
if (typeof showKeyboardHelp === 'function') {
|
||||
showKeyboardHelp();
|
||||
} else if (window.lt) {
|
||||
var h = document.getElementById('lt-keys-help');
|
||||
if (h) lt.modal.open('lt-keys-help');
|
||||
else lt.toast.info('Keyboard shortcuts: ESC=close Ctrl+K=search ?=this help');
|
||||
}
|
||||
} else if (action === 'open-settings' || action === 'open-settings-modal') {
|
||||
if (typeof openSettingsModal === 'function') {
|
||||
openSettingsModal();
|
||||
} else if (window.lt) {
|
||||
lt.toast.info('Settings available on the Dashboard');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user