Accessibility pass: ARIA roles, label associations, CSS class migrations

- Add role=dialog/aria-modal/aria-labelledby to all 12 modal overlays (JS + PHP)
- Add aria-label="Close" to all 14 modal close buttons
- Add full ARIA combobox pattern to @mention autocomplete (listbox, option, aria-selected, aria-expanded)
- Add for= attributes to admin filter form labels (AuditLog, UserActivity, ApiKeys)
- Remove dead closeOnAdvancedSearchBackdropClick() from advanced-search.js

CSS/JS style cleanup:
- Move .ascii-banner static styles from JS inline to CSS class; add .ascii-banner--glow
- Add .ascii-banner-cursor, .loading-overlay--hiding, .has-overlay, tr[data-clickable]
- Add .animate-fadein/.animate-fadeout/.comment--deleting to ticket.css
- Add .lt-toast--hiding to base.css; remove opacity/transition inline JS
- Remove redundant cursor:pointer JS (already in th{} CSS rule)
- Remove trailing space in lt-select class attributes

Bug fixes:
- base.js: boot overlay opacity inline style was overriding .fade-out class opacity via
  specificity (1000 vs 20), preventing the fade-out animation — removed
- ascii-banner.js: cursor used blink-caret (border-color only) instead of blink-cursor
  (opacity-based), so the █ cursor never actually blinked — fixed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 20:29:58 -04:00
parent 11f75fd823
commit 7695c6134c
21 changed files with 929 additions and 610 deletions

View File

@@ -13,8 +13,8 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<title>User Activity - Admin</title>
<link rel="icon" type="image/png" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/images/favicon.png">
<link rel="stylesheet" href="/assets/css/base.css">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260320">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260320">
<script nonce="<?php echo $nonce; ?>" src="/assets/js/base.js"></script>
<script nonce="<?php echo $nonce; ?>">
window.CSRF_TOKEN = '<?php echo CsrfMiddleware::getToken(); ?>';
@@ -24,7 +24,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<div class="user-header">
<div class="user-header-left">
<a href="/" class="back-link">[ ← DASHBOARD ]</a>
<span style="margin-left: 1rem; color: var(--terminal-amber);">Admin: User Activity</span>
<span class="admin-page-title">Admin: User Activity</span>
</div>
<div class="user-header-right">
<?php if (isset($GLOBALS['currentUser'])): ?>
@@ -34,7 +34,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
</div>
<div class="ascii-frame-outer" style="max-width: 1200px; margin: 2rem auto;">
<div class="ascii-frame-outer admin-container">
<span class="bottom-left-corner">╚</span>
<span class="bottom-right-corner">╝</span>
@@ -42,37 +42,38 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<div class="ascii-content">
<div class="ascii-frame-inner">
<!-- Date Range Filter -->
<form method="GET" style="display: flex; gap: 1rem; margin-bottom: 1.5rem; align-items: flex-end;">
<div>
<label style="display: block; font-size: 0.8rem; color: var(--terminal-amber);">Date From</label>
<input type="date" name="date_from" value="<?php echo htmlspecialchars($dateRange['from'] ?? ''); ?>" class="setting-select">
<form method="GET" class="admin-form-row">
<div class="admin-form-field">
<label class="admin-label" for="date_from">Date From</label>
<input type="date" name="date_from" id="date_from" value="<?php echo htmlspecialchars($dateRange['from'] ?? ''); ?>" class="admin-input">
</div>
<div>
<label style="display: block; font-size: 0.8rem; color: var(--terminal-amber);">Date To</label>
<input type="date" name="date_to" value="<?php echo htmlspecialchars($dateRange['to'] ?? ''); ?>" class="setting-select">
<div class="admin-form-field">
<label class="admin-label" for="date_to">Date To</label>
<input type="date" name="date_to" id="date_to" value="<?php echo htmlspecialchars($dateRange['to'] ?? ''); ?>" class="admin-input">
</div>
<div class="admin-form-actions">
<button type="submit" class="btn">APPLY</button>
<a href="?" class="btn btn-secondary">RESET</a>
</div>
<button type="submit" class="btn">APPLY</button>
<a href="?" class="btn btn-secondary">RESET</a>
</form>
<!-- User Activity Table -->
<table style="width: 100%;">
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>User</th>
<th style="text-align: center;">Tickets Created</th>
<th style="text-align: center;">Tickets Resolved</th>
<th style="text-align: center;">Comments Added</th>
<th style="text-align: center;">Tickets Assigned</th>
<th style="text-align: center;">Last Activity</th>
<th class="text-center">Tickets Created</th>
<th class="text-center">Tickets Resolved</th>
<th class="text-center">Comments Added</th>
<th class="text-center">Tickets Assigned</th>
<th class="text-center">Last Activity</th>
</tr>
</thead>
<tbody>
<?php if (empty($userStats)): ?>
<tr>
<td colspan="6" style="text-align: center; padding: 2rem; color: var(--terminal-green-dim);">
No user activity data available.
</td>
<td colspan="6" class="empty-state">No user activity data available.</td>
</tr>
<?php else: ?>
<?php foreach ($userStats as $user): ?>
@@ -80,22 +81,22 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<td>
<strong><?php echo htmlspecialchars($user['display_name'] ?? $user['username']); ?></strong>
<?php if ($user['is_admin']): ?>
<span class="admin-badge" style="font-size: 0.7rem;">[ ADMIN ]</span>
<span class="admin-badge">[ ADMIN ]</span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<span style="color: var(--terminal-green); font-weight: bold;"><?php echo $user['tickets_created'] ?? 0; ?></span>
<td class="text-center">
<span class="text-green fw-bold"><?php echo $user['tickets_created'] ?? 0; ?></span>
</td>
<td style="text-align: center;">
<span style="color: var(--status-open); font-weight: bold;"><?php echo $user['tickets_resolved'] ?? 0; ?></span>
<td class="text-center">
<span class="text-open fw-bold"><?php echo $user['tickets_resolved'] ?? 0; ?></span>
</td>
<td style="text-align: center;">
<span style="color: var(--terminal-cyan); font-weight: bold;"><?php echo $user['comments_added'] ?? 0; ?></span>
<td class="text-center">
<span class="text-cyan fw-bold"><?php echo $user['comments_added'] ?? 0; ?></span>
</td>
<td style="text-align: center;">
<span style="color: var(--terminal-amber); font-weight: bold;"><?php echo $user['tickets_assigned'] ?? 0; ?></span>
<td class="text-center">
<span class="text-amber fw-bold"><?php echo $user['tickets_assigned'] ?? 0; ?></span>
</td>
<td style="text-align: center; font-size: 0.9rem;">
<td class="text-center text-sm">
<?php echo $user['last_activity'] ? date('M d, Y H:i', strtotime($user['last_activity'])) : 'Never'; ?>
</td>
</tr>
@@ -103,42 +104,32 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Summary Stats -->
<?php if (!empty($userStats)): ?>
<div style="margin-top: 2rem; padding: 1rem; border: 1px solid var(--terminal-green);">
<h4 style="color: var(--terminal-amber); margin-bottom: 1rem;">Summary</h4>
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; text-align: center;">
<div>
<div style="font-size: 1.5rem; color: var(--terminal-green); font-weight: bold;">
<?php echo array_sum(array_column($userStats, 'tickets_created')); ?>
</div>
<div style="font-size: 0.8rem; color: var(--terminal-green-dim);">Total Created</div>
</div>
<div>
<div style="font-size: 1.5rem; color: var(--status-open); font-weight: bold;">
<?php echo array_sum(array_column($userStats, 'tickets_resolved')); ?>
</div>
<div style="font-size: 0.8rem; color: var(--terminal-green-dim);">Total Resolved</div>
</div>
<div>
<div style="font-size: 1.5rem; color: var(--terminal-cyan); font-weight: bold;">
<?php echo array_sum(array_column($userStats, 'comments_added')); ?>
</div>
<div style="font-size: 0.8rem; color: var(--terminal-green-dim);">Total Comments</div>
</div>
<div>
<div style="font-size: 1.5rem; color: var(--terminal-amber); font-weight: bold;">
<?php echo count($userStats); ?>
</div>
<div style="font-size: 0.8rem; color: var(--terminal-green-dim);">Active Users</div>
</div>
<div class="admin-stats-grid">
<div>
<div class="admin-stat-value text-green"><?php echo array_sum(array_column($userStats, 'tickets_created')); ?></div>
<div class="admin-stat-label">Total Created</div>
</div>
<div>
<div class="admin-stat-value text-open"><?php echo array_sum(array_column($userStats, 'tickets_resolved')); ?></div>
<div class="admin-stat-label">Total Resolved</div>
</div>
<div>
<div class="admin-stat-value text-cyan"><?php echo array_sum(array_column($userStats, 'comments_added')); ?></div>
<div class="admin-stat-label">Total Comments</div>
</div>
<div>
<div class="admin-stat-value text-amber"><?php echo count($userStats); ?></div>
<div class="admin-stat-label">Active Users</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<script>if (window.lt) lt.keys.initDefaults();</script>
<script nonce="<?php echo $nonce; ?>">if (window.lt) lt.keys.initDefaults();</script>
</body>
</html>