chalker/index.html
Rama main · réplica de lectura del repositorio original.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="screen-orientation" content="portrait">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#1a1a1a">
<title>NewTon Chalker</title>
<meta name="description" content="NewTon Chalker — tablet scoring app for darts. Records visit scores, tracks leg averages, high finishes, and match statistics. Works offline, no signup required.">
<link rel="stylesheet" href="styles/chalker.css">
<link rel="manifest" href="manifest.json">
<link rel="icon" href="images/icon-192.png">
<link rel="apple-touch-icon" href="images/icon-192.png">
</head>
<body>
<!-- Scoring Screen (always shown) -->
<div id="scoring-screen" class="screen active">
<header id="scoring-header" class="scoring-header">
<span id="player1-header" class="header-player">Player 1</span>
<span id="leg-display" class="leg-score">0 - 0</span>
<span id="player2-header" class="header-player">Player 2</span>
</header>
<!-- Score anchors at top -->
<div class="score-anchors">
<div id="player1-anchor" class="score-anchor active">
<div class="anchor-score" id="player1-score">501</div>
</div>
<div id="player2-anchor" class="score-anchor">
<div class="anchor-score" id="player2-score">501</div>
</div>
</div>
<!-- Match info bar -->
<div class="match-info-bar" id="match-info-bar"></div>
<!-- Chalkboard ledger -->
<div class="chalkboard">
<div class="chalkboard-body" id="chalkboard-body">
<table class="chalk-table">
<thead>
<tr>
<th>Scored</th>
<th>To Go</th>
<th>➹</th>
<th>Scored</th>
<th>To Go</th>
</tr>
</thead>
<tbody id="chalk-tbody">
<!-- Rows rendered by JS -->
</tbody>
</table>
</div>
</div>
<!-- Match complete banner (shown instead of keypad when match is done) -->
<div id="match-complete-banner" class="match-complete-banner" style="display:none"></div>
<!-- Input section -->
<div class="input-section">
<div class="keypad-actions">
<button class="key key-action" id="key-new">NEW</button>
<button class="key key-action" id="key-history">HISTORY</button>
<button class="key key-action" id="key-stats">STATS</button>
</div>
<div class="keypad">
<button class="key" data-value="1">1</button>
<button class="key" data-value="2">2</button>
<button class="key" data-value="3">3</button>
<button class="key" data-value="4">4</button>
<button class="key" data-value="5">5</button>
<button class="key" data-value="6">6</button>
<button class="key" data-value="7">7</button>
<button class="key" data-value="8">8</button>
<button class="key" data-value="9">9</button>
<button class="key key-delete" data-action="delete">DEL</button>
<button class="key" data-value="0">0</button>
<button class="key key-enter" data-action="enter">OK</button>
</div>
</div>
</div>
<!-- Checkout Modal -->
<div id="checkout-modal" class="modal">
<div class="modal-content">
<h2>Checkout!</h2>
<p>How many darts used?</p>
<div class="dart-buttons">
<button class="btn btn-dart" data-darts="1">1</button>
<button class="btn btn-dart" data-darts="2">2</button>
<button class="btn btn-dart" data-darts="3">3</button>
</div>
<button id="checkout-cancel-btn" class="btn btn-cancel">Cancel</button>
</div>
</div>
<!-- Selection Modal (Starting Player / Tie-Break) -->
<div id="tiebreak-modal" class="modal">
<div class="modal-content">
<h2 id="tiebreak-title"></h2>
<p id="tiebreak-message"></p>
<div class="tiebreak-buttons">
<button class="btn btn-primary btn-tiebreak" id="tiebreak-p1"></button>
<button class="btn btn-primary btn-tiebreak" id="tiebreak-p2"></button>
<button class="btn btn-secondary btn-tiebreak" id="tiebreak-random" style="display: none;">Random</button>
</div>
<button id="tiebreak-cancel-btn" class="btn btn-cancel" style="display: none;">Cancel</button>
</div>
</div>
<!-- Config Modal (New Match) -->
<div id="config-modal" class="modal">
<div class="modal-content config-modal-content">
<h2>New Match</h2>
<div class="config-form-modal">
<div class="form-group">
<label for="player1-name">Player 1</label>
<input type="text" id="player1-name" placeholder="Player 1 name">
</div>
<div class="form-group">
<label for="player2-name">Player 2</label>
<input type="text" id="player2-name" placeholder="Player 2 name">
</div>
<div class="form-group">
<label for="starting-score">Starting Score</label>
<select id="starting-score">
<option value="101">101</option>
<option value="201">201</option>
<option value="301">301</option>
<option value="401">401</option>
<option value="501" selected>501</option>
<option value="601">601</option>
<option value="701">701</option>
<option value="801">801</option>
<option value="901">901</option>
<option value="1001">1001</option>
</select>
<input type="number" id="starting-score-custom" min="2" max="1001" placeholder="2–1001" style="display: none;">
<label style="margin-top: 6px; font-size: 12px; color: #888; font-weight: normal; cursor: pointer;">
<input type="checkbox" id="starting-score-custom-toggle" style="margin-right: 4px;">
Custom score
</label>
</div>
<div class="form-group">
<label for="best-of">Best Of</label>
<select id="best-of">
<option value="1">1</option>
<option value="3" selected>3</option>
<option value="5">5</option>
<option value="7">7</option>
<option value="9">9</option>
<option value="11">11</option>
<option value="13">13</option>
<option value="15">15</option>
<option value="17">17</option>
<option value="19">19</option>
<option value="21">21</option>
</select>
</div>
<div class="form-group">
<label for="max-rounds">Max Rounds</label>
<select id="max-rounds">
<option value="7">7 (21 darts)</option>
<option value="8">8 (24 darts)</option>
<option value="9">9 (27 darts)</option>
<option value="10">10 (30 darts)</option>
<option value="11">11 (33 darts)</option>
<option value="12">12 (36 darts)</option>
<option value="13" selected>13 (39 darts)</option>
<option value="14">14 (42 darts)</option>
<option value="15">15 (45 darts)</option>
<option value="16">16 (48 darts)</option>
<option value="17">17 (51 darts)</option>
<option value="18">18 (54 darts)</option>
<option value="19">19 (57 darts)</option>
<option value="20">20 (60 darts)</option>
<option value="100">Unlimited</option>
</select>
</div>
</div>
<button id="start-match-btn" class="btn btn-primary btn-large">Start Match</button>
<button id="config-cancel-btn" class="btn btn-cancel">Cancel</button>
</div>
</div>
<!-- New Match Modal (shown via NEW button) -->
<div id="settings-modal" class="modal">
<div class="modal-content">
<h2>New Match?</h2>
<p id="settings-modal-message">Current match will be lost.</p>
<button id="rematch-btn" class="btn btn-primary">Rematch</button>
<button id="new-match-btn" class="btn btn-secondary">New Match</button>
<button id="qr-mode-btn" class="btn btn-secondary">QR</button>
<button id="network-mode-btn" class="btn btn-secondary">Network</button>
<button id="settings-cancel-btn" class="btn btn-cancel">Cancel</button>
<p id="chalker-version" style="margin: 12px 0 0; font-size: 11px; color: #999; text-align: center;"></p>
</div>
</div>
<!-- QR Scan Modal -->
<div id="qr-scan-modal" class="modal">
<div class="modal-content qr-scan-modal-content">
<h2>Scan Assignment QR</h2>
<video id="qr-scan-video" class="qr-video" autoplay playsinline muted></video>
<input type="file" id="qr-image-input" accept="image/*" capture="environment" style="display: none;">
<label id="qr-image-label" for="qr-image-input" class="btn btn-primary btn-large" style="display: none; cursor: pointer; text-align: center;">Take Photo</label>
<canvas id="qr-image-canvas" style="display: none;"></canvas>
<p class="qr-scan-hint" id="qr-scan-hint">Point the camera at the QR code on the Tournament Manager screen.</p>
<p id="qr-scan-error" class="qr-scan-error" style="display: none;"></p>
<button id="qr-scan-cancel-btn" class="btn btn-cancel">Cancel</button>
</div>
</div>
<!-- QR Confirm Modal -->
<div id="qr-confirm-modal" class="modal">
<div class="modal-content">
<h2>Match Assignment</h2>
<div id="qr-confirm-details" class="qr-confirm-details"></div>
<button id="qr-confirm-start-btn" class="btn btn-primary btn-large">Start Match</button>
<button id="qr-confirm-cancel-btn" class="btn btn-cancel">Cancel</button>
</div>
</div>
<!-- Network Mode Modal -->
<div id="network-modal" class="modal">
<div class="modal-content config-modal-content">
<h2>Network Mode</h2>
<p class="network-notice">Experimental preview — not yet functional. No licence required; this will be free to use.</p>
<div class="config-form-modal">
<div class="form-group">
<label for="network-lane">Lane</label>
<select id="network-lane">
<option value="1">Lane 1</option>
<option value="2">Lane 2</option>
<option value="3">Lane 3</option>
<option value="4">Lane 4</option>
<option value="5">Lane 5</option>
<option value="6">Lane 6</option>
<option value="7">Lane 7</option>
<option value="8">Lane 8</option>
<option value="9">Lane 9</option>
<option value="10">Lane 10</option>
<option value="11">Lane 11</option>
<option value="12">Lane 12</option>
<option value="13">Lane 13</option>
<option value="14">Lane 14</option>
<option value="15">Lane 15</option>
<option value="16">Lane 16</option>
<option value="17">Lane 17</option>
<option value="18">Lane 18</option>
<option value="19">Lane 19</option>
<option value="20">Lane 20</option>
</select>
</div>
</div>
<button id="network-start-btn" class="btn btn-primary btn-large">Start</button>
<button id="network-cancel-btn" class="btn btn-cancel">Cancel</button>
</div>
</div>
<!-- Confirm Modal -->
<div id="confirm-modal" class="modal">
<div class="modal-content">
<h2 id="confirm-title">Confirm</h2>
<p id="confirm-message">Are you sure?</p>
<div class="confirm-buttons">
<button id="confirm-yes-btn" class="btn btn-danger">Yes, abandon</button>
<button id="confirm-no-btn" class="btn btn-cancel">Cancel</button>
</div>
</div>
</div>
<!-- History Screen -->
<div id="history-screen" class="screen">
<header class="history-header">
<button id="history-back-btn" class="btn-icon" aria-label="Back">←</button>
<h1>Match History</h1>
</header>
<div id="history-list" class="history-list">
<!-- Populated by JavaScript -->
</div>
</div>
<!-- Result QR Modal -->
<div id="result-qr-modal" class="modal">
<div class="modal-content">
<h2 id="result-qr-title">Match Result QR</h2>
<p id="result-qr-subtitle" class="qr-scan-hint"></p>
<div id="result-qr-code" class="result-qr-code"></div>
<p class="qr-scan-hint">Point the Tournament Manager camera at this code to record the result.</p>
<button id="result-qr-close-btn" class="btn btn-cancel">Close</button>
</div>
</div>
<!-- History Detail Screen -->
<div id="history-detail-screen" class="screen">
<header class="history-header">
<button id="history-detail-back-btn" class="btn-icon" aria-label="Back">←</button>
<h1>Match Details</h1>
</header>
<div class="history-detail-content">
<div class="history-detail-header">
<div class="history-detail-players">
<span id="detail-player1" class="detail-player"></span>
<span class="detail-vs">vs</span>
<span id="detail-player2" class="detail-player"></span>
</div>
<div id="detail-score" class="detail-score"></div>
<div id="detail-date" class="detail-date"></div>
</div>
<div class="history-detail-stats">
<h3>Match Statistics</h3>
<table class="stats-table">
<thead>
<tr>
<th id="detail-stats-p1">P1</th>
<th class="stat-label">Stat</th>
<th id="detail-stats-p2">P2</th>
</tr>
</thead>
<tbody id="detail-stats-body"></tbody>
</table>
</div>
<div class="history-detail-legs" id="detail-legs-container">
<!-- Leg tables populated by JavaScript -->
</div>
<div class="end-buttons" id="history-detail-actions">
<button id="history-detail-qr-btn" class="btn btn-secondary" style="display:none">Result QR</button>
</div>
</div>
</div>
<!-- End-of-Match Screen -->
<div id="end-screen" class="screen">
<header class="history-header">
<button id="end-back-btn" class="btn-icon" aria-label="Back">←</button>
<h1>Match Complete</h1>
</header>
<div class="history-detail-content">
<div class="history-detail-header">
<div class="history-detail-players">
<span id="winner-name" class="detail-player"></span>
<span class="detail-vs">vs</span>
<span id="loser-name" class="detail-player"></span>
</div>
<div id="final-score" class="detail-score"></div>
<div id="end-match-info" class="detail-date"></div>
</div>
<div class="history-detail-stats">
<h3>Match Statistics</h3>
<table class="stats-table">
<thead>
<tr>
<th id="stats-player1">P1</th>
<th class="stat-label">Stat</th>
<th id="stats-player2">P2</th>
</tr>
</thead>
<tbody id="end-stats-body"></tbody>
</table>
</div>
<div class="history-detail-legs" id="end-legs-container">
<!-- Leg scoresheets populated by JavaScript -->
</div>
</div>
<div class="end-buttons">
<button id="end-result-qr-btn" class="btn btn-primary btn-full" style="display:none">Result QR</button>
</div>
</div>
<!-- Live Stats Screen -->
<div id="stats-screen" class="screen">
<header class="history-header">
<button id="stats-back-btn" class="btn-icon" aria-label="Back">←</button>
<h1>Live Stats</h1>
</header>
<div class="history-detail-content">
<div class="history-detail-header">
<div class="history-detail-players">
<span id="stats-player1-name" class="detail-player"></span>
<span class="detail-vs">vs</span>
<span id="stats-player2-name" class="detail-player"></span>
</div>
<div id="stats-live-score" class="detail-score"></div>
<div id="stats-match-info" class="detail-date"></div>
</div>
<div class="history-detail-stats">
<h3>Match Statistics</h3>
<table class="stats-table">
<thead>
<tr>
<th id="stats-header-p1">P1</th>
<th class="stat-label">Stat</th>
<th id="stats-header-p2">P2</th>
</tr>
</thead>
<tbody id="stats-stats-body"></tbody>
</table>
</div>
<div class="history-detail-legs" id="stats-legs-container">
<!-- Leg scoresheets populated by JavaScript -->
</div>
</div>
</div>
<script src="lib/qrcode-generator.js"></script>
<script src="js/jsQR.js"></script>
<script src="js/qr-scanner.umd.min.js"></script>
<script src="js/db.js"></script>
<script src="js/newton-integrity.js"></script>
<script src="js/chalker.js?v=35"></script>
<!-- Optional network client. Separately licensed (see ../licensed/LICENSE.md) and
may be absent; the Chalker works fully without it. -->
<script src="../licensed/js/network-chalker.js?v=1"></script>
<div class="install-banner" id="installBanner">
<span class="install-text">Install NewTon Chalker for offline use</span>
<button class="install-btn" id="installAppBtn">Install</button>
<button class="install-dismiss" id="installDismissBtn">✕</button>
</div>
<script>
// Register service worker for PWA functionality
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js')
.then(reg => console.log('Service worker registered'))
.catch(err => console.log('Service worker registration failed:', err));
}
</script>
</body>
</html>