import { Github, Mail, Globe, BookOpen, MessageSquare, Calendar, MapPin, Coffee, Terminal, ExternalLink, } from 'lucide-react' import { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { Badge, Button, Card } from '../../shared/components' import { createDefaultProfilePageData, loadProfilePageData } from './api' import type { IconKey, ProfilePageData } from './types' const ICON_MAP = { 'book-open': BookOpen, globe: Globe, 'message-square': MessageSquare, github: Github, mail: Mail, 'external-link': ExternalLink, } const CHANNEL_ICON_CLASS: Partial> = { 'book-open': 'text-[#1e80ff]', globe: 'text-[#0f766e]', 'message-square': 'text-[#16a34a]', github: 'text-[var(--color-text-primary)]', mail: 'text-[var(--color-accent)]', } export function ProfilePage() { const navigate = useNavigate() const [clickCount, setClickCount] = useState(0) const [pageData, setPageData] = useState(() => createDefaultProfilePageData()) useEffect(() => { let active = true const syncProfile = async () => { const data = await loadProfilePageData() if (!active) return setPageData(data) } void syncProfile() return () => { active = false } }, []) const handleAuthorClick = () => { const newCount = clickCount + 1 setClickCount(newCount) if (newCount >= 5) { navigate('/admin/keygen') setClickCount(0) } } const openExternal = (url: string) => { window.open(url, '_blank', 'noopener,noreferrer') } const authorInfo = pageData.author const projectInfo = pageData.project const metaItems = [ { label: authorInfo.location, icon: MapPin, }, { label: `加入于 ${authorInfo.joinDate}`, icon: Calendar, }, ].filter((item) => item.label.trim()) return (
{authorInfo.initial}

0 ? `再点 ${5 - clickCount} 次进入开发者模式` : ''} > {authorInfo.name}

{authorInfo.title}

{authorInfo.bio}

{metaItems.map(({ label, icon: Icon }) => ( {label} ))} {authorInfo.website ? ( ) : null}
{authorInfo.github ? ( ) : null}
{authorInfo.channels.map((channel) => { const Icon = getIcon(channel.icon) const iconClassName = CHANNEL_ICON_CLASS[channel.icon || 'globe'] || 'text-[var(--color-text-primary)]' const content = (

{channel.name}

{channel.description}

{channel.detail}

{channel.href ? : null}
) if (!channel.href) { return
{content}
} return ( {content} ) })}
} className="rounded-[24px]" padding="lg" >
{authorInfo.skills.map((skill) => ( {skill} ))}
} className="rounded-[24px]" padding="lg" >

{projectInfo.introBadge} {projectInfo.introText}

{projectInfo.techStack.map((item) => ( {item} ))}

{projectInfo.description}

{projectInfo.actions.map((action) => { const Icon = getIcon(action.icon) return ( ) })}
) } function getIcon(icon?: IconKey) { return ICON_MAP[icon || 'globe'] || Globe } function stripProtocol(value: string): string { return value.replace(/^https?:\/\//, '').replace(/\/$/, '') }