Skip to content

Commit 8dde30e

Browse files
authored
Update game timer UI (openfrontio#2577)
## Description: - use hh:mm:ss for timer format or mm:ss if no hours are present - refactor classes and code to be simpler - move timer inline with the buttons so the whole ui is smaller for more game space - update fast forward icon to better represent what it does - move replay controls below game time ui ### Before: <img width="218" height="155" alt="image" src="https://github.com/user-attachments/assets/bfdbe571-3ec5-4c02-840b-112e8e3caab1" /> <img width="360" height="171" alt="image" src="https://github.com/user-attachments/assets/ceee2923-fec8-4ebc-b9de-4b30a47b38a8" /> <img width="192" height="136" alt="image" src="https://github.com/user-attachments/assets/8f8f464c-48e4-42c1-b378-51be2b1fc405" /> ### After: <img width="287" height="106" alt="image" src="https://github.com/user-attachments/assets/30246189-9795-4822-b857-0af524cacb92" /> <img width="294" height="180" alt="image" src="https://github.com/user-attachments/assets/065285ca-ae46-4481-9dd5-00d3bb4fcfb3" /> <img width="290" height="182" alt="image" src="https://github.com/user-attachments/assets/c1b3da39-0785-4d50-8105-c028fa496963" /> <img width="213" height="88" alt="image" src="https://github.com/user-attachments/assets/41e0a84c-2f68-4d24-9923-dd92bb70d161" /> ## 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: `rovi.`
1 parent ae884cb commit 8dde30e

4 files changed

Lines changed: 45 additions & 56 deletions

File tree

Lines changed: 6 additions & 0 deletions
Loading

src/client/graphics/layers/GameRightSidebar.ts

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { html, LitElement } from "lit";
22
import { customElement, state } from "lit/decorators.js";
33
import exitIcon from "../../../../resources/images/ExitIconWhite.svg";
4+
import FastForwardIconSolid from "../../../../resources/images/FastForwardIconSolidWhite.svg";
45
import pauseIcon from "../../../../resources/images/PauseIconWhite.svg";
56
import playIcon from "../../../../resources/images/PlayIconWhite.svg";
6-
import replayRegularIcon from "../../../../resources/images/ReplayRegularIconWhite.svg";
7-
import replaySolidIcon from "../../../../resources/images/ReplaySolidIconWhite.svg";
87
import settingsIcon from "../../../../resources/images/SettingIconWhite.svg";
98
import { EventBus } from "../../../core/EventBus";
109
import { GameType } from "../../../core/game/Game";
@@ -74,13 +73,17 @@ export class GameRightSidebar extends LitElement implements Layer {
7473
}
7574

7675
private secondsToHms = (d: number): string => {
76+
const pad = (n: number) => (n < 10 ? `0${n}` : n);
77+
7778
const h = Math.floor(d / 3600);
7879
const m = Math.floor((d % 3600) / 60);
7980
const s = Math.floor((d % 3600) % 60);
80-
let time = d === 0 ? "-" : `${s}s`;
81-
if (m > 0) time = `${m}m` + time;
82-
if (h > 0) time = `${h}h` + time;
83-
return time;
81+
82+
if (h !== 0) {
83+
return `${pad(h)}:${pad(m)}:${pad(s)}`;
84+
} else {
85+
return `${pad(m)}:${pad(s)}`;
86+
}
8487
};
8588

8689
private toggleReplayPanel(): void {
@@ -116,72 +119,52 @@ export class GameRightSidebar extends LitElement implements Layer {
116119
render() {
117120
if (this.game === undefined) return html``;
118121

122+
const timerColor =
123+
this.game.config().gameConfig().maxTimerValue !== undefined &&
124+
this.timer < 60
125+
? "text-red-400"
126+
: "";
127+
119128
return html`
120129
<aside
121-
class=${`flex flex-col max-h-[calc(100vh-80px)] overflow-y-auto p-2 bg-gray-800/70 backdrop-blur-sm shadow-xs rounded-lg transition-transform duration-300 ease-out transform ${
130+
class=${`w-fit flex flex-row items-center gap-3 py-2 px-3 bg-gray-800/70 backdrop-blur-sm shadow-xs rounded-lg transition-transform duration-300 ease-out transform text-white ${
122131
this._isVisible ? "translate-x-0" : "translate-x-full"
123132
}`}
124133
@contextmenu=${(e: Event) => e.preventDefault()}
125134
>
126-
<div
127-
class=${`flex justify-end items-center gap-2 text-white ${
128-
this._isReplayVisible ? "mb-2" : ""
129-
}`}
130-
>
131-
${this.maybeRenderReplayButtons()}
132-
<div
133-
class="w-6 h-6 cursor-pointer"
134-
@click=${this.onSettingsButtonClick}
135-
>
136-
<img
137-
src=${settingsIcon}
138-
alt="settings"
139-
width="20"
140-
height="20"
141-
style="vertical-align: middle;"
142-
/>
143-
</div>
144-
<div class="w-6 h-6 cursor-pointer" @click=${this.onExitButtonClick}>
145-
<img src=${exitIcon} alt="exit" width="20" height="20" />
146-
</div>
135+
<!-- In-game time -->
136+
<div class=${timerColor}>${this.secondsToHms(this.timer)}</div>
137+
138+
<!-- Buttons -->
139+
${this.maybeRenderReplayButtons()}
140+
141+
<div class="cursor-pointer" @click=${this.onSettingsButtonClick}>
142+
<img src=${settingsIcon} alt="settings" width="20" height="20" />
147143
</div>
148-
<!-- Timer display below buttons -->
149-
<div class="flex justify-center items-center mt-2">
150-
<div
151-
class="w-[70px] h-8 lg:w-24 lg:h-10 p-0.5 text-xs md:text-sm lg:text-base flex items-center justify-center text-white px-1"
152-
style="${this.game.config().gameConfig().maxTimerValue !==
153-
undefined && this.timer < 60
154-
? "color: #ff8080;"
155-
: ""}"
156-
>
157-
${this.secondsToHms(this.timer)}
158-
</div>
144+
145+
<div class="cursor-pointer" @click=${this.onExitButtonClick}>
146+
<img src=${exitIcon} alt="exit" width="20" height="20" />
159147
</div>
160148
</aside>
161149
`;
162150
}
163151

164152
maybeRenderReplayButtons() {
165153
if (this._isSinglePlayer || this.game?.config()?.isReplay()) {
166-
return html` <div
167-
class="w-6 h-6 cursor-pointer"
168-
@click=${this.toggleReplayPanel}
169-
>
154+
return html` <div class="cursor-pointer" @click=${this.toggleReplayPanel}>
170155
<img
171-
src=${this._isReplayVisible ? replaySolidIcon : replayRegularIcon}
156+
src=${FastForwardIconSolid}
172157
alt="replay"
173158
width="20"
174159
height="20"
175-
style="vertical-align: middle;"
176160
/>
177161
</div>
178-
<div class="w-6 h-6 cursor-pointer" @click=${this.onPauseButtonClick}>
162+
<div class="cursor-pointer" @click=${this.onPauseButtonClick}>
179163
<img
180164
src=${this.isPaused ? playIcon : pauseIcon}
181165
alt="play/pause"
182166
width="20"
183167
height="20"
184-
style="vertical-align: middle;"
185168
/>
186169
</div>`;
187170
} else {

src/client/graphics/layers/ReplayPanel.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ export class ReplayPanel extends LitElement implements Layer {
6666

6767
return html`
6868
<div
69-
class="flex-shrink-0 bg-opacity-60 bg-gray-900 p-1 lg:p-2 rounded-es-sm lg:rounded-lg backdrop-blur-md"
69+
class="p-2 bg-gray-800/70 backdrop-blur-sm shadow-xs rounded-lg"
7070
@contextmenu=${(e: Event) => e.preventDefault()}
7171
>
72-
<label class="block mb-1 text-white" translate="no">
72+
<label class="block mb-2 text-white" translate="no">
7373
${this.game?.config()?.isReplay()
7474
? translateText("replay_panel.replay_speed")
7575
: translateText("replay_panel.game_speed")}
7676
</label>
77-
<div class="grid grid-cols-2 gap-1">
77+
<div class="grid grid-cols-4 gap-2">
7878
${this.renderSpeedButton(ReplaySpeedMultiplier.slow, "×0.5")}
7979
${this.renderSpeedButton(ReplaySpeedMultiplier.normal, "×1")}
8080
${this.renderSpeedButton(ReplaySpeedMultiplier.fast, "×2")}
@@ -88,12 +88,12 @@ export class ReplayPanel extends LitElement implements Layer {
8888
}
8989

9090
private renderSpeedButton(value: ReplaySpeedMultiplier, label: string) {
91-
const isActive = this._replaySpeedMultiplier === value;
91+
const backgroundColor =
92+
this._replaySpeedMultiplier === value ? "bg-blue-400" : "";
93+
9294
return html`
9395
<button
94-
class="text-white font-bold py-0 rounded border transition ${isActive
95-
? "bg-blue-500 border-gray-400"
96-
: "border-gray-500"}"
96+
class="py-0.5 px-1 text-sm text-white rounded border transition border-gray-500 ${backgroundColor} hover:border-gray-200"
9797
@click=${() => this.onReplaySpeedChange(value)}
9898
>
9999
${label}

src/client/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,9 @@
408408
<game-starting-modal></game-starting-modal>
409409
<game-top-bar></game-top-bar>
410410
<unit-display></unit-display>
411-
<div class="flex fixed top-4 right-4 z-[1000] items-start gap-2">
412-
<replay-panel></replay-panel>
411+
<div class="flex flex-col items-end fixed top-4 right-4 z-[1000] gap-2">
413412
<game-right-sidebar></game-right-sidebar>
413+
<replay-panel></replay-panel>
414414
</div>
415415
<settings-modal></settings-modal>
416416
<player-panel></player-panel>

0 commit comments

Comments
 (0)