Fix visual issues and add features
- Remove white boxes around system nodes. - Reverse zoom direction. - Reduce region node size. - Implement URL encoding for region names. - Color connections based on node security.
This commit is contained in:
@@ -4,18 +4,30 @@ import React from 'react';
|
|||||||
interface ConnectionProps {
|
interface ConnectionProps {
|
||||||
from: { x: number; y: number };
|
from: { x: number; y: number };
|
||||||
to: { x: number; y: number };
|
to: { x: number; y: number };
|
||||||
|
fromColor?: string;
|
||||||
|
toColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Connection: React.FC<ConnectionProps> = ({ from, to }) => {
|
export const Connection: React.FC<ConnectionProps> = ({ from, to, fromColor = '#a855f7', toColor = '#a855f7' }) => {
|
||||||
|
// Create gradient ID based on colors to ensure uniqueness
|
||||||
|
const gradientId = `gradient-${fromColor.replace('#', '')}-${toColor.replace('#', '')}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g>
|
<g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id={gradientId} x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" stopColor={fromColor} stopOpacity="0.7" />
|
||||||
|
<stop offset="100%" stopColor={toColor} stopOpacity="0.7" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
{/* Glow effect */}
|
{/* Glow effect */}
|
||||||
<line
|
<line
|
||||||
x1={from.x}
|
x1={from.x}
|
||||||
y1={from.y}
|
y1={from.y}
|
||||||
x2={to.x}
|
x2={to.x}
|
||||||
y2={to.y}
|
y2={to.y}
|
||||||
stroke="#8b5cf6"
|
stroke={`url(#${gradientId})`}
|
||||||
strokeWidth="3"
|
strokeWidth="3"
|
||||||
opacity="0.3"
|
opacity="0.3"
|
||||||
filter="url(#glow)"
|
filter="url(#glow)"
|
||||||
@@ -27,7 +39,7 @@ export const Connection: React.FC<ConnectionProps> = ({ from, to }) => {
|
|||||||
y1={from.y}
|
y1={from.y}
|
||||||
x2={to.x}
|
x2={to.x}
|
||||||
y2={to.y}
|
y2={to.y}
|
||||||
stroke="#a855f7"
|
stroke={`url(#${gradientId})`}
|
||||||
strokeWidth="1"
|
strokeWidth="1"
|
||||||
opacity="0.7"
|
opacity="0.7"
|
||||||
className="transition-all duration-300"
|
className="transition-all duration-300"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { MapNode } from './MapNode';
|
import { MapNode } from './MapNode';
|
||||||
import { Connection } from './Connection';
|
import { Connection } from './Connection';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { getSecurityColor } from '../utils/securityColors';
|
||||||
|
|
||||||
interface Region {
|
interface Region {
|
||||||
regionName: string;
|
regionName: string;
|
||||||
@@ -102,6 +103,7 @@ export const GalaxyMap = () => {
|
|||||||
const mouseX = e.clientX - rect.left;
|
const mouseX = e.clientX - rect.left;
|
||||||
const mouseY = e.clientY - rect.top;
|
const mouseY = e.clientY - rect.top;
|
||||||
|
|
||||||
|
// Reverse scroll direction: positive deltaY zooms out, negative zooms in
|
||||||
const scale = e.deltaY > 0 ? 1.1 : 0.9;
|
const scale = e.deltaY > 0 ? 1.1 : 0.9;
|
||||||
const newWidth = viewBox.width * scale;
|
const newWidth = viewBox.width * scale;
|
||||||
const newHeight = viewBox.height * scale;
|
const newHeight = viewBox.height * scale;
|
||||||
@@ -174,11 +176,18 @@ export const GalaxyMap = () => {
|
|||||||
const toPos = nodePositions[connectedRegion];
|
const toPos = nodePositions[connectedRegion];
|
||||||
if (!fromPos || !toPos) return null;
|
if (!fromPos || !toPos) return null;
|
||||||
|
|
||||||
|
// Get colors for both regions
|
||||||
|
const fromColor = getSecurityColor(region.security);
|
||||||
|
const toRegion = regions.find(r => r.regionName === connectedRegion);
|
||||||
|
const toColor = toRegion ? getSecurityColor(toRegion.security) : fromColor;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Connection
|
<Connection
|
||||||
key={`${region.regionName}-${connectedRegion}`}
|
key={`${region.regionName}-${connectedRegion}`}
|
||||||
from={fromPos}
|
from={fromPos}
|
||||||
to={toPos}
|
to={toPos}
|
||||||
|
fromColor={fromColor}
|
||||||
|
toColor={toColor}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
: '#a855f7'; // fallback purple color
|
: '#a855f7'; // fallback purple color
|
||||||
|
|
||||||
if (type === 'region') {
|
if (type === 'region') {
|
||||||
// Render region as a pill/rounded rectangle
|
// Reduce region size to prevent overlap
|
||||||
const pillWidth = Math.max(name.length * 12, 80);
|
const pillWidth = Math.max(name.length * 8, 60); // Reduced from 12 to 8, min from 80 to 60
|
||||||
const pillHeight = 32;
|
const pillHeight = 24; // Reduced from 32 to 24
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g
|
<g
|
||||||
@@ -44,11 +44,11 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
>
|
>
|
||||||
{/* Glow effect */}
|
{/* Glow effect */}
|
||||||
<rect
|
<rect
|
||||||
x={-pillWidth/2 - 4}
|
x={-pillWidth/2 - 3}
|
||||||
y={-pillHeight/2 - 4}
|
y={-pillHeight/2 - 3}
|
||||||
width={pillWidth + 8}
|
width={pillWidth + 6}
|
||||||
height={pillHeight + 8}
|
height={pillHeight + 6}
|
||||||
rx={(pillHeight + 8) / 2}
|
rx={(pillHeight + 6) / 2}
|
||||||
fill={nodeColor}
|
fill={nodeColor}
|
||||||
opacity={isHovered ? 0.3 : 0.1}
|
opacity={isHovered ? 0.3 : 0.1}
|
||||||
filter="url(#glow)"
|
filter="url(#glow)"
|
||||||
@@ -64,7 +64,7 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
rx={pillHeight / 2}
|
rx={pillHeight / 2}
|
||||||
fill={nodeColor}
|
fill={nodeColor}
|
||||||
stroke="#ffffff"
|
stroke="#ffffff"
|
||||||
strokeWidth="2"
|
strokeWidth="1.5"
|
||||||
filter="url(#glow)"
|
filter="url(#glow)"
|
||||||
className={`transition-all duration-300 ${
|
className={`transition-all duration-300 ${
|
||||||
isHovered ? 'drop-shadow-lg' : ''
|
isHovered ? 'drop-shadow-lg' : ''
|
||||||
@@ -74,10 +74,10 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
{/* Text inside pill */}
|
{/* Text inside pill */}
|
||||||
<text
|
<text
|
||||||
x="0"
|
x="0"
|
||||||
y="5"
|
y="4"
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
fill="#ffffff"
|
fill="#ffffff"
|
||||||
fontSize="14"
|
fontSize="11"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
className="transition-all duration-300 pointer-events-none select-none"
|
className="transition-all duration-300 pointer-events-none select-none"
|
||||||
style={{ textShadow: '1px 1px 2px rgba(0,0,0,0.8)' }}
|
style={{ textShadow: '1px 1px 2px rgba(0,0,0,0.8)' }}
|
||||||
@@ -88,8 +88,8 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Render system as a dot with external label
|
// Render system as a dot with external label
|
||||||
const nodeSize = 8;
|
const nodeSize = 6;
|
||||||
const textOffset = 20; // Increased from 15 to move text further down
|
const textOffset = 18; // Position text below the dot
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g
|
<g
|
||||||
@@ -104,19 +104,17 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
>
|
>
|
||||||
{/* Node glow effect */}
|
{/* Node glow effect */}
|
||||||
<circle
|
<circle
|
||||||
r={nodeSize + 6}
|
r={nodeSize + 4}
|
||||||
fill={nodeColor}
|
fill={nodeColor}
|
||||||
opacity={isHovered ? 0.3 : 0.1}
|
opacity={isHovered ? 0.3 : 0.1}
|
||||||
filter="url(#glow)"
|
filter="url(#glow)"
|
||||||
className="transition-all duration-300"
|
className="transition-all duration-300"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Main node */}
|
{/* Main node - removed stroke to eliminate white border */}
|
||||||
<circle
|
<circle
|
||||||
r={nodeSize}
|
r={nodeSize}
|
||||||
fill={nodeColor}
|
fill={nodeColor}
|
||||||
stroke="#ffffff"
|
|
||||||
strokeWidth="2"
|
|
||||||
filter="url(#glow)"
|
filter="url(#glow)"
|
||||||
className={`transition-all duration-300 ${
|
className={`transition-all duration-300 ${
|
||||||
isHovered ? 'drop-shadow-lg' : ''
|
isHovered ? 'drop-shadow-lg' : ''
|
||||||
@@ -125,7 +123,7 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
|
|
||||||
{/* Inner core */}
|
{/* Inner core */}
|
||||||
<circle
|
<circle
|
||||||
r={nodeSize - 4}
|
r={nodeSize - 3}
|
||||||
fill={isHovered ? '#ffffff' : nodeColor}
|
fill={isHovered ? '#ffffff' : nodeColor}
|
||||||
opacity={0.8}
|
opacity={0.8}
|
||||||
className="transition-all duration-300"
|
className="transition-all duration-300"
|
||||||
@@ -137,7 +135,7 @@ export const MapNode: React.FC<MapNodeProps> = ({
|
|||||||
y={textOffset}
|
y={textOffset}
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
fill="#ffffff"
|
fill="#ffffff"
|
||||||
fontSize="12"
|
fontSize="10"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
className={`transition-all duration-300 ${
|
className={`transition-all duration-300 ${
|
||||||
isHovered ? 'fill-purple-200' : 'fill-white'
|
isHovered ? 'fill-purple-200' : 'fill-white'
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
import React, { useState, useRef, useCallback, useEffect } from 'react';
|
import React, { useState, useRef, useCallback, useEffect } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { MapNode } from './MapNode';
|
import { MapNode } from './MapNode';
|
||||||
import { Connection } from './Connection';
|
import { Connection } from './Connection';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ArrowLeft } from 'lucide-react';
|
import { ArrowLeft } from 'lucide-react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { getSecurityColor } from '../utils/securityColors';
|
||||||
|
|
||||||
interface System {
|
interface SolarSystem {
|
||||||
solarSystemName: string;
|
solarSystemName: string;
|
||||||
x: string;
|
x: string;
|
||||||
y: string;
|
y: string;
|
||||||
@@ -20,21 +21,15 @@ interface Position {
|
|||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RegionMapProps {
|
const fetchRegionData = async (regionName: string): Promise<SolarSystem[]> => {
|
||||||
regionName: string;
|
const response = await fetch(`/${regionName}.json`);
|
||||||
}
|
|
||||||
|
|
||||||
const fetchRegionData = async (regionName: string): Promise<System[]> => {
|
|
||||||
// Decode the region name to handle spaces and special characters
|
|
||||||
const decodedRegionName = decodeURIComponent(regionName);
|
|
||||||
const response = await fetch(`/${decodedRegionName}.json`);
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to fetch ${decodedRegionName} data`);
|
throw new Error('Failed to fetch region data');
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [viewBox, setViewBox] = useState({ x: 0, y: 0, width: 1200, height: 800 });
|
const [viewBox, setViewBox] = useState({ x: 0, y: 0, width: 1200, height: 800 });
|
||||||
const [isPanning, setIsPanning] = useState(false);
|
const [isPanning, setIsPanning] = useState(false);
|
||||||
@@ -42,8 +37,6 @@ export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
|||||||
const [nodePositions, setNodePositions] = useState<Record<string, Position>>({});
|
const [nodePositions, setNodePositions] = useState<Record<string, Position>>({});
|
||||||
const svgRef = useRef<SVGSVGElement>(null);
|
const svgRef = useRef<SVGSVGElement>(null);
|
||||||
|
|
||||||
const decodedRegionName = decodeURIComponent(regionName);
|
|
||||||
|
|
||||||
const { data: systems, isLoading, error } = useQuery({
|
const { data: systems, isLoading, error } = useQuery({
|
||||||
queryKey: ['region', regionName],
|
queryKey: ['region', regionName],
|
||||||
queryFn: () => fetchRegionData(regionName),
|
queryFn: () => fetchRegionData(regionName),
|
||||||
@@ -64,13 +57,8 @@ export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
|||||||
}, [systems]);
|
}, [systems]);
|
||||||
|
|
||||||
const handleSystemClick = (systemName: string) => {
|
const handleSystemClick = (systemName: string) => {
|
||||||
const encodedSystem = encodeURIComponent(systemName);
|
console.log(`Clicked system: ${systemName}`);
|
||||||
navigate(`/systems/${encodedSystem}`);
|
// Future: Navigate to system details
|
||||||
};
|
|
||||||
|
|
||||||
const handleRegionClick = (regionName: string) => {
|
|
||||||
const encodedRegion = encodeURIComponent(regionName);
|
|
||||||
navigate(`/regions/${encodedRegion}`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||||
@@ -116,6 +104,7 @@ export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
|||||||
const mouseX = e.clientX - rect.left;
|
const mouseX = e.clientX - rect.left;
|
||||||
const mouseY = e.clientY - rect.top;
|
const mouseY = e.clientY - rect.top;
|
||||||
|
|
||||||
|
// Reverse scroll direction: positive deltaY zooms out, negative zooms in
|
||||||
const scale = e.deltaY > 0 ? 1.1 : 0.9;
|
const scale = e.deltaY > 0 ? 1.1 : 0.9;
|
||||||
const newWidth = viewBox.width * scale;
|
const newWidth = viewBox.width * scale;
|
||||||
const newHeight = viewBox.height * scale;
|
const newHeight = viewBox.height * scale;
|
||||||
@@ -124,7 +113,7 @@ export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
|||||||
const mouseYInSVG = viewBox.y + (mouseY / rect.height) * viewBox.height;
|
const mouseYInSVG = viewBox.y + (mouseY / rect.height) * viewBox.height;
|
||||||
|
|
||||||
const newX = mouseXInSVG - (mouseX / rect.width) * newWidth;
|
const newX = mouseXInSVG - (mouseX / rect.width) * newWidth;
|
||||||
const newY = mouseYInSVG - (mouseY / rect.height) * newHeight;
|
const newY = mouseYInSVG - (mouseY / rect.height) * newWidth;
|
||||||
|
|
||||||
setViewBox({
|
setViewBox({
|
||||||
x: newX,
|
x: newX,
|
||||||
@@ -134,58 +123,52 @@ export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
|||||||
});
|
});
|
||||||
}, [viewBox]);
|
}, [viewBox]);
|
||||||
|
|
||||||
// Get system names that exist in current region
|
|
||||||
const systemNamesInRegion = new Set(systems?.map(s => s.solarSystemName) || []);
|
|
||||||
|
|
||||||
// Find cross-region connections and extract region names
|
|
||||||
const crossRegionConnections = new Set<string>();
|
|
||||||
systems?.forEach(system => {
|
|
||||||
system.connectedSystems?.forEach(connectedSystem => {
|
|
||||||
if (!systemNamesInRegion.has(connectedSystem)) {
|
|
||||||
// This is a cross-region connection - we'll need to determine the region
|
|
||||||
// For now, we'll just store the system name and handle it in rendering
|
|
||||||
crossRegionConnections.add(connectedSystem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-screen bg-gradient-to-br from-slate-900 via-cyan-900 to-slate-900 flex items-center justify-center">
|
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 flex items-center justify-center">
|
||||||
<div className="text-white text-xl">Loading {decodedRegionName} data...</div>
|
<div className="text-white text-xl">Loading {regionName} data...</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-screen bg-gradient-to-br from-slate-900 via-cyan-900 to-slate-900 flex items-center justify-center">
|
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 flex items-center justify-center">
|
||||||
<div className="text-red-400 text-xl">Error loading {decodedRegionName} data</div>
|
<div className="text-center">
|
||||||
|
<h1 className="text-4xl font-bold text-white mb-4">Error Loading Region</h1>
|
||||||
|
<p className="text-red-400 mb-6">Failed to load data for {regionName}</p>
|
||||||
|
<Button
|
||||||
|
onClick={() => navigate('/')}
|
||||||
|
className="bg-purple-600 hover:bg-purple-700"
|
||||||
|
>
|
||||||
|
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||||
|
Return to Galaxy Map
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-screen bg-gradient-to-br from-slate-900 via-cyan-900 to-slate-900 overflow-hidden relative">
|
<div className="w-full h-screen bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 overflow-hidden relative">
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-cyan-900/20 via-slate-900/40 to-black"></div>
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-purple-900/20 via-slate-900/40 to-black"></div>
|
||||||
|
|
||||||
<div className="relative z-10 p-8">
|
<div className="relative z-10 p-8">
|
||||||
<div className="flex items-center gap-4 mb-6">
|
<div className="flex items-center justify-between mb-8">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-4xl font-bold text-white mb-2">{regionName}</h1>
|
||||||
|
<p className="text-purple-200">Solar systems in this region</p>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
|
||||||
onClick={() => navigate('/')}
|
onClick={() => navigate('/')}
|
||||||
className="bg-black/20 border-cyan-500/30 text-cyan-200 hover:bg-cyan-500/20"
|
className="bg-purple-600 hover:bg-purple-700"
|
||||||
>
|
>
|
||||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||||
Back to Galaxy
|
Back to Galaxy
|
||||||
</Button>
|
</Button>
|
||||||
<div>
|
|
||||||
<h1 className="text-4xl font-bold text-white">{decodedRegionName} Region</h1>
|
|
||||||
<p className="text-cyan-200">Explore the systems within this region</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full h-[calc(100vh-200px)] border border-cyan-500/30 rounded-lg overflow-hidden bg-black/20 backdrop-blur-sm">
|
<div className="w-full h-[calc(100vh-200px)] border border-purple-500/30 rounded-lg overflow-hidden bg-black/20 backdrop-blur-sm">
|
||||||
<svg
|
<svg
|
||||||
ref={svgRef}
|
ref={svgRef}
|
||||||
width="100%"
|
width="100%"
|
||||||
@@ -212,15 +195,23 @@ export const RegionMap: React.FC<RegionMapProps> = ({ regionName }) => {
|
|||||||
{systems?.map((system) =>
|
{systems?.map((system) =>
|
||||||
system.connectedSystems?.map((connectedSystem) => {
|
system.connectedSystems?.map((connectedSystem) => {
|
||||||
const fromPos = nodePositions[system.solarSystemName];
|
const fromPos = nodePositions[system.solarSystemName];
|
||||||
// Only render connection if target system is in current region
|
|
||||||
const toPos = nodePositions[connectedSystem];
|
const toPos = nodePositions[connectedSystem];
|
||||||
|
|
||||||
|
// If connected system is not in current region, skip the connection
|
||||||
if (!fromPos || !toPos) return null;
|
if (!fromPos || !toPos) return null;
|
||||||
|
|
||||||
|
// Get colors for both systems
|
||||||
|
const fromColor = getSecurityColor(system.security);
|
||||||
|
const toSystem = systems.find(s => s.solarSystemName === connectedSystem);
|
||||||
|
const toColor = toSystem ? getSecurityColor(toSystem.security) : fromColor;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Connection
|
<Connection
|
||||||
key={`${system.solarSystemName}-${connectedSystem}`}
|
key={`${system.solarSystemName}-${connectedSystem}`}
|
||||||
from={fromPos}
|
from={fromPos}
|
||||||
to={toPos}
|
to={toPos}
|
||||||
|
fromColor={fromColor}
|
||||||
|
toColor={toColor}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user