152 lines
4.3 KiB
TypeScript
152 lines
4.3 KiB
TypeScript
/**
|
|
* ChannelLinkButtons — 등록된 플랫폼 URL/핸들로 새 탭 열기 버튼 묶음.
|
|
*
|
|
* Report / Plan 헤더 영역에서 공통 사용.
|
|
* - 입력은 normalized handle(@view_clinic) 또는 URL(view.co.kr) 모두 허용
|
|
* - 비어있는 플랫폼은 자동 생략
|
|
* - 디자인: white/60 backdrop-blur + 호버 시 더 진해짐 (ReportHeader 의 메타 칩과 동일 톤)
|
|
*/
|
|
import { ExternalLink, Heart, MapPin, Globe, Instagram, Youtube, Facebook, Music, FileText, type LucideIcon } from 'lucide-react';
|
|
|
|
export interface ChannelHandles {
|
|
website?: string | null;
|
|
instagram?: string | null;
|
|
youtube?: string | null;
|
|
facebook?: string | null;
|
|
tiktok?: string | null;
|
|
gangnamUnni?: string | null;
|
|
naverPlace?: string | null;
|
|
naverBlog?: string | null;
|
|
}
|
|
|
|
type PlatformKey = keyof ChannelHandles;
|
|
|
|
interface PlatformMeta {
|
|
label: string;
|
|
color: string;
|
|
Icon: LucideIcon;
|
|
buildUrl: (handle: string) => string;
|
|
}
|
|
|
|
const META: Record<PlatformKey, PlatformMeta> = {
|
|
website: {
|
|
label: '홈페이지',
|
|
color: '#6C5CE7',
|
|
Icon: Globe,
|
|
buildUrl: (h) => (/^https?:\/\//.test(h) ? h : `https://${h}`),
|
|
},
|
|
instagram: {
|
|
label: 'Instagram',
|
|
color: '#833AB4',
|
|
Icon: Instagram,
|
|
buildUrl: (h) => `https://instagram.com/${h.replace(/^@/, '')}`,
|
|
},
|
|
youtube: {
|
|
label: 'YouTube',
|
|
color: '#FF3D3D',
|
|
Icon: Youtube,
|
|
buildUrl: (h) => `https://youtube.com/${h.startsWith('@') ? h : `@${h}`}`,
|
|
},
|
|
facebook: {
|
|
label: 'Facebook',
|
|
color: '#1877F2',
|
|
Icon: Facebook,
|
|
buildUrl: (h) => (/^https?:\/\//.test(h) ? h : `https://facebook.com/${h}`),
|
|
},
|
|
tiktok: {
|
|
label: 'TikTok',
|
|
color: '#0A1128',
|
|
Icon: Music,
|
|
buildUrl: (h) => `https://tiktok.com/${h.startsWith('@') ? h : `@${h}`}`,
|
|
},
|
|
gangnamUnni: {
|
|
label: '강남언니',
|
|
color: '#FF6B8A',
|
|
Icon: Heart,
|
|
buildUrl: (h) => {
|
|
if (/^https?:\/\//.test(h)) return h;
|
|
if (/gangnamunni\.com\//.test(h)) return `https://www.${h.replace(/^\/+/, '')}`;
|
|
return `https://www.gangnamunni.com/hospitals/${h.replace(/^\//, '')}`;
|
|
},
|
|
},
|
|
naverPlace: {
|
|
label: '네이버 플레이스',
|
|
color: '#03C75A',
|
|
Icon: MapPin,
|
|
buildUrl: (h) => {
|
|
if (/^https?:\/\//.test(h)) return h;
|
|
if (/place\.naver\.com\//.test(h)) return `https://m.${h.replace(/^m\./, '').replace(/^\/+/, '')}/home`;
|
|
return `https://m.place.naver.com/hospital/${h.replace(/^\//, '')}/home`;
|
|
},
|
|
},
|
|
naverBlog: {
|
|
label: '네이버 블로그',
|
|
color: '#03C75A',
|
|
Icon: FileText,
|
|
buildUrl: (h) => {
|
|
if (/^https?:\/\//.test(h)) return h;
|
|
if (/blog\.naver\.com\//.test(h)) return `https://${h.replace(/^\/+/, '')}`;
|
|
return `https://blog.naver.com/${h.replace(/^\//, '')}`;
|
|
},
|
|
},
|
|
};
|
|
|
|
const ORDER: PlatformKey[] = [
|
|
'website',
|
|
'youtube',
|
|
'instagram',
|
|
'facebook',
|
|
'naverPlace',
|
|
'naverBlog',
|
|
'gangnamUnni',
|
|
'tiktok',
|
|
];
|
|
|
|
interface ChannelLinkButtonsProps {
|
|
handles: ChannelHandles;
|
|
variant?: 'light' | 'solid';
|
|
className?: string;
|
|
}
|
|
|
|
export function ChannelLinkButtons({
|
|
handles,
|
|
variant = 'light',
|
|
className,
|
|
}: ChannelLinkButtonsProps) {
|
|
const entries = ORDER.flatMap((key) => {
|
|
const handle = handles[key];
|
|
if (!handle) return [];
|
|
return [{ key, handle }];
|
|
});
|
|
if (entries.length === 0) return null;
|
|
|
|
const baseClass =
|
|
variant === 'light'
|
|
? 'bg-white/60 backdrop-blur-sm border border-white/40 hover:bg-white/80 text-slate-700'
|
|
: 'bg-white border border-slate-200 hover:border-slate-300 hover:bg-slate-50 text-slate-700';
|
|
|
|
return (
|
|
<div className={`flex flex-wrap gap-2 ${className ?? ''}`}>
|
|
{entries.map(({ key, handle }) => {
|
|
const meta = META[key];
|
|
const Icon = meta.Icon;
|
|
const url = meta.buildUrl(handle);
|
|
return (
|
|
<a
|
|
key={key}
|
|
href={url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className={`inline-flex items-center gap-2 rounded-full px-3.5 py-2 text-xs font-medium transition-colors ${baseClass}`}
|
|
title={`${meta.label} — ${url}`}
|
|
>
|
|
<Icon size={16} className="shrink-0" style={{ color: meta.color }} />
|
|
<span className="truncate max-w-[140px]">{handle}</span>
|
|
<ExternalLink size={12} className="text-slate-400" />
|
|
</a>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|