Some changes I should have split up

Fix the layout on mobile
Make the select input transparent
Enable type checking
This commit is contained in:
js6pak committed 2024-01-22 01:53:27 +01:00
1 parent 948aeeeb45
commit 36f169c94d
7 files changed
+158 -81

No files matched your search

+9 -5
View File
@@ -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
+15 -23
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Impostor | Among Us Private Server</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
</head>
@@ -22,38 +22,30 @@
<section class="container">
<div class="mb-4 mb-md-3">
<h3 class="text-center text-md-left mb-4 mb-md-3 w-100">Connect to a Server</h3>
<h3 class="text-center mb-4 mb-md-3 w-100">Connect to a Server</h3>
</div>
<form id="serverFileForm" class="container p-0" onsubmit="return false;">
<div class="row justify-content-center mb-5 mb-md-4">
<div class="form-row">
<div class="col">
<select name="serverProtocol" id="protocol" class="custom-select" style="height: 100%">
<option value="http" selected>http://</option>
<option value="https">https://</option>
</select>
</div>
<div class="col">
<input class="form-control form-control-lg bg-transparent text-light text-center mr-2"
type="text" placeholder="Server address" id="address" name="address" required>
</div>
<div class="col">
<input class="form-control form-control-lg bg-transparent text-light" style="max-width: 110px"
type="number" placeholder="Port" id="port" name="port" min="1" max="65535" required>
</div>
</div>
<div class="form-row justify-content-center mb-4 mx-md-5">
<select name="serverProtocol" id="protocol" class="col custom-select text-light" style="height: unset;" onchange="onProtocolChange()">
<option value="http" selected>http://</option>
<option value="https">https://</option>
</select>
<input class="col-6 col-md-8 mx-1 mx-md-2 form-control form-control-lg bg-transparent text-light text-center"
type="text" placeholder="Server address" id="address" name="address" required>
<input class="col form-control form-control-lg bg-transparent text-light" style="max-width: 110px"
type="number" placeholder="Port" id="port" name="port" min="1" max="65535" required>
</div>
<div class="row justify-content-center mb-5 mb-md-4">
<div class="row justify-content-center mb-4">
<div class="row justify-content-center flex-nowrap">
<input class="form-control form-control-lg bg-transparent text-light text-center mr-2"
type="text" placeholder="Server name" id="name" name="name">
</div>
</div>
<div class="row justify-content-center">
<button class="btn btn-primary btn-lg support-text desktop-support" onclick="downloadAsync()">Download Server File</button>
<button class="btn btn-primary btn-lg support-text android-support ios-support" onclick="openApp()">Open in Among Us</button>
<button class="btn btn-secondary btn-lg ml-5" onclick="setLocationHash()">Create sharable link</button>
<button class="col-md-4 btn btn-primary btn-lg support-text desktop-support" onclick="downloadAsync()">Download server file</button>
<button class="col-md-4 btn btn-primary btn-lg support-text android-support ios-support" onclick="openApp()">Open in Among Us</button>
<button class="col-md-4 offset-md-1 mt-1 mt-md-0 btn btn-secondary btn-lg" onclick="setLocationHash()">Create sharable link</button>
</div>
</form>
<div class="mt-4">
+4 -2
View File
@@ -1,5 +1,7 @@
{
"devDependencies": {
"@biomejs/biome": "1.5.2"
}
"@biomejs/biome": "^1",
"typescript": "^5"
},
"packageManager": "pnpm@8.14.1"
}
+10 -1
View File
@@ -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
+101 -41
View File
@@ -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<HTMLSelectElement, "value"> & { 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<Platform, HTMLAnchorElement>} */
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<HTMLElement>} */ (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();
+6 -9
View File
@@ -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;
}
+13
View File
@@ -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
}
}