From 36f169c94df692d48ee038e3c91852b7d50736cf Mon Sep 17 00:00:00 2001 From: js6pak Date: Mon, 22 Jan 2024 01:50:55 +0100 Subject: [PATCH] Some changes I should have split up Fix the layout on mobile Make the select input transparent Enable type checking --- .github/workflows/ci.yml | 14 ++-- index.html | 38 +++++------ package.json | 6 +- pnpm-lock.yaml | 11 ++- script.js | 142 ++++++++++++++++++++++++++++----------- style.css | 15 ++--- tsconfig.json | 13 ++++ 7 files changed, 158 insertions(+), 81 deletions(-) create mode 100644 tsconfig.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 933dd97a..02b08999 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,9 +6,13 @@ jobs: format: runs-on: ubuntu-latest steps: - - uses: biomejs/setup-biome@v2 - with: - version: latest - uses: actions/checkout@v4 - - name: Lint and check formatting - run: biome ci . + - uses: pnpm/action-setup@v2 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: | + pnpm biome ci . + pnpm tsc --noEmit diff --git a/index.html b/index.html index 6d3a5a38..d07deb37 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ Impostor | Among Us Private Server - + @@ -22,38 +22,30 @@
-

Connect to a Server

+

Connect to a Server

-
-
-
- -
-
- -
-
- -
-
+
+ + +
-
+
- - - + + +
diff --git a/package.json b/package.json index 3b638b85..92a93430 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,7 @@ { "devDependencies": { - "@biomejs/biome": "1.5.2" - } + "@biomejs/biome": "^1", + "typescript": "^5" + }, + "packageManager": "pnpm@8.14.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c12de9d9..9c829349 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,8 +6,11 @@ settings: devDependencies: '@biomejs/biome': - specifier: 1.5.2 + specifier: ^1 version: 1.5.2 + typescript: + specifier: ^5 + version: 5.3.3 packages: @@ -98,3 +101,9 @@ packages: requiresBuild: true dev: true optional: true + + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + dev: true diff --git a/script.js b/script.js index db81c45b..f4b628a0 100644 --- a/script.js +++ b/script.js @@ -1,52 +1,103 @@ -const DEFAULT_PORT_HTTP = "22023"; -const DEFAULT_PORT_HTTPS = "443"; +const DEFAULT_PORT_HTTP = 22023; +const DEFAULT_PORT_HTTPS = 443; + +/** + * @template {HTMLElement} T + * @param {string} elementId + * @returns {T} + */ +function getElementByIdOrThrow(elementId) { + const element = document.getElementById(elementId); + if (element === null) throw new Error(`Couldn't find the element with id ${elementId}`); + return /** @type {T} */ (element); +} + +const addressInput = /** @type {HTMLInputElement} */ (getElementByIdOrThrow("address")); +const portInput = /** @type {HTMLInputElement} */ (getElementByIdOrThrow("port")); +const nameInput = /** @type {HTMLInputElement} */ (getElementByIdOrThrow("name")); +const protocolSelect = + /** @type {Omit & { value: Protocol; }} */ + (getElementByIdOrThrow("protocol")); + +/** + * @typedef {{ protocol: Protocol, address: string, port: number, name: string, url: string }} ServerInfo + * @typedef {"desktop" | "android" | "ios"} Platform + * @typedef {"https" | "http"} Protocol + */ /** - * @typedef {{ address: string, port: number, name: string, protocol: string, url: string }} ServerInfo * @returns {ServerInfo} */ function parseForm() { - const address = document.getElementById("address").value.trim(); - const port = parseInt(document.getElementById("port").value) ?? DEFAULT_PORT_HTTP; - const name = document.getElementById("name").value || "Impostor"; - const protocol = document.querySelector("select[name=serverProtocol]").value || "http"; + const protocol = protocolSelect.value; + const address = addressInput.value.trim(); + const port = parseInt(portInput.value) || (protocol === "http" ? DEFAULT_PORT_HTTP : DEFAULT_PORT_HTTPS); + const name = nameInput.value || "Impostor"; - return { address, port, name, protocol, url: `${protocol}://${address}` }; + return { protocol, address, port, name, url: `${protocol}://${address}` }; } -async function downloadAsync() { +function downloadAsync() { const serverInfo = parseForm(); + if (!serverInfo.address) { + return false; + } const json = generateRegionInfo(serverInfo); + + console.log(`Saving ${json}`); + const blob = new Blob([json], { type: "text/plain" }); saveFile(blob, "regionInfo.json"); return false; } -async function openApp() { +function openApp() { const serverInfo = parseForm(); + if (!serverInfo.address) { + return false; + } const params = new URLSearchParams({ servername: serverInfo.name, - serverport: serverInfo.port, + serverport: serverInfo.port.toString(), serverip: serverInfo.url, - usedtls: false, + usedtls: false.toString(), }); - window.location = `amongus://init?${params.toString()}`; + + const url = `amongus://init?${params.toString()}`; + + console.log(`Opening ${url}`); + window.location.href = url; return false; } -let currentPlatform; +/** @type {Record} */ +const platformButtons = { + desktop: getElementByIdOrThrow("desktop"), + android: getElementByIdOrThrow("android"), + ios: getElementByIdOrThrow("ios"), +}; + +/** @type {?Platform} */ +let currentPlatform = null; let httpsSetExplicitly = false; +/** + * @param {Platform} platform + * @param {boolean} value + */ function setEnabled(platform, value) { - for (const e of document.querySelectorAll(`.${platform}-support`)) { + for (const e of /** @type {NodeListOf} */ (document.querySelectorAll(`.${platform}-support`))) { e.style.display = value ? "block" : "none"; } } +/** + * @param {Platform} platform + */ function setPlatform(platform) { if (currentPlatform === platform) { return; @@ -54,39 +105,44 @@ function setPlatform(platform) { if (currentPlatform) { setEnabled(currentPlatform, false); - document.getElementById(currentPlatform).classList.remove("text-primary"); + platformButtons[currentPlatform].classList.remove("text-primary"); } // HTTPS is mandatory on ios/android - const protocol = document.getElementById("protocol"); if (platform === "android" || platform === "ios") { - httpsSetExplicitly = protocol.value === "https"; - protocol.value = "https"; - protocol.disabled = true; + httpsSetExplicitly = protocolSelect.value === "https"; + protocolSelect.value = "https"; + protocolSelect.disabled = true; setPortIfDefault("https"); } else { - protocol.disabled = false; + protocolSelect.disabled = false; if (!httpsSetExplicitly) { - protocol.value = "http"; + protocolSelect.value = "http"; setPortIfDefault("http"); } } setEnabled(platform, true); - document.getElementById(platform).classList.add("text-primary"); + platformButtons[platform].classList.add("text-primary"); currentPlatform = platform; } +/** + * @param {Protocol} protocol + */ function setPortIfDefault(protocol) { const oldPort = protocol === "http" ? DEFAULT_PORT_HTTPS : DEFAULT_PORT_HTTP; const newPort = protocol === "http" ? DEFAULT_PORT_HTTP : DEFAULT_PORT_HTTPS; - const portField = document.getElementById("port"); - if (portField.value === oldPort) { - portField.value = newPort; + if (!portInput.value || portInput.value === oldPort.toString()) { + portInput.value = newPort.toString(); } } +function onProtocolChange() { + setPortIfDefault(protocolSelect.value); +} + /** * @param {ServerInfo} serverInfo * @returns {string} @@ -114,9 +170,13 @@ function generateRegionInfo(serverInfo) { Regions: regions, }; - return JSON.stringify(jsonServerData); + return JSON.stringify(jsonServerData, null, 4); } +/** + * @param {Blob} blob + * @param {string} fileName + */ function saveFile(blob, fileName) { const url = URL.createObjectURL(blob); @@ -132,26 +192,26 @@ function saveFile(blob, fileName) { function fillFromLocationHash() { const urlServerAddress = document.location.hash.substring(1).split(":"); - const serverAddress = urlServerAddress[0]; - const serverPort = urlServerAddress.length > 1 ? urlServerAddress[1] : DEFAULT_PORT_HTTP.toString(); - let protocol = urlServerAddress.length > 2 ? urlServerAddress[2] : "http"; - const serverName = urlServerAddress.length > 3 ? urlServerAddress[3] : ""; + const serverAddress = urlServerAddress.length > 0 ? urlServerAddress[0] : null; + const serverPort = urlServerAddress.length > 1 ? urlServerAddress[1] : null; + const protocol = urlServerAddress.length > 2 ? urlServerAddress[2] : null; + const serverName = urlServerAddress.length > 3 ? urlServerAddress[3] : null; if (serverAddress) { - document.getElementById("address").value = serverAddress; + addressInput.value = serverAddress; } - if (!Number.IsNan(parseInt(serverPort))) { - document.getElementById("port").value = serverPort; + if (serverPort && !Number.isNaN(parseInt(serverPort))) { + portInput.value = serverPort; } - // Set the default protocol to http - if (protocol !== "http" && protocol !== "https") { - protocol = "http"; + if (protocol === "http" || protocol === "https") { + protocolSelect.value = protocol; } - document.querySelector("select[name=serverProtocol]").value = protocol; - document.getElementById("name").value = serverName; + if (serverName) { + nameInput.value = serverName; + } } function setLocationHash() { @@ -159,6 +219,8 @@ function setLocationHash() { document.location.hash = [serverInfo.address, serverInfo.port, serverInfo.protocol, serverInfo.name].join(":"); } +fillFromLocationHash(); + if (["iPhone", "iPad", "iPod"].indexOf(window.navigator.platform) !== -1) { setPlatform("ios"); } else if (/Android/.test(window.navigator.userAgent)) { @@ -166,5 +228,3 @@ if (["iPhone", "iPad", "iPod"].indexOf(window.navigator.platform) !== -1) { } else { setPlatform("desktop"); } - -fillFromLocationHash(); diff --git a/style.css b/style.css index 2b1fb6d3..fc6abe00 100644 --- a/style.css +++ b/style.css @@ -33,15 +33,16 @@ body { font-size: 1.6rem; } -.form-control { - width: 287px; +.custom-select { + background-color: transparent; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23f8f9fa' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e"); } -select.form-control { - appearance: none; +.custom-select:disabled { + background-color: #e9ecef19; } -select.form-control option { +.custom-select option { background-color: #252525; font-size: 16px; } @@ -65,10 +66,6 @@ select.form-control option { height: 1.25em; } -code { - white-space: nowrap; -} - .platform { cursor: pointer; } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..0441a435 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "allowJs": true, + "checkJs": true + } +}