feat(frontend): implement via mode for setting destinations and add MapNode disableNavigate prop

This commit is contained in:
2025-08-09 19:51:53 +02:00
parent e7a8014a50
commit cd1cc6dc5f
3 changed files with 55 additions and 21 deletions

View File

@@ -15,6 +15,7 @@ interface MapNodeProps {
security?: number;
signatures?: number;
isDraggable?: boolean;
disableNavigate?: boolean;
}
export const MapNode: React.FC<MapNodeProps> = ({
@@ -30,7 +31,8 @@ export const MapNode: React.FC<MapNodeProps> = ({
type,
security,
signatures,
isDraggable = false
isDraggable = false,
disableNavigate = false,
}) => {
const [isHovered, setIsHovered] = useState(false);
const [isDragging, setIsDragging] = useState(false);
@@ -142,7 +144,7 @@ export const MapNode: React.FC<MapNodeProps> = ({
onMouseDown={handleMouseDown}
onClick={(e) => {
e.stopPropagation();
onClick();
if (!disableNavigate) onClick();
}}
onDoubleClick={(e) => {
e.stopPropagation();

View File

@@ -9,6 +9,7 @@ import { System, Position, Connection as ConnectionType } from '@/lib/types';
import { getSecurityColor } from '@/utils/securityColors';
import { Header } from './Header';
import { ListCharacters, StartESILogin, SetDestinationForAll, AddWaypointForAllByName } from 'wailsjs/go/main/App';
import { toast } from '@/hooks/use-toast';
interface RegionMapProps {
regionName: string;
@@ -104,7 +105,32 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
}
}, [isWormholeRegion]);
const handleSystemClick = (systemName: string) => {
const ensureAnyLoggedIn = async () => {
try {
const list = await ListCharacters();
if (Array.isArray(list) && list.length > 0) return true;
await StartESILogin();
toast({ title: 'EVE Login', description: 'Complete login in your browser, then retry.' });
return false;
} catch (e: any) {
await StartESILogin();
toast({ title: 'EVE Login', description: 'Complete login in your browser, then retry.', variant: 'destructive' });
return false;
}
};
const handleSystemClick = async (systemName: string) => {
if (viaMode) {
try {
if (!(await ensureAnyLoggedIn())) return;
await AddWaypointForAllByName(systemName, false);
toast({ title: 'Waypoint added', description: systemName });
} catch (e: any) {
console.error('Append waypoint failed:', e);
toast({ title: 'Failed to add waypoint', description: String(e), variant: 'destructive' });
}
return;
}
if (focusSystem === systemName) return;
navigate(`/regions/${regionName}/${systemName}`);
};
@@ -374,31 +400,20 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
}
};
const ensureAnyLoggedIn = async () => {
try {
const list = await ListCharacters();
if (Array.isArray(list) && list.length > 0) return true;
await StartESILogin();
return false;
} catch {
await StartESILogin();
return false;
}
};
const onSetDestination = async (systemName: string, wantVia: boolean) => {
try {
if (!(await ensureAnyLoggedIn())) return;
if (!viaMode) {
// First selection: set destination and optionally enter via mode
await SetDestinationForAll(systemName, true, false);
toast({ title: 'Destination set', description: systemName });
if (wantVia) setViaMode(true);
} else {
// Append waypoint
await AddWaypointForAllByName(systemName, false);
toast({ title: 'Waypoint added', description: systemName });
}
} catch (e) {
} catch (e: any) {
console.error('Set destination failed:', e);
toast({ title: 'Failed to set destination', description: String(e), variant: 'destructive' });
}
};
@@ -442,7 +457,7 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
width="100%"
height="100%"
viewBox={`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`}
className={`cursor-grab active:cursor-grabbing ${viaMode ? 'ring-2 ring-emerald-500' : ''}`}
className="cursor-grab active:cursor-grabbing"
onMouseDown={handleMouseDown}
onMouseMove={(e) => {
if (isPanning) {
@@ -508,6 +523,7 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
security={system.security}
signatures={system.signatures}
isDraggable={isWormholeRegion}
disableNavigate={viaMode}
/>
))}
@@ -536,6 +552,12 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
)}
</svg>
{viaMode && (
<div className="absolute top-2 right-2 px-2 py-1 rounded bg-emerald-600 text-white text-xs shadow">
VIA mode (Esc to exit)
</div>
)}
{/* Context Menu */}
{contextMenu && (
<SystemContextMenu

View File

@@ -8,7 +8,7 @@ interface SystemContextMenuProps {
onRename: (newName: string) => void;
onDelete: (system: System) => void;
onClearConnections: (system: System) => void;
onSetDestination: (systemName: string, viaMode: boolean) => void;
onSetDestination?: (systemName: string, viaMode: boolean) => void;
onClose: () => void;
}
@@ -28,6 +28,16 @@ export const SystemContextMenu = ({ x, y, system, onRename, onDelete, onClearCon
setIsRenaming(false);
};
const handleSetDestinationClick = (e: React.MouseEvent) => {
const via = !!e.shiftKey;
if (typeof onSetDestination === 'function') {
onSetDestination(system.solarSystemName, via);
} else {
console.error('onSetDestination not provided');
}
onClose();
};
return (
<div
ref={menuRef}
@@ -85,7 +95,7 @@ export const SystemContextMenu = ({ x, y, system, onRename, onDelete, onClearCon
</button>
<div className="h-px bg-slate-700 my-1" />
<button
onClick={(e) => { onSetDestination(system.solarSystemName, e.shiftKey); onClose(); }}
onClick={handleSetDestinationClick}
className="w-full px-3 py-1 text-left text-emerald-400 hover:bg-slate-700 rounded text-sm"
title="Shift-click to enter via mode and append waypoints"
>