mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 07:40:43 +00:00
Added dark mode
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
|
||||
@customElement("dark-mode-button")
|
||||
export class DarkModeButton extends LitElement {
|
||||
private userSettings: UserSettings = new UserSettings();
|
||||
@state() private darkMode: boolean = this.userSettings.darkMode();
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
toggleDarkMode() {
|
||||
this.userSettings.toggleDarkMode();
|
||||
this.darkMode = this.userSettings.darkMode();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<button
|
||||
title="Toggle Dark Mode"
|
||||
class="absolute top-0 right-0 md:top-[10px] md:right-[10px] border-none bg-none cursor-pointer text-2xl"
|
||||
@click=${() => this.toggleDarkMode()}
|
||||
>
|
||||
${this.darkMode ? "☀️" : "🌙"}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
}
|
||||
+34
-48
@@ -1,6 +1,7 @@
|
||||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import Countries from "./data/countries.json";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
|
||||
const flagKey: string = "flag";
|
||||
|
||||
@@ -9,41 +10,13 @@ export class FlagInput extends LitElement {
|
||||
@state() private flag: string = "";
|
||||
@state() private search: string = "";
|
||||
@state() private showModal: boolean = false;
|
||||
private userSettings: UserSettings = new UserSettings();
|
||||
|
||||
static styles = css`
|
||||
.hidden {
|
||||
display: none;
|
||||
.dark-mode .flag-button {
|
||||
background: rgba(55, 65, 81, 0.7);
|
||||
}
|
||||
|
||||
.flag-container {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flag-button {
|
||||
display: flex;
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.selected-flag {
|
||||
width: 48px;
|
||||
}
|
||||
// .flag-button {
|
||||
// display: flex;
|
||||
// border: 0px;
|
||||
// background: none;
|
||||
// cursor: pointer;
|
||||
// padding: 0px;
|
||||
// }
|
||||
|
||||
// .selected-flag {
|
||||
// width: 50px;
|
||||
// }
|
||||
|
||||
.flag-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -70,6 +43,12 @@ export class FlagInput extends LitElement {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.dark-mode .flag-search {
|
||||
background: rgb(55, 65, 81);
|
||||
color: white;
|
||||
border: 1px solid rgb(209, 213, 219);
|
||||
}
|
||||
|
||||
.flag-dropdown {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -115,7 +94,11 @@ export class FlagInput extends LitElement {
|
||||
}
|
||||
|
||||
private setFlag(flag: string) {
|
||||
this.flag = flag;
|
||||
if (flag == "") {
|
||||
this.flag = "";
|
||||
} else {
|
||||
this.flag = flag;
|
||||
}
|
||||
this.showModal = false;
|
||||
this.storeFlag(flag);
|
||||
}
|
||||
@@ -156,35 +139,38 @@ export class FlagInput extends LitElement {
|
||||
this.dispatchFlagEvent();
|
||||
}
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="flag-container">
|
||||
<div class="flex relative">
|
||||
<button
|
||||
@click=${() => (this.showModal = !this.showModal)}
|
||||
class="flag-button"
|
||||
class="border p-[4px] rounded-lg flex cursor-pointer border-black/30 dark:border-gray-300/60 bg-white/70 dark:bg-[rgba(55,65,81,0.7)]"
|
||||
title="Pick a flag!"
|
||||
>
|
||||
<img class="selected-flag" src="/flags/${this.flag || "xx"}.svg" />
|
||||
<img class="size-[48px]" src="/flags/${this.flag || "xx"}.svg" />
|
||||
</button>
|
||||
${this.showModal
|
||||
? html`
|
||||
<div class="flag-modal ${this.showModal ? "" : "hidden"}">
|
||||
<div
|
||||
class="text-white flex flex-col gap-[0.5rem] absolute top-[60px] left-[0px] w-[780%] h-[500px] max-h-[50vh] bg-gray-900/80 backdrop-blur-md p-[10px] rounded-[8px] z-[3] ${this
|
||||
.showModal
|
||||
? ""
|
||||
: "hidden"}"
|
||||
>
|
||||
<input
|
||||
class="flag-search"
|
||||
class="h-[2rem] border-none text-center border border-gray-300 rounded-xl shadow-sm text-2xl text-center focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:border-gray-300/60 dark:bg-gray-700 dark:text-white"
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
@change=${this.handleSearch}
|
||||
@keyup=${this.handleSearch}
|
||||
/>
|
||||
<div class="flag-dropdown">
|
||||
<!-- Show each flag as button -->
|
||||
<button
|
||||
@click=${() => this.setFlag("")}
|
||||
class="dropdown-item"
|
||||
>
|
||||
<img class="country-flag" src="/flags/xx.svg" />
|
||||
<span class="country-name">None</span>
|
||||
</button>
|
||||
<div
|
||||
class="flex flex-wrap justify-evenly gap-[1rem] overflow-y-auto overflow-x-hidden"
|
||||
>
|
||||
${Countries.filter(
|
||||
(country) =>
|
||||
country.name
|
||||
@@ -197,10 +183,10 @@ export class FlagInput extends LitElement {
|
||||
(country) => html`
|
||||
<button
|
||||
@click=${() => this.setFlag(country.code)}
|
||||
class="dropdown-item"
|
||||
class="text-center cursor-pointer border-none bg-none opacity-70 sm:w-[calc(33.3333%-15px) w-[calc(100%/4-15px)]"
|
||||
>
|
||||
<img
|
||||
class="country-flag"
|
||||
class="country-flag w-full h-auto"
|
||||
src="/flags/${country.code}.svg"
|
||||
/>
|
||||
<span class="country-name">${country.name}</span>
|
||||
|
||||
+17
-4
@@ -1,7 +1,5 @@
|
||||
import { ClientGameRunner, joinLobby } from "./ClientGameRunner";
|
||||
import backgroundImage from "../../resources/images/EuropeBackground.svg";
|
||||
import favicon from "../../resources/images/Favicon.svg";
|
||||
|
||||
import "./PublicLobby";
|
||||
import "./UsernameInput";
|
||||
import "./styles.css";
|
||||
@@ -16,15 +14,20 @@ import "./FlagInput";
|
||||
import { FlagInput } from "./FlagInput";
|
||||
import page from "page";
|
||||
import { PublicLobby } from "./PublicLobby";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import "./DarkModeButton";
|
||||
import { DarkModeButton } from "./DarkModeButton";
|
||||
|
||||
class Client {
|
||||
private gameStop: () => void;
|
||||
|
||||
private usernameInput: UsernameInput | null = null;
|
||||
private flagInput: FlagInput | null = null;
|
||||
private darkModeButton: DarkModeButton | null = null;
|
||||
|
||||
private joinModal: JoinPrivateLobbyModal;
|
||||
private publicLobby: PublicLobby;
|
||||
private userSettings: UserSettings = new UserSettings();
|
||||
|
||||
constructor() {}
|
||||
|
||||
@@ -34,6 +37,13 @@ class Client {
|
||||
consolex.warn("Flag input element not found");
|
||||
}
|
||||
|
||||
this.darkModeButton = document.querySelector(
|
||||
"dark-mode-button",
|
||||
) as DarkModeButton;
|
||||
if (!this.darkModeButton) {
|
||||
consolex.warn("Dark mode button element not found");
|
||||
}
|
||||
|
||||
this.usernameInput = document.querySelector(
|
||||
"username-input",
|
||||
) as UsernameInput;
|
||||
@@ -92,6 +102,11 @@ class Client {
|
||||
}
|
||||
});
|
||||
|
||||
if (this.userSettings.darkMode()) {
|
||||
document.body.classList.add("dark");
|
||||
} else {
|
||||
document.body.classList.remove("dark");
|
||||
}
|
||||
page("/join/:lobbyId", (ctx) => {
|
||||
const lobbyId = ctx.params.lobbyId;
|
||||
|
||||
@@ -151,8 +166,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
new Client().initialize();
|
||||
});
|
||||
|
||||
document.body.style.backgroundImage = `url(${backgroundImage})`;
|
||||
|
||||
function setFavicon(): void {
|
||||
const link = document.createElement("link");
|
||||
link.type = "image/x-icon";
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
MAX_USERNAME_LENGTH,
|
||||
validateUsername,
|
||||
} from "../core/validations/username";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
|
||||
const usernameKey: string = "username";
|
||||
|
||||
@@ -13,6 +14,7 @@ export class UsernameInput extends LitElement {
|
||||
@state() private username: string = "";
|
||||
@property({ type: String }) validationError: string = "";
|
||||
private _isValid: boolean = true;
|
||||
private userSettings: UserSettings = new UserSettings();
|
||||
|
||||
// Remove static styles since we're using Tailwind
|
||||
|
||||
@@ -40,11 +42,11 @@ export class UsernameInput extends LitElement {
|
||||
@change=${this.handleChange}
|
||||
placeholder="Enter your username"
|
||||
maxlength="${MAX_USERNAME_LENGTH}"
|
||||
class="w-full px-4 py-2 bg-white border border-gray-300 rounded-xl shadow-sm text-2xl text-gray-900 text-center focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-xl shadow-sm text-2xl text-center focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:border-gray-300/60 dark:bg-gray-700 dark:text-white"
|
||||
/>
|
||||
${this.validationError
|
||||
? html`<div
|
||||
class="mt-2 px-3 py-1 text-lg text-red-600 bg-white border border-red-600 rounded"
|
||||
class="mt-2 px-3 py-1 text-lg border rounded bg-white text-red-600 border-red-600 dark:bg-gray-700 dark:text-red-300 dark:border-red-300"
|
||||
>
|
||||
${this.validationError}
|
||||
</div>`
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"code": "xx",
|
||||
"name": "None"
|
||||
},
|
||||
{
|
||||
"code": "af",
|
||||
"continent": "Asia",
|
||||
|
||||
@@ -118,7 +118,7 @@ export function createRenderer(
|
||||
new TerritoryLayer(game, eventBus),
|
||||
new StructureLayer(game, eventBus),
|
||||
new UnitLayer(game, eventBus, clientID),
|
||||
new NameLayer(game, game.config().theme(), transformHandler, clientID),
|
||||
new NameLayer(game, transformHandler, clientID),
|
||||
eventsDisplay,
|
||||
new RadialMenu(
|
||||
eventBus,
|
||||
|
||||
@@ -114,7 +114,7 @@ export class Leaderboard extends LitElement implements Layer {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 9999;
|
||||
background-color: rgba(30, 30, 30, 0.7);
|
||||
background-color: rgb(31 41 55 / 0.7);
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||
border-radius: 10px;
|
||||
@@ -136,7 +136,7 @@ export class Leaderboard extends LitElement implements Layer {
|
||||
color: white;
|
||||
}
|
||||
th {
|
||||
background-color: rgba(44, 44, 44, 0.5);
|
||||
background-color: rgb(31 41 55 / 0.5);
|
||||
color: white;
|
||||
}
|
||||
.myPlayer {
|
||||
@@ -147,7 +147,7 @@ export class Leaderboard extends LitElement implements Layer {
|
||||
font-size: 1em;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: rgba(44, 44, 44, 0.5);
|
||||
background-color: rgb(31 41 55 / 0.5);
|
||||
}
|
||||
tbody tr {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -26,6 +26,7 @@ class RenderInfo {
|
||||
public lastRenderCalc: number,
|
||||
public location: Cell,
|
||||
public fontSize: number,
|
||||
public fontColor: string,
|
||||
public element: HTMLElement,
|
||||
) {}
|
||||
}
|
||||
@@ -45,13 +46,14 @@ export class NameLayer implements Layer {
|
||||
private container: HTMLDivElement;
|
||||
private myPlayer: PlayerView | null = null;
|
||||
private firstPlace: PlayerView | null = null;
|
||||
private theme: Theme;
|
||||
|
||||
constructor(
|
||||
private game: GameView,
|
||||
private theme: Theme,
|
||||
private transformHandler: TransformHandler,
|
||||
private clientID: ClientID,
|
||||
) {
|
||||
this.theme = game.config().theme();
|
||||
this.traitorIconImage = new Image();
|
||||
this.traitorIconImage.src = traitorIcon;
|
||||
this.allianceIconImage = new Image();
|
||||
@@ -96,6 +98,9 @@ export class NameLayer implements Layer {
|
||||
this.firstPlace = sorted[0];
|
||||
}
|
||||
|
||||
if (this.theme !== this.game.config().theme()) {
|
||||
this.theme = this.game.config().theme();
|
||||
}
|
||||
for (const player of this.game.playerViews()) {
|
||||
if (player.isAlive()) {
|
||||
if (!this.seenPlayers.has(player)) {
|
||||
@@ -106,6 +111,7 @@ export class NameLayer implements Layer {
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
"",
|
||||
this.createPlayerElement(player),
|
||||
),
|
||||
);
|
||||
@@ -149,12 +155,10 @@ export class NameLayer implements Layer {
|
||||
element.style.alignItems = "center";
|
||||
element.style.gap = "0px";
|
||||
|
||||
const textColor = player.type() == PlayerType.Human ? "#000000" : "#4D4D4D";
|
||||
|
||||
const nameDiv = document.createElement("div");
|
||||
nameDiv.classList.add("player-name");
|
||||
nameDiv.innerHTML = player.name();
|
||||
nameDiv.style.color = textColor;
|
||||
nameDiv.style.color = this.theme.textColor(player.info());
|
||||
nameDiv.style.fontFamily = this.theme.font();
|
||||
nameDiv.style.whiteSpace = "nowrap";
|
||||
nameDiv.style.overflow = "hidden";
|
||||
@@ -178,7 +182,7 @@ export class NameLayer implements Layer {
|
||||
const troopsDiv = document.createElement("div");
|
||||
troopsDiv.classList.add("player-troops");
|
||||
troopsDiv.textContent = renderTroops(player.troops());
|
||||
troopsDiv.style.color = textColor;
|
||||
troopsDiv.style.color = this.theme.textColor(player.info());
|
||||
troopsDiv.style.fontFamily = this.theme.font();
|
||||
troopsDiv.style.zIndex = "3";
|
||||
troopsDiv.style.marginTop = "-5%";
|
||||
@@ -219,6 +223,7 @@ export class NameLayer implements Layer {
|
||||
// Calculate base size and scale
|
||||
const baseSize = Math.max(1, Math.floor(render.player.nameLocation().size));
|
||||
render.fontSize = Math.max(4, Math.floor(baseSize * 0.4));
|
||||
render.fontColor = this.theme.textColor(render.player.info());
|
||||
|
||||
// Screen space calculations
|
||||
const size = this.transformHandler.scale * baseSize;
|
||||
@@ -243,7 +248,9 @@ export class NameLayer implements Layer {
|
||||
".player-troops",
|
||||
) as HTMLDivElement;
|
||||
nameDiv.style.fontSize = `${render.fontSize}px`;
|
||||
nameDiv.style.color = render.fontColor;
|
||||
troopsDiv.style.fontSize = `${render.fontSize}px`;
|
||||
troopsDiv.style.color = render.fontColor;
|
||||
troopsDiv.textContent = renderTroops(render.player.troops());
|
||||
|
||||
// Handle icons
|
||||
|
||||
@@ -156,11 +156,11 @@ export class OptionsMenu extends LitElement implements Layer {
|
||||
title: "Toggle Emojis",
|
||||
children: "🙂: " + (this.userSettings.emojis() ? "On" : "Off"),
|
||||
})}
|
||||
<!-- ${button({
|
||||
${button({
|
||||
onClick: this.onToggleDarkModeButtonClick,
|
||||
title: "Dark Mode",
|
||||
children: "🌙: " + (this.userSettings.darkMode() ? "On" : "Off"),
|
||||
})} -->
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import { Layer } from "./Layer";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { Theme } from "../../../core/configuration/Config";
|
||||
|
||||
export class TerrainLayer implements Layer {
|
||||
private canvas: HTMLCanvasElement;
|
||||
private context: CanvasRenderingContext2D;
|
||||
private imageData: ImageData;
|
||||
private theme: Theme;
|
||||
|
||||
constructor(private game: GameView) {}
|
||||
shouldTransform(): boolean {
|
||||
return true;
|
||||
}
|
||||
tick() {}
|
||||
tick() {
|
||||
if (this.game.config().theme() !== this.theme) {
|
||||
this.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
console.log("redrew terrain layer");
|
||||
@@ -34,9 +40,9 @@ export class TerrainLayer implements Layer {
|
||||
}
|
||||
|
||||
initImageData() {
|
||||
const theme = this.game.config().theme();
|
||||
this.theme = this.game.config().theme();
|
||||
this.game.forEachTile((tile) => {
|
||||
let terrainColor = theme.terrainColor(this.game, tile);
|
||||
let terrainColor = this.theme.terrainColor(this.game, tile);
|
||||
// TODO: isn'te tileref and index the same?
|
||||
const index = this.game.y(tile) * this.game.width() + this.game.x(tile);
|
||||
const offset = index * 4;
|
||||
|
||||
+15
-4
@@ -25,18 +25,25 @@
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
body::before {
|
||||
.bg-image {
|
||||
content: "";
|
||||
background-image: url("/images/EuropeBackground.svg");
|
||||
background-position: center;
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backdrop-filter: blur(4px);
|
||||
-webkit-backdrop-filter: blur(4px);
|
||||
filter: blur(4px);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.dark .bg-image {
|
||||
filter: blur(4px) brightness(0.7);
|
||||
}
|
||||
|
||||
/* Critical styles to prevent layout shift */
|
||||
.container {
|
||||
opacity: 1;
|
||||
@@ -148,13 +155,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-image"></div>
|
||||
|
||||
<dark-mode-button></dark-mode-button>
|
||||
|
||||
<!-- Main container with responsive padding -->
|
||||
<div class="flex justify-center items-center flex-grow">
|
||||
<div class="container px-4 sm:px-6 lg:px-8 py-4 sm:py-6 lg:py-8">
|
||||
<div
|
||||
class="relative flex gap-1 items-center max-w-sm sm:max-w-md lg:max-w-lg xl:max-w-xl mx-auto p-2 pb-4"
|
||||
>
|
||||
<flag-input></flag-input>
|
||||
<flag-input class="w-[20%] md:w-[15%]"></flag-input>
|
||||
<username-input class="w-full"></username-input>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* Add custom scrollbar styles */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ export interface Theme {
|
||||
backgroundColor(): Colord;
|
||||
falloutColor(): Colord;
|
||||
font(): string;
|
||||
textColor(playerInfo: PlayerInfo): string;
|
||||
// unit color for alternate view
|
||||
selfColor(): Colord;
|
||||
allyColor(): Colord;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { UserSettings } from "../game/UserSettings";
|
||||
import { GameConfig } from "../Schemas";
|
||||
import { assertNever, within } from "../Util";
|
||||
import { Config, GameEnv, ServerConfig, Theme } from "./Config";
|
||||
import { pastelTheme } from "./PastelTheme";
|
||||
import { pastelTheme, pastelThemeDark } from "./PastelTheme";
|
||||
|
||||
export abstract class DefaultServerConfig implements ServerConfig {
|
||||
abstract env(): GameEnv;
|
||||
@@ -245,7 +245,7 @@ export class DefaultConfig implements Config {
|
||||
return 400;
|
||||
}
|
||||
theme(): Theme {
|
||||
return pastelTheme;
|
||||
return this.userSettings().darkMode() ? pastelThemeDark : pastelTheme;
|
||||
}
|
||||
|
||||
attackLogic(
|
||||
|
||||
@@ -11,6 +11,7 @@ import { time } from "console";
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
import { simpleHash } from "../Util";
|
||||
import { GameMap, TileRef } from "../game/GameMap";
|
||||
import { PlayerView } from "../game/GameView";
|
||||
|
||||
export const pastelTheme = new (class implements Theme {
|
||||
private rand = new PseudoRandom(123);
|
||||
@@ -251,6 +252,10 @@ export const pastelTheme = new (class implements Theme {
|
||||
];
|
||||
}
|
||||
|
||||
textColor(playerInfo: PlayerInfo): string {
|
||||
return playerInfo.playerType == PlayerType.Human ? "#000000" : "#4D4D4D";
|
||||
}
|
||||
|
||||
borderColor(playerInfo: PlayerInfo): Colord {
|
||||
const tc = this.territoryColor(playerInfo).rgba;
|
||||
return colord({
|
||||
@@ -335,3 +340,331 @@ export const pastelTheme = new (class implements Theme {
|
||||
return this._spawnHighlightColor;
|
||||
}
|
||||
})();
|
||||
|
||||
export const pastelThemeDark = new (class implements Theme {
|
||||
private rand = new PseudoRandom(123);
|
||||
|
||||
private background = colord({ r: 0, g: 0, b: 0 });
|
||||
private land = colord({ r: 194, g: 193, b: 148 });
|
||||
private shore = colord({ r: 134, g: 133, b: 88 });
|
||||
private falloutColors = [
|
||||
colord({ r: 120, g: 255, b: 71 }), // Original color
|
||||
colord({ r: 130, g: 255, b: 85 }), // Slightly lighter
|
||||
colord({ r: 110, g: 245, b: 65 }), // Slightly darker
|
||||
colord({ r: 125, g: 255, b: 75 }), // Warmer tint
|
||||
colord({ r: 115, g: 250, b: 68 }), // Cooler tint
|
||||
];
|
||||
private water = colord({ r: 14, g: 11, b: 30 });
|
||||
private shorelineWater = colord({ r: 50, g: 50, b: 50 });
|
||||
|
||||
private territoryColors: Colord[] = [
|
||||
colord({ r: 230, g: 100, b: 100 }), // Bright Red
|
||||
colord({ r: 100, g: 180, b: 230 }), // Sky Blue
|
||||
colord({ r: 230, g: 180, b: 80 }), // Golden Yellow
|
||||
colord({ r: 180, g: 100, b: 230 }), // Purple
|
||||
colord({ r: 80, g: 200, b: 120 }), // Emerald Green
|
||||
colord({ r: 230, g: 130, b: 180 }), // Pink
|
||||
colord({ r: 100, g: 160, b: 80 }), // Olive Green
|
||||
colord({ r: 230, g: 150, b: 100 }), // Peach
|
||||
colord({ r: 80, g: 130, b: 190 }), // Navy Blue
|
||||
colord({ r: 210, g: 210, b: 100 }), // Lime Yellow
|
||||
colord({ r: 190, g: 100, b: 130 }), // Maroon
|
||||
colord({ r: 100, g: 210, b: 210 }), // Turquoise
|
||||
colord({ r: 210, g: 140, b: 80 }), // Light Orange
|
||||
colord({ r: 150, g: 110, b: 190 }), // Lavender
|
||||
colord({ r: 180, g: 210, b: 120 }), // Light Green
|
||||
colord({ r: 210, g: 100, b: 160 }), // Hot Pink
|
||||
colord({ r: 100, g: 140, b: 110 }), // Sea Green
|
||||
colord({ r: 230, g: 180, b: 180 }), // Light Pink
|
||||
colord({ r: 120, g: 120, b: 190 }), // Periwinkle
|
||||
colord({ r: 190, g: 170, b: 100 }), // Sand
|
||||
colord({ r: 100, g: 180, b: 160 }), // Aquamarine
|
||||
colord({ r: 210, g: 160, b: 200 }), // Orchid
|
||||
colord({ r: 170, g: 190, b: 100 }), // Yellow Green
|
||||
colord({ r: 100, g: 130, b: 150 }), // Steel Blue
|
||||
colord({ r: 230, g: 140, b: 140 }), // Salmon
|
||||
colord({ r: 140, g: 180, b: 220 }), // Light Blue
|
||||
colord({ r: 200, g: 160, b: 110 }), // Tan
|
||||
colord({ r: 180, g: 130, b: 180 }), // Plum
|
||||
colord({ r: 130, g: 200, b: 130 }), // Light Sea Green
|
||||
colord({ r: 220, g: 120, b: 120 }), // Coral
|
||||
colord({ r: 120, g: 160, b: 200 }), // Cornflower Blue
|
||||
colord({ r: 200, g: 200, b: 140 }), // Khaki
|
||||
colord({ r: 160, g: 120, b: 160 }), // Purple Gray
|
||||
colord({ r: 140, g: 180, b: 140 }), // Dark Sea Green
|
||||
colord({ r: 200, g: 130, b: 110 }), // Dark Salmon
|
||||
colord({ r: 130, g: 170, b: 190 }), // Cadet Blue
|
||||
colord({ r: 190, g: 180, b: 160 }), // Tan Gray
|
||||
colord({ r: 170, g: 140, b: 190 }), // Medium Purple
|
||||
colord({ r: 160, g: 190, b: 160 }), // Pale Green
|
||||
colord({ r: 190, g: 150, b: 130 }), // Rosy Brown
|
||||
colord({ r: 140, g: 150, b: 180 }), // Light Slate Gray
|
||||
colord({ r: 180, g: 170, b: 140 }), // Dark Khaki
|
||||
colord({ r: 150, g: 130, b: 150 }), // Thistle
|
||||
colord({ r: 170, g: 190, b: 180 }), // Pale Blue Green
|
||||
colord({ r: 190, g: 140, b: 150 }), // Puce
|
||||
colord({ r: 130, g: 180, b: 170 }), // Medium Aquamarine
|
||||
colord({ r: 180, g: 160, b: 180 }), // Mauve
|
||||
colord({ r: 160, g: 180, b: 140 }), // Dark Olive Green
|
||||
colord({ r: 170, g: 150, b: 170 }), // Dusty Rose
|
||||
colord({ r: 100, g: 180, b: 230 }), // Sky Blue
|
||||
colord({ r: 230, g: 180, b: 80 }), // Golden Yellow
|
||||
colord({ r: 180, g: 100, b: 230 }), // Purple
|
||||
colord({ r: 80, g: 200, b: 120 }), // Emerald Green
|
||||
colord({ r: 230, g: 130, b: 180 }), // Pink
|
||||
colord({ r: 100, g: 160, b: 80 }), // Olive Green
|
||||
colord({ r: 230, g: 150, b: 100 }), // Peach
|
||||
colord({ r: 80, g: 130, b: 190 }), // Navy Blue
|
||||
colord({ r: 210, g: 210, b: 100 }), // Lime Yellow
|
||||
colord({ r: 190, g: 100, b: 130 }), // Maroon
|
||||
colord({ r: 100, g: 210, b: 210 }), // Turquoise
|
||||
colord({ r: 210, g: 140, b: 80 }), // Light Orange
|
||||
colord({ r: 150, g: 110, b: 190 }), // Lavender
|
||||
colord({ r: 180, g: 210, b: 120 }), // Light Green
|
||||
colord({ r: 210, g: 100, b: 160 }), // Hot Pink
|
||||
colord({ r: 100, g: 140, b: 110 }), // Sea Green
|
||||
colord({ r: 230, g: 180, b: 180 }), // Light Pink
|
||||
colord({ r: 120, g: 120, b: 190 }), // Periwinkle
|
||||
colord({ r: 190, g: 170, b: 100 }), // Sand
|
||||
colord({ r: 100, g: 180, b: 160 }), // Aquamarine
|
||||
colord({ r: 210, g: 160, b: 200 }), // Orchid
|
||||
colord({ r: 170, g: 190, b: 100 }), // Yellow Green
|
||||
colord({ r: 100, g: 130, b: 150 }), // Steel Blue
|
||||
colord({ r: 230, g: 140, b: 140 }), // Salmon
|
||||
colord({ r: 140, g: 180, b: 220 }), // Light Blue
|
||||
colord({ r: 200, g: 160, b: 110 }), // Tan
|
||||
colord({ r: 180, g: 130, b: 180 }), // Plum
|
||||
colord({ r: 130, g: 200, b: 130 }), // Light Sea Green
|
||||
colord({ r: 220, g: 120, b: 120 }), // Coral
|
||||
colord({ r: 120, g: 160, b: 200 }), // Cornflower Blue
|
||||
colord({ r: 200, g: 200, b: 140 }), // Khaki
|
||||
colord({ r: 160, g: 120, b: 160 }), // Purple Gray
|
||||
colord({ r: 140, g: 180, b: 140 }), // Dark Sea Green
|
||||
colord({ r: 200, g: 130, b: 110 }), // Dark Salmon
|
||||
colord({ r: 130, g: 170, b: 190 }), // Cadet Blue
|
||||
colord({ r: 190, g: 180, b: 160 }), // Tan Gray
|
||||
colord({ r: 170, g: 140, b: 190 }), // Medium Purple
|
||||
colord({ r: 160, g: 190, b: 160 }), // Pale Green
|
||||
colord({ r: 190, g: 150, b: 130 }), // Rosy Brown
|
||||
colord({ r: 140, g: 150, b: 180 }), // Light Slate Gray
|
||||
colord({ r: 180, g: 170, b: 140 }), // Dark Khaki
|
||||
colord({ r: 150, g: 130, b: 150 }), // Thistle
|
||||
colord({ r: 170, g: 190, b: 180 }), // Pale Blue Green
|
||||
colord({ r: 190, g: 140, b: 150 }), // Puce
|
||||
colord({ r: 130, g: 180, b: 170 }), // Medium Aquamarine
|
||||
colord({ r: 180, g: 160, b: 180 }), // Mauve
|
||||
colord({ r: 160, g: 180, b: 140 }), // Dark Olive Green
|
||||
colord({ r: 170, g: 150, b: 170 }), // Dusty Rose
|
||||
];
|
||||
|
||||
private humanColors: Colord[] = [
|
||||
// Original set
|
||||
colord({ r: 235, g: 75, b: 75 }), // Bright Red
|
||||
colord({ r: 67, g: 190, b: 84 }), // Fresh Green
|
||||
colord({ r: 59, g: 130, b: 246 }), // Royal Blue
|
||||
colord({ r: 245, g: 158, b: 11 }), // Amber
|
||||
colord({ r: 236, g: 72, b: 153 }), // Deep Pink
|
||||
colord({ r: 48, g: 178, b: 180 }), // Teal
|
||||
colord({ r: 168, g: 85, b: 247 }), // Vibrant Purple
|
||||
colord({ r: 251, g: 191, b: 36 }), // Marigold
|
||||
colord({ r: 74, g: 222, b: 128 }), // Mint
|
||||
colord({ r: 239, g: 68, b: 68 }), // Crimson
|
||||
colord({ r: 34, g: 197, b: 94 }), // Emerald
|
||||
colord({ r: 96, g: 165, b: 250 }), // Sky Blue
|
||||
colord({ r: 249, g: 115, b: 22 }), // Tangerine
|
||||
colord({ r: 192, g: 132, b: 252 }), // Lavender
|
||||
colord({ r: 45, g: 212, b: 191 }), // Turquoise
|
||||
colord({ r: 244, g: 114, b: 182 }), // Rose
|
||||
colord({ r: 132, g: 204, b: 22 }), // Lime
|
||||
colord({ r: 56, g: 189, b: 248 }), // Light Blue
|
||||
colord({ r: 234, g: 179, b: 8 }), // Sunflower
|
||||
colord({ r: 217, g: 70, b: 239 }), // Fuchsia
|
||||
colord({ r: 16, g: 185, b: 129 }), // Sea Green
|
||||
colord({ r: 251, g: 146, b: 60 }), // Light Orange
|
||||
colord({ r: 147, g: 51, b: 234 }), // Bright Purple
|
||||
colord({ r: 79, g: 70, b: 229 }), // Indigo
|
||||
colord({ r: 245, g: 101, b: 101 }), // Coral
|
||||
colord({ r: 134, g: 239, b: 172 }), // Light Green
|
||||
colord({ r: 59, g: 130, b: 246 }), // Cerulean
|
||||
colord({ r: 253, g: 164, b: 175 }), // Salmon Pink
|
||||
colord({ r: 147, g: 197, b: 253 }), // Powder Blue
|
||||
colord({ r: 252, g: 211, b: 77 }), // Golden
|
||||
colord({ r: 190, g: 92, b: 251 }), // Amethyst
|
||||
colord({ r: 82, g: 183, b: 136 }), // Jade
|
||||
colord({ r: 248, g: 113, b: 113 }), // Warm Red
|
||||
colord({ r: 99, g: 202, b: 253 }), // Azure
|
||||
colord({ r: 240, g: 171, b: 252 }), // Orchid
|
||||
colord({ r: 163, g: 230, b: 53 }), // Yellow Green
|
||||
colord({ r: 234, g: 88, b: 12 }), // Burnt Orange
|
||||
colord({ r: 125, g: 211, b: 252 }), // Crystal Blue
|
||||
colord({ r: 251, g: 113, b: 133 }), // Watermelon
|
||||
colord({ r: 52, g: 211, b: 153 }), // Spearmint
|
||||
colord({ r: 167, g: 139, b: 250 }), // Periwinkle
|
||||
colord({ r: 245, g: 158, b: 11 }), // Honey
|
||||
colord({ r: 110, g: 231, b: 183 }), // Seafoam
|
||||
colord({ r: 233, g: 213, b: 255 }), // Light Lilac
|
||||
colord({ r: 202, g: 138, b: 4 }), // Rich Gold
|
||||
colord({ r: 151, g: 255, b: 187 }), // Fresh Mint
|
||||
colord({ r: 220, g: 38, b: 38 }), // Ruby
|
||||
colord({ r: 124, g: 58, b: 237 }), // Royal Purple
|
||||
colord({ r: 45, g: 212, b: 191 }), // Ocean
|
||||
colord({ r: 252, g: 165, b: 165 }), // Peach
|
||||
|
||||
// Additional 50 colors
|
||||
colord({ r: 179, g: 136, b: 255 }), // Light Purple
|
||||
colord({ r: 133, g: 77, b: 14 }), // Chocolate
|
||||
colord({ r: 52, g: 211, b: 153 }), // Aquamarine
|
||||
colord({ r: 234, g: 179, b: 8 }), // Mustard
|
||||
colord({ r: 236, g: 72, b: 153 }), // Hot Pink
|
||||
colord({ r: 147, g: 197, b: 253 }), // Sky
|
||||
colord({ r: 249, g: 115, b: 22 }), // Pumpkin
|
||||
colord({ r: 167, g: 139, b: 250 }), // Iris
|
||||
colord({ r: 16, g: 185, b: 129 }), // Pine
|
||||
colord({ r: 251, g: 146, b: 60 }), // Mango
|
||||
colord({ r: 192, g: 132, b: 252 }), // Wisteria
|
||||
colord({ r: 79, g: 70, b: 229 }), // Sapphire
|
||||
colord({ r: 245, g: 101, b: 101 }), // Salmon
|
||||
colord({ r: 134, g: 239, b: 172 }), // Spring Green
|
||||
colord({ r: 59, g: 130, b: 246 }), // Ocean Blue
|
||||
colord({ r: 253, g: 164, b: 175 }), // Rose Gold
|
||||
colord({ r: 16, g: 185, b: 129 }), // Forest
|
||||
colord({ r: 252, g: 211, b: 77 }), // Sunshine
|
||||
colord({ r: 190, g: 92, b: 251 }), // Grape
|
||||
colord({ r: 82, g: 183, b: 136 }), // Eucalyptus
|
||||
colord({ r: 248, g: 113, b: 113 }), // Cherry
|
||||
colord({ r: 99, g: 202, b: 253 }), // Arctic
|
||||
colord({ r: 240, g: 171, b: 252 }), // Lilac
|
||||
colord({ r: 163, g: 230, b: 53 }), // Chartreuse
|
||||
colord({ r: 234, g: 88, b: 12 }), // Rust
|
||||
colord({ r: 125, g: 211, b: 252 }), // Ice Blue
|
||||
colord({ r: 251, g: 113, b: 133 }), // Strawberry
|
||||
colord({ r: 52, g: 211, b: 153 }), // Sage
|
||||
colord({ r: 167, g: 139, b: 250 }), // Violet
|
||||
colord({ r: 245, g: 158, b: 11 }), // Apricot
|
||||
colord({ r: 110, g: 231, b: 183 }), // Mint Green
|
||||
colord({ r: 233, g: 213, b: 255 }), // Thistle
|
||||
colord({ r: 202, g: 138, b: 4 }), // Bronze
|
||||
colord({ r: 151, g: 255, b: 187 }), // Pistachio
|
||||
colord({ r: 220, g: 38, b: 38 }), // Fire Engine
|
||||
colord({ r: 124, g: 58, b: 237 }), // Electric Purple
|
||||
colord({ r: 45, g: 212, b: 191 }), // Caribbean
|
||||
colord({ r: 252, g: 165, b: 165 }), // Melon
|
||||
colord({ r: 168, g: 85, b: 247 }), // Byzantium
|
||||
colord({ r: 74, g: 222, b: 128 }), // Kelly Green
|
||||
colord({ r: 239, g: 68, b: 68 }), // Cardinal
|
||||
colord({ r: 34, g: 197, b: 94 }), // Shamrock
|
||||
colord({ r: 96, g: 165, b: 250 }), // Marina
|
||||
colord({ r: 249, g: 115, b: 22 }), // Carrot
|
||||
colord({ r: 192, g: 132, b: 252 }), // Heliotrope
|
||||
colord({ r: 45, g: 212, b: 191 }), // Lagoon
|
||||
colord({ r: 244, g: 114, b: 182 }), // Bubble Gum
|
||||
colord({ r: 132, g: 204, b: 22 }), // Apple
|
||||
colord({ r: 56, g: 189, b: 248 }), // Electric Blue
|
||||
colord({ r: 234, g: 179, b: 8 }), // Daffodil
|
||||
];
|
||||
|
||||
private _selfColor = colord({ r: 0, g: 255, b: 0 });
|
||||
private _allyColor = colord({ r: 255, g: 255, b: 0 });
|
||||
private _enemyColor = colord({ r: 255, g: 0, b: 0 });
|
||||
|
||||
private _spawnHighlightColor = colord({ r: 255, g: 213, b: 79 });
|
||||
|
||||
territoryColor(playerInfo: PlayerInfo): Colord {
|
||||
if (playerInfo.playerType == PlayerType.Human) {
|
||||
return this.humanColors[
|
||||
simpleHash(playerInfo.name) % this.humanColors.length
|
||||
];
|
||||
}
|
||||
return this.territoryColors[
|
||||
simpleHash(playerInfo.name) % this.territoryColors.length
|
||||
];
|
||||
}
|
||||
|
||||
textColor(playerInfo: PlayerInfo): string {
|
||||
return playerInfo.playerType == PlayerType.Human ? "#ffffff" : "#dbdbdb";
|
||||
}
|
||||
|
||||
borderColor(playerInfo: PlayerInfo): Colord {
|
||||
const tc = this.territoryColor(playerInfo).rgba;
|
||||
return colord({
|
||||
r: Math.max(tc.r - 40, 0),
|
||||
g: Math.max(tc.g - 40, 0),
|
||||
b: Math.max(tc.b - 40, 0),
|
||||
});
|
||||
}
|
||||
defendedBorderColor(playerInfo: PlayerInfo): Colord {
|
||||
const bc = this.borderColor(playerInfo).rgba;
|
||||
return colord({
|
||||
r: Math.max(bc.r - 40, 0),
|
||||
g: Math.max(bc.g - 40, 0),
|
||||
b: Math.max(bc.b - 40, 0),
|
||||
});
|
||||
}
|
||||
|
||||
terrainColor(gm: GameMap, tile: TileRef): Colord {
|
||||
let mag = gm.magnitude(tile);
|
||||
if (gm.isShore(tile)) {
|
||||
return this.shore;
|
||||
}
|
||||
switch (gm.terrainType(tile)) {
|
||||
case TerrainType.Ocean:
|
||||
case TerrainType.Lake:
|
||||
const w = this.water.rgba;
|
||||
if (gm.isShoreline(tile) && gm.isWater(tile)) {
|
||||
return this.shorelineWater;
|
||||
}
|
||||
if (gm.magnitude(tile) < 10) {
|
||||
return colord({
|
||||
r: Math.max(w.r - 10 + mag, 0),
|
||||
g: Math.max(w.g - 10 + mag, 0),
|
||||
b: Math.max(w.b - 10 + mag, 0),
|
||||
});
|
||||
}
|
||||
return this.water;
|
||||
case TerrainType.Plains:
|
||||
return colord({
|
||||
r: 140,
|
||||
g: 170 - 2 * mag,
|
||||
b: 88,
|
||||
});
|
||||
case TerrainType.Highland:
|
||||
return colord({
|
||||
r: 150 + 2 * mag,
|
||||
g: 133 + 2 * mag,
|
||||
b: 88 + 2 * mag,
|
||||
});
|
||||
case TerrainType.Mountain:
|
||||
return colord({
|
||||
r: 180 + mag / 2,
|
||||
g: 180 + mag / 2,
|
||||
b: 180 + mag / 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
backgroundColor(): Colord {
|
||||
return this.background;
|
||||
}
|
||||
|
||||
falloutColor(): Colord {
|
||||
return this.rand.randElement(this.falloutColors);
|
||||
}
|
||||
|
||||
font(): string {
|
||||
return "Overpass, sans-serif";
|
||||
}
|
||||
|
||||
selfColor(): Colord {
|
||||
return this._selfColor;
|
||||
}
|
||||
allyColor(): Colord {
|
||||
return this._allyColor;
|
||||
}
|
||||
enemyColor(): Colord {
|
||||
return this._enemyColor;
|
||||
}
|
||||
|
||||
spawnHighlightColor(): Colord {
|
||||
return this._spawnHighlightColor;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -10,6 +10,7 @@ export class UserSettings {
|
||||
|
||||
set(key: string, value: boolean) {
|
||||
localStorage.setItem(key, value ? "true" : "false");
|
||||
document.body.classList.toggle("dark");
|
||||
}
|
||||
|
||||
emojis() {
|
||||
|
||||
@@ -6,4 +6,5 @@ export default {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
darkMode: "class",
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user