mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-01 08:33:27 +00:00
feat: add search bar to effects picker modal
Mirror the flag/pattern modals with a search input in the EffectsModal header. Filters the effects grid by name — matching either the raw effect id or its displayed label — and hides the Default tile while searching, the same way FlagInputModal hides its no-flag tile. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -394,6 +394,7 @@
|
||||
},
|
||||
"effects": {
|
||||
"button_title": "Pick an effect!",
|
||||
"search": "Search...",
|
||||
"title": "Effects",
|
||||
"type": {
|
||||
"transportShipTrail": "Boat Trail"
|
||||
|
||||
@@ -15,6 +15,11 @@ export class EffectsModal extends BaseModal {
|
||||
|
||||
@state() private cosmetics: Cosmetics | null = null;
|
||||
@state() private userMeResponse: UserMeResponse | false = false;
|
||||
@state() private search = "";
|
||||
|
||||
private handleSearch(event: Event) {
|
||||
this.search = (event.target as HTMLInputElement).value;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
@@ -43,6 +48,19 @@ export class EffectsModal extends BaseModal {
|
||||
ariaLabel: translateText("common.back"),
|
||||
rightContent: html`<not-logged-in-warning></not-logged-in-warning>`,
|
||||
})}
|
||||
|
||||
<div class="md:flex items-center gap-2 justify-center mt-4">
|
||||
<input
|
||||
class="h-12 w-full max-w-md border border-white/10 bg-black/60
|
||||
rounded-xl shadow-inner text-xl text-center focus:outline-none
|
||||
focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 text-white placeholder-white/30 transition-all"
|
||||
type="text"
|
||||
placeholder=${translateText("effects.search")}
|
||||
.value=${this.search}
|
||||
@change=${this.handleSearch}
|
||||
@keyup=${this.handleSearch}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -66,6 +84,7 @@ export class EffectsModal extends BaseModal {
|
||||
mode="select"
|
||||
.cosmetics=${this.cosmetics}
|
||||
.userMeResponse=${this.userMeResponse}
|
||||
.search=${this.search}
|
||||
></effects-grid>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
purchaseCosmetic,
|
||||
resolveCosmetics,
|
||||
ResolvedCosmetic,
|
||||
translateCosmetic,
|
||||
} from "../Cosmetics";
|
||||
import { translateText } from "../Utils";
|
||||
import "./CosmeticButton";
|
||||
@@ -47,6 +48,7 @@ export class EffectsGrid extends LitElement {
|
||||
false;
|
||||
@property({ type: String }) mode: "select" | "purchase" = "select";
|
||||
@property({ attribute: false }) affiliateCode: string | null = null;
|
||||
@property({ type: String }) search = "";
|
||||
|
||||
private userSettings = new UserSettings();
|
||||
private _onChange = () => this.requestUpdate();
|
||||
@@ -77,6 +79,17 @@ export class EffectsGrid extends LitElement {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private matchesSearch(r: ResolvedCosmetic): boolean {
|
||||
const q = this.search.trim().toLowerCase();
|
||||
if (!q) return true;
|
||||
const name = (r.cosmetic as Effect | null)?.name;
|
||||
if (!name) return false;
|
||||
return (
|
||||
name.toLowerCase().includes(q) ||
|
||||
translateCosmetic("effects", name).toLowerCase().includes(q)
|
||||
);
|
||||
}
|
||||
|
||||
private itemsForType(
|
||||
all: ResolvedCosmetic[],
|
||||
effectType: EffectType,
|
||||
@@ -85,15 +98,15 @@ export class EffectsGrid extends LitElement {
|
||||
(r) =>
|
||||
r.type === "effect" &&
|
||||
r.cosmetic !== null &&
|
||||
r.effectType === effectType,
|
||||
r.effectType === effectType &&
|
||||
this.matchesSearch(r),
|
||||
);
|
||||
if (this.mode === "purchase") {
|
||||
return ofType.filter((r) => r.relationship === "purchasable");
|
||||
}
|
||||
return [
|
||||
noneTile(effectType),
|
||||
...ofType.filter((r) => r.relationship === "owned"),
|
||||
];
|
||||
const owned = ofType.filter((r) => r.relationship === "owned");
|
||||
// The Default tile has no name to match — hide it while searching.
|
||||
return this.search.trim() ? owned : [noneTile(effectType), ...owned];
|
||||
}
|
||||
|
||||
private renderTile(
|
||||
|
||||
Reference in New Issue
Block a user