Enhance CSS/HTML with semantic elements, utility classes, and breakpoints

- Move inline styles to CSS classes in ticket.css and dashboard.css
- Add intermediate responsive breakpoints (600px, 900px, 1200px)
- Convert HTML to semantic elements (header, section, article)
- Add ARIA attributes for modals and navigation
- Add utility classes for text styling and spacing
- Update cache-busting version numbers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 10:29:20 -05:00
parent 73162d9a9b
commit 2657e86d24
4 changed files with 461 additions and 101 deletions

View File

@@ -50,12 +50,12 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ticket #<?php echo $ticket['ticket_id']; ?></title>
<link rel="icon" type="image/png" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/images/favicon.png">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260126c">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260124e">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260131a">
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260131a">
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/toast.js"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/markdown.js?v=20260124e"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/dashboard.js?v=20260124e"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/ticket.js?v=20260124e"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/markdown.js?v=20260131a"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/dashboard.js?v=20260131a"></script>
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/ticket.js?v=20260131a"></script>
<script nonce="<?php echo $nonce; ?>">
// CSRF Token for AJAX requests
window.CSRF_TOKEN = '<?php echo CsrfMiddleware::getToken(); ?>';
@@ -77,7 +77,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</script>
</head>
<body>
<div class="user-header">
<header class="user-header">
<div class="user-header-left">
<a href="/" class="back-link">← Dashboard</a>
</div>
@@ -90,8 +90,10 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<button class="settings-icon" title="Settings (Alt+S)" id="settingsBtn" aria-label="Settings">⚙</button>
<?php endif; ?>
</div>
</div>
<div class="ticket-container ascii-frame-outer" data-priority="<?php echo $ticket["priority"]; ?>">
</header>
<main>
<h1 class="sr-only">Ticket: <?php echo htmlspecialchars($ticket["title"]); ?></h1>
<article class="ticket-container ascii-frame-outer" data-priority="<?php echo $ticket["priority"]; ?>">
<span class="bottom-left-corner">╚</span>
<span class="bottom-right-corner">╝</span>
@@ -132,7 +134,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<span class="age-icon"><?php echo $ageClass === 'age-critical' ? '⚠️' : ($ageClass === 'age-warning' ? '⏰' : '📅'); ?></span>
<span class="age-text">Last activity: <?php echo $ageStr; ?> ago</span>
</div>
<div class="ticket-user-info" style="font-size: 0.85rem; color: #666; margin-top: 0.25rem;">
<div class="ticket-user-info">
<?php
$creator = $ticket['creator_display_name'] ?? $ticket['creator_username'] ?? 'System';
echo "Created by: <strong>" . htmlspecialchars($creator) . "</strong>";
@@ -148,9 +150,9 @@ $nonce = SecurityHeadersMiddleware::getNonce();
}
?>
</div>
<div class="ticket-assignment" style="margin-top: 0.5rem;">
<label style="font-weight: 500; margin-right: 0.5rem;">Assigned to:</label>
<select id="assignedToSelect" class="assignment-select" style="padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green);">
<div class="ticket-assignment">
<label class="ticket-assignment-label">Assigned to:</label>
<select id="assignedToSelect" class="assignment-select">
<option value="">Unassigned</option>
<?php foreach ($allUsers as $user): ?>
<option value="<?php echo $user['user_id']; ?>"
@@ -162,10 +164,10 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
<!-- Metadata Fields: Priority, Category, Type -->
<div class="ticket-metadata-fields" style="margin-top: 0.75rem; display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem;">
<div class="ticket-metadata-fields">
<div class="metadata-field">
<label style="font-weight: 500; display: block; margin-bottom: 0.25rem; color: var(--terminal-amber); font-family: var(--font-mono); font-size: 0.85rem;">Priority:</label>
<select id="prioritySelect" class="metadata-select editable-metadata" disabled style="width: 100%; padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
<label class="metadata-label">Priority:</label>
<select id="prioritySelect" class="metadata-select editable-metadata" disabled>
<option value="1" <?php echo $ticket['priority'] == 1 ? 'selected' : ''; ?>>P1 - Critical</option>
<option value="2" <?php echo $ticket['priority'] == 2 ? 'selected' : ''; ?>>P2 - High</option>
<option value="3" <?php echo $ticket['priority'] == 3 ? 'selected' : ''; ?>>P3 - Medium</option>
@@ -175,8 +177,8 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
<div class="metadata-field">
<label style="font-weight: 500; display: block; margin-bottom: 0.25rem; color: var(--terminal-amber); font-family: var(--font-mono); font-size: 0.85rem;">Category:</label>
<select id="categorySelect" class="metadata-select editable-metadata" disabled style="width: 100%; padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
<label class="metadata-label">Category:</label>
<select id="categorySelect" class="metadata-select editable-metadata" disabled>
<option value="Hardware" <?php echo $ticket['category'] == 'Hardware' ? 'selected' : ''; ?>>Hardware</option>
<option value="Software" <?php echo $ticket['category'] == 'Software' ? 'selected' : ''; ?>>Software</option>
<option value="Network" <?php echo $ticket['category'] == 'Network' ? 'selected' : ''; ?>>Network</option>
@@ -186,8 +188,8 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
<div class="metadata-field">
<label style="font-weight: 500; display: block; margin-bottom: 0.25rem; color: var(--terminal-amber); font-family: var(--font-mono); font-size: 0.85rem;">Type:</label>
<select id="typeSelect" class="metadata-select editable-metadata" disabled style="width: 100%; padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
<label class="metadata-label">Type:</label>
<select id="typeSelect" class="metadata-select editable-metadata" disabled>
<option value="Maintenance" <?php echo $ticket['type'] == 'Maintenance' ? 'selected' : ''; ?>>Maintenance</option>
<option value="Install" <?php echo $ticket['type'] == 'Install' ? 'selected' : ''; ?>>Install</option>
<option value="Task" <?php echo $ticket['type'] == 'Task' ? 'selected' : ''; ?>>Task</option>
@@ -206,31 +208,31 @@ $nonce = SecurityHeadersMiddleware::getNonce();
$visUserModel = new UserModel($conn);
$allAvailableGroups = $visUserModel->getAllGroups();
?>
<div class="ticket-visibility-settings" style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--terminal-green);">
<div style="display: grid; grid-template-columns: 1fr 2fr; gap: 0.75rem;">
<div class="ticket-visibility-settings">
<div class="visibility-settings-grid">
<div class="metadata-field">
<label style="font-weight: 500; display: block; margin-bottom: 0.25rem; color: var(--terminal-cyan); font-family: var(--font-mono); font-size: 0.85rem;">Visibility:</label>
<select id="visibilitySelect" class="metadata-select editable-metadata" disabled data-action="toggle-visibility-groups" style="width: 100%; padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
<label class="metadata-label metadata-label-cyan">Visibility:</label>
<select id="visibilitySelect" class="metadata-select editable-metadata" disabled data-action="toggle-visibility-groups">
<option value="public" <?php echo $currentVisibility == 'public' ? 'selected' : ''; ?>>Public</option>
<option value="internal" <?php echo $currentVisibility == 'internal' ? 'selected' : ''; ?>>Internal</option>
<option value="confidential" <?php echo $currentVisibility == 'confidential' ? 'selected' : ''; ?>>Confidential</option>
</select>
</div>
<div class="metadata-field" id="visibilityGroupsField" style="<?php echo $currentVisibility !== 'internal' ? 'display: none;' : ''; ?>">
<label style="font-weight: 500; display: block; margin-bottom: 0.25rem; color: var(--terminal-cyan); font-family: var(--font-mono); font-size: 0.85rem;">Allowed Groups:</label>
<div class="visibility-groups-edit" style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
<div class="metadata-field" id="visibilityGroupsField" <?php echo $currentVisibility !== 'internal' ? 'style="display: none;"' : ''; ?>>
<label class="metadata-label metadata-label-cyan">Allowed Groups:</label>
<div class="visibility-groups-edit">
<?php foreach ($allAvailableGroups as $group):
$isChecked = in_array($group, $currentVisibilityGroups);
?>
<label style="display: flex; align-items: center; gap: 0.3rem; cursor: pointer;">
<label class="visibility-group-label">
<input type="checkbox" class="visibility-group-checkbox editable-metadata" disabled
value="<?php echo htmlspecialchars($group); ?>"
<?php echo $isChecked ? 'checked' : ''; ?>>
<span class="group-badge" style="font-size: 0.7rem;"><?php echo htmlspecialchars($group); ?></span>
<span class="group-badge"><?php echo htmlspecialchars($group); ?></span>
</label>
<?php endforeach; ?>
<?php if (empty($allAvailableGroups)): ?>
<span style="color: var(--text-muted); font-size: 0.85rem;">No groups available</span>
<span class="no-groups-message">No groups available</span>
<?php endif; ?>
</div>
</div>
@@ -293,7 +295,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
</div>
<div id="comments-tab" class="tab-content" role="tabpanel" aria-labelledby="comments-tab-btn">
<section id="comments-tab" class="tab-content" role="tabpanel" aria-labelledby="comments-tab-btn">
<div class="ascii-subsection-header">Comments Section</div>
<div class="comments-section">
<div class="ascii-frame-inner">
@@ -413,22 +415,22 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<div class="ascii-subsection-header">File Attachments</div>
<div class="attachments-container">
<!-- Upload Form -->
<div class="ascii-frame-inner" style="margin-bottom: 1rem;">
<div class="ascii-frame-inner frame-inner-spacing">
<h3>Upload Files</h3>
<div class="upload-zone" id="uploadZone">
<div class="upload-zone-content">
<div class="upload-icon">📁</div>
<p>Drag and drop files here or click to browse</p>
<p class="upload-hint">Max file size: <?php echo $GLOBALS['config']['MAX_UPLOAD_SIZE'] ? number_format($GLOBALS['config']['MAX_UPLOAD_SIZE'] / 1048576, 0) . 'MB' : '10MB'; ?></p>
<input type="file" id="fileInput" multiple style="display: none;" aria-label="Upload files">
<button type="button" id="browseFilesBtn" class="btn" style="margin-top: 1rem;">Browse Files</button>
<input type="file" id="fileInput" multiple class="sr-only" aria-label="Upload files">
<button type="button" id="browseFilesBtn" class="btn upload-browse-btn">Browse Files</button>
</div>
</div>
<div id="uploadProgress" style="display: none; margin-top: 1rem;">
<div id="uploadProgress" class="upload-progress" style="display: none;">
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<p id="uploadStatus" style="margin-top: 0.5rem; color: var(--terminal-green); font-family: var(--font-mono); font-size: 0.85rem;"></p>
<p id="uploadStatus" class="upload-status-text"></p>
</div>
</div>
@@ -446,14 +448,13 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<div class="ascii-subsection-header">Ticket Dependencies</div>
<div class="dependencies-container">
<!-- Add Dependency Form -->
<div class="ascii-frame-inner" style="margin-bottom: 1rem;">
<div class="ascii-frame-inner frame-inner-spacing">
<h3>Add Dependency</h3>
<div class="add-dependency-form" style="display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center;">
<div class="add-dependency-form">
<label for="dependencyTicketId" class="sr-only">Ticket ID for dependency</label>
<input type="text" id="dependencyTicketId" placeholder="Ticket ID (e.g., 123456789)" aria-label="Ticket ID for dependency"
style="flex: 1; min-width: 150px; padding: 0.5rem; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
<input type="text" id="dependencyTicketId" class="dependency-input" placeholder="Ticket ID (e.g., 123456789)" aria-label="Ticket ID for dependency">
<label for="dependencyType" class="sr-only">Dependency type</label>
<select id="dependencyType" aria-label="Dependency type" style="padding: 0.5rem; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
<select id="dependencyType" class="dependency-type-select" aria-label="Dependency type">
<option value="blocks">Blocks</option>
<option value="blocked_by">Blocked By</option>
<option value="relates_to">Relates To</option>
@@ -472,7 +473,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
<!-- Dependent Tickets -->
<div class="ascii-frame-inner" style="margin-top: 1rem;">
<div class="ascii-frame-inner frame-inner-spacing-top">
<h3>Tickets That Depend On This</h3>
<div id="dependentsList" class="dependencies-list">
<p class="loading-text">Loading dependents...</p>
@@ -510,7 +511,8 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
</div>
</div>
</div>
</article>
</main>
<!-- END OUTER FRAME -->
<script nonce="<?php echo $nonce; ?>">
// Initialize the ticket view and attach event listeners (CSP-compliant)
@@ -685,14 +687,14 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</script>
<!-- Settings Modal (same as dashboard) -->
<div class="settings-modal" id="settingsModal" style="display: none;">
<div class="settings-modal" id="settingsModal" style="display: none;" role="dialog" aria-modal="true" aria-labelledby="ticketSettingsTitle">
<div class="settings-content">
<span class="bottom-left-corner">╚</span>
<span class="bottom-right-corner">╝</span>
<div class="settings-header">
<h3>⚙ System Preferences</h3>
<button class="close-settings" id="closeSettingsBtn">✗</button>
<h3 id="ticketSettingsTitle">⚙ System Preferences</h3>
<button class="close-settings" id="closeSettingsBtn" aria-label="Close settings">✗</button>
</div>
<div class="settings-body">
@@ -806,7 +808,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
endforeach;
if (empty(trim($GLOBALS['currentUser']['groups'] ?? ''))):
?>
<span style="color: var(--text-muted);">No groups assigned</span>
<span class="text-muted">No groups assigned</span>
<?php endif; ?>
</div>
</div>