feat: add per-country coloring and individual region clicks to continent selector

Enhance the continent selector with colorful individual regions:

Per-Country Coloring:
- Each country/region now has its own distinct color using the game's color algorithm
- Same 8-color deterministic palette as the main game
- Unselected continents shown at 20% opacity for subtle visibility
- Selected continent regions shown at full color intensity
- Hovered regions get enhanced borders and highlighting

Individual Region Interaction:
- Click any individual country to select its continent
- Hover over any country highlights that specific region
- Smooth transitions between states (0.15s)
- Thicker stroke on hover (1.5px) for clear feedback
- Visual feedback shows exactly which country you're pointing at

Benefits:
- Much more visually appealing and educational
- Users can see individual countries within each continent
- Clearer geographic boundaries and relationships
- More engaging interaction model
- Same visual language as the main game map

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-18 15:58:39 -06:00
parent 07e92240e8
commit 2e9f409f26
1 changed files with 44 additions and 28 deletions

View File

@ -5,6 +5,7 @@ import { css } from '@styled/css'
import { useTheme } from '@/contexts/ThemeContext'
import { WORLD_MAP } from '../maps'
import { getContinentForCountry, CONTINENTS, type ContinentId } from '../continents'
import { getRegionColor } from '../mapColors'
interface ContinentSelectorProps {
selectedContinent: ContinentId | 'all'
@ -18,6 +19,7 @@ export function ContinentSelector({
const { resolvedTheme } = useTheme()
const isDark = resolvedTheme === 'dark'
const [hoveredContinent, setHoveredContinent] = useState<ContinentId | 'all' | null>(null)
const [hoveredRegion, setHoveredRegion] = useState<string | null>(null)
// Group regions by continent
const regionsByContinent = new Map<ContinentId | 'all', typeof WORLD_MAP.regions>()
@ -34,23 +36,29 @@ export function ContinentSelector({
}
})
// Get color for continent based on state
const getContinentColor = (continentId: ContinentId | 'all'): string => {
// Get color for a region based on its continent's state
const getRegionColorForSelector = (
regionId: string,
continentId: ContinentId | 'all'
): string => {
const isSelected = selectedContinent === continentId
const isHovered = hoveredContinent === continentId
const isHovered = hoveredContinent === continentId || hoveredRegion === regionId
if (isSelected) {
return isDark ? '#3b82f6' : '#2563eb' // Solid blue for selected
// Use the game's color algorithm, but adjust opacity based on selection state
const baseColor = getRegionColor(regionId, isSelected, isHovered, isDark)
// If this continent is not selected and not hovered, make it more transparent
if (!isSelected && !isHovered) {
// Extract the color and add low opacity
return baseColor.includes('#') ? `${baseColor}33` : baseColor // 20% opacity
}
if (isHovered) {
return isDark ? '#60a5fa66' : '#3b82f655' // Semi-transparent blue for hover
}
return isDark ? '#4b556333' : '#d1d5db44' // Very light for unselected
return baseColor
}
const getContinentStroke = (continentId: ContinentId | 'all'): string => {
const getRegionStroke = (continentId: ContinentId | 'all', regionId: string): string => {
const isSelected = selectedContinent === continentId
const isHovered = hoveredContinent === continentId
const isHovered = hoveredContinent === continentId || hoveredRegion === regionId
if (isSelected) {
return isDark ? '#60a5fa' : '#1d4ed8'
@ -61,6 +69,15 @@ export function ContinentSelector({
return isDark ? '#374151' : '#9ca3af'
}
const getRegionStrokeWidth = (continentId: ContinentId | 'all', regionId: string): number => {
const isSelected = selectedContinent === continentId
const isHovered = hoveredContinent === continentId || hoveredRegion === regionId
if (isHovered) return 1.5
if (isSelected) return 1
return 0.3
}
return (
<div data-component="continent-selector">
<div
@ -110,28 +127,27 @@ export function ContinentSelector({
if (regions.length === 0) return null
return (
<g
key={continent.id}
data-continent={continent.id}
onMouseEnter={() => setHoveredContinent(continent.id)}
onMouseLeave={() => setHoveredContinent(null)}
onClick={() => onSelectContinent(continent.id)}
style={{
cursor: 'pointer',
transition: 'all 0.2s ease',
}}
>
{/* All regions in this continent */}
<g key={continent.id} data-continent={continent.id}>
{/* All regions in this continent - each individually clickable */}
{regions.map((region) => (
<path
key={region.id}
d={region.path}
fill={getContinentColor(continent.id)}
stroke={getContinentStroke(continent.id)}
strokeWidth={selectedContinent === continent.id ? 1 : 0.5}
fill={getRegionColorForSelector(region.id, continent.id)}
stroke={getRegionStroke(continent.id, region.id)}
strokeWidth={getRegionStrokeWidth(continent.id, region.id)}
onMouseEnter={() => {
setHoveredContinent(continent.id)
setHoveredRegion(region.id)
}}
onMouseLeave={() => {
setHoveredContinent(null)
setHoveredRegion(null)
}}
onClick={() => onSelectContinent(continent.id)}
style={{
pointerEvents: 'none',
transition: 'all 0.2s ease',
cursor: 'pointer',
transition: 'all 0.15s ease',
}}
/>
))}