diff --git a/src/app/game/setup/editor/page.tsx b/src/app/game/setup/editor/page.tsx index a3f40cd9..93ca0f46 100644 --- a/src/app/game/setup/editor/page.tsx +++ b/src/app/game/setup/editor/page.tsx @@ -4,12 +4,23 @@ import { Suspense, useState, useEffect, useCallback, useRef } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { EditorCore, VOIDSTRIKE_EDITOR_CONFIG } from '@/editor'; import { voidstrikeDataProvider } from '@/editor/providers/voidstrike'; -import { useGameSetupStore, loadEditorMapDataFromStorage } from '@/store/gameSetupStore'; +import { useGameSetupStore, loadEditorMapDataFromStorage, type GameSetupState } from '@/store/gameSetupStore'; import { debugInitialization } from '@/utils/debugLogger'; import type { EditorMapData } from '@/editor'; import type { MapListItem } from '@/editor/core/EditorHeader'; import type { MapData } from '@/data/maps/MapTypes'; +// Battle simulator launch helper +const useBattleSimulator = () => { + const router = useRouter(); + const startBattleSimulator = useGameSetupStore((state: GameSetupState) => state.startBattleSimulator); + + return useCallback(() => { + startBattleSimulator(); + router.push('/game'); + }, [startBattleSimulator, router]); +}; + /** * Map Editor Page * @@ -27,6 +38,9 @@ function EditorPageContent() { const isNewMap = searchParams.get('new') === 'true'; const mapIdParam = searchParams.get('map'); + // Battle simulator + const handleBattleSimulator = useBattleSimulator(); + // State for map selection const [mapList, setMapList] = useState([]); const [currentMapId, setCurrentMapId] = useState( @@ -154,6 +168,7 @@ function EditorPageContent() { mapList={mapList} onLoadMap={handleLoadMap} onNewMap={handleNewMap} + onBattleSimulator={handleBattleSimulator} /> ); } diff --git a/src/editor/core/EditorCore.tsx b/src/editor/core/EditorCore.tsx index ba36f374..05a39c41 100644 --- a/src/editor/core/EditorCore.tsx +++ b/src/editor/core/EditorCore.tsx @@ -67,6 +67,7 @@ export interface EditorCoreProps extends EditorCallbacks { mapList?: MapListItem[]; onLoadMap?: (mapId: string) => void; onNewMap?: () => void; + onBattleSimulator?: () => void; } // ============================================ @@ -87,6 +88,7 @@ export function EditorCore({ mapList, onLoadMap, onNewMap, + onBattleSimulator, }: EditorCoreProps) { const editorState = useEditorState(config); const { state, loadMap } = editorState; @@ -625,6 +627,7 @@ export function EditorCore({ currentMapId={mapId} onLoadMap={onLoadMap} onNewMap={onNewMap} + onBattleSimulator={onBattleSimulator} /> {/* Main content */} diff --git a/src/editor/core/EditorHeader.tsx b/src/editor/core/EditorHeader.tsx index cc660d0d..910463dc 100644 --- a/src/editor/core/EditorHeader.tsx +++ b/src/editor/core/EditorHeader.tsx @@ -4,7 +4,7 @@ 'use client'; -import { useRef, useState } from 'react'; +import { useRef, useState, useMemo } from 'react'; import type { EditorConfig, EditorMapData } from '../config/EditorConfig'; export interface MapListItem { @@ -34,6 +34,8 @@ export interface EditorHeaderProps { currentMapId?: string; onLoadMap?: (mapId: string) => void; onNewMap?: () => void; + // Battle Simulator + onBattleSimulator?: () => void; } export function EditorHeader({ @@ -56,12 +58,22 @@ export function EditorHeader({ currentMapId, onLoadMap, onNewMap, + onBattleSimulator, }: EditorHeaderProps) { const fileInputRef = useRef(null); const [showLoadDropdown, setShowLoadDropdown] = useState(false); + const [mapSearch, setMapSearch] = useState(''); const hasLoadMapFeature = mapList && onLoadMap && onNewMap; + // Filter maps based on search + const filteredMaps = useMemo(() => { + if (!mapList) return []; + if (!mapSearch.trim()) return mapList; + const searchLower = mapSearch.toLowerCase(); + return mapList.filter(map => map.name.toLowerCase().includes(searchLower)); + }, [mapList, mapSearch]); + // Handle file import const handleFileSelect = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; @@ -182,22 +194,59 @@ export function EditorHeader({ {/* Click outside to close */}
setShowLoadDropdown(false)} + onClick={() => { + setShowLoadDropdown(false); + setMapSearch(''); + }} />
+ {/* Search input */} +
+
+ + + + setMapSearch(e.target.value)} + className="w-full pl-8 pr-3 py-1.5 text-sm rounded outline-none" + style={{ + backgroundColor: 'var(--editor-surface)', + color: 'var(--editor-text)', + border: '1px solid var(--editor-border)', + }} + autoFocus + onClick={(e) => e.stopPropagation()} + /> +
+
+ {/* New Map option */} - {/* Existing maps */} -
+ {/* Scrollable maps list */} +
- Existing Maps + {mapSearch.trim() ? `Results (${filteredMaps.length})` : 'Existing Maps'}
- {mapList.map((map: MapListItem) => ( - - ))} + No maps found +
+ ) : ( + filteredMaps.map((map: MapListItem) => ( + + )) + )}
@@ -328,6 +390,21 @@ export function EditorHeader({ Cancel + {/* Battle Simulator button */} + {onBattleSimulator && ( + + )} + {/* Preview button */} {onPreview && (