UI Extraction Host/Solo Modal (#3181)

## Description:

UI Extraction Host/Solo Modal
- Made all buttons do the same "press" feel (options/settings/random
map) are now the same as the map button.
- Also fixed a bug where you could "drag" the map image off the button.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n
This commit is contained in:
Ryan
2026-02-12 10:41:14 -08:00
committed by GitHub
parent bd96bcca0d
commit f8c14398c8
9 changed files with 1322 additions and 1334 deletions
+93
View File
@@ -0,0 +1,93 @@
import { GameMapType, UnitType } from "../../core/game/Game";
export function toOptionalNumber(
value: number | string | undefined,
): number | undefined {
if (typeof value === "number") {
return Number.isFinite(value) ? value : undefined;
}
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed) return undefined;
const numeric = Number(trimmed);
return Number.isFinite(numeric) ? numeric : undefined;
}
return undefined;
}
export function preventDisallowedKeys(
e: KeyboardEvent,
disallowedKeys: string[],
): void {
if (disallowedKeys.includes(e.key)) {
e.preventDefault();
}
}
export function parseBoundedIntegerFromInput(
input: HTMLInputElement,
{
min,
max,
stripPattern = /[eE+-]/g,
radix = 10,
}: {
min: number;
max: number;
stripPattern?: RegExp;
radix?: number;
},
): number | undefined {
input.value = input.value.replace(stripPattern, "");
const value = parseInt(input.value, radix);
if (isNaN(value) || value < min || value > max) {
return undefined;
}
return value;
}
export function parseBoundedFloatFromInput(
input: HTMLInputElement,
{ min, max }: { min: number; max: number },
): number | undefined {
const value = parseFloat(input.value);
if (isNaN(value) || value < min || value > max) {
return undefined;
}
return value;
}
export function getBotsForCompactMap(
bots: number,
compactMapEnabled: boolean,
): number {
if (compactMapEnabled && bots === 400) {
return 100;
}
if (!compactMapEnabled && bots === 100) {
return 400;
}
return bots;
}
export function getRandomMapType(): GameMapType {
const maps = Object.values(GameMapType);
const randIdx = Math.floor(Math.random() * maps.length);
return maps[randIdx] as GameMapType;
}
export function getUpdatedDisabledUnits(
disabledUnits: UnitType[],
unit: UnitType,
checked: boolean,
): UnitType[] {
return checked
? [...disabledUnits, unit]
: disabledUnits.filter((u) => u !== unit);
}