mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:30:43 +00:00
Move settings to it's own modal (#1366)
## Description: The settings has grown to the point where it deserves its own modal. <img width="1144" alt="Screenshot 2025-07-07 at 3 55 23 PM" src="https://github.com/user-attachments/assets/a1527d79-93c3-4bf3-ba67-dce643bc81ea" /> NOTE: styling is still needed. ## 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 - [ ] I have added relevant tests to the test directory - [ ] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [ ] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
@@ -198,6 +198,7 @@ export class LangSelector extends LitElement {
|
||||
"player-panel",
|
||||
"replay-panel",
|
||||
"help-modal",
|
||||
"settings-modal",
|
||||
"username-input",
|
||||
"public-lobby",
|
||||
"user-setting",
|
||||
|
||||
@@ -27,6 +27,7 @@ import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay";
|
||||
import { PlayerPanel } from "./layers/PlayerPanel";
|
||||
import { RailroadLayer } from "./layers/RailroadLayer";
|
||||
import { ReplayPanel } from "./layers/ReplayPanel";
|
||||
import { SettingsModal } from "./layers/SettingsModal";
|
||||
import { SpawnAd } from "./layers/SpawnAd";
|
||||
import { SpawnTimer } from "./layers/SpawnTimer";
|
||||
import { StructureIconsLayer } from "./layers/StructureIconsLayer";
|
||||
@@ -152,6 +153,15 @@ export function createRenderer(
|
||||
gameRightSidebar.game = game;
|
||||
gameRightSidebar.eventBus = eventBus;
|
||||
|
||||
const settingsModal = document.querySelector(
|
||||
"settings-modal",
|
||||
) as SettingsModal;
|
||||
if (!(settingsModal instanceof SettingsModal)) {
|
||||
console.error("settings modal not found");
|
||||
}
|
||||
settingsModal.userSettings = userSettings;
|
||||
settingsModal.eventBus = eventBus;
|
||||
|
||||
const gameTopBar = document.querySelector("game-top-bar") as GameTopBar;
|
||||
if (!(gameTopBar instanceof GameTopBar)) {
|
||||
console.error("top bar not found");
|
||||
@@ -252,6 +262,7 @@ export function createRenderer(
|
||||
playerInfo,
|
||||
winModal,
|
||||
replayPanel,
|
||||
settingsModal,
|
||||
teamStats,
|
||||
playerPanel,
|
||||
headsUpMessage,
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import darkModeIcon from "../../../../resources/images/DarkModeIconWhite.svg";
|
||||
import emojiIcon from "../../../../resources/images/EmojiIconWhite.svg";
|
||||
import exitIcon from "../../../../resources/images/ExitIconWhite.svg";
|
||||
import explosionIcon from "../../../../resources/images/ExplosionIconWhite.svg";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import goldCoinIcon from "../../../../resources/images/GoldCoinIcon.svg";
|
||||
import mouseIcon from "../../../../resources/images/MouseIconWhite.svg";
|
||||
import ninjaIcon from "../../../../resources/images/NinjaIconWhite.svg";
|
||||
import populationIcon from "../../../../resources/images/PopulationIconSolidWhite.svg";
|
||||
import settingsIcon from "../../../../resources/images/SettingIconWhite.svg";
|
||||
import treeIcon from "../../../../resources/images/TreeIconWhite.svg";
|
||||
import troopIcon from "../../../../resources/images/TroopIconWhite.svg";
|
||||
import workerIcon from "../../../../resources/images/WorkerIconWhite.svg";
|
||||
import { translateText } from "../../../client/Utils";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { UserSettings } from "../../../core/game/UserSettings";
|
||||
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
|
||||
import { renderNumber, renderTroops } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
import { ShowSettingsModalEvent } from "./SettingsModal";
|
||||
|
||||
@customElement("game-top-bar")
|
||||
export class GameTopBar extends LitElement implements Layer {
|
||||
@@ -33,17 +25,9 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
private _popRateIsIncreasing = false;
|
||||
private hasWinner = false;
|
||||
|
||||
@state()
|
||||
private showSettingsMenu = false;
|
||||
@state()
|
||||
private alternateView: boolean = false;
|
||||
|
||||
@state()
|
||||
private timer: number = 0;
|
||||
|
||||
@query(".settings-container")
|
||||
private settingsContainer!: HTMLElement;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
@@ -70,66 +54,8 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("click", this.handleOutsideClick, true);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener("click", this.handleOutsideClick, true);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
private handleOutsideClick = (event: MouseEvent) => {
|
||||
if (
|
||||
this.showSettingsMenu &&
|
||||
this.settingsContainer &&
|
||||
!this.settingsContainer.contains(event.target as Node)
|
||||
) {
|
||||
this.showSettingsMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
private onExitButtonClick() {
|
||||
const isAlive = this.game.myPlayer()?.isAlive();
|
||||
if (isAlive) {
|
||||
const isConfirmed = confirm("Are you sure you want to exit the game?");
|
||||
if (!isConfirmed) return;
|
||||
}
|
||||
// redirect to the home page
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
private onTerrainButtonClick() {
|
||||
this.alternateView = !this.alternateView;
|
||||
this.eventBus.emit(new AlternateViewEvent(this.alternateView));
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleEmojisButtonClick() {
|
||||
this._userSettings.toggleEmojis();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleSpecialEffectsButtonClick() {
|
||||
this._userSettings.toggleFxLayer();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleDarkModeButtonClick() {
|
||||
this._userSettings.toggleDarkMode();
|
||||
this.requestUpdate();
|
||||
this.eventBus.emit(new RefreshGraphicsEvent());
|
||||
}
|
||||
|
||||
private onToggleRandomNameModeButtonClick() {
|
||||
this._userSettings.toggleRandomName();
|
||||
}
|
||||
private onToggleLeftClickOpensMenu() {
|
||||
this._userSettings.toggleLeftClickOpenMenu();
|
||||
}
|
||||
|
||||
private toggleSettingsMenu() {
|
||||
this.showSettingsMenu = !this.showSettingsMenu;
|
||||
private onSettingsButtonClick() {
|
||||
this.eventBus.emit(new ShowSettingsModalEvent(true));
|
||||
}
|
||||
|
||||
private updatePopulationIncrease() {
|
||||
@@ -270,116 +196,15 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
>
|
||||
${this.secondsToHms(this.timer)}
|
||||
</div>
|
||||
<div class="relative settings-container">
|
||||
<img
|
||||
class="cursor-pointer bg-slate-800/20 border border-slate-400 p-0.5"
|
||||
src=${settingsIcon}
|
||||
alt="settings"
|
||||
width="28"
|
||||
height="28"
|
||||
style="vertical-align: middle;"
|
||||
@click=${this.toggleSettingsMenu}
|
||||
/>
|
||||
${this.showSettingsMenu
|
||||
? html`
|
||||
<div
|
||||
class="absolute right-0 mt-1.5 bg-slate-700 border border-slate-500 rounded shadow-lg z-[1100] w-max min-w-[10rem] whitespace-nowrap"
|
||||
>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onTerrainButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${treeIcon}
|
||||
alt="treeIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
Toggle Terrain ${this.alternateView ? "On" : "Off"}
|
||||
</button>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onToggleEmojisButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${emojiIcon}
|
||||
alt="emojiIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
${translateText("user_setting.emojis_label")}
|
||||
${this._userSettings.emojis() ? "On" : "Off"}
|
||||
</button>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onToggleDarkModeButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${darkModeIcon}
|
||||
alt="darkModeIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
${translateText("user_setting.dark_mode_label")}
|
||||
${this._userSettings.darkMode() ? "On" : "Off"}
|
||||
</button>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onToggleSpecialEffectsButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${explosionIcon}
|
||||
alt="onExitButtonClick"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
${translateText("user_setting.special_effects_label")}
|
||||
${this._userSettings.fxLayer() ? "On" : "Off"}
|
||||
</button>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onToggleRandomNameModeButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${ninjaIcon}
|
||||
alt="ninjaIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
${translateText("user_setting.anonymous_names_label")}
|
||||
${this._userSettings.anonymousNames() ? "On" : "Off"}
|
||||
</button>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onToggleLeftClickOpensMenu}"
|
||||
>
|
||||
<img
|
||||
src=${mouseIcon}
|
||||
alt="mouseIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
Left click
|
||||
${this._userSettings.leftClickOpensMenu()
|
||||
? "On"
|
||||
: "Off"}
|
||||
</button>
|
||||
<button
|
||||
class="flex gap-1 items-center w-full text-left px-2 py-1 hover:bg-slate-600 text-white text-sm"
|
||||
@click="${this.onExitButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${exitIcon}
|
||||
alt="exitIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
Exit game
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
: null}
|
||||
</div>
|
||||
<img
|
||||
class="cursor-pointer bg-slate-800/20 border border-slate-400 p-0.5"
|
||||
src=${settingsIcon}
|
||||
alt="settings"
|
||||
width="28"
|
||||
height="28"
|
||||
style="vertical-align: middle;"
|
||||
@click=${this.onSettingsButtonClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import darkModeIcon from "../../../../resources/images/DarkModeIconWhite.svg";
|
||||
import emojiIcon from "../../../../resources/images/EmojiIconWhite.svg";
|
||||
import exitIcon from "../../../../resources/images/ExitIconWhite.svg";
|
||||
import explosionIcon from "../../../../resources/images/ExplosionIconWhite.svg";
|
||||
import mouseIcon from "../../../../resources/images/MouseIconWhite.svg";
|
||||
import ninjaIcon from "../../../../resources/images/NinjaIconWhite.svg";
|
||||
import settingsIcon from "../../../../resources/images/SettingIconWhite.svg";
|
||||
import treeIcon from "../../../../resources/images/TreeIconWhite.svg";
|
||||
import { translateText } from "../../../client/Utils";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { UserSettings } from "../../../core/game/UserSettings";
|
||||
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
export class ShowSettingsModalEvent {
|
||||
constructor(public readonly isVisible: boolean = true) {}
|
||||
}
|
||||
|
||||
@customElement("settings-modal")
|
||||
export class SettingsModal extends LitElement implements Layer {
|
||||
public eventBus: EventBus;
|
||||
public userSettings: UserSettings;
|
||||
|
||||
@state()
|
||||
private isVisible: boolean = false;
|
||||
|
||||
@state()
|
||||
private alternateView: boolean = false;
|
||||
|
||||
@query(".modal-overlay")
|
||||
private modalOverlay!: HTMLElement;
|
||||
|
||||
init() {
|
||||
this.eventBus.on(ShowSettingsModalEvent, (event) => {
|
||||
this.isVisible = event.isVisible;
|
||||
});
|
||||
}
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("click", this.handleOutsideClick, true);
|
||||
window.addEventListener("keydown", this.handleKeyDown);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener("click", this.handleOutsideClick, true);
|
||||
window.removeEventListener("keydown", this.handleKeyDown);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
private handleOutsideClick = (event: MouseEvent) => {
|
||||
if (
|
||||
this.isVisible &&
|
||||
this.modalOverlay &&
|
||||
event.target === this.modalOverlay
|
||||
) {
|
||||
this.closeModal();
|
||||
}
|
||||
};
|
||||
|
||||
private handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (this.isVisible && event.key === "Escape") {
|
||||
this.closeModal();
|
||||
}
|
||||
};
|
||||
|
||||
public openModal() {
|
||||
this.isVisible = true;
|
||||
document.body.style.overflow = "hidden";
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
public closeModal() {
|
||||
this.isVisible = false;
|
||||
document.body.style.overflow = "";
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onTerrainButtonClick() {
|
||||
this.alternateView = !this.alternateView;
|
||||
this.eventBus.emit(new AlternateViewEvent(this.alternateView));
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleEmojisButtonClick() {
|
||||
this.userSettings.toggleEmojis();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleSpecialEffectsButtonClick() {
|
||||
this.userSettings.toggleFxLayer();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleDarkModeButtonClick() {
|
||||
this.userSettings.toggleDarkMode();
|
||||
this.eventBus.emit(new RefreshGraphicsEvent());
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleRandomNameModeButtonClick() {
|
||||
this.userSettings.toggleRandomName();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onToggleLeftClickOpensMenu() {
|
||||
this.userSettings.toggleLeftClickOpenMenu();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private onExitButtonClick() {
|
||||
// redirect to the home page
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="modal-overlay fixed inset-0 bg-black/50 backdrop-blur-sm z-[2000] flex items-center justify-center p-4"
|
||||
@contextmenu=${(e: Event) => e.preventDefault()}
|
||||
>
|
||||
<div
|
||||
class="bg-slate-800 border border-slate-600 rounded-lg shadow-xl max-w-md w-full max-h-[80vh] overflow-y-auto"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between p-4 border-b border-slate-600"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<img
|
||||
src=${settingsIcon}
|
||||
alt="settings"
|
||||
width="24"
|
||||
height="24"
|
||||
style="vertical-align: middle;"
|
||||
/>
|
||||
<h2 class="text-xl font-semibold text-white">Settings</h2>
|
||||
</div>
|
||||
<button
|
||||
class="text-slate-400 hover:text-white text-2xl font-bold leading-none"
|
||||
@click=${this.closeModal}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="p-4 space-y-3">
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onTerrainButtonClick}"
|
||||
>
|
||||
<img src=${treeIcon} alt="treeIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">Toggle Terrain</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.alternateView
|
||||
? "Terrain view enabled"
|
||||
: "Terrain view disabled"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.alternateView ? "On" : "Off"}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onToggleEmojisButtonClick}"
|
||||
>
|
||||
<img src=${emojiIcon} alt="emojiIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.emojis_label")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.emojis()
|
||||
? "Emojis are visible"
|
||||
: "Emojis are hidden"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.emojis() ? "On" : "Off"}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onToggleDarkModeButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${darkModeIcon}
|
||||
alt="darkModeIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.dark_mode_label")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.darkMode()
|
||||
? "Dark mode enabled"
|
||||
: "Light mode enabled"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.darkMode() ? "On" : "Off"}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onToggleSpecialEffectsButtonClick}"
|
||||
>
|
||||
<img
|
||||
src=${explosionIcon}
|
||||
alt="specialEffects"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.special_effects_label")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.fxLayer()
|
||||
? "Special effects enabled"
|
||||
: "Special effects disabled"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.fxLayer() ? "On" : "Off"}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onToggleRandomNameModeButtonClick}"
|
||||
>
|
||||
<img src=${ninjaIcon} alt="ninjaIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.anonymous_names_label")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.anonymousNames()
|
||||
? "Anonymous names enabled"
|
||||
: "Real names shown"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.anonymousNames() ? "On" : "Off"}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onToggleLeftClickOpensMenu}"
|
||||
>
|
||||
<img src=${mouseIcon} alt="mouseIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">Left Click Menu</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.leftClickOpensMenu()
|
||||
? "Left click opens menu"
|
||||
: "Right click opens menu"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${this.userSettings.leftClickOpensMenu() ? "On" : "Off"}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="border-t border-slate-600 pt-3 mt-4">
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-red-600/20 rounded text-red-400 transition-colors"
|
||||
@click="${this.onExitButtonClick}"
|
||||
>
|
||||
<img src=${exitIcon} alt="exitIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">Exit Game</div>
|
||||
<div class="text-sm text-slate-400">Return to main menu</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -362,7 +362,7 @@
|
||||
<game-top-bar></game-top-bar>
|
||||
<unit-display></unit-display>
|
||||
<game-right-sidebar></game-right-sidebar>
|
||||
|
||||
<settings-modal></settings-modal>
|
||||
<player-panel></player-panel>
|
||||
<help-modal></help-modal>
|
||||
<dark-mode-button></dark-mode-button>
|
||||
|
||||
Reference in New Issue
Block a user