130 lines
3.2 KiB
TypeScript
130 lines
3.2 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
// ISO 3166-1 alpha-2 country code to full country name mapping
|
|
const countryNames: Record<string, string> = {
|
|
'US': 'United States',
|
|
'GB': 'United Kingdom',
|
|
'CA': 'Canada',
|
|
'AU': 'Australia',
|
|
'NZ': 'New Zealand',
|
|
'DE': 'Germany',
|
|
'FR': 'France',
|
|
'IT': 'Italy',
|
|
'ES': 'Spain',
|
|
'NL': 'Netherlands',
|
|
'BE': 'Belgium',
|
|
'SE': 'Sweden',
|
|
'NO': 'Norway',
|
|
'DK': 'Denmark',
|
|
'FI': 'Finland',
|
|
'PL': 'Poland',
|
|
'CZ': 'Czech Republic',
|
|
'AT': 'Austria',
|
|
'CH': 'Switzerland',
|
|
'PT': 'Portugal',
|
|
'IE': 'Ireland',
|
|
'BR': 'Brazil',
|
|
'MX': 'Mexico',
|
|
'AR': 'Argentina',
|
|
'JP': 'Japan',
|
|
'CN': 'China',
|
|
'KR': 'South Korea',
|
|
'IN': 'India',
|
|
'SG': 'Singapore',
|
|
'TH': 'Thailand',
|
|
'MY': 'Malaysia',
|
|
'ID': 'Indonesia',
|
|
'PH': 'Philippines',
|
|
'ZA': 'South Africa',
|
|
'RU': 'Russia',
|
|
'MC': 'Monaco',
|
|
'TR': 'Turkey',
|
|
'GR': 'Greece',
|
|
'HU': 'Hungary',
|
|
'RO': 'Romania',
|
|
'BG': 'Bulgaria',
|
|
'HR': 'Croatia',
|
|
'SI': 'Slovenia',
|
|
'SK': 'Slovakia',
|
|
'LT': 'Lithuania',
|
|
'LV': 'Latvia',
|
|
'EE': 'Estonia',
|
|
};
|
|
|
|
// ISO 3166-1 alpha-2 country code to flag emoji conversion
|
|
const countryCodeToFlag = (countryCode: string): string => {
|
|
if (!countryCode || countryCode.length !== 2) return '🏁';
|
|
|
|
// Convert ISO 3166-1 alpha-2 to regional indicator symbols
|
|
const codePoints = countryCode
|
|
.toUpperCase()
|
|
.split('')
|
|
.map(char => 127397 + char.charCodeAt(0));
|
|
return String.fromCodePoint(...codePoints);
|
|
};
|
|
|
|
interface CountryFlagProps {
|
|
/**
|
|
* ISO 3166-1 alpha-2 country code (e.g., 'US', 'GB', 'DE')
|
|
*/
|
|
countryCode: string;
|
|
/**
|
|
* Size of the flag emoji
|
|
* @default 'md'
|
|
*/
|
|
size?: 'sm' | 'md' | 'lg';
|
|
/**
|
|
* Additional CSS classes
|
|
*/
|
|
className?: string;
|
|
/**
|
|
* Whether to show tooltip with country name
|
|
* @default true
|
|
*/
|
|
showTooltip?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Reusable component for displaying country flags with tooltips
|
|
*
|
|
* @example
|
|
* <CountryFlag countryCode="US" />
|
|
* <CountryFlag countryCode="GB" size="lg" />
|
|
* <CountryFlag countryCode="DE" showTooltip={false} />
|
|
*/
|
|
export default function CountryFlag({
|
|
countryCode,
|
|
size = 'md',
|
|
className = '',
|
|
showTooltip = true
|
|
}: CountryFlagProps) {
|
|
const [showTooltipState, setShowTooltipState] = useState(false);
|
|
|
|
const sizeClasses = {
|
|
sm: 'text-xs',
|
|
md: 'text-sm',
|
|
lg: 'text-base'
|
|
};
|
|
|
|
const flag = countryCodeToFlag(countryCode);
|
|
const countryName = countryNames[countryCode.toUpperCase()] || countryCode;
|
|
|
|
return (
|
|
<span
|
|
className={`inline-flex items-center relative ${sizeClasses[size]} ${className}`}
|
|
onMouseEnter={() => setShowTooltipState(true)}
|
|
onMouseLeave={() => setShowTooltipState(false)}
|
|
title={showTooltip ? countryName : undefined}
|
|
>
|
|
<span className="select-none">{flag}</span>
|
|
{showTooltip && showTooltipState && (
|
|
<span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs font-medium text-white bg-deep-graphite border border-charcoal-outline rounded shadow-lg whitespace-nowrap z-50">
|
|
{countryName}
|
|
<span className="absolute top-full left-1/2 -translate-x-1/2 -mt-px border-4 border-transparent border-t-charcoal-outline"></span>
|
|
</span>
|
|
)}
|
|
</span>
|
|
);
|
|
} |