feat: build resume website with MagicUI components
- 6 sections: Hero, About, Experience, Skills, Projects, Contact - MagicUI: Globe, Particles, Meteors, AnimatedList, IconCloud, BentoGrid - Dark mode support, scroll-triggered animations - Static export ready for deployment
This commit is contained in:
92
components/sections/about.tsx
Normal file
92
components/sections/about.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
CodeIcon,
|
||||
CpuIcon,
|
||||
TerminalIcon,
|
||||
GlobeIcon,
|
||||
DatabaseIcon,
|
||||
LayerIcon,
|
||||
} from "@hugeicons/core-free-icons"
|
||||
import { HugeiconsIcon } from "@hugeicons/react"
|
||||
|
||||
import { OrbitingCircles } from "@/components/ui/orbiting-circles"
|
||||
import { SectionWrapper } from "@/components/section-wrapper"
|
||||
|
||||
const techIcons = [
|
||||
{ icon: <HugeiconsIcon icon={CodeIcon} className="size-6" />, label: "Go" },
|
||||
{ icon: <HugeiconsIcon icon={TerminalIcon} className="size-6" />, label: "Python" },
|
||||
{ icon: <HugeiconsIcon icon={DatabaseIcon} className="size-6" />, label: "TypeScript" },
|
||||
{ icon: <HugeiconsIcon icon={CpuIcon} className="size-6" />, label: "C#" },
|
||||
{ icon: <HugeiconsIcon icon={LayerIcon} className="size-6" />, label: "React" },
|
||||
{ icon: <HugeiconsIcon icon={GlobeIcon} className="size-6" />, label: "Django" },
|
||||
]
|
||||
|
||||
export function About() {
|
||||
return (
|
||||
<SectionWrapper id="about" className="py-24">
|
||||
<div className="mx-auto max-w-5xl px-6">
|
||||
<div className="grid gap-12 lg:grid-cols-2 lg:items-center">
|
||||
{/* 简介文字 */}
|
||||
<div>
|
||||
<h2 className="mb-4 text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
关于我
|
||||
</h2>
|
||||
<div className="space-y-3 text-muted-foreground">
|
||||
<p className="text-base">
|
||||
AI 驱动的全栈工程师,擅长把 AI、自动化和业务系统做成可落地、可衡量的产品。
|
||||
</p>
|
||||
<p className="text-sm">
|
||||
从 Go / Python / C# 后端、React 前端到 Docker / Linux 部署都能直接落地,覆盖全链路开发。
|
||||
</p>
|
||||
<p className="text-sm">
|
||||
正在寻找能把 AI 深度接入真实业务、以结果衡量价值的团队。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 环绕动画 */}
|
||||
<div className="relative flex items-center justify-center">
|
||||
<div className="relative flex size-80 items-center justify-center">
|
||||
{/* 中心文字 */}
|
||||
<div className="z-10 text-center">
|
||||
<div className="text-4xl font-bold">6+</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
年经验
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<OrbitingCircles radius={110} duration={25} iconSize={40}>
|
||||
{techIcons.slice(0, 3).map((tech, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex size-10 items-center justify-center rounded-full border border-border bg-background p-2"
|
||||
title={tech.label}
|
||||
>
|
||||
{tech.icon}
|
||||
</div>
|
||||
))}
|
||||
</OrbitingCircles>
|
||||
<OrbitingCircles
|
||||
radius={160}
|
||||
duration={35}
|
||||
reverse
|
||||
iconSize={40}
|
||||
>
|
||||
{techIcons.slice(3).map((tech, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex size-10 items-center justify-center rounded-full border border-border bg-background p-2"
|
||||
title={tech.label}
|
||||
>
|
||||
{tech.icon}
|
||||
</div>
|
||||
))}
|
||||
</OrbitingCircles>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionWrapper>
|
||||
)
|
||||
}
|
||||
40
components/sections/contact.tsx
Normal file
40
components/sections/contact.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
"use client"
|
||||
|
||||
import { ShinyButton } from "@/components/ui/shiny-button"
|
||||
import { SectionWrapper } from "@/components/section-wrapper"
|
||||
|
||||
export function Contact() {
|
||||
return (
|
||||
<SectionWrapper id="contact" className="py-24">
|
||||
<div className="mx-auto max-w-2xl px-6 text-center">
|
||||
<h2 className="mb-4 text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
一起合作吧
|
||||
</h2>
|
||||
<p className="mb-8 text-muted-foreground">
|
||||
正在寻找能把 AI 深度接入真实业务、并以结果衡量价值的岗位或团队。随时联系我!
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<a href="mailto:liukersun@gmail.com">
|
||||
<ShinyButton>发送邮件</ShinyButton>
|
||||
</a>
|
||||
<a href="https://github.com/LiukerSun" target="_blank" rel="noopener noreferrer">
|
||||
<ShinyButton>GitHub</ShinyButton>
|
||||
</a>
|
||||
<a
|
||||
href="https://t.me/DrJhaha"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<ShinyButton>Telegram</ShinyButton>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 页脚 */}
|
||||
<footer className="mt-24 border-t border-border pt-8 text-center text-sm text-muted-foreground">
|
||||
<p>© 2026 Evan Sun. 保留所有权利。</p>
|
||||
</footer>
|
||||
</SectionWrapper>
|
||||
)
|
||||
}
|
||||
101
components/sections/experience.tsx
Normal file
101
components/sections/experience.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Building03Icon,
|
||||
CodeIcon,
|
||||
Award02Icon,
|
||||
ProjectorIcon,
|
||||
} from "@hugeicons/core-free-icons"
|
||||
import { HugeiconsIcon } from "@hugeicons/react"
|
||||
|
||||
import { AnimatedList, AnimatedListItem } from "@/components/ui/animated-list"
|
||||
import { SectionWrapper } from "@/components/section-wrapper"
|
||||
|
||||
interface ExperienceItem {
|
||||
role: string
|
||||
company: string
|
||||
period: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const experiences: ExperienceItem[] = [
|
||||
{
|
||||
role: "全栈开发工程师",
|
||||
company: "MakeBlock",
|
||||
period: "2024.10 - 2025.4",
|
||||
description:
|
||||
"负责内部质检与业务系统的全栈开发,覆盖前端页面、后端接口、数据流转与部署协作。",
|
||||
},
|
||||
{
|
||||
role: "项目经理 / 技术负责人",
|
||||
company: "HIT 重庆",
|
||||
period: "2024.1 - 2024.9",
|
||||
description:
|
||||
"担任项目管理与技术负责人,统筹技术选型与团队协作,推动项目按期高质量交付。",
|
||||
},
|
||||
{
|
||||
role: "测试开发工程师",
|
||||
company: "ByteDance(字节跳动)",
|
||||
period: "2021.12 - 2023.3",
|
||||
description:
|
||||
"负责内部测试工具与自动化流程的开发,保障产品质量与交付效率。",
|
||||
},
|
||||
{
|
||||
role: "BIM 工程师",
|
||||
company: "亚厦集团",
|
||||
period: "2020.8 - 2021.11",
|
||||
description:
|
||||
"负责建筑信息模型(BIM)相关工作,进行 3D 建模与工程协调。",
|
||||
},
|
||||
]
|
||||
|
||||
const icons = [
|
||||
<HugeiconsIcon key="makeblock" icon={Building03Icon} className="size-5" />,
|
||||
<HugeiconsIcon key="hit" icon={ProjectorIcon} className="size-5" />,
|
||||
<HugeiconsIcon key="bytedance" icon={Award02Icon} className="size-5" />,
|
||||
<HugeiconsIcon key="yasha" icon={CodeIcon} className="size-5" />,
|
||||
]
|
||||
|
||||
export function Experience() {
|
||||
return (
|
||||
<SectionWrapper id="experience" className="py-24">
|
||||
<div className="mx-auto max-w-3xl px-6">
|
||||
<h2 className="mb-12 text-center text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
工作经历
|
||||
</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
{experiences.map((exp, i) => (
|
||||
<AnimatedListItem key={exp.company}>
|
||||
<div className="group relative flex gap-4 rounded-xl border border-border bg-card p-6 transition-colors hover:bg-accent/50">
|
||||
{/* 时间线 */}
|
||||
<div className="relative flex flex-col items-center">
|
||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-full border border-border bg-background text-muted-foreground transition-colors group-hover:border-primary/50 group-hover:text-foreground">
|
||||
{icons[i]}
|
||||
</div>
|
||||
{i < experiences.length - 1 && (
|
||||
<div className="absolute top-12 h-full w-px bg-border" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 内容 */}
|
||||
<div className="flex-1">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
<h3 className="font-semibold">{exp.role}</h3>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{exp.period}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">{exp.company}</p>
|
||||
<p className="mt-2 text-sm text-muted-foreground">
|
||||
{exp.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedListItem>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</SectionWrapper>
|
||||
)
|
||||
}
|
||||
100
components/sections/hero.tsx
Normal file
100
components/sections/hero.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
"use client"
|
||||
|
||||
import { useMemo } from "react"
|
||||
import { useTheme } from "next-themes"
|
||||
import type { COBEOptions } from "cobe"
|
||||
|
||||
import { Globe } from "@/components/ui/globe"
|
||||
import { Particles } from "@/components/ui/particles"
|
||||
import { Meteors } from "@/components/ui/meteors"
|
||||
import { AnimatedGradientText } from "@/components/ui/animated-gradient-text"
|
||||
import { TextAnimate } from "@/components/ui/text-animate"
|
||||
|
||||
export function Hero() {
|
||||
const { resolvedTheme } = useTheme()
|
||||
const isDark = resolvedTheme === "dark"
|
||||
|
||||
const globeConfig = useMemo((): Omit<COBEOptions, "width" | "height"> => {
|
||||
const baseConfig: Omit<COBEOptions, "width" | "height"> = {
|
||||
phi: 0,
|
||||
theta: 0.3,
|
||||
dark: isDark ? 1 : 0,
|
||||
diffuse: 0.4,
|
||||
mapSamples: 12000,
|
||||
mapBrightness: 1.2,
|
||||
devicePixelRatio: 2,
|
||||
baseColor: isDark ? [0.3, 0.3, 0.3] as [number, number, number] : [1, 1, 1] as [number, number, number],
|
||||
markerColor: [251 / 255, 100 / 255, 21 / 255] as [number, number, number],
|
||||
glowColor: isDark ? [0.5, 0.5, 0.5] as [number, number, number] : [1, 1, 1] as [number, number, number],
|
||||
markers: [
|
||||
{ location: [39.9042, 116.4074], size: 0.08 },
|
||||
{ location: [40.7128, -74.006], size: 0.1 },
|
||||
{ location: [51.5074, -0.1278], size: 0.07 },
|
||||
{ location: [35.6762, 139.6503], size: 0.06 },
|
||||
],
|
||||
}
|
||||
return baseConfig
|
||||
}, [isDark])
|
||||
|
||||
return (
|
||||
<section className="relative flex min-h-svh items-center justify-center overflow-hidden">
|
||||
{/* Background effects */}
|
||||
<div className="absolute inset-0">
|
||||
<Globe className="opacity-40" config={globeConfig} />
|
||||
</div>
|
||||
<Particles
|
||||
className="absolute inset-0"
|
||||
quantity={40}
|
||||
color={isDark ? "#ffffff" : "#000000"}
|
||||
/>
|
||||
<Meteors number={12} />
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 mx-auto max-w-4xl px-6 text-center">
|
||||
<AnimatedGradientText className="mb-4 text-lg font-medium tracking-wide sm:text-xl">
|
||||
你好,世界 👋
|
||||
</AnimatedGradientText>
|
||||
|
||||
<h1 className="mb-4 text-5xl font-bold tracking-tight sm:text-7xl md:text-8xl">
|
||||
<TextAnimate
|
||||
by="character"
|
||||
animation="blurInUp"
|
||||
delay={0.3}
|
||||
once
|
||||
>
|
||||
Evan Sun
|
||||
</TextAnimate>
|
||||
</h1>
|
||||
|
||||
<TextAnimate
|
||||
as="p"
|
||||
className="mx-auto max-w-2xl text-lg text-muted-foreground sm:text-xl"
|
||||
by="word"
|
||||
animation="fadeIn"
|
||||
delay={0.8}
|
||||
once
|
||||
>
|
||||
全栈工程师 / AI 工程师
|
||||
</TextAnimate>
|
||||
|
||||
<div className="mt-8 flex justify-center gap-4">
|
||||
<a
|
||||
href="#contact"
|
||||
className="rounded-lg bg-foreground px-6 py-2.5 text-sm font-medium text-background transition-opacity hover:opacity-80"
|
||||
>
|
||||
联系我
|
||||
</a>
|
||||
<a
|
||||
href="#projects"
|
||||
className="rounded-lg border border-border px-6 py-2.5 text-sm font-medium transition-colors hover:bg-accent"
|
||||
>
|
||||
查看作品
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Fade gradient at bottom */}
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-gradient-to-t from-background to-transparent" />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
209
components/sections/projects.tsx
Normal file
209
components/sections/projects.tsx
Normal file
@@ -0,0 +1,209 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
DatabaseIcon,
|
||||
CodeIcon,
|
||||
RepeatIcon,
|
||||
AiVideoIcon,
|
||||
Chatting01Icon,
|
||||
FolderOpenIcon,
|
||||
TranslateIcon,
|
||||
BarChartIcon,
|
||||
BotIcon,
|
||||
CloudUploadIcon,
|
||||
FileAttachmentIcon,
|
||||
} from "@hugeicons/core-free-icons"
|
||||
import { HugeiconsIcon } from "@hugeicons/react"
|
||||
|
||||
import { BentoCard, BentoGrid } from "@/components/ui/bento-grid"
|
||||
import { SectionWrapper } from "@/components/section-wrapper"
|
||||
|
||||
const GITHUB_BASE = "https://github.com/LiukerSun"
|
||||
|
||||
const projects = [
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={DatabaseIcon} {...props} />
|
||||
),
|
||||
name: "ERP 管理系统",
|
||||
description:
|
||||
"管理超过 1200 件商品 SKU,覆盖库存、供应链、图片和出入库流程。Go 后端 + TypeScript 前端,整体效率提升 3-4 倍。",
|
||||
href: `${GITHUB_BASE}/erp_backend`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/10 via-transparent to-purple-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-2",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={RepeatIcon} {...props} />
|
||||
),
|
||||
name: "自动化交易系统",
|
||||
description:
|
||||
"基于 MetaTrader 5 的量化交易自动化系统,支持策略回测与实时监控。",
|
||||
href: `${GITHUB_BASE}/metatrader5-quant-server-python`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-amber-500/10 via-transparent to-orange-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={Chatting01Icon} {...props} />
|
||||
),
|
||||
name: "Telegram AI 翻译机器人",
|
||||
description:
|
||||
"集成 OpenAI 的 Telegram 机器人,支持自定义预设、多轮对话上下文管理和用户权限系统。",
|
||||
href: `${GITHUB_BASE}/tg_ai_translate_bot_go`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-green-500/10 via-transparent to-teal-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={AiVideoIcon} {...props} />
|
||||
),
|
||||
name: "Agent Dispatcher",
|
||||
description:
|
||||
"AI Agent 调度系统,智能分配任务与资源管理。",
|
||||
href: `${GITHUB_BASE}/agentdispatcher`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-pink-500/10 via-transparent to-rose-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={BarChartIcon} {...props} />
|
||||
),
|
||||
name: "直播数据分析",
|
||||
description:
|
||||
"实时直播数据抓取与分析工具。",
|
||||
href: `${GITHUB_BASE}/liveDataAnalysis`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-cyan-500/10 via-transparent to-blue-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={CodeIcon} {...props} />
|
||||
),
|
||||
name: "cc-cli 命令行工具",
|
||||
description:
|
||||
"通用命令行工具集,提升开发效率。",
|
||||
href: `${GITHUB_BASE}/cc-cli`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-violet-500/10 via-transparent to-indigo-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={FileAttachmentIcon} {...props} />
|
||||
),
|
||||
name: "Excel JSON 转换工具",
|
||||
description:
|
||||
"Excel 表格转 JSON 格式的 Python 工具,支持自定义模板。",
|
||||
href: `${GITHUB_BASE}/excel-json-tool`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-emerald-500/10 via-transparent to-green-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
{
|
||||
Icon: (props: { className?: string }) => (
|
||||
<HugeiconsIcon icon={CloudUploadIcon} {...props} />
|
||||
),
|
||||
name: "DevTools 开发网关",
|
||||
description:
|
||||
"基于 Docker + Traefik + Cloudflare DNS 验证的本地开发网关系统。",
|
||||
href: `${GITHUB_BASE}/DevTools`,
|
||||
cta: "查看源码",
|
||||
background: (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-sky-500/10 via-transparent to-blue-500/10" />
|
||||
),
|
||||
className: "col-span-1 lg:col-span-1",
|
||||
},
|
||||
]
|
||||
|
||||
const otherProjects = [
|
||||
{
|
||||
name: "OpenManage",
|
||||
href: `${GITHUB_BASE}/openmanage`,
|
||||
icon: <HugeiconsIcon icon={FolderOpenIcon} className="size-5" />,
|
||||
},
|
||||
{
|
||||
name: "抖音弹幕录制",
|
||||
href: `${GITHUB_BASE}/DouyinDanmu`,
|
||||
icon: <HugeiconsIcon icon={BotIcon} className="size-5" />,
|
||||
},
|
||||
{
|
||||
name: "微信机器人",
|
||||
href: `${GITHUB_BASE}/weixinbot`,
|
||||
icon: <HugeiconsIcon icon={Chatting01Icon} className="size-5" />,
|
||||
},
|
||||
{
|
||||
name: "Excel 转 MySQL",
|
||||
href: `${GITHUB_BASE}/excel2mysql`,
|
||||
icon: <HugeiconsIcon icon={TranslateIcon} className="size-5" />,
|
||||
},
|
||||
{
|
||||
name: "抖店 Excel",
|
||||
href: `${GITHUB_BASE}/doudian_excel`,
|
||||
icon: <HugeiconsIcon icon={FileAttachmentIcon} className="size-5" />,
|
||||
},
|
||||
{
|
||||
name: "Flip Game",
|
||||
href: `${GITHUB_BASE}/flipgame`,
|
||||
icon: <HugeiconsIcon icon={RepeatIcon} className="size-5" />,
|
||||
},
|
||||
]
|
||||
|
||||
export function Projects() {
|
||||
return (
|
||||
<SectionWrapper id="projects" className="py-24">
|
||||
<div className="mx-auto max-w-5xl px-6">
|
||||
<h2 className="mb-12 text-center text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
项目作品
|
||||
</h2>
|
||||
<BentoGrid>
|
||||
{projects.map((project) => (
|
||||
<BentoCard key={project.name} {...project} />
|
||||
))}
|
||||
</BentoGrid>
|
||||
|
||||
{/* 其他开源项目 */}
|
||||
<h3 className="mt-16 mb-6 text-center text-xl font-semibold">
|
||||
更多开源项目
|
||||
</h3>
|
||||
<div className="grid gap-3 sm:grid-cols-3 lg:grid-cols-6">
|
||||
{otherProjects.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex flex-col items-center gap-2 rounded-xl border border-border bg-card p-4 text-center transition-colors hover:bg-accent/50"
|
||||
>
|
||||
<div className="flex size-10 items-center justify-center rounded-full border border-border bg-background text-muted-foreground">
|
||||
{item.icon}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground underline">
|
||||
{item.name}
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</SectionWrapper>
|
||||
)
|
||||
}
|
||||
119
components/sections/skills.tsx
Normal file
119
components/sections/skills.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
"use client"
|
||||
|
||||
import { SectionWrapper } from "@/components/section-wrapper"
|
||||
import { IconCloud } from "@/components/ui/icon-cloud"
|
||||
|
||||
const skills = [
|
||||
"Go",
|
||||
"Python",
|
||||
"TypeScript",
|
||||
"C#",
|
||||
"JavaScript",
|
||||
"Swift",
|
||||
"Shell",
|
||||
"Django",
|
||||
"React",
|
||||
"Docker",
|
||||
"Traefik",
|
||||
"MT5",
|
||||
"OpenAI",
|
||||
"TG Bot",
|
||||
"MySQL",
|
||||
"Git",
|
||||
"CI/CD",
|
||||
"DevOps",
|
||||
"ERP",
|
||||
"量化",
|
||||
]
|
||||
|
||||
// 为每个技能生成 SVG 文本元素
|
||||
function SkillIcon({ text }: { text: string }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
>
|
||||
<circle cx="20" cy="20" r="18" fill="currentColor" opacity="0.1" />
|
||||
<text
|
||||
x="20"
|
||||
y="24"
|
||||
textAnchor="middle"
|
||||
fontSize="8"
|
||||
fill="currentColor"
|
||||
fontWeight="500"
|
||||
>
|
||||
{text.slice(0, 5)}
|
||||
</text>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function Skills() {
|
||||
const iconElements = skills.map((skill, i) => <SkillIcon key={i} text={skill} />)
|
||||
|
||||
return (
|
||||
<SectionWrapper id="skills" className="py-24">
|
||||
<div className="mx-auto max-w-5xl px-6">
|
||||
<h2 className="mb-12 text-center text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
技能与技术
|
||||
</h2>
|
||||
|
||||
<div className="flex flex-col items-center gap-8 lg:flex-row lg:justify-center lg:gap-16">
|
||||
{/* 3D 图标云 */}
|
||||
<div className="relative flex items-center justify-center">
|
||||
<IconCloud icons={iconElements} />
|
||||
</div>
|
||||
|
||||
{/* 技能分类 */}
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="mb-2 font-semibold">编程语言</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["Go", "Python", "TypeScript", "C#", "JavaScript", "Swift"].map(
|
||||
(s) => (
|
||||
<span
|
||||
key={s}
|
||||
className="rounded-full border border-border px-3 py-1 text-xs text-muted-foreground"
|
||||
>
|
||||
{s}
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="mb-2 font-semibold">框架与服务</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["Django", "React", "MT5", "OpenAI API", "TG Bot"].map(
|
||||
(s) => (
|
||||
<span
|
||||
key={s}
|
||||
className="rounded-full border border-border px-3 py-1 text-xs text-muted-foreground"
|
||||
>
|
||||
{s}
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="mb-2 font-semibold">运维与工具</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["Docker", "Traefik", "MySQL", "CI/CD", "DevOps"].map((s) => (
|
||||
<span
|
||||
key={s}
|
||||
className="rounded-full border border-border px-3 py-1 text-xs text-muted-foreground"
|
||||
>
|
||||
{s}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionWrapper>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user