mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-01 04:43:28 +00:00
Add map picker with Featured/All tabs (#3005)
Resolves #2996 ## Description: Replace map selection UI in src/client/SinglePlayerModal.ts and src/client/HostLobbyModal.ts with the picker (Featured/All tabs + random map card). Also, since the html was getting quite long, I extracted the shared parts into a separate component. <img width="575" height="592" alt="スクリーンショット 2026-01-23 21 57 03" src="https://github.com/user-attachments/assets/fc6bfbc3-cb66-452a-b971-436940b0fb99" /> <img width="633" height="648" alt="スクリーンショット 2026-01-23 21 57 12" src="https://github.com/user-attachments/assets/1aa409a1-b801-4a60-8b26-ba20e343d66e" /> I separated Map.ts because the display logic looked reusable in other places, but I’m also open to merging it back if that makes more sense. If the review prefers it integrated, I can combine them again. ## 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 - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: aotumuri
This commit is contained in:
@@ -13,7 +13,6 @@ import {
|
||||
Quads,
|
||||
Trios,
|
||||
UnitType,
|
||||
mapCategories,
|
||||
} from "../core/game/Game";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { TeamCountConfig } from "../core/Schemas";
|
||||
@@ -24,7 +23,7 @@ import "./components/baseComponents/Modal";
|
||||
import { BaseModal } from "./components/BaseModal";
|
||||
import "./components/Difficulties";
|
||||
import "./components/FluentSlider";
|
||||
import "./components/Maps";
|
||||
import "./components/map/MapPicker";
|
||||
import { modalHeader } from "./components/ui/ModalHeader";
|
||||
import { fetchCosmetics } from "./Cosmetics";
|
||||
import { FlagInput } from "./FlagInput";
|
||||
@@ -35,7 +34,6 @@ import {
|
||||
renderToggleInputCardInput,
|
||||
} from "./utilities/RenderToggleInputCard";
|
||||
import { renderUnitTypeOptions } from "./utilities/RenderUnitTypeOptions";
|
||||
import randomMap from "/images/RandomMap.webp?url";
|
||||
|
||||
@customElement("single-player-modal")
|
||||
export class SinglePlayerModal extends BaseModal {
|
||||
@@ -197,84 +195,15 @@ export class SinglePlayerModal extends BaseModal {
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="space-y-8">
|
||||
${Object.entries(mapCategories).map(
|
||||
([categoryKey, maps]) => html`
|
||||
<div class="w-full">
|
||||
<h4
|
||||
class="text-xs font-bold text-white/40 uppercase tracking-widest mb-4 pl-2"
|
||||
>
|
||||
${translateText(`map_categories.${categoryKey}`)}
|
||||
</h4>
|
||||
<div
|
||||
class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4"
|
||||
>
|
||||
${maps.map((mapValue) => {
|
||||
const mapKey = Object.keys(GameMapType).find(
|
||||
(key) =>
|
||||
GameMapType[key as keyof typeof GameMapType] ===
|
||||
mapValue,
|
||||
);
|
||||
return html`
|
||||
<div
|
||||
@click=${() => this.handleMapSelection(mapValue)}
|
||||
class="cursor-pointer transition-transform duration-200 active:scale-95"
|
||||
>
|
||||
<map-display
|
||||
.mapKey=${mapKey}
|
||||
.selected=${!this.useRandomMap &&
|
||||
this.selectedMap === mapValue}
|
||||
.showMedals=${this.showAchievements}
|
||||
.wins=${this.mapWins.get(mapValue) ?? new Set()}
|
||||
.translation=${translateText(
|
||||
`map.${mapKey?.toLowerCase()}`,
|
||||
)}
|
||||
></map-display>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
|
||||
<!-- Random Map Card -->
|
||||
<div class="w-full">
|
||||
<h4
|
||||
class="text-xs font-bold text-white/40 uppercase tracking-widest mb-4 pl-2"
|
||||
>
|
||||
${translateText("map_categories.special")}
|
||||
</h4>
|
||||
<div
|
||||
class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4"
|
||||
>
|
||||
<button
|
||||
class="relative group rounded-xl border transition-all duration-200 overflow-hidden flex flex-col items-stretch ${this
|
||||
.useRandomMap
|
||||
? "bg-blue-500/20 border-blue-500/50 shadow-[0_0_15px_rgba(59,130,246,0.3)]"
|
||||
: "bg-white/5 border-white/10 hover:bg-white/10 hover:border-white/20"}"
|
||||
@click=${this.handleSelectRandomMap}
|
||||
>
|
||||
<div
|
||||
class="aspect-[2/1] w-full relative overflow-hidden bg-black/20"
|
||||
>
|
||||
<img
|
||||
src=${randomMap}
|
||||
alt=${translateText("map.random")}
|
||||
class="w-full h-full object-cover opacity-60 group-hover:opacity-100 transition-opacity"
|
||||
/>
|
||||
</div>
|
||||
<div class="p-3 text-center border-t border-white/5">
|
||||
<div
|
||||
class="text-xs font-bold text-white uppercase tracking-wider break-words hyphens-auto"
|
||||
>
|
||||
${translateText("map.random")}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<map-picker
|
||||
.selectedMap=${this.selectedMap}
|
||||
.useRandomMap=${this.useRandomMap}
|
||||
.showMedals=${this.showAchievements}
|
||||
.mapWins=${this.mapWins}
|
||||
.onSelectMap=${(mapValue: GameMapType) =>
|
||||
this.handleMapSelection(mapValue)}
|
||||
.onSelectRandom=${() => this.handleSelectRandomMap()}
|
||||
></map-picker>
|
||||
</div>
|
||||
|
||||
<!-- Difficulty Selection -->
|
||||
|
||||
Reference in New Issue
Block a user