mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 16:26:37 +00:00
633556effe
Flags are now only rendered and fetched when the modal is actually opened Additionally, duplicate Tailwind CSS classes have been cleaned up. - [x] I have added screenshots for all UI updates No visible UI changes - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file No new user-facing text - [x] I have added relevant tests to the test directory No new tests needed for this UI rendering change. - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced regression is found: abodcraft1
117 lines
3.5 KiB
TypeScript
117 lines
3.5 KiB
TypeScript
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 = "";
|
|
@state() private isModalOpen = false;
|
|
|
|
createRenderRoot() {
|
|
return this;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<o-modal title="Flag Selector Modal" alwaysMaximized>
|
|
<input
|
|
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 text-black dark:border-gray-300/60 dark:bg-gray-700 dark:text-white"
|
|
type="text"
|
|
placeholder="Search..."
|
|
@change=${this.handleSearch}
|
|
@keyup=${this.handleSearch}
|
|
/>
|
|
<div
|
|
class="flex flex-wrap justify-evenly gap-[1rem] overflow-y-auto overflow-x-hidden h-[90%]"
|
|
>
|
|
${this.isModalOpen
|
|
? Countries.filter(
|
|
(country) =>
|
|
!country.restricted && this.includedInSearch(country),
|
|
).map(
|
|
(country) => html`
|
|
<button
|
|
@click=${() => {
|
|
this.setFlag(country.code);
|
|
this.close();
|
|
}}
|
|
class="text-center cursor-pointer border-none bg-none opacity-70
|
|
w-[calc(100%/2-15px)] sm:w-[calc(100%/4-15px)]
|
|
md:w-[calc(100%/6-15px)] lg:w-[calc(100%/8-15px)]
|
|
xl:w-[calc(100%/10-15px)] min-w-[80px]"
|
|
>
|
|
<img
|
|
class="country-flag w-full h-auto"
|
|
src="/flags/${country.code}.svg"
|
|
@error=${(e: Event) => {
|
|
const img = e.currentTarget as HTMLImageElement;
|
|
const fallback = "/flags/xx.svg";
|
|
if (img.src && !img.src.endsWith(fallback)) {
|
|
img.src = fallback;
|
|
}
|
|
}}
|
|
/>
|
|
<span class="country-name">${country.name}</span>
|
|
</button>
|
|
`,
|
|
)
|
|
: html``}
|
|
</div>
|
|
</o-modal>
|
|
`;
|
|
}
|
|
|
|
private includedInSearch(country: { name: string; code: string }): boolean {
|
|
return (
|
|
country.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
|
country.code.toLowerCase().includes(this.search.toLowerCase())
|
|
);
|
|
}
|
|
|
|
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.isModalOpen = true;
|
|
this.modalEl?.open();
|
|
}
|
|
public close() {
|
|
this.isModalOpen = false;
|
|
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();
|
|
}
|
|
};
|
|
}
|