diff --git a/src/components/Connection.tsx b/src/components/Connection.tsx index a194023..f6a009e 100644 --- a/src/components/Connection.tsx +++ b/src/components/Connection.tsx @@ -4,18 +4,30 @@ import React from 'react'; interface ConnectionProps { from: { x: number; y: number }; to: { x: number; y: number }; + fromColor?: string; + toColor?: string; } -export const Connection: React.FC = ({ from, to }) => { +export const Connection: React.FC = ({ from, to, fromColor = '#a855f7', toColor = '#a855f7' }) => { + // Create gradient ID based on colors to ensure uniqueness + const gradientId = `gradient-${fromColor.replace('#', '')}-${toColor.replace('#', '')}`; + return ( + + + + + + + {/* Glow effect */} = ({ from, to }) => { y1={from.y} x2={to.x} y2={to.y} - stroke="#a855f7" + stroke={`url(#${gradientId})`} strokeWidth="1" opacity="0.7" className="transition-all duration-300" diff --git a/src/components/GalaxyMap.tsx b/src/components/GalaxyMap.tsx index 02b9e57..362a9e9 100644 --- a/src/components/GalaxyMap.tsx +++ b/src/components/GalaxyMap.tsx @@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'; import { MapNode } from './MapNode'; import { Connection } from './Connection'; import { useQuery } from '@tanstack/react-query'; +import { getSecurityColor } from '../utils/securityColors'; interface Region { regionName: string; @@ -102,6 +103,7 @@ export const GalaxyMap = () => { const mouseX = e.clientX - rect.left; 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 newWidth = viewBox.width * scale; const newHeight = viewBox.height * scale; @@ -174,11 +176,18 @@ export const GalaxyMap = () => { const toPos = nodePositions[connectedRegion]; 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 ( ); }) diff --git a/src/components/MapNode.tsx b/src/components/MapNode.tsx index 714f927..66f44b5 100644 --- a/src/components/MapNode.tsx +++ b/src/components/MapNode.tsx @@ -27,9 +27,9 @@ export const MapNode: React.FC = ({ : '#a855f7'; // fallback purple color if (type === 'region') { - // Render region as a pill/rounded rectangle - const pillWidth = Math.max(name.length * 12, 80); - const pillHeight = 32; + // Reduce region size to prevent overlap + const pillWidth = Math.max(name.length * 8, 60); // Reduced from 12 to 8, min from 80 to 60 + const pillHeight = 24; // Reduced from 32 to 24 return ( = ({ > {/* Glow effect */} = ({ rx={pillHeight / 2} fill={nodeColor} stroke="#ffffff" - strokeWidth="2" + strokeWidth="1.5" filter="url(#glow)" className={`transition-all duration-300 ${ isHovered ? 'drop-shadow-lg' : '' @@ -74,10 +74,10 @@ export const MapNode: React.FC = ({ {/* Text inside pill */} = ({ ); } else { // Render system as a dot with external label - const nodeSize = 8; - const textOffset = 20; // Increased from 15 to move text further down + const nodeSize = 6; + const textOffset = 18; // Position text below the dot return ( = ({ > {/* Node glow effect */} - {/* Main node */} + {/* Main node - removed stroke to eliminate white border */} = ({ {/* Inner core */} = ({ y={textOffset} textAnchor="middle" fill="#ffffff" - fontSize="12" + fontSize="10" fontWeight="bold" className={`transition-all duration-300 ${ isHovered ? 'fill-purple-200' : 'fill-white' diff --git a/src/components/RegionMap.tsx b/src/components/RegionMap.tsx index 44a0dc0..5399b94 100644 --- a/src/components/RegionMap.tsx +++ b/src/components/RegionMap.tsx @@ -1,13 +1,14 @@ 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 { Connection } from './Connection'; import { Button } from '@/components/ui/button'; import { ArrowLeft } from 'lucide-react'; import { useQuery } from '@tanstack/react-query'; +import { getSecurityColor } from '../utils/securityColors'; -interface System { +interface SolarSystem { solarSystemName: string; x: string; y: string; @@ -20,21 +21,15 @@ interface Position { y: number; } -interface RegionMapProps { - regionName: string; -} - -const fetchRegionData = async (regionName: string): Promise => { - // Decode the region name to handle spaces and special characters - const decodedRegionName = decodeURIComponent(regionName); - const response = await fetch(`/${decodedRegionName}.json`); +const fetchRegionData = async (regionName: string): Promise => { + const response = await fetch(`/${regionName}.json`); if (!response.ok) { - throw new Error(`Failed to fetch ${decodedRegionName} data`); + throw new Error('Failed to fetch region data'); } return response.json(); }; -export const RegionMap: React.FC = ({ regionName }) => { +export const RegionMap: React.FC<{ regionName: string }> = ({ regionName }) => { const navigate = useNavigate(); const [viewBox, setViewBox] = useState({ x: 0, y: 0, width: 1200, height: 800 }); const [isPanning, setIsPanning] = useState(false); @@ -42,8 +37,6 @@ export const RegionMap: React.FC = ({ regionName }) => { const [nodePositions, setNodePositions] = useState>({}); const svgRef = useRef(null); - const decodedRegionName = decodeURIComponent(regionName); - const { data: systems, isLoading, error } = useQuery({ queryKey: ['region', regionName], queryFn: () => fetchRegionData(regionName), @@ -64,13 +57,8 @@ export const RegionMap: React.FC = ({ regionName }) => { }, [systems]); const handleSystemClick = (systemName: string) => { - const encodedSystem = encodeURIComponent(systemName); - navigate(`/systems/${encodedSystem}`); - }; - - const handleRegionClick = (regionName: string) => { - const encodedRegion = encodeURIComponent(regionName); - navigate(`/regions/${encodedRegion}`); + console.log(`Clicked system: ${systemName}`); + // Future: Navigate to system details }; const handleMouseDown = useCallback((e: React.MouseEvent) => { @@ -116,6 +104,7 @@ export const RegionMap: React.FC = ({ regionName }) => { const mouseX = e.clientX - rect.left; 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 newWidth = viewBox.width * scale; const newHeight = viewBox.height * scale; @@ -124,7 +113,7 @@ export const RegionMap: React.FC = ({ regionName }) => { const mouseYInSVG = viewBox.y + (mouseY / rect.height) * viewBox.height; const newX = mouseXInSVG - (mouseX / rect.width) * newWidth; - const newY = mouseYInSVG - (mouseY / rect.height) * newHeight; + const newY = mouseYInSVG - (mouseY / rect.height) * newWidth; setViewBox({ x: newX, @@ -134,58 +123,52 @@ export const RegionMap: React.FC = ({ regionName }) => { }); }, [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(); - 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) { return ( -
-
Loading {decodedRegionName} data...
+
+
Loading {regionName} data...
); } if (error) { return ( -
-
Error loading {decodedRegionName} data
+
+
+

Error Loading Region

+

Failed to load data for {regionName}

+ +
); } return ( -
-
+
+
-
+
+
+

{regionName}

+

Solar systems in this region

+
-
-

{decodedRegionName} Region

-

Explore the systems within this region

-
-
+
= ({ regionName }) => { {systems?.map((system) => system.connectedSystems?.map((connectedSystem) => { const fromPos = nodePositions[system.solarSystemName]; - // Only render connection if target system is in current region const toPos = nodePositions[connectedSystem]; + + // If connected system is not in current region, skip the connection 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 ( ); })