Files
hearts/public/index.html
T

443 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Hearts</title>
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#0d2744">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Hearts">
<link rel="apple-touch-icon" href="/icons/icon-192.png">
<link rel="icon" type="image/svg+xml" href="/icons/icon.svg">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- ══════════════ LOBBY ══════════════ -->
<div id="screen-lobby" class="screen active">
<div class="lobby-box">
<h1 class="logo">♥ Hearts ♠</h1>
<p class="tagline">The classic trick-taking card game</p>
<button id="btn-install" class="btn-install hidden">📲 Add to Home Screen</button>
<div id="auth-bar" class="auth-bar">
<span id="auth-status" class="auth-status">Playing as guest</span>
<div class="auth-bar-actions">
<button id="btn-show-leaderboard" class="btn-text">🏆 Leaderboard</button>
<button id="btn-show-profile" class="btn-text hidden">👤 Profile</button>
<button id="btn-logout" class="btn-text hidden">Logout</button>
<button id="btn-show-auth" class="btn-text">Login / Register</button>
</div>
</div>
<div class="field">
<label>Your Name</label>
<input id="input-name" type="text" maxlength="16" placeholder="Enter your name…" autocomplete="off">
</div>
<div class="lobby-tabs">
<button class="tab-btn active" data-tab="create">Create Game</button>
<button class="tab-btn" data-tab="join">Join Game</button>
</div>
<div id="tab-create" class="tab-panel active">
<div class="field">
<label>Score limit <small>(game ends when a player reaches this)</small></label>
<div class="score-limit-row">
<button class="score-btn active" data-score="100">100</button>
<button class="score-btn" data-score="50">50</button>
<button class="score-btn" data-score="200">200</button>
</div>
</div>
<div class="field">
<label>Visibility</label>
<div class="visibility-toggle">
<button class="visibility-btn active" data-public="false">🔒 Private</button>
<button class="visibility-btn" data-public="true">🌐 Public</button>
</div>
</div>
<button id="btn-create" class="btn-primary">Create Game</button>
</div>
<div id="tab-join" class="tab-panel">
<div class="public-rooms-section">
<div class="rooms-header">
<span>Public Rooms</span>
<button id="btn-refresh-rooms" class="btn-refresh">↺ Refresh</button>
</div>
<div id="public-rooms-list"><p class="hint">Switch to this tab to load rooms.</p></div>
</div>
<div class="field">
<label>Or enter a Room Code</label>
<input id="input-code" type="text" maxlength="8" placeholder="e.g. AB12CD" autocomplete="off" style="text-transform:uppercase">
</div>
<button id="btn-join" class="btn-primary">Join by Code</button>
<hr style="border-color:rgba(255,255,255,.1);margin:4px 0">
<div class="field">
<label>Watch as spectator</label>
<input id="input-spectate-code" type="text" maxlength="8" placeholder="Room code" style="text-transform:uppercase" autocomplete="off">
</div>
<button id="btn-spectate" class="btn-secondary">👁 Watch Game</button>
</div>
<p id="lobby-error" class="error-msg"></p>
</div>
</div>
<!-- ══════════════ WAITING ROOM ══════════════ -->
<div id="screen-waiting" class="screen">
<div class="waiting-box">
<button id="btn-leave-waiting" class="btn-leave-screen">← Leave</button>
<h2>Waiting for Players</h2>
<div id="waiting-public-badge" class="waiting-public-badge">🔒 Private</div>
<div class="room-code-box">
<span class="label">Room Code</span>
<span id="display-room-code" class="room-code">——</span>
<button id="btn-copy" class="btn-copy" title="Copy code"></button>
</div>
<p class="hint">Share this code — 4 players needed</p>
<div class="waiting-seats" id="waiting-seats">
<div class="seat-slot" data-seat="0"><span class="seat-num">1</span><span class="seat-name"></span></div>
<div class="seat-slot" data-seat="1"><span class="seat-num">2</span><span class="seat-name"></span></div>
<div class="seat-slot" data-seat="2"><span class="seat-num">3</span><span class="seat-name"></span></div>
<div class="seat-slot" data-seat="3"><span class="seat-num">4</span><span class="seat-name"></span></div>
</div>
<p id="waiting-status" class="waiting-status">Waiting for 3 more players…</p>
<button id="btn-fill-bots" class="btn-fill-bots hidden">🤖 Fill empty seats with bots</button>
</div>
</div>
<!-- ══════════════ GAME TABLE ══════════════ -->
<div id="screen-game" class="screen">
<!-- Info bar -->
<div id="info-bar">
<button id="btn-leave-game" class="btn-leave-screen">← Menu</button>
<!-- Individual scores -->
<div id="score-block">
<div id="score-display"></div>
<div id="hand-points-display"></div>
</div>
<!-- Hearts broken indicator -->
<div id="hearts-broken-display" class="hearts-broken hidden">♥ Broken</div>
<!-- Pass direction indicator -->
<div id="pass-dir-display" class="pass-dir-display hidden"></div>
<div class="game-menu-wrap">
<button id="btn-game-menu" class="btn-leave-screen" title="Options"></button>
<div id="game-menu-dropdown" class="game-menu-dropdown hidden">
<button id="btn-info-pos" class="game-menu-item">↕ Move score bar</button>
<button id="btn-refresh-game" class="game-menu-item">↺ Reload</button>
<button id="btn-exit-game" class="game-menu-item game-menu-exit">🚪 Exit</button>
</div>
</div>
</div>
<!-- Spectator banner -->
<div id="spectator-banner" class="spectator-banner hidden">👁 Spectating — watching only</div>
<!-- AFK warning banner -->
<div id="afk-banner" class="afk-banner hidden">
<span id="afk-banner-msg"></span>
<button id="afk-vote-btn">Let AI Play</button>
<button id="afk-dismiss-btn">Dismiss</button>
</div>
<!-- AI control banner -->
<div id="ai-control-banner" class="ai-control-banner hidden">
<span id="ai-control-msg"></span>
</div>
<!-- Table grid -->
<div id="table-grid">
<!-- Top player -->
<div id="area-top" class="player-area area-top">
<div class="player-label">
<span id="top-name"></span>
<span id="top-turn" class="turn-dot hidden"></span>
<span id="top-score" class="player-score-badge"></span>
</div>
<div id="top-cards" class="opp-cards"></div>
</div>
<!-- Left player -->
<div id="area-left" class="player-area area-left">
<div class="player-label vertical">
<span id="left-name"></span>
<span id="left-turn" class="turn-dot hidden"></span>
<span id="left-score" class="player-score-badge"></span>
</div>
<div id="left-cards" class="opp-cards vertical"></div>
</div>
<!-- Center / trick area -->
<div id="trick-area">
<div id="trick-top" class="trick-slot"></div>
<div id="trick-middle" class="trick-middle-row">
<div id="trick-left" class="trick-slot"></div>
<div id="trick-center" class="trick-center-info">
<div id="phase-msg" class="phase-msg"></div>
</div>
<div id="trick-right" class="trick-slot"></div>
</div>
<div id="trick-bottom" class="trick-slot"></div>
</div>
<!-- Right player -->
<div id="area-right" class="player-area area-right">
<div class="player-label vertical">
<span id="right-name"></span>
<span id="right-turn" class="turn-dot hidden"></span>
<span id="right-score" class="player-score-badge"></span>
</div>
<div id="right-cards" class="opp-cards vertical"></div>
</div>
</div><!-- /table-grid -->
<!-- Bottom: my hand -->
<div id="my-area">
<div id="my-label">
<span id="my-name">You</span>
<span id="my-turn" class="turn-dot hidden"></span>
<span id="my-score" class="player-score-badge"></span>
<span id="my-hand-pts" class="hand-pts-badge"></span>
<button id="btn-play-mode" class="btn-play-mode hidden" title="Switch play mode">👆 Tap</button>
<button id="btn-hand-mode" class="btn-hand-mode" title="Switch hand display">📜 Scroll</button>
</div>
<div id="my-hand" class="my-hand"></div>
</div>
</div><!-- /screen-game -->
<!-- ══════════════ PASS OVERLAY ══════════════ -->
<div id="overlay-pass" class="overlay hidden">
<div class="overlay-box pass-box">
<h3 id="pass-title">Pass 3 cards</h3>
<p id="pass-hint" class="pass-hint"></p>
<div id="pass-hand" class="pass-hand"></div>
<div class="pass-selected-row">
<span class="pass-selected-label">Selected:</span>
<div id="pass-selected-preview" class="pass-selected-preview"></div>
</div>
<button id="btn-confirm-pass" class="btn-primary" disabled>Confirm Pass</button>
<p id="pass-waiting" class="hint" style="min-height:18px"></p>
</div>
</div>
<!-- ══════════════ HAND RESULT OVERLAY ══════════════ -->
<div id="overlay-hand" class="overlay hidden">
<div class="overlay-box">
<div id="hand-result-icon" class="result-icon"></div>
<h3 id="hand-result-title"></h3>
<p id="hand-result-detail"></p>
<div id="hand-result-scores" class="result-scores"></div>
<p class="hint">Next hand starting…</p>
</div>
</div>
<!-- ══════════════ GAME OVER OVERLAY ══════════════ -->
<div id="overlay-gameover" class="overlay hidden">
<div class="overlay-box">
<div class="result-icon big">🏆</div>
<h2 id="gameover-title"></h2>
<div id="gameover-scores" class="gameover-scores"></div>
<button id="btn-new-game" class="btn-primary">New Game</button>
</div>
</div>
<!-- ══════════════ AUTH MODAL ══════════════ -->
<div id="overlay-auth" class="overlay hidden">
<div class="overlay-box auth-box">
<button id="btn-auth-close" class="btn-close"></button>
<div class="auth-tabs">
<button class="auth-tab active" data-auth-tab="login">Login</button>
<button class="auth-tab" data-auth-tab="register">Register</button>
</div>
<div id="auth-panel-login" class="auth-panel active">
<div class="field">
<label>Username</label>
<input id="auth-login-user" type="text" maxlength="16" placeholder="Username" autocomplete="username">
</div>
<div class="field">
<label>Password</label>
<input id="auth-login-pass" type="password" placeholder="Password" autocomplete="current-password">
</div>
<p class="hint" style="font-size:.8rem;color:rgba(255,255,255,.5)">Hokm accounts work here too</p>
<button id="btn-do-login" class="btn-primary">Login</button>
<p id="auth-login-error" class="error-msg"></p>
</div>
<div id="auth-panel-register" class="auth-panel">
<div id="reg-step-form">
<div class="field">
<label>Username <small>(216 chars)</small></label>
<input id="auth-reg-user" type="text" maxlength="16" placeholder="Choose a username" autocomplete="username">
</div>
<div class="field">
<label>Email</label>
<input id="auth-reg-email" type="email" placeholder="your@email.com" autocomplete="email">
</div>
<div class="field">
<label>Password <small>(min 4 chars)</small></label>
<input id="auth-reg-pass" type="password" placeholder="Choose a password" autocomplete="new-password">
</div>
<div id="auth-captcha-wrap" class="hidden" style="margin:6px 0"></div>
<button id="btn-do-register" class="btn-primary">Send Verification Code</button>
<p id="auth-reg-error" class="error-msg"></p>
</div>
<div id="reg-step-verify" class="hidden">
<p id="reg-verify-hint" style="margin:0 0 12px;color:var(--muted);font-size:.9em"></p>
<div class="field">
<label>Verification Code</label>
<input id="auth-reg-code" type="text" inputmode="numeric" maxlength="6" placeholder="6-digit code" autocomplete="one-time-code">
</div>
<button id="btn-do-verify" class="btn-primary">Create Account</button>
<button id="btn-reg-back" class="btn-secondary" style="margin-top:6px;width:100%">← Back</button>
<p id="auth-verify-error" class="error-msg"></p>
</div>
</div>
</div>
</div>
<!-- ══════════════ PROFILE SCREEN ══════════════ -->
<div id="screen-profile" class="screen">
<div class="profile-wrap">
<div class="profile-box">
<button id="btn-profile-back" class="btn-back">← Back</button>
<div class="profile-avatar"></div>
<h2 id="profile-username" class="profile-name"></h2>
<div class="stat-grid">
<div class="stat-card">
<span class="stat-num" id="stat-games-played"></span>
<span class="stat-label">Games Played</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-games-won"></span>
<span class="stat-label">Games Won</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-moon-shots"></span>
<span class="stat-label">Moon Shots 🌙</span>
</div>
<div class="stat-card">
<span class="stat-num" id="stat-total-score"></span>
<span class="stat-label">Total Score</span>
</div>
</div>
<div class="points-legend">
<h4>How to win</h4>
<ul>
<li><strong>1 pt</strong> each ♥ heart taken</li>
<li><strong>13 pts</strong> taking the ♠Q (Queen of Spades)</li>
<li><strong>Shoot the Moon</strong> take all 13 hearts + ♠Q: you score 0, everyone else scores 26</li>
<li>Game ends when any player reaches the score limit. <strong>Lowest score wins.</strong></li>
</ul>
</div>
<div class="profile-section">
<button id="btn-show-change-pass" class="btn-secondary" style="width:100%">🔑 Change Password</button>
<div id="change-pass-form" class="hidden" style="margin-top:10px;display:flex;flex-direction:column;gap:8px">
<div class="field">
<label>Current Password</label>
<input id="change-pass-current" type="password" placeholder="Current password" autocomplete="current-password">
</div>
<div class="field">
<label>New Password <small>(min 4 chars)</small></label>
<input id="change-pass-new" type="password" placeholder="New password" autocomplete="new-password">
</div>
<button id="btn-do-change-pass" class="btn-primary">Update Password</button>
<p id="change-pass-msg" class="error-msg"></p>
</div>
</div>
<div id="admin-panel" class="profile-section admin-section hidden">
<h4 class="admin-title">⚙ Admin</h4>
<div class="admin-row">
<span>New registrations</span>
<button id="btn-toggle-signups" class="btn-secondary btn-admin-toggle"></button>
</div>
</div>
</div>
</div>
</div>
<!-- ══════════════ LEADERBOARD ══════════════ -->
<div id="screen-leaderboard" class="screen">
<div class="profile-wrap">
<div class="profile-box" style="max-width:520px">
<button id="btn-lb-back" class="btn-back">← Back</button>
<div class="profile-avatar">🏆</div>
<h2 class="profile-name">Leaderboard</h2>
<table class="lb-table">
<thead>
<tr>
<th>#</th>
<th>Player</th>
<th>Avg ♥</th>
<th>W</th>
<th>Played</th>
<th>🌙</th>
<th></th>
</tr>
</thead>
<tbody id="lb-body"></tbody>
</table>
</div>
</div>
</div>
<!-- ══════════════ PLAYER DETAILS MODAL ══════════════ -->
<div id="overlay-player-details" class="overlay hidden">
<div class="modal-box">
<button id="btn-details-close" class="btn-back" style="margin-bottom:12px">← Close</button>
<div class="profile-avatar" style="font-size:2rem"></div>
<h3 id="details-username" style="margin:8px 0 16px;color:#fff"></h3>
<table class="lb-table" style="width:100%">
<tbody id="details-body"></tbody>
</table>
</div>
</div>
<!-- ══════════════ EXIT CONFIRM ══════════════ -->
<div id="overlay-exit-confirm" class="overlay hidden">
<div class="overlay-box small" style="text-align:center">
<h3>Leave Game?</h3>
<p style="font-size:.88rem;color:rgba(255,255,255,.65);margin:8px 0 20px">Your session will be discarded.<br>You will not be able to rejoin.</p>
<div style="display:flex;gap:10px;justify-content:center">
<button id="btn-exit-confirm-yes" class="btn-primary" style="background:rgba(200,50,50,.7);border-color:rgba(200,50,50,.9)">Leave & Exit</button>
<button id="btn-exit-confirm-no" class="btn-secondary">Cancel</button>
</div>
</div>
</div>
<!-- ── PWA Install Banner ── -->
<div id="pwa-banner" class="pwa-banner hidden">
<img src="/icons/icon-192.png" class="pwa-banner-icon" alt="">
<div class="pwa-banner-text">
<strong>Install Hearts</strong>
<span>Play offline, launch like an app</span>
</div>
<button id="pwa-banner-install" class="pwa-banner-btn">Install</button>
<button id="pwa-banner-dismiss" class="pwa-banner-close" aria-label="Dismiss"></button>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="app.js"></script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
</script>
</body>
</html>