o2o-infinith-frontend/src/shared/ui/platform-icon.tsx

126 lines
3.3 KiB
TypeScript

/**
* PlatformIcon — 플랫폼 식별자 (string variant) 로 lucide line icon 을 반환.
*
* 입력은 'youtube', 'YouTube', 'naver-blog', '네이버 블로그' 같이 다양한 형태가
* 들어올 수 있어 normalize 후 부분 일치까지 시도합니다. 매칭 실패 시 Globe.
*/
import {
Globe,
Instagram,
Youtube,
Facebook,
Music,
FileText,
Heart,
MapPin,
Search,
type LucideIcon,
} from 'lucide-react';
export type PlatformVariant =
| 'website'
| 'instagram'
| 'youtube'
| 'facebook'
| 'tiktok'
| 'naverPlace'
| 'naverBlog'
| 'naver'
| 'gangnamUnni'
| 'blog';
export const PLATFORM_ICONS: Record<PlatformVariant, LucideIcon> = {
website: Globe,
instagram: Instagram,
youtube: Youtube,
facebook: Facebook,
tiktok: Music,
naverPlace: MapPin,
naverBlog: FileText,
naver: Search,
gangnamUnni: Heart,
blog: FileText,
};
export const PLATFORM_COLORS: Record<PlatformVariant, string> = {
website: '#6C5CE7',
instagram: '#833AB4',
youtube: '#FF3D3D',
facebook: '#1877F2',
tiktok: '#0A1128',
naverPlace: '#03C75A',
naverBlog: '#03C75A',
naver: '#03C75A',
gangnamUnni: '#FF6B8A',
blog: '#03C75A',
};
/** 별칭 → canonical key. lowercase / 한글 / 공백·하이픈 변형을 흡수. */
const ALIAS: Record<string, PlatformVariant> = {
website: 'website',
homepage: 'website',
web: 'website',
site: 'website',
: 'website',
instagram: 'instagram',
ig: 'instagram',
: 'instagram',
: 'instagram',
youtube: 'youtube',
yt: 'youtube',
: 'youtube',
facebook: 'facebook',
fb: 'facebook',
: 'facebook',
tiktok: 'tiktok',
: 'tiktok',
naverplace: 'naverPlace',
: 'naverPlace',
: 'naverPlace',
place: 'naverPlace',
naverblog: 'naverBlog',
: 'naverBlog',
naver: 'naver',
: 'naver',
blog: 'blog',
: 'blog',
gangnamunni: 'gangnamUnni',
: 'gangnamUnni',
};
/** 자유 문자열 → PlatformVariant. 못 찾으면 undefined. */
export function resolvePlatformVariant(raw: string | null | undefined): PlatformVariant | undefined {
if (!raw) return undefined;
const norm = raw.toLowerCase().replace(/[\s\-_]+/g, '');
if (norm in ALIAS) return ALIAS[norm];
// 부분 일치 (예: "naver blog" → "naverblog" → naverBlog)
for (const key of Object.keys(ALIAS)) {
if (norm.includes(key)) return ALIAS[key];
}
return undefined;
}
interface PlatformIconProps {
/** 플랫폼 식별 문자열. 'youtube' / 'Instagram' / '네이버 블로그' 등 자유 형식 */
variant: string | null | undefined;
size?: number;
className?: string;
/** 색상을 자동으로 플랫폼 컬러로 채울지 (false 면 현재 텍스트 색 상속) */
colored?: boolean;
/** 매칭 실패 시 사용할 fallback icon. 기본 Globe. */
fallback?: LucideIcon;
}
export function PlatformIcon({
variant,
size = 16,
className,
colored = false,
fallback = Globe,
}: PlatformIconProps) {
const key = resolvePlatformVariant(variant);
const Icon = key ? PLATFORM_ICONS[key] : fallback;
const color = colored && key ? PLATFORM_COLORS[key] : undefined;
return <Icon size={size} className={className} style={color ? { color } : undefined} />;
}