Files
OpenFrontIO/src/client/graphics/layers/GameLeftSidebar.ts
T
Martin I 070b5060d8 fix: swap team text and buttons position; fix gap space on leaderboard (#3135)
## Description:

1. Swaps the position of the teams text and leaderboard buttons;
2. Edits the text and button margins
3. Fixes spacing bug where because of a "gap-2", if only one leaderboard
is open, there's empty space on the left or right of the leaderboard.
4. Small code refactor proposed by code rabbit / icon description

Button swap and spacing changes were suggested by:
@FloPinguin  @ryanbarlow97  

## 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

***
Screenshots:
Before swapping the position and editing the spacing:
<img width="242" height="151" alt="image"
src="https://github.com/user-attachments/assets/cf196842-b469-45ab-a685-0a5e56b56378"
/>

After swapping the position and editing the spacing: ✔️
<img width="233" height="149" alt="image"
src="https://github.com/user-attachments/assets/c88da4ec-0f23-4670-af5d-fce4124d4936"
/>

Before swapping the position and editing the spacing without the text:
<img width="528" height="398" alt="image"
src="https://github.com/user-attachments/assets/e1e31352-31d1-42a4-ad92-a60b0014b779"
/>

After swapping the position and editing the spacing without the text: ✔️
<img width="514" height="350" alt="image"
src="https://github.com/user-attachments/assets/6a1f2391-e2f1-478e-bada-9436b7cb2e13"
/>

Before fixing the spacing on mobile:
<img width="579" height="158" alt="image"
src="https://github.com/user-attachments/assets/8d5e225b-6dbd-4a07-afeb-97035000a09d"
/>

After fixing the spacing on mobile: ✔️
<img width="575" height="134" alt="image"
src="https://github.com/user-attachments/assets/f9016060-ac9e-47fc-8886-e3eee6359906"
/>

Before fixing the leaderboard space issue:
<img width="511" height="398" alt="image"
src="https://github.com/user-attachments/assets/0fadddcd-2c5f-4caf-b641-c7a3e19a5a14"
/>

<img width="511" height="398" alt="image"
src="https://github.com/user-attachments/assets/2a9a9f7d-e08d-4908-b2d1-f26500c4c602"
/>

<img width="585" height="204" alt="image"
src="https://github.com/user-attachments/assets/9dbb4c51-56ae-4e7a-b603-f49cd1dc2286"
/>

After fixing the leaderboard space issue: ✔️
<img width="533" height="463" alt="image"
src="https://github.com/user-attachments/assets/c0608e83-974a-4950-94cd-896bc7dd7720"
/>

##Discord username: martoi

***
Signed-off-by: MartinIvovIv <https://github.com/martinIvovIv>
2026-02-06 19:39:35 -08:00

182 lines
5.9 KiB
TypeScript

import { Colord } from "colord";
import { html, LitElement } from "lit";
import { customElement, state } from "lit/decorators.js";
import { GameMode } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { translateText } from "../../Utils";
import { Layer } from "./Layer";
import leaderboardRegularIcon from "/images/LeaderboardIconRegularWhite.svg?url";
import leaderboardSolidIcon from "/images/LeaderboardIconSolidWhite.svg?url";
import teamRegularIcon from "/images/TeamIconRegularWhite.svg?url";
import teamSolidIcon from "/images/TeamIconSolidWhite.svg?url";
@customElement("game-left-sidebar")
export class GameLeftSidebar extends LitElement implements Layer {
@state()
private isLeaderboardShow = false;
@state()
private isTeamLeaderboardShow = false;
@state()
private isVisible = false;
@state()
private isPlayerTeamLabelVisible = false;
@state()
private playerTeam: string | null = null;
private playerColor: Colord = new Colord("#FFFFFF");
public game: GameView;
private _shownOnInit = false;
createRenderRoot() {
return this;
}
init() {
this.isVisible = true;
if (this.isTeamGame) {
this.isPlayerTeamLabelVisible = true;
}
// Make it visible by default on large screens
if (window.innerWidth >= 1024) {
// lg breakpoint
this._shownOnInit = true;
}
this.requestUpdate();
}
tick() {
if (!this.playerTeam && this.game.myPlayer()?.team()) {
this.playerTeam = this.game.myPlayer()!.team();
if (this.playerTeam) {
this.playerColor = this.game
.config()
.theme()
.teamColor(this.playerTeam);
this.requestUpdate();
}
}
if (this._shownOnInit && !this.game.inSpawnPhase()) {
this._shownOnInit = false;
this.isLeaderboardShow = true;
this.requestUpdate();
}
if (!this.game.inSpawnPhase() && this.isPlayerTeamLabelVisible) {
this.isPlayerTeamLabelVisible = false;
this.requestUpdate();
}
}
private toggleLeaderboard(): void {
this.isLeaderboardShow = !this.isLeaderboardShow;
}
private toggleTeamLeaderboard(): void {
this.isTeamLeaderboardShow = !this.isTeamLeaderboardShow;
}
private get isTeamGame(): boolean {
return this.game?.config().gameConfig().gameMode === GameMode.Team;
}
private getTranslatedPlayerTeamLabel(): string {
if (!this.playerTeam) return "";
const translationKey = `team_colors.${this.playerTeam.toLowerCase()}`;
const translated = translateText(translationKey);
return translated === translationKey ? this.playerTeam : translated;
}
render() {
return html`
<aside
class=${`fixed top-4 left-4 z-1000 flex flex-col max-h-[calc(100vh-80px)] overflow-y-auto p-2 bg-slate-800/40 backdrop-blur-xs shadow-xs rounded-lg transition-transform duration-300 ease-out transform ${
this.isVisible ? "translate-x-0" : "hidden"
}`}
>
<div class="flex items-center gap-4 xl:gap-6 text-white">
<div
class="cursor-pointer p-0.5 bg-gray-700/50 hover:bg-gray-600 border rounded-md border-slate-500 transition-colors"
@click=${this.toggleLeaderboard}
role="button"
tabindex="0"
@keydown=${(e: KeyboardEvent) => {
if (e.key === "Enter" || e.key === " " || e.code === "Space") {
e.preventDefault();
this.toggleLeaderboard();
}
}}
>
<img
src=${this.isLeaderboardShow
? leaderboardSolidIcon
: leaderboardRegularIcon}
alt=${translateText("help_modal.icon_alt_player_leaderboard") ||
"Player Leaderboard Icon"}
width="20"
height="20"
/>
</div>
${this.isTeamGame
? html`
<div
class="cursor-pointer p-0.5 bg-gray-700/50 hover:bg-gray-600 border rounded-md border-slate-500 transition-colors"
@click=${this.toggleTeamLeaderboard}
role="button"
tabindex="0"
@keydown=${(e: KeyboardEvent) => {
if (
e.key === "Enter" ||
e.key === " " ||
e.code === "Space"
) {
e.preventDefault();
this.toggleTeamLeaderboard();
}
}}
>
<img
src=${this.isTeamLeaderboardShow
? teamSolidIcon
: teamRegularIcon}
alt=${translateText(
"help_modal.icon_alt_team_leaderboard",
) || "Team Leaderboard Icon"}
width="20"
height="20"
/>
</div>
`
: null}
</div>
${this.isPlayerTeamLabelVisible
? html`
<div
class="flex items-center w-full text-white"
@contextmenu=${(e: Event) => e.preventDefault()}
>
${translateText("help_modal.ui_your_team")}
<span
style="--color: ${this.playerColor.toRgbString()}"
class="text-(--color)"
>
&nbsp;${this.getTranslatedPlayerTeamLabel()} &#10687;
</span>
</div>
`
: null}
<div
class=${`block lg:flex flex-wrap ${this.isLeaderboardShow && this.isTeamLeaderboardShow ? "gap-2" : ""}`}
>
<leader-board .visible=${this.isLeaderboardShow}></leader-board>
<team-stats
class="flex-1"
.visible=${this.isTeamLeaderboardShow && this.isTeamGame}
></team-stats>
</div>
<slot></slot>
</aside>
`;
}
}