refactor(about): enhance design and structure for socials, contact, and skills sections
- Reorganized contact and socials into dynamic configurations with expanded icons and link support. - Improved layout for skills and interests sections with responsive spacing and modernized card styles. - Added reusable `IconMap` for consistent icon handling across components. - Updated translations for better localization and scalability.
This commit is contained in:
@@ -112,11 +112,21 @@ export const translations = {
|
|||||||
contact: {
|
contact: {
|
||||||
title: 'Contact Me 📫',
|
title: 'Contact Me 📫',
|
||||||
warning: 'Since everyone\'s time is valuable, please add a note when contacting me, such as: collaboration, consultation, project requirements, etc. I may not reply to or might ignore messages without notes. Thank you for your cooperation!',
|
warning: 'Since everyone\'s time is valuable, please add a note when contacting me, such as: collaboration, consultation, project requirements, etc. I may not reply to or might ignore messages without notes. Thank you for your cooperation!',
|
||||||
methods: {
|
methods: [
|
||||||
email: 'Email: zhaoguiyang18@gmail.com',
|
{ label: 'Email', value: 'zhaoguiyang18@gmail.com', icon: 'mail', link: 'mailto:zhaoguiyang18@gmail.com' },
|
||||||
qq: 'QQ: 2770723534',
|
{ label: 'WeChat', value: 'JoyCodeing', icon: 'wechat' },
|
||||||
wechat: 'WeChat: JoyCodeing',
|
{ label: 'QQ', value: '2770723534', icon: 'qq' },
|
||||||
|
{ label: 'Telegram', value: '@joyzhao', icon: 'send', link: 'https://t.me/joyzhao' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
socials: {
|
||||||
|
title: 'Community & Media 🌐',
|
||||||
|
items: [
|
||||||
|
{ label: 'GitHub', value: 'github.com/zhaoguiyang', icon: 'github', link: 'https://github.com/zhaoguiyang' },
|
||||||
|
{ label: 'Twitter / X', value: '@joyzhao', icon: 'twitter', link: 'https://twitter.com/joyzhao' },
|
||||||
|
{ label: 'LinkedIn', value: 'linkedin.com/in/zhaoguiyang', icon: 'linkedin', link: 'https://linkedin.com/in/zhaoguiyang' },
|
||||||
|
{ label: 'Blog', value: 'zhaoguiyang.site', icon: 'globe', link: 'https://zhaoguiyang.site' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
home: {
|
home: {
|
||||||
@@ -289,11 +299,21 @@ export const translations = {
|
|||||||
contact: {
|
contact: {
|
||||||
title: '联系我 📫',
|
title: '联系我 📫',
|
||||||
warning: '由于大家的时间都很宝贵,所以请在联系我时添加备注,如:合作、咨询、项目需求等,不予备注的我可能不会回复或直接忽略,谢谢合作!',
|
warning: '由于大家的时间都很宝贵,所以请在联系我时添加备注,如:合作、咨询、项目需求等,不予备注的我可能不会回复或直接忽略,谢谢合作!',
|
||||||
methods: {
|
methods: [
|
||||||
email: '邮箱:zhaoguiyang18@gmail.com',
|
{ label: '邮箱', value: 'zhaoguiyang18@gmail.com', icon: 'mail', link: 'mailto:zhaoguiyang18@gmail.com' },
|
||||||
qq: 'QQ: 2770723534',
|
{ label: '微信', value: 'JoyCodeing', icon: 'wechat' },
|
||||||
wechat: '微信:JoyCodeing',
|
{ label: 'QQ', value: '2770723534', icon: 'qq' },
|
||||||
|
{ label: 'Telegram', value: '@joyzhao', icon: 'send', link: 'https://t.me/joyzhao' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
socials: {
|
||||||
|
title: '社区与媒体 🌐',
|
||||||
|
items: [
|
||||||
|
{ label: 'GitHub', value: 'github.com/zhaoguiyang', icon: 'github', link: 'https://github.com/zhaoguiyang' },
|
||||||
|
{ label: 'Twitter / X', value: '@joyzhao', icon: 'twitter', link: 'https://twitter.com/joyzhao' },
|
||||||
|
{ label: 'LinkedIn', value: 'linkedin.com/in/zhaoguiyang', icon: 'linkedin', link: 'https://linkedin.com/in/zhaoguiyang' },
|
||||||
|
{ label: 'Blog', value: 'zhaoguiyang.site', icon: 'globe', link: 'https://zhaoguiyang.site' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
home: {
|
home: {
|
||||||
|
|||||||
@@ -7,7 +7,29 @@ import HighlightBox from "@/components/markdown/HighlightBox.astro";
|
|||||||
import { useTranslations } from "@/i18n/utils";
|
import { useTranslations } from "@/i18n/utils";
|
||||||
import type { Lang } from "@/types/i18n";
|
import type { Lang } from "@/types/i18n";
|
||||||
import { defaultLang } from "@/i18n/ui";
|
import { defaultLang } from "@/i18n/ui";
|
||||||
import { Sparkles, Heart, Zap, Mail, MessageSquare } from "lucide-react";
|
import {
|
||||||
|
Sparkles,
|
||||||
|
Heart,
|
||||||
|
Zap,
|
||||||
|
Mail,
|
||||||
|
MessageSquare,
|
||||||
|
Send,
|
||||||
|
Github,
|
||||||
|
Twitter,
|
||||||
|
Linkedin,
|
||||||
|
Globe
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
const IconMap: Record<string, any> = {
|
||||||
|
mail: Mail,
|
||||||
|
wechat: MessageSquare,
|
||||||
|
qq: MessageSquare, // Lucide doesn't have QQ, using MessageSquare
|
||||||
|
send: Send,
|
||||||
|
github: Github,
|
||||||
|
twitter: Twitter,
|
||||||
|
linkedin: Linkedin,
|
||||||
|
globe: Globe,
|
||||||
|
};
|
||||||
|
|
||||||
const lang = (Astro.currentLocale as Lang) || defaultLang;
|
const lang = (Astro.currentLocale as Lang) || defaultLang;
|
||||||
const t = useTranslations(lang);
|
const t = useTranslations(lang);
|
||||||
@@ -83,14 +105,13 @@ const pageTitle = t("about.title");
|
|||||||
<Zap className="w-6 h-6 text-yellow-500" />
|
<Zap className="w-6 h-6 text-yellow-500" />
|
||||||
{t('about.skills.mastered.title')}
|
{t('about.skills.mastered.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<ul class="space-y-3">
|
<div class="flex flex-wrap gap-2">
|
||||||
{(t('about.skills.mastered.items') as unknown as string[]).map((item: string) => (
|
{(t('about.skills.mastered.items') as unknown as string[]).map((item: string) => (
|
||||||
<li class="flex items-start gap-3 text-muted-foreground">
|
<div class="px-3 py-1.5 rounded-lg bg-primary/5 border border-primary/10 text-muted-foreground text-xs font-medium">
|
||||||
<span class="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-primary"></span>
|
{item}
|
||||||
<span>{item}</span>
|
</div>
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
|
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
|
||||||
@@ -98,65 +119,95 @@ const pageTitle = t("about.title");
|
|||||||
<Heart className="w-6 h-6 text-red-500" />
|
<Heart className="w-6 h-6 text-red-500" />
|
||||||
{t('about.skills.learning.title')}
|
{t('about.skills.learning.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<ul class="space-y-3">
|
<div class="flex flex-wrap gap-2">
|
||||||
{(t('about.skills.learning.items') as unknown as string[]).map((item: string) => (
|
{(t('about.skills.learning.items') as unknown as string[]).map((item: string) => (
|
||||||
<li class="flex items-start gap-3 text-muted-foreground">
|
<div class="px-3 py-1.5 rounded-lg bg-muted/30 border border-border/50 text-muted-foreground/70 text-xs font-medium">
|
||||||
<span class="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/30"></span>
|
{item}
|
||||||
<span>{item}</span>
|
</div>
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Interests -->
|
<!-- Interests -->
|
||||||
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-8">
|
<div class="space-y-8">
|
||||||
<h2 class="text-2xl font-bold">
|
<h2 class="text-2xl font-bold flex items-center gap-3 px-2">
|
||||||
|
<Heart className="w-6 h-6 text-red-500" />
|
||||||
{t('about.interests.title')}
|
{t('about.interests.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="grid sm:grid-cols-2 gap-6">
|
<ul class="grid sm:grid-cols-2 gap-4">
|
||||||
{(t('about.interests.items') as unknown as any[]).map((item) => (
|
{(t('about.interests.items') as unknown as any[]).map((item) => (
|
||||||
<div class="p-4 rounded-xl bg-muted/30 border border-border/50 transition-colors hover:bg-muted/50">
|
<li class="flex items-start gap-4 p-4 rounded-xl border border-border/40 bg-card/20 hover:bg-card/40 transition-colors group">
|
||||||
<h3 class="font-bold mb-2">{item.title}</h3>
|
<div class="mt-1.5 w-1.5 h-1.5 rounded-full bg-primary/40 group-hover:bg-primary transition-colors shrink-0" />
|
||||||
|
<div class="space-y-1">
|
||||||
|
<span class="font-bold text-foreground">{item.title}</span>
|
||||||
<p class="text-sm text-muted-foreground leading-relaxed">{item.content}</p>
|
<p class="text-sm text-muted-foreground leading-relaxed">{item.content}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Socials & Community -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
<h2 class="text-2xl font-bold flex items-center gap-3 px-2">
|
||||||
|
<Globe className="w-6 h-6 text-primary" />
|
||||||
|
{t('about.socials.title')}
|
||||||
|
</h2>
|
||||||
|
<div class="flex flex-wrap gap-4 px-2">
|
||||||
|
{(t('about.socials.items') as unknown as any[]).map((item) => {
|
||||||
|
const Icon = IconMap[item.icon] || Globe;
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={item.link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="flex items-center gap-2 px-4 py-2 rounded-lg bg-muted/30 border border-border/50 hover:border-primary/50 hover:bg-primary/5 transition-all group text-sm font-medium"
|
||||||
|
>
|
||||||
|
<Icon className="w-4 h-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Contact -->
|
<!-- Contact -->
|
||||||
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-8 overflow-hidden relative">
|
<div class="space-y-8 py-8">
|
||||||
<div class="absolute top-0 right-0 p-8 opacity-5">
|
<div class="px-2 space-y-4">
|
||||||
<Mail className="w-32 h-32" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative z-10 space-y-6">
|
|
||||||
<h2 class="text-2xl font-bold flex items-center gap-3">
|
<h2 class="text-2xl font-bold flex items-center gap-3">
|
||||||
<MessageSquare className="w-6 h-6 text-primary" />
|
<Mail className="w-6 h-6 text-primary" />
|
||||||
{t('about.contact.title')}
|
{t('about.contact.title')}
|
||||||
</h2>
|
</h2>
|
||||||
|
<p class="text-muted-foreground leading-relaxed max-w-2xl">
|
||||||
<HighlightBox type="warning" title={lang === 'zh' ? '注意' : 'Notice'}>
|
|
||||||
{t('about.contact.warning')}
|
{t('about.contact.warning')}
|
||||||
</HighlightBox>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid sm:grid-cols-3 gap-4 mt-8">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div class="flex flex-col p-4 rounded-xl bg-muted/30 border border-border/50 items-center text-center gap-2">
|
{(t('about.contact.methods') as unknown as any[]).map((method) => {
|
||||||
<Mail className="w-5 h-5 text-primary" />
|
const Icon = IconMap[method.icon] || MessageSquare;
|
||||||
<span class="text-xs font-medium text-muted-foreground uppercase tracking-wider">Email</span>
|
const content = (
|
||||||
<span class="text-sm font-semibold break-all">{(t('about.contact.methods.email') as string).split(':')[1] || (t('about.contact.methods.email') as string).split(': ')[1]}</span>
|
<div class="flex items-center gap-4 p-4 rounded-xl border border-border/40 bg-card/20 hover:bg-card/40 transition-all group">
|
||||||
|
<div class="p-2.5 rounded-lg bg-primary/5 text-primary/70 group-hover:bg-primary/10 group-hover:text-primary transition-colors">
|
||||||
|
<Icon className="w-5 h-5" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col p-4 rounded-xl bg-muted/30 border border-border/50 items-center text-center gap-2">
|
<div class="flex flex-col">
|
||||||
<span class="font-bold text-primary">QQ</span>
|
<span class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{method.label}</span>
|
||||||
<span class="text-xs font-medium text-muted-foreground uppercase tracking-wider">QQ</span>
|
<span class="text-sm font-medium break-all">{method.value}</span>
|
||||||
<span class="text-sm font-semibold">{(t('about.contact.methods.qq') as string).split(':')[1] || (t('about.contact.methods.qq') as string).split(': ')[1]}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col p-4 rounded-xl bg-muted/30 border border-border/50 items-center text-center gap-2">
|
|
||||||
<MessageSquare className="w-5 h-5 text-primary" />
|
|
||||||
<span class="text-xs font-medium text-muted-foreground uppercase tracking-wider">WeChat</span>
|
|
||||||
<span class="text-sm font-semibold">{(t('about.contact.methods.wechat') as string).split(':')[1] || (t('about.contact.methods.wechat') as string).split(': ')[1]}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (method.link) {
|
||||||
|
return (
|
||||||
|
<a href={method.link} class="block transition-transform hover:-translate-y-0.5">
|
||||||
|
{content}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <div class="cursor-default">{content}</div>;
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,29 @@ import HighlightBox from "@/components/markdown/HighlightBox.astro";
|
|||||||
import { useTranslations } from "@/i18n/utils";
|
import { useTranslations } from "@/i18n/utils";
|
||||||
import type { Lang } from "@/types/i18n";
|
import type { Lang } from "@/types/i18n";
|
||||||
import { defaultLang } from "@/i18n/ui";
|
import { defaultLang } from "@/i18n/ui";
|
||||||
import { Sparkles, Heart, Zap, Mail, MessageSquare } from "lucide-react";
|
import {
|
||||||
|
Sparkles,
|
||||||
|
Heart,
|
||||||
|
Zap,
|
||||||
|
Mail,
|
||||||
|
MessageSquare,
|
||||||
|
Send,
|
||||||
|
Github,
|
||||||
|
Twitter,
|
||||||
|
Linkedin,
|
||||||
|
Globe
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
const IconMap: Record<string, any> = {
|
||||||
|
mail: Mail,
|
||||||
|
wechat: MessageSquare,
|
||||||
|
qq: MessageSquare, // Lucide doesn't have QQ, using MessageSquare
|
||||||
|
send: Send,
|
||||||
|
github: Github,
|
||||||
|
twitter: Twitter,
|
||||||
|
linkedin: Linkedin,
|
||||||
|
globe: Globe,
|
||||||
|
};
|
||||||
|
|
||||||
const lang = (Astro.currentLocale as Lang) || 'zh';
|
const lang = (Astro.currentLocale as Lang) || 'zh';
|
||||||
const t = useTranslations(lang);
|
const t = useTranslations(lang);
|
||||||
@@ -83,14 +105,13 @@ const pageTitle = t("about.title");
|
|||||||
<Zap className="w-6 h-6 text-yellow-500" />
|
<Zap className="w-6 h-6 text-yellow-500" />
|
||||||
{t('about.skills.mastered.title')}
|
{t('about.skills.mastered.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<ul class="space-y-3">
|
<div class="flex flex-wrap gap-2">
|
||||||
{(t('about.skills.mastered.items') as unknown as string[]).map((item: string) => (
|
{(t('about.skills.mastered.items') as unknown as string[]).map((item: string) => (
|
||||||
<li class="flex items-start gap-3 text-muted-foreground">
|
<div class="px-3 py-1.5 rounded-lg bg-primary/5 border border-primary/10 text-muted-foreground text-xs font-medium">
|
||||||
<span class="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-primary"></span>
|
{item}
|
||||||
<span>{item}</span>
|
</div>
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
|
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
|
||||||
@@ -98,65 +119,95 @@ const pageTitle = t("about.title");
|
|||||||
<Heart className="w-6 h-6 text-red-500" />
|
<Heart className="w-6 h-6 text-red-500" />
|
||||||
{t('about.skills.learning.title')}
|
{t('about.skills.learning.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<ul class="space-y-3">
|
<div class="flex flex-wrap gap-2">
|
||||||
{(t('about.skills.learning.items') as unknown as string[]).map((item: string) => (
|
{(t('about.skills.learning.items') as unknown as string[]).map((item: string) => (
|
||||||
<li class="flex items-start gap-3 text-muted-foreground">
|
<div class="px-3 py-1.5 rounded-lg bg-muted/30 border border-border/50 text-muted-foreground/70 text-xs font-medium">
|
||||||
<span class="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/30"></span>
|
{item}
|
||||||
<span>{item}</span>
|
</div>
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Interests -->
|
<!-- Interests -->
|
||||||
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-8">
|
<div class="space-y-8">
|
||||||
<h2 class="text-2xl font-bold">
|
<h2 class="text-2xl font-bold flex items-center gap-3 px-2">
|
||||||
|
<Heart className="w-6 h-6 text-red-500" />
|
||||||
{t('about.interests.title')}
|
{t('about.interests.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="grid sm:grid-cols-2 gap-6">
|
<ul class="grid sm:grid-cols-2 gap-4">
|
||||||
{(t('about.interests.items') as unknown as any[]).map((item) => (
|
{(t('about.interests.items') as unknown as any[]).map((item) => (
|
||||||
<div class="p-4 rounded-xl bg-muted/30 border border-border/50 transition-colors hover:bg-muted/50">
|
<li class="flex items-start gap-4 p-4 rounded-xl border border-border/40 bg-card/20 hover:bg-card/40 transition-colors group">
|
||||||
<h3 class="font-bold mb-2">{item.title}</h3>
|
<div class="mt-1.5 w-1.5 h-1.5 rounded-full bg-primary/40 group-hover:bg-primary transition-colors shrink-0" />
|
||||||
|
<div class="space-y-1">
|
||||||
|
<span class="font-bold text-foreground">{item.title}</span>
|
||||||
<p class="text-sm text-muted-foreground leading-relaxed">{item.content}</p>
|
<p class="text-sm text-muted-foreground leading-relaxed">{item.content}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Socials & Community -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
<h2 class="text-2xl font-bold flex items-center gap-3 px-2">
|
||||||
|
<Globe className="w-6 h-6 text-primary" />
|
||||||
|
{t('about.socials.title')}
|
||||||
|
</h2>
|
||||||
|
<div class="flex flex-wrap gap-4 px-2">
|
||||||
|
{(t('about.socials.items') as unknown as any[]).map((item) => {
|
||||||
|
const Icon = IconMap[item.icon] || Globe;
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={item.link}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="flex items-center gap-2 px-4 py-2 rounded-lg bg-muted/30 border border-border/50 hover:border-primary/50 hover:bg-primary/5 transition-all group text-sm font-medium"
|
||||||
|
>
|
||||||
|
<Icon className="w-4 h-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Contact -->
|
<!-- Contact -->
|
||||||
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-8 overflow-hidden relative">
|
<div class="space-y-8 py-8">
|
||||||
<div class="absolute top-0 right-0 p-8 opacity-5">
|
<div class="px-2 space-y-4">
|
||||||
<Mail className="w-32 h-32" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative z-10 space-y-6">
|
|
||||||
<h2 class="text-2xl font-bold flex items-center gap-3">
|
<h2 class="text-2xl font-bold flex items-center gap-3">
|
||||||
<MessageSquare className="w-6 h-6 text-primary" />
|
<Mail className="w-6 h-6 text-primary" />
|
||||||
{t('about.contact.title')}
|
{t('about.contact.title')}
|
||||||
</h2>
|
</h2>
|
||||||
|
<p class="text-muted-foreground leading-relaxed max-w-2xl">
|
||||||
<HighlightBox type="warning" title={lang === 'zh' ? '注意' : 'Notice'}>
|
|
||||||
{t('about.contact.warning')}
|
{t('about.contact.warning')}
|
||||||
</HighlightBox>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid sm:grid-cols-3 gap-4 mt-8">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div class="flex flex-col p-4 rounded-xl bg-muted/30 border border-border/50 items-center text-center gap-2">
|
{(t('about.contact.methods') as unknown as any[]).map((method) => {
|
||||||
<Mail className="w-5 h-5 text-primary" />
|
const Icon = IconMap[method.icon] || MessageSquare;
|
||||||
<span class="text-xs font-medium text-muted-foreground uppercase tracking-wider">Email</span>
|
const content = (
|
||||||
<span class="text-sm font-semibold break-all">{(t('about.contact.methods.email') as string).split(':')[1] || (t('about.contact.methods.email') as string).split(': ')[1]}</span>
|
<div class="flex items-center gap-4 p-4 rounded-xl border border-border/40 bg-card/20 hover:bg-card/40 transition-all group">
|
||||||
|
<div class="p-2.5 rounded-lg bg-primary/5 text-primary/70 group-hover:bg-primary/10 group-hover:text-primary transition-colors">
|
||||||
|
<Icon className="w-5 h-5" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col p-4 rounded-xl bg-muted/30 border border-border/50 items-center text-center gap-2">
|
<div class="flex flex-col">
|
||||||
<span class="font-bold text-primary">QQ</span>
|
<span class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{method.label}</span>
|
||||||
<span class="text-xs font-medium text-muted-foreground uppercase tracking-wider">QQ</span>
|
<span class="text-sm font-medium break-all">{method.value}</span>
|
||||||
<span class="text-sm font-semibold">{(t('about.contact.methods.qq') as string).split(':')[1] || (t('about.contact.methods.qq') as string).split(': ')[1]}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col p-4 rounded-xl bg-muted/30 border border-border/50 items-center text-center gap-2">
|
|
||||||
<MessageSquare className="w-5 h-5 text-primary" />
|
|
||||||
<span class="text-xs font-medium text-muted-foreground uppercase tracking-wider">WeChat</span>
|
|
||||||
<span class="text-sm font-semibold">{(t('about.contact.methods.wechat') as string).split(':')[1] || (t('about.contact.methods.wechat') as string).split(': ')[1]}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (method.link) {
|
||||||
|
return (
|
||||||
|
<a href={method.link} class="block transition-transform hover:-translate-y-0.5">
|
||||||
|
{content}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <div class="cursor-default">{content}</div>;
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user