Refactor HTML structure and CSS classes for video player and chat components to improve accessibility and maintainability

This commit is contained in:
Vincent 2025-09-28 22:46:56 -04:00
parent 14bc8e6f44
commit 9ca65f3c62
2 changed files with 103 additions and 103 deletions

View file

@ -315,32 +315,32 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
<link href="static/css/utilities.css" rel="stylesheet"> <link href="static/css/utilities.css" rel="stylesheet">
</head> </head>
<body> <body>
<div class="theater-container"> <main class="theater" role="main">
<div class="video-section" id="videoSection"> <section class="theater__video-section" id="videoSection" aria-label="Video Player">
<div class="video-header"> <header class="video-player__header">
<div class="header-left"> <div class="video-player__header-left">
<div class="logo">DODGERS STREAM</div> <h1 class="stream-logo">DODGERS STREAM</h1>
<div class="stream-stats"> <div class="stream-stats">
<div class="stream-badge">WAITING...</div> <span class="stream-stats__status" role="status">WAITING...</span>
<div class="viewer-count" id="viewerCount">0 viewers</div> <span class="stream-stats__viewer-count" id="viewerCount" aria-live="polite">0 viewers</span>
</div> </div>
</div> </div>
<div class="header-controls"> <div class="video-player__header-controls">
<button class="manual-refresh-btn" onclick="manualRecovery()" title="Manual Stream Refresh"> <button class="stream-stats__refresh-btn" data-action="manual-refresh" title="Manual Stream Refresh" aria-label="Refresh stream">
🔄 Refresh 🔄 Refresh
</button> </button>
<select class="quality-selector" id="qualitySelector" style="display:none;"> <select class="video-player__quality-selector" id="qualitySelector" style="display:none;" aria-label="Video quality">
<option value="auto">Auto Quality</option> <option value="auto">Auto Quality</option>
<option value="1080p">1080p</option> <option value="1080p">1080p</option>
<option value="720p">720p</option> <option value="720p">720p</option>
<option value="480p">480p</option> <option value="480p">480p</option>
</select> </select>
<button class="toggle-chat-btn" onclick="toggleChat()"> <button class="video-player__toggle-chat-btn" data-action="toggle-chat" aria-expanded="false" aria-controls="chatSection">
<span id="chatToggleText">Hide Chat</span> <span id="chatToggleText">Hide Chat</span>
<span class="notification-badge" id="notificationBadge">0</span> <span class="video-player__notification-badge" id="notificationBadge" aria-label="New messages">0</span>
</button> </button>
</div> </div>
</div> </header>
<div class="video-wrapper"> <div class="video-wrapper">
<video <video
id="video-player" id="video-player"
@ -358,46 +358,46 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
</div> </div>
</div> </div>
<div class="chat-section" id="chatSection"> <aside class="theater__chat-section" id="chatSection" aria-label="Live Chat">
<div class="chat-header"> <header class="chat__header">
<div class="chat-header-left">Live Chat</div> <h2 class="chat__header-title">Live Chat</h2>
<div class="admin-controls" id="adminControls" style="display:none;"> <div class="chat__admin-controls" id="adminControls" style="display:none;">
<button class="admin-btn" onclick="clearChat()">Clear</button> <button class="chat__admin-btn" data-action="clear-chat" aria-label="Clear all chat messages">Clear</button>
</div> </div>
</div> </header>
<div class="user-info"> <section class="chat__user-info" aria-labelledby="user-info-heading">
<div class="user-id-display"> <h3 id="user-info-heading" class="sr-only">User Information</h3>
Your ID: <span class="id-badge" id="userId">Loading...</span> <div class="chat__user-id-display">
Your ID: <span class="chat__user-id-badge" id="userId">Loading...</span>
</div> </div>
<div class="nickname-input"> <div class="chat__nickname-input">
<input type="text" id="nickname" placeholder="Choose a nickname..." maxlength="20" autocomplete="off"> <input type="text" id="nickname" placeholder="Choose a nickname..." maxlength="20" autocomplete="off" aria-label="Enter your nickname">
</div> </div>
</div> </section>
<div class="connection-status"> <div class="chat__connection-status" aria-live="assertive">
<span class="status-dot" id="statusDot"></span> <span class="chat__connection-indicator" id="statusDot" role="status" aria-label="Connection status"></span>
<span id="statusText">Connected</span> <span id="statusText">Connected</span>
</div> </div>
<div class="chat-messages" id="chatMessages"> <section class="chat__messages" id="chatMessages" aria-live="polite" aria-label="Chat messages" role="log" aria-atomic="false">
<div class="empty-chat">No messages yet. Be the first to say hello! 👋</div> <div class="chat__empty-state">No messages yet. Be the first to say hello! 👋</div>
</div> </section>
<div class="typing-indicator" id="typingIndicator"> <div class="chat__typing-indicator" id="typingIndicator" aria-live="assertive">
Someone is typing<span>.</span><span>.</span><span>.</span> Someone is typing<span>.</span><span>.</span><span>.</span>
</div> </div>
<div class="chat-input">
<div class="input-group">
<input type="text" id="messageInput" placeholder="Type a message..." maxlength="1000" autocomplete="off">
<button onclick="sendMessage()">Send</button>
</div>
</div>
</div>
</div>
</div> <section class="chat__input" aria-labelledby="chat-input-heading">
<h3 id="chat-input-heading" class="sr-only">Send Message</h3>
<div class="chat__input-group">
<input type="text" id="messageInput" placeholder="Type a message..." maxlength="1000" autocomplete="off" aria-label="Type your message">
<button data-action="send-message" aria-label="Send message">Send</button>
</div>
</section>
</aside>
</main>
<!-- Toast Notification --> <!-- Toast Notification -->
<div class="toast" id="toast"></div> <div class="toast" id="toast"></div>

View file

@ -4,7 +4,7 @@
VIDEO HEADER - Top section of video area VIDEO HEADER - Top section of video area
================================================================= */ ================================================================= */
.video-header { .video-player__header {
background: linear-gradient(135deg, var(--dodgers-blue-700) 0%, var(--dodgers-blue-500) 100%); background: linear-gradient(135deg, var(--dodgers-blue-700) 0%, var(--dodgers-blue-500) 100%);
padding: var(--spacing-3) var(--spacing-5); padding: var(--spacing-3) var(--spacing-5);
display: flex; display: flex;
@ -14,13 +14,13 @@
z-index: 10; z-index: 10;
} }
.header-left { .video-player__header-left {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--spacing-5); gap: var(--spacing-5);
} }
.logo { .stream-logo {
font-size: var(--font-size-xl); font-size: var(--font-size-xl);
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
color: white; color: white;
@ -30,7 +30,7 @@
gap: var(--spacing-2); gap: var(--spacing-2);
} }
.logo::before { .stream-logo::before {
content: "⚾"; content: "⚾";
font-size: var(--font-size-2xl); font-size: var(--font-size-2xl);
} }
@ -45,7 +45,18 @@
gap: var(--spacing-4); gap: var(--spacing-4);
} }
.viewer-count { .stream-stats__status {
background: var(--dodgers-red);
color: white;
padding: var(--spacing-2) var(--spacing-4);
border-radius: var(--border-radius-2xl);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-bold);
text-transform: uppercase;
animation: pulse 2s infinite;
}
.stream-stats__viewer-count {
background: rgba(255,255,255,0.2); background: rgba(255,255,255,0.2);
padding: var(--spacing-2) var(--spacing-4); padding: var(--spacing-2) var(--spacing-4);
border-radius: var(--border-radius-2xl); border-radius: var(--border-radius-2xl);
@ -58,33 +69,22 @@
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
} }
.viewer-count::before { .stream-stats__viewer-count::before {
content: "👥"; content: "👥";
} }
.stream-badge {
background: var(--dodgers-red);
color: white;
padding: var(--spacing-2) var(--spacing-4);
border-radius: var(--border-radius-2xl);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-bold);
text-transform: uppercase;
animation: pulse 2s infinite;
}
/* ================================================================= /* =================================================================
HEADER CONTROLS - Buttons and selectors HEADER CONTROLS - Buttons and selectors
================================================================= */ ================================================================= */
.header-controls { .video-player__header-controls {
display: flex; display: flex;
gap: var(--spacing-3); gap: var(--spacing-3);
align-items: center; align-items: center;
} }
/* Ensure all header control buttons have identical dimensions */ /* Ensure all header control buttons have identical dimensions */
.header-controls > * { .video-player__header-controls > * {
height: 35px; height: 35px;
display: flex; display: flex;
align-items: center; align-items: center;
@ -94,7 +94,7 @@
line-height: 1; line-height: 1;
} }
.quality-selector { .video-player__quality-selector {
background: rgba(255,255,255,0.2); background: rgba(255,255,255,0.2);
border: none; border: none;
color: white; color: white;
@ -111,7 +111,7 @@
min-height: auto; min-height: auto;
} }
.toggle-chat-btn { .video-player__toggle-chat-btn {
background: rgba(255,255,255,0.2); background: rgba(255,255,255,0.2);
border: none; border: none;
color: white; color: white;
@ -125,12 +125,12 @@
position: relative; position: relative;
} }
.toggle-chat-btn:hover { .video-player__toggle-chat-btn:hover {
background: rgba(255,255,255,0.3); background: rgba(255,255,255,0.3);
transform: translateY(-1px); transform: translateY(-1px);
} }
.manual-refresh-btn { .stream-stats__refresh-btn {
background: rgba(255,255,255,0.2); background: rgba(255,255,255,0.2);
border: none; border: none;
color: white; color: white;
@ -144,7 +144,7 @@
position: relative; position: relative;
} }
.manual-refresh-btn:hover { .stream-stats__refresh-btn:hover {
background: rgba(255,255,255,0.3); background: rgba(255,255,255,0.3);
transform: translateY(-1px); transform: translateY(-1px);
} }
@ -153,7 +153,7 @@
CHAT HEADER CHAT HEADER
================================================================= */ ================================================================= */
.chat-header { .chat__header {
background: linear-gradient(135deg, var(--dodgers-blue-500) 0%, var(--dodgers-blue-300) 100%); background: linear-gradient(135deg, var(--dodgers-blue-500) 0%, var(--dodgers-blue-300) 100%);
padding: var(--spacing-4) var(--spacing-5); padding: var(--spacing-4) var(--spacing-5);
color: white; color: white;
@ -165,23 +165,23 @@
justify-content: space-between; justify-content: space-between;
} }
.chat-header-left { .chat__header-title {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--spacing-2); gap: var(--spacing-2);
} }
.chat-header-left::before { .chat__header-title::before {
content: "💬"; content: "💬";
font-size: var(--font-size-lg); font-size: var(--font-size-lg);
} }
.admin-controls { .chat__admin-controls {
display: flex; display: flex;
gap: var(--spacing-2); gap: var(--spacing-2);
} }
.admin-btn { .chat__admin-btn {
background: rgba(255,215,0,0.3); background: rgba(255,215,0,0.3);
border: 1px solid var(--dodgers-gold); border: 1px solid var(--dodgers-gold);
color: white; color: white;
@ -192,7 +192,7 @@
transition: all var(--transition-fast); transition: all var(--transition-fast);
} }
.admin-btn:hover { .chat__admin-btn:hover {
background: rgba(255,215,0,0.5); background: rgba(255,215,0,0.5);
} }
@ -200,13 +200,13 @@
USER INFO SECTION USER INFO SECTION
================================================================= */ ================================================================= */
.user-info { .chat__user-info {
padding: var(--spacing-3) var(--spacing-4); padding: var(--spacing-3) var(--spacing-4);
background: var(--card-bg); background: var(--card-bg);
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
.user-id-display { .chat__user-id-display {
font-size: var(--font-size-xs); font-size: var(--font-size-xs);
color: var(--text-muted); color: var(--text-muted);
margin-bottom: var(--spacing-2); margin-bottom: var(--spacing-2);
@ -215,7 +215,7 @@
gap: var(--spacing-2); gap: var(--spacing-2);
} }
.id-badge { .chat__user-id-badge {
background: var(--dodgers-blue-500); background: var(--dodgers-blue-500);
color: white; color: white;
padding: var(--spacing-1) var(--spacing-2); padding: var(--spacing-1) var(--spacing-2);
@ -224,16 +224,16 @@
font-family: var(--font-family-mono); font-family: var(--font-family-mono);
} }
.id-badge.admin { .chat__user-id-badge.admin {
background: linear-gradient(135deg, var(--dodgers-gold), #FFB700); background: linear-gradient(135deg, var(--dodgers-gold), #FFB700);
color: #333; color: #333;
} }
.nickname-input { .chat__nickname-input {
position: relative; position: relative;
} }
.nickname-input input { .chat__nickname-input input {
width: 100%; width: 100%;
padding: var(--spacing-3) var(--spacing-3); padding: var(--spacing-3) var(--spacing-3);
border: 2px solid var(--border-color); border: 2px solid var(--border-color);
@ -244,11 +244,11 @@
color: var(--text-primary); color: var(--text-primary);
} }
.nickname-input input::placeholder { .chat__nickname-input input::placeholder {
color: var(--text-muted); color: var(--text-muted);
} }
.nickname-input input:focus { .chat__nickname-input input:focus {
outline: none; outline: none;
border-color: var(--dodgers-blue-500); border-color: var(--dodgers-blue-500);
box-shadow: 0 0 0 3px var(--focus-ring); box-shadow: 0 0 0 3px var(--focus-ring);
@ -258,7 +258,7 @@
CHAT MESSAGES CONTAINER CHAT MESSAGES CONTAINER
================================================================= */ ================================================================= */
.chat-messages { .chat__messages {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: var(--spacing-4); padding: var(--spacing-4);
@ -378,7 +378,7 @@
border-radius: var(--border-radius-md); border-radius: var(--border-radius-md);
} }
.typing-indicator { .chat__typing-indicator {
padding: 0 var(--spacing-4) var(--spacing-2); padding: 0 var(--spacing-4) var(--spacing-2);
font-size: var(--font-size-xs); font-size: var(--font-size-xs);
color: var(--text-muted); color: var(--text-muted);
@ -386,19 +386,19 @@
display: none; display: none;
} }
.typing-indicator.active { .chat__typing-indicator.active {
display: block; display: block;
} }
.typing-indicator span { .chat__typing-indicator span {
animation: blink 1.4s infinite; animation: blink 1.4s infinite;
} }
.typing-indicator span:nth-child(2) { .chat__typing-indicator span:nth-child(2) {
animation-delay: 0.2s; animation-delay: 0.2s;
} }
.typing-indicator span:nth-child(3) { .chat__typing-indicator span:nth-child(3) {
animation-delay: 0.4s; animation-delay: 0.4s;
} }
@ -406,18 +406,18 @@
CHAT INPUT AREA CHAT INPUT AREA
================================================================= */ ================================================================= */
.chat-input { .chat__input {
padding: var(--spacing-3) var(--spacing-4); padding: var(--spacing-3) var(--spacing-4);
background: var(--card-bg); background: var(--card-bg);
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
} }
.input-group { .chat__input-group {
display: flex; display: flex;
gap: var(--spacing-2); gap: var(--spacing-2);
} }
.chat-input input { .chat__input input {
flex: 1; flex: 1;
padding: var(--spacing-3) var(--spacing-4); padding: var(--spacing-3) var(--spacing-4);
border: 2px solid var(--border-color); border: 2px solid var(--border-color);
@ -428,17 +428,17 @@
color: var(--text-primary); color: var(--text-primary);
} }
.chat-input input::placeholder { .chat__input input::placeholder {
color: var(--text-muted); color: var(--text-muted);
} }
.chat-input input:focus { .chat__input input:focus {
outline: none; outline: none;
border-color: var(--dodgers-blue-500); border-color: var(--dodgers-blue-500);
box-shadow: 0 0 0 3px var(--focus-ring); box-shadow: 0 0 0 3px var(--focus-ring);
} }
.chat-input button { .chat__input button {
padding: var(--spacing-3) var(--spacing-5); padding: var(--spacing-3) var(--spacing-5);
background: linear-gradient(135deg, var(--dodgers-blue-500), var(--dodgers-blue-300)); background: linear-gradient(135deg, var(--dodgers-blue-500), var(--dodgers-blue-300));
color: white; color: white;
@ -451,16 +451,16 @@
box-shadow: var(--shadow-dodgers-sm); box-shadow: var(--shadow-dodgers-sm);
} }
.chat-input button:hover { .chat__input button:hover {
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: var(--shadow-dodgers-md); box-shadow: var(--shadow-dodgers-md);
} }
.chat-input button:active { .chat__input button:active {
transform: translateY(0); transform: translateY(0);
} }
.empty-chat { .chat__empty-state {
text-align: center; text-align: center;
color: var(--text-muted); color: var(--text-muted);
padding: var(--spacing-12) var(--spacing-5); padding: var(--spacing-12) var(--spacing-5);
@ -471,7 +471,7 @@
CONNECTION STATUS CONNECTION STATUS
================================================================= */ ================================================================= */
.connection-status { .chat__connection-status {
padding: var(--spacing-2); padding: var(--spacing-2);
background: var(--bg-darker); background: var(--bg-darker);
text-align: center; text-align: center;
@ -484,7 +484,7 @@
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
} }
.status-dot { .chat__connection-indicator {
width: var(--spacing-2); width: var(--spacing-2);
height: var(--spacing-2); height: var(--spacing-2);
border-radius: 50%; border-radius: 50%;
@ -492,7 +492,7 @@
animation: blink 2s infinite; animation: blink 2s infinite;
} }
.status-dot.offline { .chat__connection-indicator.offline {
background: #f44336; background: #f44336;
animation: none; animation: none;
} }
@ -520,7 +520,7 @@
opacity: 1; opacity: 1;
} }
.notification-badge { .video-player__notification-badge {
position: absolute; position: absolute;
top: calc(var(--spacing-2) * -1); top: calc(var(--spacing-2) * -1);
right: calc(var(--spacing-2) * -1); right: calc(var(--spacing-2) * -1);
@ -534,7 +534,7 @@
animation: bounce 0.5s; animation: bounce 0.5s;
} }
.notification-badge.show { .video-player__notification-badge.show {
display: block; display: block;
} }