diff --git a/.hintrc b/.hintrc
new file mode 100644
index 0000000..5b02c11
--- /dev/null
+++ b/.hintrc
@@ -0,0 +1,13 @@
+{
+ "extends": [
+ "development"
+ ],
+ "hints": {
+ "axe/forms": [
+ "default",
+ {
+ "label": "off"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..1bdcfb1
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "workbench.iconTheme": "symbols"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 3e25fef..dbeca32 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+# Table Tennis Counter
+
The code is running, well, good!
凑活凑活用用吧
diff --git a/assets/css/styles.css b/assets/css/styles.css
new file mode 100644
index 0000000..73e26b3
--- /dev/null
+++ b/assets/css/styles.css
@@ -0,0 +1,139 @@
+:root {
+ --reset-button-bg-color: #e74c3c;
+ --reset-button-hover-bg-color: #c0392b;
+}
+* {
+ max-width: none;
+ scrollbar-width: 0;
+ scrollbar-color: none;
+ scroll-behavior: smooth;
+}
+*::-webkit-scrollbar {
+ display: none;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ margin-block: 0;
+ margin-inline: 0;
+ padding-block: 0;
+ padding-inline: 0;
+}
+s-page {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-direction: column;
+}
+main {
+ font-family: Arial, sans-serif;
+ display: flex;
+ flex-direction: column;
+ align-content: center;
+ justify-content: center;
+ align-items: center;
+ margin: 0;
+ flex: 1;
+}
+
+#top-loading {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+}
+#top-bar, #main {
+ visibility: hidden;
+}
+
+h1 {
+ margin: 20px 0;
+}
+
+.form-group {
+ margin: 5px;
+}
+#setup {
+ min-width: 40%;
+ padding: 10px;
+ display: block;
+}
+s-text-field {
+ display: block;
+}
+
+.player-list ul, #playerScoreList, #matchOrderList, #historyList {
+ list-style: none;
+ padding: 0;
+}
+
+.player-list li, #playerScoreList li, #matchOrderList li, #historyList li {
+ margin: 5px 0;
+}
+
+.score-button {
+ padding: 20px 30px;
+ font-size: 24px;
+}
+
+.reset-button {
+ width: 100%;
+ background-color: var(--reset-button-bg-color);
+ color: var(--primary-text-color);
+}
+
+.reset-button:hover {
+ background-color: var(--reset-button-hover-bg-color);
+}
+
+label {
+ font-size: 18px;
+ margin-bottom: 10px;
+}
+
+.game-board {
+ display: flex;
+ flex-direction: row;
+ max-width: 90%;
+ min-width: 50%;
+ max-height: 80%;
+ min-height: 40%;
+ padding: 20px;
+ box-sizing: border-box;
+ justify-content: center;
+ align-items: stretch;
+}
+.game-board:not(.active) {
+ display: none;
+}
+.game-board>div {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+}
+.game-board>div>s-card {
+ flex: 1;
+ margin: 5px;
+}
+
+.player-scores, .current-match, .match-order, .history {
+ padding: 20px;
+ border-radius: 12px;
+ overflow-y: auto;
+}
+h2 {
+ margin-top: 0;
+}
+
+.current-match .player {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+}
diff --git a/script.js b/assets/js/script.js
similarity index 82%
rename from script.js
rename to assets/js/script.js
index e52b5f0..397cb37 100644
--- a/script.js
+++ b/assets/js/script.js
@@ -1,166 +1,170 @@
-let players = [];
-let totalScores = {};
-let currentMatchScores = {};
-let currentMatch = [0, 1]; // Indexes of the players in the current match
-let winBalls = 5;
-let matchHistory = [];
-
-document.addEventListener('DOMContentLoaded', () => {
- document.getElementById('addPlayerButton').addEventListener('click', addPlayer);
- document.getElementById('startGameButton').addEventListener('click', startGame);
-});
-
-function addPlayer() {
- const playerName = document.getElementById('playerName').value.trim();
- if (playerName === '' || players.includes(playerName)) {
- alert('Please enter a unique valid player name');
- return;
- }
- players.push(playerName);
- totalScores[playerName] = 0;
- updatePlayerList();
- document.getElementById('playerName').value = '';
-}
-
-function updatePlayerList() {
- const playerList = document.getElementById('playerList');
- playerList.innerHTML = '';
- players.forEach(player => {
- const li = document.createElement('li');
- li.textContent = player;
- playerList.appendChild(li);
- });
-}
-
-function startGame() {
- if (players.length < 2) {
- alert('Please add at least two players');
- return;
- }
- winBalls = parseInt(document.getElementById('winBalls').value);
- if (isNaN(winBalls) || winBalls <= 0) {
- alert('Please enter a valid number of winning balls');
- return;
- }
- document.getElementById('initialSetup').style.display = 'none';
- document.getElementById('playerInputGroup').style.display = 'none';
- document.getElementById('playerListGroup').style.display = 'none';
- document.getElementById('initialButtons').style.display = 'none';
- document.getElementById('gameBoard').style.display = 'grid';
- updatePlayerScoreList();
- updateMatchOrderList();
- startNewMatch();
-}
-
-function startNewMatch() {
- currentMatchScores = {};
- players.forEach(player => {
- currentMatchScores[player] = 0;
- });
- updateCurrentMatch();
-}
-
-function incrementCurrentMatchScore(playerName) {
- currentMatchScores[playerName]++;
- updateCurrentMatch();
- if (currentMatchScores[playerName] >= winBalls) {
- totalScores[playerName]++;
- document.getElementById('result').innerText = `${playerName} Wins this round!`;
- matchHistory.push(`${players[currentMatch[0]]} vs ${players[currentMatch[1]]}: ${playerName} won`);
- disableScoreButtons();
- setTimeout(() => {
- document.getElementById('result').innerText = '';
- updatePlayerScoreList();
- updateMatchOrder();
- updateMatchOrderList();
- updateHistoryList();
- enableScoreButtons();
- startNewMatch();
- }, 2000);
- }
-}
-
-function disableScoreButtons() {
- document.querySelectorAll('.score-button').forEach(button => {
- button.disabled = true;
- });
-}
-
-function enableScoreButtons() {
- document.querySelectorAll('.score-button').forEach(button => {
- button.disabled = false;
- });
-}
-
-function updateCurrentMatch() {
- const match = document.getElementById('currentMatch');
- const player1 = players[currentMatch[0]];
- const player2 = players[currentMatch[1]];
- match.innerHTML = `
-
-
-
-
-
-
-
-
- `;
-}
-
-function updatePlayerScoreList() {
- const playerScoreList = document.getElementById('playerScoreList');
- playerScoreList.innerHTML = '';
- players.forEach(player => {
- const li = document.createElement('li');
- li.textContent = `${player}: ${totalScores[player]}`;
- playerScoreList.appendChild(li);
- });
-}
-
-function updateMatchOrderList() {
- const matchOrderList = document.getElementById('matchOrderList');
- matchOrderList.innerHTML = '';
- for (let i = 0; i < players.length; i++) {
- const player1 = players[i];
- const player2 = players[(i + 1) % players.length];
- const li = document.createElement('li');
- li.textContent = `${player1} vs ${player2}`;
- matchOrderList.appendChild(li);
- }
-}
-
-function updateHistoryList() {
- const historyList = document.getElementById('historyList');
- historyList.innerHTML = '';
- matchHistory.forEach(match => {
- const li = document.createElement('li');
- li.textContent = match;
- historyList.appendChild(li);
- });
-}
-
-function updateMatchOrder() {
- currentMatch[0] = (currentMatch[0] + 1) % players.length;
- currentMatch[1] = (currentMatch[1] + 1) % players.length;
- if (currentMatch[0] === currentMatch[1]) {
- currentMatch[1] = (currentMatch[1] + 1) % players.length;
- }
-}
-
-function resetScores() {
- players = [];
- totalScores = {};
- currentMatchScores = {};
- currentMatch = [0, 1];
- matchHistory = [];
- document.getElementById('playerList').innerHTML = '';
- document.getElementById('gameBoard').style.display = 'none';
- document.getElementById('initialSetup').style.display = 'block';
- document.getElementById('playerInputGroup').style.display = 'block';
- document.getElementById('playerListGroup').style.display = 'block';
- document.getElementById('initialButtons').style.display = 'block';
- document.getElementById('historyList').innerHTML = '';
-}
-
-window.incrementCurrentMatchScore = incrementCurrentMatchScore;
+let players = [];
+let totalScores = {};
+let currentMatchScores = {};
+let currentMatch = [0, 1]; // Indexes of the players in the current match
+let winBalls = 5;
+let matchHistory = [];
+
+document.addEventListener('DOMContentLoaded', () => {
+ // 虽然但是,onclick:?
+});
+
+function addPlayer() {
+ const playerName = document.getElementById('playerName').value.trim();
+ if (playerName === '' || players.includes(playerName)) {
+ showSnackBar('Please enter a unique valid player name', 'PlayerNameError');
+ return;
+ }
+ players.push(playerName);
+ totalScores[playerName] = 0;
+ updatePlayerList();
+ document.getElementById('playerName').value = '';
+}
+
+function updatePlayerList() {
+ showLoading();
+ const playerList = document.getElementById('playerList');
+ playerList.innerHTML = '';
+ players.forEach(player => {
+ const li = document.createElement('li');
+ li.textContent = player;
+ playerList.appendChild(li);
+ });
+ hideLoading();
+}
+
+function startGame() {
+ showLoading();
+ if (players.length < 2) {
+ showSnackBar('Please add at least two players', 'PlayerAmountError');
+ hideLoading();
+ return;
+ }
+ winBalls = parseInt(document.getElementById('winBalls').value);
+ if (isNaN(winBalls) || winBalls <= 0) {
+ showSnackBar('Please enter a valid number of winning balls', 'WinningBallsError');
+ hideLoading();
+ return;
+ }
+ document.getElementById('setup').style.display = 'none';
+ document.getElementById('gameBoard').classList.add('active');
+ updatePlayerScoreList();
+ updateMatchOrderList();
+ startNewMatch();
+ hideLoading();
+}
+
+function startNewMatch() {
+ showLoading();
+ currentMatchScores = {};
+ players.forEach(player => {
+ currentMatchScores[player] = 0;
+ });
+ updateCurrentMatch();
+ hideLoading();
+}
+
+function incrementCurrentMatchScore(playerName) {
+ currentMatchScores[playerName]++;
+ updateCurrentMatch();
+ if (currentMatchScores[playerName] >= winBalls) {
+ totalScores[playerName]++;
+ document.getElementById('result').innerText = `${playerName} Wins this round!`;
+ matchHistory.push(`${players[currentMatch[0]]} vs ${players[currentMatch[1]]}: ${playerName} won`);
+ disableScoreButtons();
+ setTimeout(() => {
+ document.getElementById('result').innerText = '';
+ updatePlayerScoreList();
+ updateMatchOrder();
+ updateMatchOrderList();
+ updateHistoryList();
+ enableScoreButtons();
+ startNewMatch();
+ }, 2000);
+ }
+}
+
+function disableScoreButtons() {
+ document.querySelectorAll('.score-button').forEach(button => {
+ button.disabled = true;
+ });
+}
+
+function enableScoreButtons() {
+ document.querySelectorAll('.score-button').forEach(button => {
+ button.disabled = false;
+ });
+}
+
+function updateCurrentMatch() {
+ const match = document.getElementById('currentMatch');
+ const player1 = players[currentMatch[0]];
+ const player2 = players[currentMatch[1]];
+ match.innerHTML = `
+
+
+ Score
+
+
+
+ Score
+
+ `;
+}
+
+function updatePlayerScoreList() {
+ const playerScoreList = document.getElementById('playerScoreList');
+ playerScoreList.innerHTML = '';
+ players.forEach(player => {
+ const li = document.createElement('li');
+ li.textContent = `${player}: ${totalScores[player]}`;
+ playerScoreList.appendChild(li);
+ });
+}
+
+function updateMatchOrderList() {
+ const matchOrderList = document.getElementById('matchOrderList');
+ matchOrderList.innerHTML = '';
+ for (let i = 0; i < players.length; i++) {
+ const player1 = players[i];
+ const player2 = players[(i + 1) % players.length];
+ const li = document.createElement('li');
+ li.textContent = `${player1} vs ${player2}`;
+ matchOrderList.appendChild(li);
+ }
+}
+
+function updateHistoryList() {
+ const historyList = document.getElementById('historyList');
+ historyList.innerHTML = '';
+ matchHistory.forEach(match => {
+ const li = document.createElement('li');
+ li.textContent = match;
+ historyList.appendChild(li);
+ });
+}
+
+function updateMatchOrder() {
+ currentMatch[0] = (currentMatch[0] + 1) % players.length;
+ currentMatch[1] = (currentMatch[1] + 1) % players.length;
+ if (currentMatch[0] === currentMatch[1]) {
+ currentMatch[1] = (currentMatch[1] + 1) % players.length;
+ }
+}
+
+function resetScores() {
+ players = [];
+ totalScores = {};
+ currentMatchScores = {};
+ currentMatch = [0, 1];
+ matchHistory = [];
+ document.getElementById('playerList').innerHTML = '';
+ document.getElementById('gameBoard').style.display = 'none';
+ document.getElementById('initialSetup').style.display = 'block';
+ document.getElementById('playerInputGroup').style.display = 'block';
+ document.getElementById('playerListGroup').style.display = 'block';
+ document.getElementById('initialButtons').style.display = 'block';
+ document.getElementById('historyList').innerHTML = '';
+}
+
+window.incrementCurrentMatchScore = incrementCurrentMatchScore;
diff --git a/assets/js/ui.js b/assets/js/ui.js
new file mode 100644
index 0000000..b663da5
--- /dev/null
+++ b/assets/js/ui.js
@@ -0,0 +1,81 @@
+
+document.addEventListener('DOMContentLoaded', () => { // 虽然但是,onclick:?
+ let pageEl = document.getElementById('page');
+
+ document.getElementById('sober').addEventListener('load', function () {
+ e_toggleTheme('auto')
+ setTimeout(function () { // 等Sober执行完
+ document.getElementById('main').style.visibility = 'visible';
+ document.getElementById('top-bar').style.visibility = 'visible';
+ hideLoading();
+ }, 500);
+ });
+});
+
+function showSnackBar(message, id = 'snackbar') {
+ let snackBarEl = document.getElementById('snackbar-' + id);
+ if (snackBarEl === null) {
+ snackBarEl = document.createElement('s-snackbar');
+ snackBarEl.id ='snackbar-' + id;
+ document.getElementById('tooltips').appendChild(snackBarEl);
+ }
+ snackBarEl.innerText = message;
+ snackBarEl.show();
+}
+function showLoading() {
+ document.getElementById('top-loading').style.visibility = 'visible';
+}
+function hideLoading() {
+ document.getElementById('top-loading').style.visibility = 'hidden';
+}
+
+function e_toggleTheme(theme) {
+ let pageEl = document.getElementById('page');
+ let themeIconEl = document.getElementById('theme-icon');
+ if (!theme) {
+ switch (pageEl.theme) {
+ case 'auto':
+ theme = 'light';
+ break;
+ case 'light':
+ theme = 'dark';
+ break;
+ case 'dark':
+ theme = 'auto';
+ break;
+ default:
+ theme = 'light';
+ break;
+ }
+ }
+ switch (theme) {
+ case 'auto':
+ pageEl.theme = 'auto';
+ themeIconEl.type = '';
+ themeIconEl.innerHTML = `
+`;
+ showSnackBar('Theme set to auto', 'Theme');
+ break;
+ case 'light':
+ pageEl.theme = 'light';
+ themeIconEl.type = 'light_mode';
+ themeIconEl.innerHTML = '';
+ showSnackBar('Theme set to light', 'Theme');
+ break;
+ case 'dark':
+ pageEl.theme = 'dark';
+ themeIconEl.type = 'dark_mode';
+ themeIconEl.innerHTML = '';
+ showSnackBar('Theme set to dark', 'Theme');
+ break;
+ }
+}
+function e_gotoGitHub() {
+ showSnackBar('Issues and PRs are welcome!!!', 'RepoTips');
+ window.open('https://github.com/Minemetero/Table-Tennis-Counter', '_blank');
+}
\ No newline at end of file
diff --git a/index.html b/index.html
index e2f7788..dff57ae 100644
--- a/index.html
+++ b/index.html
@@ -1,51 +1,106 @@
-
-
+
+
Table Tennis Counter
-
+
- Table Tennis Counter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Current Match
-
-
-
+
+
+
+
+ Table Tennis Counter
+
+
+
+
+
+ Theme
+
+
+
+
+
+
+
+
+ GitHub
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Player
+
+
+
+
+
Start Game
+
+
+
+ Player Scores
+
+
+ Match History
+
+
+
+
+
+ Current Match
+
+
+
+
+
+
+
+
+
+ Snackbar Message
+
-
-
+
+
-
+
+
+
+
diff --git a/styles.css b/styles.css
deleted file mode 100644
index 812c38e..0000000
--- a/styles.css
+++ /dev/null
@@ -1,126 +0,0 @@
-:root {
- --primary-bg-color: #2980b9;
- --secondary-bg-color: #3498db;
- --primary-text-color: #ecf0f1;
- --button-bg-color: #ecf0f1;
- --button-text-color: #2980b9;
- --button-hover-bg-color: #bdc3c7;
- --reset-button-bg-color: #e74c3c;
- --reset-button-hover-bg-color: #c0392b;
-}
-
-body {
- font-family: Arial, sans-serif;
- background: linear-gradient(to bottom right, #2980b9, #3498db);
- color: var(--primary-text-color);
- display: flex;
- flex-direction: column;
- align-items: center;
- height: 100vh;
- margin: 0;
-}
-
-h1 {
- margin: 20px 0;
-}
-
-.input-group, .player-input-group, .player-list, .buttons, .game-board {
- margin-bottom: 20px;
-}
-
-.input-group input, .player-input-group input {
- padding: 5px;
- border-radius: 5px;
- border: none;
- transition: background-color 0.3s ease;
-}
-
-.input-group input:focus, .player-input-group input:focus {
- background-color: #ecf0f1;
-}
-
-.player-input-group input {
- width: 150px;
- margin-right: 10px;
-}
-
-.player-list ul, #playerScoreList, #matchOrderList, #historyList {
- list-style: none;
- padding: 0;
-}
-
-.player-list li, #playerScoreList li, #matchOrderList li, #historyList li {
- margin: 5px 0;
-}
-
-button {
- padding: 15px 25px;
- font-size: 18px;
- border: none;
- border-radius: 8px;
- cursor: pointer;
- color: var(--button-text-color);
- background-color: var(--button-bg-color);
- transition: background-color 0.3s ease, transform 0.2s;
-}
-
-button:hover {
- background-color: var(--button-hover-bg-color);
- transform: scale(1.1);
-}
-
-.score-button {
- padding: 20px 30px;
- font-size: 24px;
-}
-
-.reset-button {
- width: 100%;
- background-color: var(--reset-button-bg-color);
- color: var(--primary-text-color);
-}
-
-.reset-button:hover {
- background-color: var(--reset-button-hover-bg-color);
-}
-
-label {
- font-size: 18px;
- margin-bottom: 10px;
-}
-
-.game-board {
- display: grid;
- grid-template-columns: 1fr 2fr 1fr;
- grid-template-rows: 1fr 1fr;
- gap: 20px;
- width: 90%;
- padding: 20px;
- box-sizing: border-box;
-}
-
-.player-scores, .current-match, .match-order, .history {
- background-color: var(--secondary-bg-color);
- padding: 20px;
- border-radius: 12px;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- overflow-y: auto;
- max-height: 300px;
-}
-
-.current-match {
- grid-column: 2 / 3;
- grid-row: 1 / 3;
- padding: 40px;
-}
-
-h2 {
- margin-top: 0;
-}
-
-.current-match .player {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 10px;
-}