From 944fc2715e967a51e4ccca49d87e987ee2727bc2 Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Thu, 13 Nov 2025 21:48:40 +0100 Subject: Transitioned to npm --- index.html | 97 ++++++ package-lock.json | 882 +++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 22 ++ public/favicon.ico | Bin 0 -> 13054 bytes public/icon.png | Bin 0 -> 1453 bytes src/court.mjs | 53 ++++ src/game.mjs | 186 +++++++++++ src/guest.mjs | 69 +++++ src/main.js | 20 ++ src/player.mjs | 150 +++++++++ src/style.css | 12 + src/timer.js | 88 ++++++ src/utils.mjs | 51 ++++ 13 files changed, 1630 insertions(+) create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/favicon.ico create mode 100644 public/icon.png create mode 100644 src/court.mjs create mode 100644 src/game.mjs create mode 100644 src/guest.mjs create mode 100644 src/main.js create mode 100644 src/player.mjs create mode 100644 src/style.css create mode 100644 src/timer.js create mode 100644 src/utils.mjs diff --git a/index.html b/index.html new file mode 100644 index 0000000..287841a --- /dev/null +++ b/index.html @@ -0,0 +1,97 @@ + + + + + + Match Up! + + +
+ +
+
+ + + + + + + + + + +
CourtTeam 1Team 2
+
+
+
+ +
+ +
+ + +
+
+
+

Courts

+
+
+
+

Regulars

+
+
+
+

Guests

+
+
+
+

Player Update

+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2e440f5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,882 @@ +{ + "name": "matchup", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "matchup", + "version": "0.0.0", + "dependencies": { + "@fortawesome/fontawesome-free": "^7.1.0", + "bulma": "^1.0.4", + "notyf": "^3.10.0" + }, + "devDependencies": { + "vite": "npm:rolldown-vite@7.2.2" + } + }, + "node_modules/@emnapi/core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.0.tgz", + "integrity": "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.0.tgz", + "integrity": "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.1.0.tgz", + "integrity": "sha512-+WxNld5ZCJHvPQCr/GnzCTVREyStrAJjisUPtUxG5ngDA8TMlPnKp6dddlTpai4+1GNmltAeuk1hJEkBohwZYA==", + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", + "engines": { + "node": ">=6" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.96.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.96.0.tgz", + "integrity": "sha512-34lh4o9CcSw09Hx6fKihPu85+m+4pmDlkXwJrLvN5nMq5JrcGhhihVM415zDqT8j8IixO1PYYdQZRN4SwQCncg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.96.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.96.0.tgz", + "integrity": "sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.47.tgz", + "integrity": "sha512-vPP9/MZzESh9QtmvQYojXP/midjgkkc1E4AdnPPAzQXo668ncHJcVLKjJKzoBdsQmaIvNjrMdsCwES8vTQHRQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.47.tgz", + "integrity": "sha512-Lc3nrkxeaDVCVl8qR3qoxh6ltDZfkQ98j5vwIr5ALPkgjZtDK4BGCrrBoLpGVMg+csWcaqUbwbKwH5yvVa0oOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.47.tgz", + "integrity": "sha512-eBYxQDwP0O33plqNVqOtUHqRiSYVneAknviM5XMawke3mwMuVlAsohtOqEjbCEl/Loi/FWdVeks5WkqAkzkYWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.47.tgz", + "integrity": "sha512-Ns+kgp2+1Iq/44bY/Z30DETUSiHY7ZuqaOgD5bHVW++8vme9rdiWsN4yG4rRPXkdgzjvQ9TDHmZZKfY4/G11AA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.47.tgz", + "integrity": "sha512-4PecgWCJhTA2EFOlptYJiNyVP2MrVP4cWdndpOu3WmXqWqZUmSubhb4YUAIxAxnXATlGjC1WjxNPhV7ZllNgdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.47.tgz", + "integrity": "sha512-CyIunZ6D9U9Xg94roQI1INt/bLkOpPsZjZZkiaAZ0r6uccQdICmC99M9RUPlMLw/qg4yEWLlQhG73W/mG437NA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.47.tgz", + "integrity": "sha512-doozc/Goe7qRCSnzfJbFINTHsMktqmZQmweull6hsZZ9sjNWQ6BWQnbvOlfZJe4xE5NxM1NhPnY5Giqnl3ZrYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.47.tgz", + "integrity": "sha512-fodvSMf6Aqwa0wEUSTPewmmZOD44rc5Tpr5p9NkwQ6W1SSpUKzD3SwpJIgANDOhwiYhDuiIaYPGB7Ujkx1q0UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.47.tgz", + "integrity": "sha512-Rxm5hYc0mGjwLh5sjlGmMygxAaV2gnsx7CNm2lsb47oyt5UQyPDZf3GP/ct8BEcwuikdqzsrrlIp8+kCSvMFNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.47.tgz", + "integrity": "sha512-YakuVe+Gc87jjxazBL34hbr8RJpRuFBhun7NEqoChVDlH5FLhLXjAPHqZd990TVGVNkemourf817Z8u2fONS8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.47.tgz", + "integrity": "sha512-ak2GvTFQz3UAOw8cuQq8pWE+TNygQB6O47rMhvevvTzETh7VkHRFtRUwJynX5hwzFvQMP6G0az5JrBGuwaMwYQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.7" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.47.tgz", + "integrity": "sha512-o5BpmBnXU+Cj+9+ndMcdKjhZlPb79dVPBZnWwMnI4RlNSSq5yOvFZqvfPYbyacvnW03Na4n5XXQAPhu3RydZ0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.47.tgz", + "integrity": "sha512-FVOmfyYehNE92IfC9Kgs913UerDog2M1m+FADJypKz0gmRg3UyTt4o1cZMCAl7MiR89JpM9jegNO1nXuP1w1vw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.47.tgz", + "integrity": "sha512-by/70F13IUE101Bat0oeH8miwWX5mhMFPk1yjCdxoTNHTyTdLgb0THNaebRM6AP7Kz+O3O2qx87sruYuF5UxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", + "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/bulma": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.4.tgz", + "integrity": "sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/notyf": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/notyf/-/notyf-3.10.0.tgz", + "integrity": "sha512-Mtnp+0qiZxgrH+TzVlzhWyZceHdAZ/UWK0/ju9U0HQeDpap1mZ8cC7H5wSI5mwgni6yeAjaxsTw0sbMK+aSuHw==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.47.tgz", + "integrity": "sha512-Mid74GckX1OeFAOYz9KuXeWYhq3xkXbMziYIC+ULVdUzPTG9y70OBSBQDQn9hQP8u/AfhuYw1R0BSg15nBI4Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.96.0", + "@rolldown/pluginutils": "1.0.0-beta.47" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.47", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.47", + "@rolldown/binding-darwin-x64": "1.0.0-beta.47", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.47", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.47", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.47", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.47", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.47", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.47", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.47", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.47", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.47", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.47", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.47" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/vite": { + "name": "rolldown-vite", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.2.tgz", + "integrity": "sha512-Fl3ZdmJhDMJGcqrr342pPVrhugXdOcuNBRBauz4S7QGSRXbQy7y8q5QYJtgkcrG8XjY0EENSZeTk58c3m20FxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/runtime": "0.96.0", + "fdir": "^6.5.0", + "lightningcss": "^1.30.2", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rolldown": "1.0.0-beta.47", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "esbuild": "^0.25.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6e96392 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "matchup", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "npm:rolldown-vite@7.2.2" + }, + "overrides": { + "vite": "npm:rolldown-vite@7.2.2" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^7.1.0", + "bulma": "^1.0.4", + "notyf": "^3.10.0" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..6cb5040 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 0000000..655915f Binary files /dev/null and b/public/icon.png differ diff --git a/src/court.mjs b/src/court.mjs new file mode 100644 index 0000000..713c488 --- /dev/null +++ b/src/court.mjs @@ -0,0 +1,53 @@ +import { Manager } from "./utils.mjs"; + +class Court { + constructor(id, status) { + this.id = id; + this.status = typeof status !== "undefined" ? status : true; + this.name = "Court " + (id + 1); + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + return ``; + } +} + +export class CourtManager extends Manager { + maxCourtCount = 12; + + constructor() { + super("court", []); + console.log("Loading court data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length != this.maxCourtCount) { + console.log("Court data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < this.maxCourtCount; i++) { + this.listData.push(new Court(data[i].id, data[i].status)); + } + console.log("Loaded " + this.listData.length + " courts."); + this.render(); + this.addBehaviour(); + } + generate() { + console.log("Generating court data."); + for (let i = 0; i < this.maxCourtCount; i++) { + this.listData.push(new Court(i)); + } + console.log("Generated data for " + this.listData.length + " courts"); + this.store(); + this.render(); + this.addBehaviour(); + } +} diff --git a/src/game.mjs b/src/game.mjs new file mode 100644 index 0000000..c8931ac --- /dev/null +++ b/src/game.mjs @@ -0,0 +1,186 @@ +import { Notyf } from 'notyf'; +import { Manager } from "./utils.mjs"; +import { CourtManager } from "./court.mjs"; +import { PlayerManager } from "./player.mjs"; + +class Team { + constructor(playerOne, playerTwo) { + this.playerOne = playerOne; + this.playerTwo = playerTwo; + } + print() { + console.log(this.playerOne + " and " + this.playerTwo); + } + render() { + let p1 = `${this.playerOne}`; + let p2 = `${this.playerTwo}`; + return p1 + p2; + } +} + +class Game { + constructor(id, teamOne, teamTwo, status) { + this.id = id; + this.teamOne = teamOne; + this.teamTwo = teamTwo; + this.status = typeof status !== "undefined" ? status : false; + } + print() { + let teamOne = this.teamOne.playerOne + " and " + this.teamOne.playerTwo; + let teamTwo = this.teamTwo.playerOne + " and " + this.teamTwo.playerTwo; + console.log(teamOne + " is playing against " + teamTwo); + } + render() { + let blockedState = this.teamOne.playerOne === "RESERVED"; + let type = blockedState ? `class="is-danger is-dark"` : ``; + return `${ + this.id + 1 + }${this.teamOne.render()}${this.teamTwo.render()}`; + } +} + +function generateDummyGames(courts, description) { + let team = new Team(description, description); + let games = []; + for (const court of courts) { + let game = new Game(court.id, team, team); + games.push(game); + } + return games; +} + +export class GameManager extends Manager { + courts = new CourtManager(); + players = new PlayerManager(); + + constructor() { + super("game", []); + this.round = Number(localStorage.getItem("round")) || 0; + console.log("Loading game data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length === 0) { + console.log("Game data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < data.length; i++) { + let id = Number(data[i].id); + let teamOne = new Team( + data[i].teamOne.playerOne, + data[i].teamOne.playerTwo + ); + let teamTwo = new Team( + data[i].teamTwo.playerOne, + data[i].teamTwo.playerTwo + ); + let status = Boolean(data[i].status); + this.listData.push(new Game(id, teamOne, teamTwo, status)); + } + console.log("Loaded " + this.listData.length + " games."); + this.render(); + } + isConfirmed() { + return this.listData[0].status; + } + generate() { + console.log("Generating the dummy round."); + this.listData = generateDummyGames(this.courts.listData, "---"); + console.log("Loaded " + this.listData.length + " dummy round."); + for (let i = 0; i < this.listData.length; i++) { + this.listData[i].status = true; + } + console.log(this.listData); + this.store(); + this.render(); + } + addBehaviour() { + let description = this.isConfirmed() ? "Round " + this.round : "Proposal"; + document.getElementById("game_description").innerHTML = description; + } + getBlockedGames() { + const inactiveCourts = this.courts.inactive(); + console.log("Total reserved courts are " + inactiveCourts.length + "."); + return generateDummyGames(inactiveCourts, "RESERVED"); + } + inactive(courts) { + return generateDummyGames(courts, "---"); + } + active(courts, players) { + let games = []; + for (let index = 0; index < courts.length; index++) { + const startIndex = 4 * index; + const endIndex = startIndex + 4; + const courtPlayers = players.slice(startIndex, endIndex); + const team_1 = new Team(courtPlayers[0].name, courtPlayers[3].name); + const team_2 = new Team(courtPlayers[1].name, courtPlayers[2].name); + const game = new Game(courts[index].id, team_1, team_2); + game.print(); + games.push(game); + } + return games; + } + propose() { + console.log("Proposing new games!"); + let possibleMatches = getMatchCount( + this.players.listData, + this.courts.listData + ); + console.log("Total possible matches are " + possibleMatches + "."); + this.listData = this.getBlockedGames(); + const activeCourts = this.courts.active(); + const unusedCourts = activeCourts.slice(possibleMatches + 1); + this.listData = this.listData.concat(this.inactive(unusedCourts)); + const usedCourts = activeCourts.slice(0, possibleMatches); + let requiredPlayerCount = possibleMatches * 4; + const selectedPlayers = this.players.propose(requiredPlayerCount); + console.log("The matches are:"); + this.listData = this.listData.concat( + this.active(usedCourts, selectedPlayers) + ); + this.listData.sort((a, b) => a.id - b.id); + this.render(); + } + confirm() { + if (this.isConfirmed()) { + const notification = new Notyf(); + notification.error("Create a proposal first!"); + return; + } + console.log("Confirm the proposal for round " + this.round + "."); + this.round += 1; + localStorage.setItem("round", this.round); + for (let i = 0; i < this.listData.length; i++) { + this.listData[i].status = true; + } + // Need to update the number of games played here + this.store(); + this.render(); + document.getElementById("timer-start").click(); + const notification = new Notyf(); + notification.success("Round confirmed!"); + } + reset() { + localStorage.removeItem("round"); + localStorage.removeItem(this.description); + localStorage.removeItem(this.courts.description); + document.getElementById("timer-stop").click(); + window.location.reload(); + const notification = new Notyf(); + notification.error("Session has been reset!"); + } +} + +function getMatchCount(players, courts) { + courts = courts.filter(function (c) { + return c.status; + }); + console.log("There are a total of " + courts.length + " courts available."); + console.log(players); + players = players.filter(function (p) { + return p.status; + }); + console.log("There are a total of " + players.length + " players available."); + var possibleMatches = Math.floor(players.length / 4); + possibleMatches = Math.min(possibleMatches, courts.length); + return possibleMatches; +} diff --git a/src/guest.mjs b/src/guest.mjs new file mode 100644 index 0000000..ba9e8cc --- /dev/null +++ b/src/guest.mjs @@ -0,0 +1,69 @@ +import { Manager } from "./utils.mjs"; + +export class Guest { + constructor(id, name, level, status, totalPlayed) { + this.id = id; + this.status = typeof status !== "undefined" ? status : false; + this.name = name; + this.level = typeof level !== "undefined" ? level : 1; + this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + return ``; + } +} + +export class GuestManager extends Manager { + constructor() { + super("guest", []); + console.log("Loading guest data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length === 0) { + console.log("Guest data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < data.length; i++) { + let id = Number(data[i].id); + let name = data[i].name; + let level = data[i].level; + let status = data[i].status; + let totalPlayed = data[i].totalPlayed; + this.listData.push(new Player(id, name, level, status, totalPlayed)); + } + console.log("Loaded " + this.listData.length + " players."); + this.render(); + } + generate() { + console.log("Generating guest data."); + let maxPlayerCount = 12; + for (let i = 0; i < maxPlayerCount; i++) { + let level = i < 3 ? 1 : ( i < 6 ? 3 : 7); + let p = new Player(i, "Player " + i, level, false, 0); + this.listData.push(p); + } + console.log("Generated data for " + this.listData.length + " guest"); + this.store(); + this.render(); + } + active(factor) { + factor = typeof factor !== "undefined" ? factor : 1; + let data = super.active(); + console.log("Normalize skill by a factor of " + factor + "."); + let players = data.map(function (p) { + p.skill = Math.ceil(p.skill / factor); + return p; + }); + return players; + } +} \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..91ac386 --- /dev/null +++ b/src/main.js @@ -0,0 +1,20 @@ +import 'notyf/notyf.min.css' +import 'bulma/css/bulma.css' +import '@fortawesome/fontawesome-free/css/all.css' +import './style.css' + +import { GameManager } from "./game.mjs"; + +// Court and player handling +let g = new GameManager(); + +// Game handling +document.getElementById("propose").addEventListener("click", () => { + g.propose(); +}); +document.getElementById("confirm").addEventListener("click", () => { + g.confirm(); +}); +document.getElementById("reset").addEventListener("click", () => { + g.reset(); +}); diff --git a/src/player.mjs b/src/player.mjs new file mode 100644 index 0000000..adf874d --- /dev/null +++ b/src/player.mjs @@ -0,0 +1,150 @@ +import { GuestManager } from "./guest.mjs"; +import { shuffle, Manager } from "./utils.mjs"; + +class Player { + constructor(id, name, level, status, totalPlayed) { + this.id = id; + this.status = typeof status !== "undefined" ? status : false; + this.name = name; + this.level = typeof level !== "undefined" ? level : 1; + this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + return ``; + } +} + +function randomLevel() { + const max_level = 10; + return Math.floor(Math.random() * max_level + 1); +} + +function randomStatus() { + return Math.random() < 0.5; +} + +function parseLineToPlayer(data) { + var info = data.split(","); + var id = Number(info[0].trim()); + var name = info[1].trim() + " " + info[2].trim(); + var level = Number(info[3].trim()); + return new Player(id, name, level, true, 0); +} + +export class PlayerManager extends Manager { + // g = new GuestManager(); + + constructor() { + super("regular", []); + console.log("Loading player data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length === 0) { + console.log("Player data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < data.length; i++) { + let id = Number(data[i].id); + let name = data[i].name; + let level = data[i].level; + let status = data[i].status; + let totalPlayed = data[i].totalPlayed; + this.listData.push(new Player(id, name, level, status, totalPlayed)); + } + console.log("Loaded " + this.listData.length + " players."); + this.render(); + this.addBehaviour(); + addLoadBehaviour(this); + } + generate() { + console.log("Generating player data."); + let maxPlayerCount = 71; + for (let i = 0; i < maxPlayerCount; i++) { + let p = new Player(i, "Player " + i, randomLevel(), randomStatus(), 0); + this.listData.push(p); + } + console.log("Generated data for " + this.listData.length + " players"); + this.store(); + this.render(); + } + import(data) { + var lines = data.split("\n"); + var players = []; + for (var i = 1; i < lines.length; i++) { + if (lines[i] == undefined || lines[i].trim() == "") { + continue; + } + players.push(parseLineToPlayer(lines[i])); + } + console.log("Loaded " + players.length + " Players"); + for (var i = 0; i < players.length; i++) { + players[i].print(); + } + this.listData = players; + this.store(); + this.render(); + } + active(factor) { + factor = typeof factor !== "undefined" ? factor : 1; + let data = super.active(); + console.log("Normalize skill by a factor of " + factor + "."); + let players = data.map(function (p) { + p.skill = Math.ceil(p.skill / factor); + return p; + }); + return players; + } + propose(count) { + console.log("Required players are " + count); + let factor = Number(document.getElementById("skill").value); + console.log("Skill normalized by a factor of " + factor + "."); + const activePlayers = this.active(factor); + console.log("Active players are:"); + console.log( + activePlayers + .map((i) => { + return i.name; + }) + .join(",") + ); + const shuffledPlayers = shuffle(activePlayers); + shuffledPlayers.sort((a, b) => a.totalPlayed - b.totalPlayed); + const selectedPlayers = shuffledPlayers.slice(0, count); + selectedPlayers.sort((a, b) => a.level - b.level); + console.log("Selected players are:"); + console.log( + selectedPlayers + .map((i) => { + return i.name; + }) + .join(",") + ); + return selectedPlayers; + } +} + +// TODO Add load behaviour to constructor +export function addLoadBehaviour(p) { + const f = document.querySelector("#player-load input[type=file]"); + f.addEventListener("change", () => { + const file = f.files[0]; + let importData; + console.log("Loading data from " + file.name); + const reader = new FileReader(); + reader.onload = function (e) { + importData = reader.result; + p.import(importData); + }; + reader.readAsText(file); + }); +} diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..8e3b713 --- /dev/null +++ b/src/style.css @@ -0,0 +1,12 @@ +.button-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-gap: 15px; +} +#timer-display { + text-align: center; + width: fit-content; +} +table { + font-size: 1.5em; +} \ No newline at end of file diff --git a/src/timer.js b/src/timer.js new file mode 100644 index 0000000..09189c0 --- /dev/null +++ b/src/timer.js @@ -0,0 +1,88 @@ +let minsPerRound = Number(sessionStorage.getItem("minsPerRound")) || 12; +let timerRunningFlag = Number(sessionStorage.getItem("timerRunningFlag")) || 0; +let deadline = + Number(sessionStorage.getItem("deadline")) || new Date().getTime(); +let clock = 0; + +function setTimer(m, s) { + let timer = document.getElementById("timer-display"); + m = m < 10 ? "0" + m : m; + s = s < 10 ? "0" + s : s; + timer.value = `${m}:${s}`; +} + +function setSessionData() { + sessionStorage.setItem("deadline", deadline); + sessionStorage.setItem("minsPerRound", minsPerRound); + sessionStorage.setItem("timerRunningFlag", timerRunningFlag); +} + +function resetTimer() { + clearInterval(clock); + let mins = Math.floor(minsPerRound); + let secs = (minsPerRound - mins) * 60; + setTimer(mins, secs); + timerRunningFlag = 0; + setSessionData(); +} + +function updateTimer(milliseconds) { + const m = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60)); + const s = Math.floor((milliseconds % (1000 * 60)) / 1000); + setTimer(m, s); +} + +function refreshTimer() { + const now = new Date().getTime(); + const millisecondsToDeadline = deadline - now; + if (millisecondsToDeadline > 0) { + updateTimer(millisecondsToDeadline); + return; + } + resetTimer(); + const notification = new Notyf({ + duration: 0, + position: { x: "center", y: "top" }, + dismissible: true, + }); + notification.error("Round completed"); +} + +function startTimer(fresh) { + if (fresh) { + let now = new Date().getTime(); + const millisecondsToDeadline = minsPerRound * 60 * 1000; + deadline = now + millisecondsToDeadline; + } + timerRunningFlag = 1; + setSessionData(); + clock = setInterval(refreshTimer, 1000); +} + +window.onload = function () { + if (timerRunningFlag) startTimer(0); + else resetTimer(); + + document.getElementById("timer-start").addEventListener("click", () => { + if (timerRunningFlag != 0) return; + startTimer(1); + }); + + document.getElementById("timer-stop").addEventListener("click", () => { + resetTimer(); + }); + + document.getElementById("timer-inc").addEventListener("click", () => { + if (timerRunningFlag == 0) { + minsPerRound += 0.5; + resetTimer(); + } + }); + + document.getElementById("timer-dec").addEventListener("click", () => { + if (timerRunningFlag == 0 && minsPerRound != 0) { + minsPerRound -= 0.5; + resetTimer(); + } + }); +}; diff --git a/src/utils.mjs b/src/utils.mjs new file mode 100644 index 0000000..06a2519 --- /dev/null +++ b/src/utils.mjs @@ -0,0 +1,51 @@ +export class Manager { + constructor(description, listData) { + this.description = description; + this.listData = listData; + this.count = listData.length; + } + store() { + let stringData = JSON.stringify(this.listData); + localStorage.setItem(this.description, stringData); + } + render() { + let renderedHTML = this.listData + .map((i) => { + return i.render(); + }) + .join(""); + let elementId = this.description + "_list"; + document.getElementById(elementId).innerHTML = renderedHTML; + this.addBehaviour(); + } + addBehaviour() { + for (let idx = 0; idx < this.listData.length; ++idx) { + const elementId = this.description + "_" + this.listData[idx].id; + const p = document.getElementById(elementId); + p.addEventListener("click", () => { + this.listData[idx].toggle(); + this.store(); + p.classList.toggle("is-success"); + p.classList.toggle("is-danger"); + }); + } + } + active() { + return this.listData.filter(function (c) { + return c.status; + }); + } + inactive() { + return this.listData.filter(function (c) { + return !c.status; + }); + } +} + +export function shuffle(array) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; +} -- cgit v1.3.1