import type { AttackEntry, LeaderboardEntry } from "@/shared/api/types"; // Format troop count for human-readable display // 100 => "100", 12,493 => "12.4k", 980,455 => "980k" export function formatTroopCount(count: number): string { if (count < 1000) return count.toString(); if (count < 1000000) { const k = count / 1000; return k % 1 === 0 ? `${k}k` : `${k.toFixed(1)}k`; } const m = count / 1000000; return m % 1 === 0 ? `${m}M` : `${m.toFixed(1)}M`; } // Calculate the background width percentage based on troop count // Uses power scale (x^0.4): 100 troops = 5%, 1k = 7.9%, 10k = 15.3%, 100k = 33.7%, 1M = 80% function calculateBackgroundWidth(troops: number): number { const minTroops = 100; const maxTroops = 1000000; const minWidth = 5; const maxWidth = 80; // Clamp troops to range const clampedTroops = Math.max(minTroops, Math.min(maxTroops, troops)); // Power scale with exponent 0.4 provides gentler progression than logarithmic const powerMin = Math.pow(minTroops, 0.4); const powerMax = Math.pow(maxTroops, 0.4); const powerTroops = Math.pow(clampedTroops, 0.4); // Map to 5-80% range const normalized = (powerTroops - powerMin) / (powerMax - powerMin); return minWidth + normalized * (maxWidth - minWidth); } interface AttackRowProps { attack: AttackEntry; playerMap: Map; onNationHover?: (nationId: number | null) => void; } export function AttackRow({ attack, playerMap, onNationHover }: AttackRowProps) { // For outgoing attacks, show target's name (who we're attacking) // For incoming attacks, show attacker's name (who is attacking us) const displayPlayerId = attack.is_outgoing ? attack.target_id : attack.attacker_id; const displayPlayer = displayPlayerId !== null ? playerMap.get(displayPlayerId) : null; const displayName = displayPlayer?.name || "Unclaimed Territory"; const backgroundWidth = calculateBackgroundWidth(attack.troops); const backgroundColor = attack.is_outgoing ? "rgba(59, 130, 246, 0.3)" // Blue with 30% opacity : "rgba(239, 68, 68, 0.3)"; // Red with 30% opacity return ( ); }