Move ASCII banner into boot sequence, fix remaining UI issues

- Remove collapsible ASCII banner from dashboard (was cluttering the UI)
- Show ASCII banner in the boot overlay on first session visit, above
  the boot messages, with a 400ms pause before messages begin
- Add scroll fade indicator (green-tinted gradient edges) to .table-wrapper
  so users can see when the table is horizontally scrollable
- Fix null guards for tab switcher in ticket.js (tabEl, activeBtn)
- Fix Reset → RESET uppercase in AuditLogView and UserActivityView

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 10:41:57 -04:00
parent d8220da1e0
commit 1046537429
5 changed files with 39 additions and 48 deletions

View File

@@ -4650,8 +4650,18 @@ table td:nth-child(4) {
overflow-y: visible; overflow-y: visible;
margin: 0; margin: 0;
padding: 0; padding: 0;
/* Subtle scroll hint via gradient on right edge */
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
/* Scroll fade indicator: fades out right edge when content overflows */
background-image:
linear-gradient(to right, var(--bg-primary), var(--bg-primary)),
linear-gradient(to right, var(--bg-primary), var(--bg-primary)),
linear-gradient(to right, rgba(0,255,65,0.12), transparent),
linear-gradient(to left, rgba(0,255,65,0.12), transparent);
background-position: left center, right center, left center, right center;
background-repeat: no-repeat;
background-color: var(--bg-primary);
background-size: 20px 100%, 20px 100%, 12px 100%, 12px 100%;
background-attachment: local, local, scroll, scroll;
} }
@media (max-width: 768px) { @media (max-width: 768px) {

View File

@@ -548,10 +548,13 @@ function showTab(tabName) {
}); });
// Show selected tab and activate its button // Show selected tab and activate its button
document.getElementById(`${tabName}-tab`).style.display = 'block'; const tabEl = document.getElementById(`${tabName}-tab`);
if (tabEl) tabEl.style.display = 'block';
const activeBtn = document.querySelector(`.tab-btn[data-tab="${tabName}"]`); const activeBtn = document.querySelector(`.tab-btn[data-tab="${tabName}"]`);
activeBtn.classList.add('active'); if (activeBtn) {
activeBtn.setAttribute('aria-selected', 'true'); activeBtn.classList.add('active');
activeBtn.setAttribute('aria-selected', 'true');
}
// Load attachments when tab is shown // Load attachments when tab is shown
if (tabName === 'attachments') { if (tabName === 'attachments') {

View File

@@ -33,18 +33,18 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<!-- Terminal Boot Sequence --> <!-- Terminal Boot Sequence -->
<div id="boot-sequence" class="boot-overlay"> <div id="boot-sequence" class="boot-overlay">
<div id="boot-banner" style="text-align:center; margin-bottom: 1rem;"></div>
<pre id="boot-text"></pre> <pre id="boot-text"></pre>
</div> </div>
<script nonce="<?php echo $nonce; ?>"> <script nonce="<?php echo $nonce; ?>">
function showBootSequence() { function showBootSequence() {
const bootText = document.getElementById('boot-text'); const bootText = document.getElementById('boot-text');
const bootOverlay = document.getElementById('boot-sequence'); const bootOverlay = document.getElementById('boot-sequence');
// Render ASCII banner first, then start boot messages
renderResponsiveBanner('#boot-banner', 0);
const messages = [ const messages = [
'╔═══════════════════════════════════════╗',
'║ TINKER TICKETS TERMINAL v1.0 ║',
'║ BOOTING SYSTEM... ║',
'╚═══════════════════════════════════════╝',
'',
'[ OK ] Loading kernel modules...', '[ OK ] Loading kernel modules...',
'[ OK ] Initializing ticket database...', '[ OK ] Initializing ticket database...',
'[ OK ] Mounting user session...', '[ OK ] Mounting user session...',
@@ -56,18 +56,21 @@ $nonce = SecurityHeadersMiddleware::getNonce();
]; ];
let i = 0; let i = 0;
const interval = setInterval(() => { // Brief pause after banner renders before boot text begins
if (i < messages.length) { setTimeout(() => {
bootText.textContent += messages[i] + '\n'; const interval = setInterval(() => {
i++; if (i < messages.length) {
} else { bootText.textContent += messages[i] + '\n';
setTimeout(() => { i++;
bootOverlay.style.opacity = '0'; } else {
setTimeout(() => bootOverlay.remove(), 500); setTimeout(() => {
}, 500); bootOverlay.style.opacity = '0';
clearInterval(interval); setTimeout(() => bootOverlay.remove(), 500);
} }, 500);
}, 80); clearInterval(interval);
}
}, 80);
}, 400);
} }
// Run on first visit only (per session) // Run on first visit only (per session)
@@ -104,28 +107,6 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div> </div>
</header> </header>
<!-- Collapsible ASCII Banner -->
<div class="ascii-banner-wrapper collapsed">
<button class="banner-toggle" data-action="toggle-banner">
<span class="toggle-icon">▼</span> ASCII Banner
</button>
<div id="ascii-banner-container" class="banner-content"></div>
</div>
<script nonce="<?php echo $nonce; ?>">
function toggleBanner() {
const wrapper = document.querySelector('.ascii-banner-wrapper');
const icon = document.querySelector('.toggle-icon');
wrapper.classList.toggle('collapsed');
icon.textContent = wrapper.classList.contains('collapsed') ? '▼' : '▲';
// Render banner on first expand (no animation for instant display)
if (!wrapper.classList.contains('collapsed') && !wrapper.dataset.rendered) {
renderResponsiveBanner('#ascii-banner-container', 0); // Speed 0 = no animation
wrapper.dataset.rendered = 'true';
}
}
</script>
<!-- Dashboard Layout with Sidebar --> <!-- Dashboard Layout with Sidebar -->
<div class="dashboard-layout" id="dashboardLayout"> <div class="dashboard-layout" id="dashboardLayout">
<!-- Left Sidebar with Filters --> <!-- Left Sidebar with Filters -->
@@ -888,9 +869,6 @@ $nonce = SecurityHeadersMiddleware::getNonce();
saveSettings(); saveSettings();
break; break;
case 'toggle-banner':
toggleBanner();
break;
case 'toggle-sidebar': case 'toggle-sidebar':
toggleSidebar(); toggleSidebar();

View File

@@ -78,7 +78,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div> </div>
<div style="display: flex; align-items: flex-end;"> <div style="display: flex; align-items: flex-end;">
<button type="submit" class="btn">FILTER</button> <button type="submit" class="btn">FILTER</button>
<a href="?" class="btn btn-secondary" style="margin-left: 0.5rem;">Reset</a> <a href="?" class="btn btn-secondary" style="margin-left: 0.5rem;">RESET</a>
</div> </div>
</form> </form>

View File

@@ -52,7 +52,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<input type="date" name="date_to" value="<?php echo htmlspecialchars($dateRange['to'] ?? ''); ?>" class="setting-select"> <input type="date" name="date_to" value="<?php echo htmlspecialchars($dateRange['to'] ?? ''); ?>" class="setting-select">
</div> </div>
<button type="submit" class="btn">APPLY</button> <button type="submit" class="btn">APPLY</button>
<a href="?" class="btn btn-secondary">Reset</a> <a href="?" class="btn btn-secondary">RESET</a>
</form> </form>
<!-- User Activity Table --> <!-- User Activity Table -->