All files / web/src/arcade-games/know-your-world/features/magnifier MagnifierRegions.tsx

0% Statements 0/159
0% Branches 0/1
0% Functions 0/1
0% Lines 0/159

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160                                                                                                                                                                                                                                                                                                                               
/**
 * Magnifier Regions Component
 *
 * Renders all map regions inside the magnified SVG view.
 * Handles region coloring, celebration/give-up animations,
 * and player attribution for found regions.
 */

'use client'

import { memo } from 'react'
import type { MapRegion } from '../../types'

// ============================================================================
// Types
// ============================================================================

// Re-export MapRegion for convenience
export type { MapRegion }

export interface RegionState {
  /** IDs of regions that have been found */
  regionsFound: string[]
  /** Currently hovered region ID */
  hoveredRegion: string | null
  /** Region currently celebrating (just found) */
  celebrationRegionId: string | null
  /** Region being revealed in give-up animation */
  giveUpRegionId: string | null
  /** Whether give-up animation is playing */
  isGiveUpAnimating: boolean
}

export interface FlashProgress {
  /** Celebration flash animation progress (0-1) */
  celebrationFlash: number
  /** Give-up flash animation progress (0-1) */
  giveUpFlash: number
}

export interface MagnifierRegionsProps {
  /** All regions to render */
  regions: MapRegion[]
  /** Current region state */
  regionState: RegionState
  /** Animation progress for flashing effects */
  flashProgress: FlashProgress
  /** Whether dark mode is active */
  isDark: boolean
  /** Get player ID who found a region */
  getPlayerWhoFoundRegion: (regionId: string) => string | null
  /** Get region fill color */
  getRegionColor: (
    regionId: string,
    isFound: boolean,
    isHovered: boolean,
    isDark: boolean
  ) => string
  /** Get region stroke color */
  getRegionStroke: (isFound: boolean, isDark: boolean) => string
  /** Whether to show region outline */
  showOutline: (region: MapRegion) => boolean
}

// ============================================================================
// Component
// ============================================================================

/**
 * Renders regions inside the magnifier's SVG view.
 *
 * Features:
 * - Celebration glow effect for just-found regions
 * - Give-up reveal animation with pulsing
 * - Player pattern fill for found regions
 * - Dimming of non-revealed regions during give-up
 */
export const MagnifierRegions = memo(function MagnifierRegions({
  regions,
  regionState,
  flashProgress,
  isDark,
  getPlayerWhoFoundRegion,
  getRegionColor,
  getRegionStroke,
  showOutline,
}: MagnifierRegionsProps) {
  const { regionsFound, hoveredRegion, celebrationRegionId, giveUpRegionId, isGiveUpAnimating } =
    regionState
  const { celebrationFlash, giveUpFlash } = flashProgress

  return (
    <>
      {regions.map((region) => {
        const isFound = regionsFound.includes(region.id)
        const playerId = isFound ? getPlayerWhoFoundRegion(region.id) : null
        const isBeingRevealed = giveUpRegionId === region.id
        const isCelebrating = celebrationRegionId === region.id

        // Bright gold flash for celebration and give up reveal
        const fill = isCelebrating
          ? `rgba(255, 215, 0, ${0.7 + celebrationFlash * 0.3})`
          : isBeingRevealed
            ? `rgba(255, 200, 0, ${0.6 + giveUpFlash * 0.4})`
            : isFound && playerId
              ? `url(#player-pattern-${playerId})`
              : getRegionColor(region.id, isFound, hoveredRegion === region.id, isDark)

        // During give-up animation, dim all non-revealed regions
        const dimmedOpacity = isGiveUpAnimating && !isBeingRevealed ? 0.25 : 1

        // Revealed/celebrating region gets a prominent stroke
        // Unfound regions get thicker borders for better visibility against sea
        const stroke = isCelebrating
          ? `rgba(255, 180, 0, ${0.8 + celebrationFlash * 0.2})`
          : isBeingRevealed
            ? `rgba(255, 140, 0, ${0.8 + giveUpFlash * 0.2})`
            : getRegionStroke(isFound, isDark)
        const strokeWidth = isCelebrating ? 3 : isBeingRevealed ? 2 : isFound ? 0.5 : 1

        return (
          <g key={`mag-${region.id}`} style={{ opacity: dimmedOpacity }}>
            {/* Glow effect for revealed region */}
            {isBeingRevealed && (
              <path
                d={region.path}
                fill="none"
                stroke={`rgba(255, 215, 0, ${0.3 + giveUpFlash * 0.5})`}
                strokeWidth={5}
                vectorEffect="non-scaling-stroke"
                style={{ filter: 'blur(2px)' }}
              />
            )}
            {/* Glow effect for celebrating region */}
            {isCelebrating && (
              <path
                d={region.path}
                fill={`rgba(255, 215, 0, ${0.2 + celebrationFlash * 0.4})`}
                stroke={`rgba(255, 215, 0, ${0.4 + celebrationFlash * 0.6})`}
                strokeWidth={8}
                vectorEffect="non-scaling-stroke"
                style={{ filter: 'blur(4px)' }}
              />
            )}
            {/* Main region path */}
            <path
              d={region.path}
              fill={fill}
              stroke={stroke}
              strokeWidth={strokeWidth}
              vectorEffect="non-scaling-stroke"
              opacity={showOutline(region) ? 1 : 0.3}
            />
          </g>
        )
      })}
    </>
  )
})