diff --git a/src/client/FlagInput.ts b/src/client/FlagInput.ts index 8ae13ca77..584253700 100644 --- a/src/client/FlagInput.ts +++ b/src/client/FlagInput.ts @@ -1,13 +1,11 @@ import { LitElement, css, html } from "lit"; import { customElement, state } from "lit/decorators.js"; -import Countries from "./data/countries.json"; +import { renderPlayerFlag } from "../core/CustomFlag"; const flagKey: string = "flag"; @customElement("flag-input") export class FlagInput extends LitElement { - @state() private flag: string = ""; - @state() private search: string = ""; - @state() private showModal: boolean = false; + @state() public flag: string = ""; static styles = css` @media (max-width: 768px) { @@ -21,19 +19,6 @@ export class FlagInput extends LitElement { } `; - private handleSearch(e: Event) { - this.search = String((e.target as HTMLInputElement).value); - } - - private setFlag(flag: string) { - if (flag === "xx") { - flag = ""; - } - this.flag = flag; - this.showModal = false; - this.storeFlag(flag); - } - public getCurrentFlag(): string { return this.flag; } @@ -46,14 +31,6 @@ export class FlagInput extends LitElement { return ""; } - private storeFlag(flag: string) { - if (flag) { - localStorage.setItem(flagKey, flag); - } else if (flag === "") { - localStorage.removeItem(flagKey); - } - } - private dispatchFlagEvent() { this.dispatchEvent( new CustomEvent("flag-change", { @@ -68,86 +45,51 @@ export class FlagInput extends LitElement { super.connectedCallback(); this.flag = this.getStoredFlag(); this.dispatchFlagEvent(); - window.addEventListener("keydown", this.handleKeyDown); } - disconnectedCallback() { - window.removeEventListener("keydown", this.handleKeyDown); - super.disconnectedCallback(); - } - - private handleKeyDown = (e: KeyboardEvent) => { - if (e.code === "Escape") { - e.preventDefault(); - this.showModal = false; - } - }; - createRenderRoot() { return this; } render() { return html` -
(this.showModal = false)} - >
- ${this.showModal - ? html` -
- -
- ${Countries.filter( - (country) => - country.name - .toLowerCase() - .includes(this.search.toLowerCase()) || - country.code - .toLowerCase() - .includes(this.search.toLowerCase()), - ).map( - (country) => html` - - `, - )} -
-
- ` - : ""}
`; } + + updated() { + const preview = this.renderRoot.querySelector( + "#flag-preview", + ) as HTMLElement; + if (!preview) return; + + preview.innerHTML = ""; + + if (this.flag?.startsWith("!")) { + renderPlayerFlag(this.flag, preview); + } else { + const img = document.createElement("img"); + img.src = this.flag ? `/flags/${this.flag}.svg` : `/flags/xx.svg`; + img.style.width = "100%"; + img.style.height = "100%"; + img.style.objectFit = "contain"; + img.onerror = () => { + if (!img.src.endsWith("/flags/xx.svg")) { + img.src = "/flags/xx.svg"; + } + }; + preview.appendChild(img); + } + } } diff --git a/src/client/FlagInputModal.ts b/src/client/FlagInputModal.ts new file mode 100644 index 000000000..86e413677 --- /dev/null +++ b/src/client/FlagInputModal.ts @@ -0,0 +1,105 @@ +import { LitElement, html } from "lit"; +import { customElement, query, state } from "lit/decorators.js"; +import Countries from "./data/countries.json"; + +@customElement("flag-input-modal") +export class FlagInputModal extends LitElement { + @query("o-modal") private modalEl!: HTMLElement & { + open: () => void; + close: () => void; + }; + + @state() private search: string = ""; + + createRenderRoot() { + return this; + } + + render() { + return html` + + +
+ ${Countries.filter( + (country) => + country.name.toLowerCase().includes(this.search.toLowerCase()) || + country.code.toLowerCase().includes(this.search.toLowerCase()), + ).map( + (country) => html` + + `, + )} +
+
+ `; + } + + private handleSearch(event: Event) { + this.search = (event.target as HTMLInputElement).value; + } + + private setFlag(flag: string) { + localStorage.setItem("flag", flag); + this.dispatchEvent( + new CustomEvent("flag-change", { + detail: { flag }, + bubbles: true, + composed: true, + }), + ); + } + + public open() { + this.modalEl?.open(); + } + public close() { + this.modalEl?.close(); + } + + connectedCallback() { + super.connectedCallback(); + window.addEventListener("keydown", this.handleKeyDown); + } + + disconnectedCallback() { + window.removeEventListener("keydown", this.handleKeyDown); + super.disconnectedCallback(); + } + + private handleKeyDown = (e: KeyboardEvent) => { + if (e.code === "Escape") { + e.preventDefault(); + this.close(); + } + }; +} diff --git a/src/client/Main.ts b/src/client/Main.ts index c45057e81..732a58c12 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -11,6 +11,7 @@ import "./DarkModeButton"; import { DarkModeButton } from "./DarkModeButton"; import "./FlagInput"; import { FlagInput } from "./FlagInput"; +import { FlagInputModal } from "./FlagInputModal"; import { GameStartingModal } from "./GameStartingModal"; import "./GoogleAdElement"; import { HelpModal } from "./HelpModal"; @@ -194,6 +195,16 @@ class Client { hlpModal.open(); }); + const flagInputModal = document.querySelector( + "flag-input-modal", + ) as FlagInputModal; + flagInputModal instanceof FlagInputModal; + const flgInput = document.getElementById("flag-input_"); + if (flgInput === null) throw new Error("Missing flag-input_"); + flgInput.addEventListener("click", () => { + flagInputModal.open(); + }); + const territoryModal = document.querySelector( "territory-patterns-modal", ) as TerritoryPatternsModal; diff --git a/src/client/components/baseComponents/Modal.ts b/src/client/components/baseComponents/Modal.ts index af7c37440..0841b4ba4 100644 --- a/src/client/components/baseComponents/Modal.ts +++ b/src/client/components/baseComponents/Modal.ts @@ -7,6 +7,7 @@ export class OModal extends LitElement { @state() public isModalOpen = false; @property({ type: String }) title = ""; @property({ type: String }) translationKey = ""; + @property({ type: Boolean }) alwaysMaximized = false; static styles = css` .c-modal { @@ -31,6 +32,17 @@ export class OModal extends LitElement { max-width: 860px; } + .c-modal__wrapper.always-maximized { + width: 100%; + min-width: 340px; + max-width: 860px; + min-height: 320px; + /* Fallback for older browsers */ + height: 60vh; + /* Use dvh if supported for dynamic viewport handling */ + height: 60dvh; + } + .c-modal__header { position: relative; border-top-left-radius: 4px; @@ -74,7 +86,11 @@ export class OModal extends LitElement { ${this.isModalOpen ? html`