Main Menu UI Overhaul (#2829)

## Description:

Overhauls the Main Menu UI, visit https://menu.openfront.dev to see
everything.

## 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-01-09 20:26:34 -08:00
committed by GitHub
parent 848a3a5633
commit 5e6c90d9bb
60 changed files with 7671 additions and 4546 deletions
+29 -16
View File
@@ -53,7 +53,7 @@ describe("FluentSlider", () => {
describe("Value Updates from Range Slider", () => {
it("should update value when slider input changes", async () => {
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
expect(rangeInput).toBeTruthy();
@@ -67,7 +67,7 @@ describe("FluentSlider", () => {
});
it("should update value when slider change event fires", async () => {
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
@@ -84,7 +84,7 @@ describe("FluentSlider", () => {
const eventSpy = vi.fn();
slider.addEventListener("value-changed", eventSpy);
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
rangeInput.valueAsNumber = 200;
@@ -107,7 +107,7 @@ describe("FluentSlider", () => {
const eventSpy = vi.fn();
slider.addEventListener("value-changed", eventSpy);
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
@@ -138,7 +138,7 @@ describe("FluentSlider", () => {
slider.addEventListener("value-changed", mockHandler);
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
rangeInput.valueAsNumber = 250;
@@ -163,7 +163,7 @@ describe("FluentSlider", () => {
slider.addEventListener("value-changed", mockHandler);
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
rangeInput.valueAsNumber = 350;
@@ -221,9 +221,7 @@ describe("FluentSlider", () => {
describe("Component Structure", () => {
it("should render a range input", () => {
const rangeInput = slider.shadowRoot?.querySelector(
'input[type="range"]',
);
const rangeInput = slider.querySelector('input[type="range"]');
expect(rangeInput).toBeTruthy();
});
@@ -233,7 +231,7 @@ describe("FluentSlider", () => {
slider.max = 400;
slider.step = 1;
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
@@ -242,11 +240,11 @@ describe("FluentSlider", () => {
expect(rangeInput.step).toBe("1");
});
it("should render an editable span for the value display", () => {
const editableSpan = slider.shadowRoot?.querySelector("span.editable");
expect(editableSpan).toBeTruthy();
expect(editableSpan?.getAttribute("role")).toBe("button");
expect(editableSpan?.getAttribute("tabindex")).toBe("0");
it("should render a span for the value display with role button", () => {
const valueSpan = slider.querySelector('span[role="button"]');
expect(valueSpan).toBeTruthy();
expect(valueSpan?.getAttribute("role")).toBe("button");
expect(valueSpan?.getAttribute("tabindex")).toBe("0");
});
});
@@ -262,7 +260,7 @@ describe("FluentSlider", () => {
slider.value = 0;
await slider.updateComplete;
const rangeInput = slider.shadowRoot?.querySelector(
const rangeInput = slider.querySelector(
'input[type="range"]',
) as HTMLInputElement;
@@ -279,4 +277,19 @@ describe("FluentSlider", () => {
expect(slider.value).toBe(400);
});
});
describe("Edge Cases", () => {
it("should handle min equal to max without NaN in style", async () => {
slider.min = 100;
slider.max = 100;
slider.value = 100;
await slider.updateComplete;
const rangeInput = slider.querySelector('input[type="range"]');
const style = rangeInput?.getAttribute("style");
expect(style).not.toContain("NaN");
expect(style).toContain("0%");
});
});
});