mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-24 05:23:36 +00:00
## Description: - rips out some duped code, making tables use the same layout, where the only thing different is the row content. - updated text to be emojis to save space - updated columns to be as wide as they need to be - updated cells to have left/right thin borders to read easier - added more supported column types - removed the + button to always show everyone, where the current player is either at the bottom or in the top 5 - added a cogwheel to change options - can select different options for each menu type (player/team stats) <img width="582" height="630" alt="image" src="https://github.com/user-attachments/assets/e54dc3d5-eb2c-4bab-8732-06bea68aec45" /> works fine on mobile, will probably need some future love though (has h-scroll, so all options can be seen by scrolling): ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: w.o.n
121 lines
3.7 KiB
TypeScript
121 lines
3.7 KiB
TypeScript
import type { ColumnDef } from "../src/client/hud/layers/lib/StatsColumns";
|
|
import {
|
|
aggregateTeamValues,
|
|
TeamStats,
|
|
} from "../src/client/hud/layers/TeamStats";
|
|
import type { GameView, PlayerView } from "../src/client/view";
|
|
import { PlayerType } from "../src/core/game/Game";
|
|
import { UserSettings } from "../src/core/game/UserSettings";
|
|
import { playerInfo, setup } from "./util/Setup";
|
|
|
|
describe("aggregateTeamValues", () => {
|
|
it("sums values for alive players only", async () => {
|
|
const game = await setup("plains", {}, [
|
|
playerInfo("alive", PlayerType.Human),
|
|
playerInfo("other-alive", PlayerType.Human),
|
|
playerInfo("dead", PlayerType.Human),
|
|
]);
|
|
const alivePlayer = game.player("alive");
|
|
const otherAlivePlayer = game.player("other-alive");
|
|
const deadPlayer = game.player("dead");
|
|
|
|
for (let x = 0; x < 12; x++) alivePlayer.conquer(game.ref(x, 0));
|
|
for (let x = 0; x < 8; x++) otherAlivePlayer.conquer(game.ref(x, 1));
|
|
alivePlayer.addGold(50n);
|
|
otherAlivePlayer.addGold(30n);
|
|
deadPlayer.addGold(100n);
|
|
|
|
const selected: ColumnDef[] = [
|
|
{
|
|
id: "tiles",
|
|
labelKey: "leaderboard.owned",
|
|
valueAlignment: "end",
|
|
value: (player) => player.numTilesOwned(),
|
|
renderValue: (value) => `tiles:${value}`,
|
|
},
|
|
{
|
|
id: "gold",
|
|
labelKey: "leaderboard.gold",
|
|
valueAlignment: "end",
|
|
value: (player) => Number(player.gold()),
|
|
renderValue: (value) => `gold:${value}`,
|
|
},
|
|
];
|
|
|
|
expect(
|
|
Object.fromEntries(
|
|
aggregateTeamValues(
|
|
game.allPlayers() as unknown as PlayerView[],
|
|
selected,
|
|
game as unknown as GameView,
|
|
),
|
|
),
|
|
).toEqual({ tiles: 20, gold: 80 });
|
|
});
|
|
});
|
|
|
|
describe("TeamStats", () => {
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
(
|
|
UserSettings as unknown as { cache: Map<string, string | null> }
|
|
).cache.clear();
|
|
});
|
|
|
|
it("renders team ranks with the shared stats table", async () => {
|
|
const players = [
|
|
{
|
|
id: () => "blue-player",
|
|
team: () => "Blue",
|
|
numTilesOwned: () => 10,
|
|
gold: () => 10n,
|
|
isAlive: () => true,
|
|
},
|
|
{
|
|
id: () => "red-player",
|
|
team: () => "Red",
|
|
numTilesOwned: () => 5,
|
|
gold: () => 20n,
|
|
isAlive: () => true,
|
|
},
|
|
] as unknown as PlayerView[];
|
|
const game = {
|
|
myPlayer: () => players[0],
|
|
playerViews: () => players,
|
|
config: () => ({ maxTroops: () => 100 }),
|
|
numLandTiles: () => 100,
|
|
numTilesWithFallout: () => 0,
|
|
} as unknown as GameView;
|
|
const teamStats = new TeamStats();
|
|
teamStats.game = game;
|
|
teamStats.visible = true;
|
|
document.body.append(teamStats);
|
|
|
|
teamStats.refresh();
|
|
await teamStats.updateComplete;
|
|
|
|
const table = teamStats.querySelector(".stats-table");
|
|
const picker = teamStats.querySelector("column-picker");
|
|
const rowCells = teamStats.querySelectorAll(
|
|
'.stats-table-row > [role="cell"]',
|
|
);
|
|
expect(teamStats.children).toHaveLength(1);
|
|
expect(picker?.closest(".stats-table")).toBe(table);
|
|
expect(table?.querySelector(".stats-table-header")).not.toBeNull();
|
|
expect(rowCells[0]?.textContent?.trim()).toBe("1");
|
|
expect(rowCells[1]?.textContent?.trim()).toContain("Blue");
|
|
|
|
const headers = teamStats.querySelectorAll(
|
|
'.stats-table-header > [role="columnheader"]',
|
|
);
|
|
(headers[3].querySelector("button") as HTMLButtonElement).click();
|
|
await teamStats.updateComplete;
|
|
expect(
|
|
teamStats.querySelectorAll('.stats-table-row > [role="cell"]')[1]
|
|
?.textContent,
|
|
).toContain("Red");
|
|
|
|
teamStats.remove();
|
|
});
|
|
});
|