feat(contact): add multilingual contact pages and dynamic configurations

- Created `src/pages/contact.astro` and `src/pages/zh/contact.astro` to support multilingual contact functionality.
- Introduced `contactIntents` and `contactMethods` dynamic configurations in `src/lib/data/contact.ts` for streamlined content management.
- Designed responsive and localized layouts with enhanced UX for both languages.
This commit is contained in:
zguiyang
2026-03-16 15:32:40 +08:00
parent 965ae613f8
commit ce6110588f
40 changed files with 3474 additions and 2547 deletions

View File

@@ -39,7 +39,7 @@ export default function Footer({ lang: propLang }: FooterProps) {
className="text-sm text-primary font-medium text-center md:text-left"
whileHover={{ scale: 1.01 }}
>
{lang === 'zh' ? '构建 AI 产品?寻找技术合伙人?联系我' : 'Building AI Products? Need a Technical Co-founder? Contact me!'}
{lang === 'zh' ? '正在招聘远程工程师或寻求项目合作?欢迎联系我' : 'Hiring for a remote engineering role or looking for project collaboration? Lets connect.'}
</motion.p>
</motion.div>
<motion.p

View File

@@ -5,7 +5,7 @@ import Container from "./ui/Container.tsx";
import { useTranslations, getLocalizedPath } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { useState, useEffect } from "react";
import { Menu, X, Home, Rocket, PenTool, Zap, Briefcase, User } from "lucide-react";
import { Menu, X, Home, Rocket, PenTool, Zap, User, Wrench, Mail } from "lucide-react";
import { defaultLang } from "@/i18n/ui";
import { type GlassHeaderProps } from "@/types";
import { motion } from "framer-motion";
@@ -40,11 +40,12 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) {
const navItems = [
{ key: 'nav.home', icon: Home, href: getLocalizedPath('/', lang) },
{ key: 'nav.about', icon: User, href: getLocalizedPath('/about', lang) },
{ key: 'nav.projects', icon: Rocket, href: getLocalizedPath('/projects', lang) },
{ key: 'nav.blog', icon: PenTool, href: getLocalizedPath('/blog', lang) },
{ key: 'nav.now', icon: Zap, href: getLocalizedPath('/now', lang) },
{ key: 'nav.hire', icon: Briefcase, href: getLocalizedPath('/hire', lang) },
{ key: 'nav.about', icon: User, href: getLocalizedPath('/about', lang) },
{ key: 'nav.uses', icon: Wrench, href: getLocalizedPath('/uses', lang) },
{ key: 'nav.contact', icon: Mail, href: getLocalizedPath('/contact', lang) },
];
const isActive = (path: string) => {

View File

@@ -17,7 +17,15 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro
const [currentLang, setCurrentLang] = useState<Lang>(propLang || defaultLang);
useEffect(() => {
if (typeof document !== 'undefined') {
if (typeof window !== "undefined") {
const pathLang = window.location.pathname.startsWith("/zh") ? "zh" : "en";
if (pathLang !== currentLang) {
setCurrentLang(pathLang);
}
return;
}
if (typeof document !== "undefined") {
const htmlLang = document.documentElement.lang as Lang;
if (htmlLang && (!propLang || htmlLang !== currentLang)) {
setCurrentLang(htmlLang);
@@ -43,35 +51,14 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro
const handleSelectLanguage = (languageOpt: typeof availableLanguages[0]) => {
setSelectedLanguage(languageOpt);
setIsOpen(false);
if (typeof window !== 'undefined') {
if (typeof window !== "undefined") {
const currentPathname = window.location.pathname;
const currentPathParts = currentPathname.split('/').filter(p => p);
let basePath = '';
const basePath = currentPathname.replace(/^\/(en|zh)(?=\/|$)/, "") || "/";
const targetPath = getLocalizedPath(basePath, languageOpt.code);
if (currentPathParts.length > 0 && Object.keys(i18nLanguages).includes(currentPathParts[0])) {
basePath = '/' + currentPathParts.slice(1).join('/');
} else {
basePath = currentPathname;
}
if (!basePath.startsWith('/')) {
basePath = '/' + basePath;
}
if (basePath === '//') basePath = '/';
if (basePath === '') basePath = '/';
let newPath;
if (languageOpt.code === defaultLang) {
newPath = basePath;
} else {
newPath = `/${languageOpt.code}${basePath}`;
}
newPath = newPath.replace(/\/\/+/g, '/');
if (newPath === '') newPath = '/';
if (newPath !== currentPathname) {
window.location.href = newPath;
const normalize = (value: string) => value.replace(/\/+$/, "") || "/";
if (normalize(targetPath) !== normalize(currentPathname)) {
window.location.assign(targetPath);
}
}
};
@@ -119,4 +106,4 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro
</AnimatePresence>
</div>
);
}
}

View File

@@ -9,16 +9,15 @@ export const translations = {
nav: {
home: 'Home',
about: 'About',
services: 'Services',
projects: 'Projects',
blog: 'Blog',
uses: 'Uses',
contact: 'Contact',
now: 'Now',
hire: 'Hire',
},
site: {
title: 'Joey Zhao - Full Stack Developer',
description: 'Full Stack Developer specializing in React, Node.js, and modern web technologies',
title: 'Joey Zhao - Senior Frontend Engineer',
description: 'Senior Frontend Engineer building complex systems and AI-assisted products',
},
hero: {
greeting: "Hello, I'm",
@@ -70,7 +69,7 @@ export const translations = {
},
blog: {
slogan: 'This is where innovative thinking meets complex problems.',
backToList: 'Back to Blog',
backToList: 'Back to Writing',
},
services: {
title: 'What I Do',
@@ -196,16 +195,15 @@ export const translations = {
nav: {
home: '首页',
about: '关于',
services: '服务',
projects: '项目',
blog: '博客',
uses: '工具',
contact: '联系',
now: '现在',
hire: '合作',
},
site: {
title: 'Joey Zhao - 全栈开发者',
description: '专注于 React、Node.js 和现代 Web 技术的全栈开发者',
title: 'Joey Zhao - 资深前端工程师',
description: '专注复杂系统与 AI 协作工程实践的资深前端工程师',
},
hero: {
greeting: '你好,我是',
@@ -257,7 +255,7 @@ export const translations = {
},
blog: {
slogan: '这里是创新思维与复杂问题相遇的地方。',
backToList: '返回博客列表',
backToList: '返回写作列表',
},
services: {
title: '我能做什么',

View File

@@ -12,7 +12,7 @@ interface Props {
}
const lang = Astro.currentLocale as Lang || defaultLang;
const { title = "Rishikesh S - Portfolio", description = "My Portfolio" } =
const { title = "Joey Zhao - Portfolio", description = "Engineering-focused personal website" } =
Astro.props;
const t = useTranslations(lang);
---

44
src/lib/data/contact.ts Normal file
View File

@@ -0,0 +1,44 @@
import type { ContactIntent, ContactMethod } from '@/types';
export const contactIntents: ContactIntent[] = [
{
id: 'remote-role',
title: {
en: 'Remote Role',
zh: '远程岗位沟通',
},
description: {
en: 'Preferred for senior frontend/full-stack roles on complex products and systems.',
zh: '优先沟通资深前端/全栈远程岗位,偏好复杂产品与系统场景。',
},
},
{
id: 'project-collaboration',
title: {
en: 'Project Collaboration',
zh: '项目合作咨询',
},
description: {
en: 'Available for scoped project work involving architecture, delivery, and optimization.',
zh: '可承接范围明确的项目合作,包括架构设计、交付落地与性能优化。',
},
},
];
export const contactMethods: ContactMethod[] = [
{
label: { en: 'Email', zh: '邮箱' },
value: 'zhaoguiyang18@gmail.com',
href: 'mailto:zhaoguiyang18@gmail.com',
},
{
label: { en: 'GitHub', zh: 'GitHub' },
value: 'github.com/zguiyang',
href: 'https://github.com/zguiyang',
},
{
label: { en: 'LinkedIn', zh: 'LinkedIn' },
value: 'linkedin.com/in/zhaoguiyang',
href: 'https://linkedin.com/in/zhaoguiyang',
},
];

View File

@@ -1,3 +1,5 @@
export { personalInfo } from './personal-info';
export { projects } from './projects';
export { services } from './services';
export { services } from './services';
export { uses } from './uses';
export { contactIntents, contactMethods } from './contact';

View File

@@ -1,46 +1,47 @@
import type { PersonalInfo } from '@/types';
export const personalInfo: PersonalInfo = {
name: "Joey Zhao",
location: "China",
avatar: "https://avatars.githubusercontent.com/u/24975063?v=4",
email: "zhaoguiyang18@gmail.com",
github: "https://github.com/zguiyang",
linkedin: "https://linkedin.com/in/zhaoguiyang",
website: "https://zhaoguiyang.com",
twitter: "https://twitter.com/zhaoguiyang",
name: 'Joey Zhao',
location: 'Hangzhou, China',
avatar: 'https://avatars.githubusercontent.com/u/24975063?v=4',
email: 'zhaoguiyang18@gmail.com',
github: 'https://github.com/zguiyang',
linkedin: 'https://linkedin.com/in/zhaoguiyang',
website: 'https://zhaoguiyang.com',
twitter: 'https://twitter.com/zhaoguiyang',
position: {
en: "Full-stack + AI Product Builder",
zh: "全栈 + AI 产品构建者"
en: 'Senior Frontend Engineer · Full-stack Developer',
zh: '资深前端工程师 · 全栈开发者',
},
description: {
en: "Building AI-powered products and turning ambitious ideas into reality. Currently focused on Elynd - an open AI workspace for builders.",
zh: "构建 AI 驱动产品,将雄心勃勃的想法变为现实。目前专注于 Elynd - 一个面向构建者的开放 AI 工作空间。"
en: '8 years building enterprise systems, financial platforms, and blockchain infrastructure. Focused on frontend architecture, complex system design, and AI-assisted engineering workflows.',
zh: '8 年企业系统、金融平台与区块链基础设施研发经验,专注前端架构、复杂系统设计与 AI 协作工程化实践。',
},
about: {
en: [
"I started my programming journey in 2016 when I accidentally encountered programming. This opportunity became the catalyst for my coding adventure, and I fell in love with programming during my subsequent self-learning journey.",
"I enjoy creating websites and applications with code and sharing them with users. The sense of achievement I get from this process makes me increasingly fascinated. My dream is to become a lifelong coder.",
"I love reading, traveling (especially road trips), enjoying various cuisines (particularly hot pot), and playing mobile games like League of Legends, Honor of Kings, and PUBG Mobile."
'I build reliable web systems with strong architecture discipline and delivery ownership.',
'My core experience comes from enterprise, finance, and blockchain product domains.',
'I work effectively in remote-first teams with clear async communication and stable execution cadence.',
],
zh: [
"在2016年一次偶然的机会中接触到了编程以此为契机开始了我的编程之旅并在后续的自学之旅中爱上了编程。",
"我喜欢用代码编写出一个个的网页、应用,分享给用户使用,这其中获得的成就感让我愈发着迷。梦想是成为一名终身编码者。",
"热爱生活、阅读以及编程,寻找远程工作的机会,探索自由职业的可能性。喜欢自驾,去追寻那些美丽的风景,尝试新的事物。"
]
'我专注构建稳定、可维护、可扩展的 Web 系统,并对交付结果负责。',
'核心经验来自企业级、金融科技与区块链产品场景。',
'擅长远程协作与异步沟通,能够保持稳定节奏持续交付。',
],
},
stats: {
repositories: 152,
commits: "42K",
contributions: 87
commits: '42K',
contributions: 87,
},
skills: {
frontend: ["HTML", "CSS", "JavaScript", "Vue.js", "React.js", "TypeScript"],
backend: ["Node.js"],
database: ["MySQL", "MongoDB"],
devops: ["Linux", "Git", "Docker", "Nginx", "Apache"],
mobile: ["React Native", "Flutter"]
frontend: ['TypeScript', 'React', 'Vue', 'Astro'],
backend: ['Node.js', 'NestJS', 'Fastify'],
database: ['PostgreSQL', 'MySQL', 'MongoDB'],
devops: ['Linux', 'Git', 'Docker', 'Nginx'],
mobile: ['React Native', 'Flutter'],
},
terminal: {
username: "joy@dev-workspace"
}
};
username: 'joy@engineer',
},
};

View File

@@ -1,207 +1,258 @@
import type { Project } from '@/types';
const sharedCases: Project[] = [
{
id: 'digital-securities-platform',
featured: true,
type: 'product',
status: 'completed',
role: 'Frontend Architecture Lead',
impact: 'Delivered a stable trading platform for multi-role financial institutions',
systemType: 'Financial blockchain trading platform',
context: 'A digital securities trading system for regulated institutions and operations teams.',
title: 'Digital Securities Trading Platform',
icon: 'Landmark',
color: 'blue',
image: {
bg: 'from-blue-500/20 to-indigo-600/20',
hover: 'from-blue-500/30 to-indigo-600/30',
text: 'text-blue-500',
},
challenges: [
'Complex multi-role permission boundaries',
'High reliability requirements for trading operations',
'Integration with blockchain wallet services',
],
responsibilities: [
'Designed frontend module architecture and domain boundaries',
'Led user management and permission refactor',
'Integrated bank login and compliance-related flows',
],
outcomes: [
'Improved operational stability with reliable release rhythm',
'Reduced permission-related defects through clearer boundaries',
'Supported business launch for institutional users',
],
description: [
'A digital asset trading system supporting regulated workflows.',
'Built for role-based operations, auditing, and risk-sensitive processes.',
],
tech: ['TypeScript', 'React', 'Node.js', 'Permission System'],
link: '#',
},
{
id: 'baas-platform',
featured: true,
type: 'product',
status: 'completed',
role: 'Senior Frontend Engineer',
impact: 'Enabled enterprise clients to manage blockchain services efficiently',
systemType: 'Blockchain BaaS platform',
context: 'Enterprise-grade blockchain service platform for chain management and operations.',
title: 'Blockchain BaaS Platform',
icon: 'Blocks',
color: 'violet',
image: {
bg: 'from-violet-500/20 to-fuchsia-500/20',
hover: 'from-violet-500/30 to-fuchsia-500/30',
text: 'text-violet-500',
},
challenges: [
'High-density operational console information',
'Complex asynchronous task status visibility',
'Multi-environment configuration consistency',
],
responsibilities: [
'Built scalable admin UI architecture for service management',
'Implemented observable task state flows and feedback loops',
'Drove reusable component patterns across modules',
],
outcomes: [
'Improved operation efficiency of chain service workflows',
'Reduced repetitive UI implementation with reusable patterns',
'Increased delivery speed in subsequent modules',
],
description: [
'A platform for enterprise blockchain network and service operations.',
'Focused on maintainability and operational efficiency.',
],
tech: ['React', 'TypeScript', 'Ant Design', 'WebSocket'],
link: '#',
},
{
id: 'supply-chain-finance',
featured: true,
type: 'client',
status: 'completed',
role: 'Full-stack Engineer',
impact: 'Supported finance workflows for upstream and downstream participants',
systemType: 'Supply chain finance platform',
context: 'A collaborative system connecting enterprises, finance teams, and partner organizations.',
title: 'Supply Chain Finance Platform',
icon: 'Network',
color: 'emerald',
image: {
bg: 'from-emerald-500/20 to-teal-500/20',
hover: 'from-emerald-500/30 to-teal-500/30',
text: 'text-emerald-500',
},
challenges: [
'Long business流程 with many states and edge cases',
'Cross-role data visibility requirements',
'Need for high traceability in approvals and operations',
],
responsibilities: [
'Implemented core workflow modules and state transitions',
'Designed role-specific views and permission controls',
'Optimized key pages for faster operational handling',
],
outcomes: [
'Improved workflow transparency across participants',
'Reduced process handover friction in finance operations',
'Enabled stable iterative delivery for business expansion',
],
description: [
'A multi-role financial workflow system for supply chain participants.',
'Focused on process clarity, reliability, and operations efficiency.',
],
tech: ['TypeScript', 'React', 'Node.js', 'PostgreSQL'],
link: '#',
},
{
id: 'smart-park-system',
featured: false,
type: 'client',
status: 'completed',
role: 'Frontend Engineer',
impact: 'Integrated business modules for industrial operations management',
systemType: 'Industrial smart park management system',
context: 'A digital management system for operations, resources, and service workflows in industrial parks.',
title: 'Industrial Smart Park Management System',
icon: 'Building2',
color: 'orange',
image: {
bg: 'from-orange-500/20 to-amber-500/20',
hover: 'from-orange-500/30 to-amber-500/30',
text: 'text-orange-500',
},
challenges: [
'Many business modules with different usage patterns',
'Dashboard readability for operation teams',
'Need for maintainable long-term module evolution',
],
responsibilities: [
'Developed key modules and unified UI interaction patterns',
'Improved dashboard information hierarchy and readability',
'Collaborated with backend and product teams for iterative delivery',
],
outcomes: [
'Improved operator experience in daily management tasks',
'Reduced UI inconsistency across modules',
'Supported long-term maintainability for continued delivery',
],
description: [
'A comprehensive system for industrial park operations and services.',
'Designed for clarity, consistency, and scalable module growth.',
],
tech: ['React', 'TypeScript', 'ECharts', 'REST API'],
link: '#',
},
{
id: 'elynd',
featured: false,
type: 'experiment',
status: 'building',
role: 'Founder & Developer',
impact: 'Exploring AI-assisted development workflows in production-like scenarios',
systemType: 'AI-assisted workspace',
context: 'An open workspace product exploring practical AI collaboration in software development.',
title: 'Elynd',
icon: 'Zap',
color: 'purple',
image: {
bg: 'from-purple-500/20 to-blue-500/20',
hover: 'from-purple-500/30 to-blue-500/30',
text: 'text-purple-500',
},
challenges: ['Designing useful AI workflows without adding process burden'],
responsibilities: ['Product exploration and end-to-end implementation'],
outcomes: ['Validated several practical AI-assisted development patterns'],
description: [
'An open AI workspace for builders.',
'Used as an R&D track, not the primary professional narrative.',
],
tech: ['TypeScript', 'React', 'AI Workflow', 'Open Source'],
link: '#',
},
];
export const projects = {
en: [
{
id: "elynd",
featured: true,
type: "product",
status: "building",
role: "Founder & Lead Developer",
impact: "Building an open AI workspace for builders",
title: "Elynd",
icon: "Zap",
color: "purple",
image: {
bg: "from-purple-500/20 to-blue-500/20",
hover: "from-purple-500/30 to-blue-500/30",
text: "text-purple-400",
},
description: [
"An open AI workspace for builders to work smarter.",
"Built with AI-first principles, making AI your co-builder.",
"Fully open source and self-hostable.",
"Currently in active development with early access coming soon.",
],
tech: ["TypeScript", "React", "AI/ML", "Open Source"],
link: "#",
links: {
demo: "#",
github: "https://github.com",
},
},
{
id: "taskify",
type: "client",
status: "completed",
role: "Lead Developer",
impact: "Helped startup launch MVP in 3 months",
title: "Taskify App",
tag: "business",
icon: "Smartphone",
color: "purple",
image: {
bg: "from-purple-500/20 to-purple-600/20",
hover: "from-purple-500/20 to-purple-600/20",
text: "text-purple-400",
},
description: [
"A comprehensive task management application with drag-and-drop functionality.",
"Built with React, TypeScript, and Tailwind CSS using modern development approaches.",
"Real-time collaboration through WebSocket integration for instant updates.",
"Advanced task filtering, sorting, and project management capabilities.",
],
tech: ["React", "Node.js", "MongoDB"],
link: "#",
},
{
id: "eshop",
type: "client",
status: "completed",
role: "Full-stack Developer",
impact: "E-commerce platform handling $100K+ monthly revenue",
title: "E-Shop Platform",
tag: "business",
icon: "ShoppingCart",
color: "green",
image: {
bg: "from-green-500/20 to-green-600/20",
hover: "from-green-500/20 to-green-600/20",
text: "text-green-400",
},
description: [
"Scalable e-commerce platform built with Next.js, Stripe payments, and TailwindCSS.",
"Mobile-first responsive design for optimal user experience across devices.",
"Integrated payment processing with Stripe for secure transactions.",
"Admin dashboard for inventory management and order processing.",
],
tech: ["Next.js", "Stripe", "TailwindCSS"],
link: "#",
},
{
id: "portfolio",
type: "experiment",
status: "completed",
role: "Creator",
impact: "Personal brand and portfolio showcasing",
title: "Portfolio Site",
tag: "portfolio",
icon: "Globe",
color: "purple",
image: {
bg: "from-purple-500/20 to-purple-600/20",
hover: "from-purple-500/20 to-purple-600/20",
text: "text-purple-400",
},
description: [
"Personal portfolio showcasing my work, built with HTML, TailwindCSS, and Alpine.js.",
"Responsive design with dark mode support and smooth animations.",
"Optimized for performance with minimal JavaScript and efficient CSS.",
"Integrated blog section with markdown support for content management.",
],
tech: ["HTML", "TailwindCSS", "Alpine.js"],
link: "#",
},
],
en: sharedCases,
zh: [
{
id: "elynd",
featured: true,
type: "product",
status: "building",
role: "创始人 & 首席开发者",
impact: "构建面向构建者的开放 AI 工作空间",
title: "Elynd",
icon: "Zap",
color: "purple",
image: {
bg: "from-purple-500/20 to-blue-500/20",
hover: "from-purple-500/30 to-blue-500/30",
text: "text-purple-400",
},
description: [
"一个面向构建者的开放 AI 工作空间。",
"从 AI 第一性原理出发,让 AI 成为你的共同构建者。",
"完全开源,可自托管。",
"目前正在积极开发中,早期访问即将推出。",
],
tech: ["TypeScript", "React", "AI/ML", "开源"],
link: "#",
links: {
demo: "#",
github: "https://github.com",
},
...sharedCases[0],
role: '前端架构负责人',
impact: '为多角色金融机构交付稳定的交易平台',
systemType: '数字证券金融区块链交易平台',
context: '面向受监管机构与运营团队的数字证券交易系统。',
title: '数字证券交易平台',
challenges: ['多角色复杂权限边界', '交易场景下的高稳定性要求', '区块链钱包服务集成'],
responsibilities: ['设计前端模块化架构与领域边界', '主导用户与权限体系重构', '接入银行登录与合规相关流程'],
outcomes: ['提升系统稳定性与发版可控性', '通过边界治理降低权限类缺陷', '支撑机构端业务落地'],
description: ['支持受监管流程的数字资产交易系统。', '强调角色权限、审计可追踪和风险敏感流程。'],
tech: ['TypeScript', 'React', 'Node.js', '权限系统'],
},
{
id: "taskify",
type: "client",
status: "completed",
role: "首席开发者",
impact: "帮助创业公司在3个月内推出 MVP",
title: "Taskify 应用",
tag: "business",
icon: "Smartphone",
color: "purple",
image: {
bg: "from-purple-500/20 to-purple-600/20",
hover: "from-purple-500/20 to-purple-600/20",
text: "text-purple-400",
},
description: [
"一个全面的任务管理应用,具有拖放功能。",
"使用React、TypeScript和Tailwind CSS构建采用现代开发方法。",
"通过WebSocket集成实现实时协作功能实现即时更新。",
"高级任务筛选、排序和项目管理功能。",
],
tech: ["React", "Node.js", "MongoDB"],
link: "#",
...sharedCases[1],
role: '资深前端工程师',
impact: '帮助企业客户高效管理区块链服务',
systemType: '区块链 BaaS 平台',
context: '面向企业的链服务管理与运维平台。',
title: '区块链 BaaS 平台',
challenges: ['高密度运维信息的可读性', '异步任务状态可观察性', '多环境配置一致性'],
responsibilities: ['构建可扩展的管理端前端架构', '实现可追踪任务状态反馈链路', '推动跨模块可复用组件方案'],
outcomes: ['提升链服务运维效率', '减少重复 UI 开发成本', '提高后续模块迭代速度'],
description: ['面向企业区块链网络与服务运维的平台。', '重点优化可维护性与操作效率。'],
tech: ['React', 'TypeScript', 'Ant Design', 'WebSocket'],
},
{
id: "eshop",
type: "client",
status: "completed",
role: "全栈开发者",
impact: "电商平台月营收超过 10 万美元",
title: "电商平台",
tag: "business",
icon: "ShoppingCart",
color: "green",
image: {
bg: "from-green-500/20 to-green-600/20",
hover: "from-green-500/20 to-green-600/20",
text: "text-green-400",
},
description: [
"使用Next.js、Stripe支付和TailwindCSS构建的可扩展电子商务平台。",
"采用移动优先的响应式设计,提供最佳用户体验。",
"集成Stripe支付处理确保交易安全。",
"管理员仪表板,用于库存管理和订单处理。",
],
tech: ["Next.js", "Stripe", "TailwindCSS"],
link: "#",
...sharedCases[2],
role: '全栈工程师',
impact: '支撑上下游参与方的金融协作流程',
systemType: '供应链金融平台',
context: '连接企业、金融团队与合作方的协同业务系统。',
title: '供应链金融平台',
challenges: ['长链路流程状态与边界处理', '跨角色数据可见性策略', '审批与操作的高可追踪性'],
responsibilities: ['实现核心流程模块与状态流转', '设计角色化视图与权限控制', '优化关键页面操作效率'],
outcomes: ['提升参与方流程透明度', '降低金融业务交接摩擦', '支撑业务扩展中的稳定迭代'],
description: ['面向多角色协同的金融业务流程系统。', '强调流程清晰、可靠与高效操作。'],
tech: ['TypeScript', 'React', 'Node.js', 'PostgreSQL'],
},
{
id: "portfolio",
type: "experiment",
status: "completed",
role: "创作者",
impact: "个人品牌和作品集展示",
title: "个人作品集网站",
tag: "portfolio",
icon: "Globe",
color: "purple",
image: {
bg: "from-purple-500/20 to-purple-600/20",
hover: "from-purple-500/20 to-purple-600/20",
text: "text-purple-400",
},
description: [
"展示我的作品的个人作品集使用HTML、TailwindCSS和Alpine.js构建。",
"响应式设计,支持暗黑模式和平滑动画。",
"通过最小化JavaScript和高效CSS优化性能。",
"集成博客部分支持markdown内容管理。",
],
tech: ["HTML", "TailwindCSS", "Alpine.js"],
link: "#",
...sharedCases[3],
role: '前端工程师',
impact: '整合园区管理核心业务模块',
systemType: '工业智慧园区管理系统',
context: '覆盖园区运营、资源和服务流程的数字化管理平台。',
title: '工业智慧园区管理系统',
challenges: ['多业务模块交互差异大', '运营看板信息层级复杂', '模块长期演进可维护性要求高'],
responsibilities: ['开发关键模块并统一交互模式', '优化看板信息层级与可读性', '与后端及产品团队协同迭代交付'],
outcomes: ['提升日常运营管理效率', '减少跨模块 UI 不一致问题', '支撑长期可维护迭代'],
description: ['园区运营与服务协同的一体化系统。', '强调清晰性、一致性与可扩展演进。'],
tech: ['React', 'TypeScript', 'ECharts', 'REST API'],
},
{
...sharedCases[4],
role: '创始人 & 开发者',
impact: '在真实场景中探索 AI 协作开发工作流',
systemType: 'AI 协作工作空间',
context: '探索 AI 在软件工程中可落地协作方式的开放产品。',
title: 'Elynd',
challenges: ['在不增加流程负担前提下设计有效 AI 工作流'],
responsibilities: ['产品探索与端到端实现'],
outcomes: ['验证多种可实践的 AI 协作开发模式'],
description: ['一个面向构建者的开放 AI 工作空间。', '作为研发探索方向,不作为职业主叙事。'],
tech: ['TypeScript', 'React', 'AI 协作', '开源'],
},
],
};

39
src/lib/data/uses.ts Normal file
View File

@@ -0,0 +1,39 @@
import type { UsesGroup } from '@/types';
export const uses: UsesGroup[] = [
{
title: {
en: 'Editor',
zh: '编辑器',
},
items: ['VS Code', 'Cursor', 'Zed'],
},
{
title: {
en: 'Languages',
zh: '语言',
},
items: ['TypeScript', 'JavaScript', 'SQL', 'Bash'],
},
{
title: {
en: 'Frameworks',
zh: '框架',
},
items: ['React', 'Astro', 'Node.js', 'Vue 3'],
},
{
title: {
en: 'Infrastructure',
zh: '基础设施',
},
items: ['Docker', 'Nginx', 'Linux', 'PostgreSQL'],
},
{
title: {
en: 'AI Workflow',
zh: 'AI 协作工作流',
},
items: ['ChatGPT', 'Claude', 'Codex', 'Agentic development workflow'],
},
];

View File

@@ -1,220 +1,70 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import HighlightBox from "@/components/markdown/HighlightBox.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
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,
};
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { personalInfo } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const t = useTranslations(lang);
const pageTitle = t("about.title");
const isZh = lang === 'zh';
const focusAreas = isZh
? ['前端架构设计与模块治理', '大型企业应用工程化交付', '金融与区块链系统前端建设', 'AI 协作开发流程实践']
: ['Frontend architecture and module governance', 'Large-scale enterprise application delivery', 'Financial and blockchain system engineering', 'AI-assisted development workflow practices'];
const experienceNotes = isZh
? [
'8 年专业开发经验,持续参与复杂业务系统建设。',
'参与多个政府与金融科技相关系统,包括交易平台、区块链基础设施、产业管理系统。',
'擅长跨角色协作与远程异步沟通,注重稳定交付与长期可维护性。',
]
: [
'8 years of professional development experience across complex business systems.',
'Contributed to government- and fintech-related systems, including trading platforms, blockchain infrastructure, and industrial management systems.',
'Strong in cross-functional collaboration and remote async execution with long-term maintainability in mind.',
];
---
<Layout title={pageTitle}>
<GlassHeader client:load transition:persist="header" lang={lang} />
<main class="min-h-screen relative overflow-hidden pt-16 sm:pt-20">
<!-- Background Decor -->
<div class="fixed inset-0 -z-10 h-full w-full bg-background">
<div class="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-primary/5 dark:from-primary/10 dark:via-transparent dark:to-primary/5"></div>
</div>
<Layout title={isZh ? '关于' : 'About'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<!-- Hero Section -->
<section class="relative z-10 py-16 md:py-24">
<Container>
<div class="max-w-4xl mx-auto">
<div class="flex flex-col md:flex-row items-center gap-12 mb-16">
<div class="relative group">
<div class="absolute -inset-1 rounded-full bg-gradient-to-r from-primary to-purple-600 opacity-75 blur transition duration-1000 group-hover:opacity-100 group-hover:duration-200"></div>
<div class="relative h-48 w-48 rounded-full border-4 border-background overflow-hidden bg-muted">
<img
src="/avatar.png"
alt="Joey Zhao"
class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-110"
onerror="this.src='https://ui-avatars.com/api/?name=Joy+Zhao&background=0D8ABC&color=fff&size=200'"
/>
</div>
</div>
<div class="text-center md:text-left space-y-6">
<h1 class="text-4xl md:text-6xl font-bold tracking-tight">
<span class="bg-gradient-to-r from-foreground to-foreground/70 bg-clip-text text-transparent">
{t('about.title')}
</span>
</h1>
<p class="text-xl text-muted-foreground leading-relaxed">
{t('about.description')}
</p>
</div>
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '关于我' : 'About'}</h1>
<p class="mt-6 text-lg leading-relaxed text-muted-foreground">{personalInfo.description[lang]}</p>
</section>
<section class="page-content-main mt-12 grid gap-6 lg:grid-cols-2">
<article class="page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '背景' : 'Background'}</h2>
<div class="mt-4 space-y-4 text-muted-foreground">
{personalInfo.about[lang].map((line) => <p>{line}</p>)}
</div>
</article>
<div class="grid gap-8">
<!-- Intro Box -->
<HighlightBox type="tip" title={t('about.intro.title')}>
<div class="space-y-4 py-2">
<p class="text-lg leading-relaxed whitespace-pre-line">{t('about.intro.content')}</p>
<div class="p-4 rounded-xl bg-primary/5 border border-primary/10 italic text-primary/80">
{t('about.intro.belief')}
</div>
</div>
</HighlightBox>
<article class="page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '技术焦点' : 'Technical Focus'}</h2>
<ul class="mt-4 space-y-3 text-muted-foreground">
{focusAreas.map((item) => (
<li class="flex gap-3"><span class="mt-2 h-1.5 w-1.5 rounded-full bg-primary"></span><span>{item}</span></li>
))}
</ul>
</article>
</section>
<!-- Self Intro -->
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Sparkles className="w-6 h-6 text-primary" />
{t('about.me.title')}
</h2>
<div class="prose dark:prose-invert max-w-none">
<p class="text-lg leading-relaxed text-muted-foreground whitespace-pre-line">
{t('about.me.content')}
</p>
</div>
</div>
<!-- Skills Grid -->
<div class="grid md:grid-cols-2 gap-8">
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Zap className="w-6 h-6 text-yellow-500" />
{t('about.skills.mastered.title')}
</h2>
<div class="flex flex-wrap gap-2">
{(t('about.skills.mastered.items') as unknown as string[]).map((item: string) => (
<div class="px-3 py-1.5 rounded-lg bg-primary/5 border border-primary/10 text-muted-foreground text-xs font-medium">
{item}
</div>
))}
</div>
</div>
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Heart className="w-6 h-6 text-red-500" />
{t('about.skills.learning.title')}
</h2>
<div class="flex flex-wrap gap-2">
{(t('about.skills.learning.items') as unknown as string[]).map((item: string) => (
<div class="px-3 py-1.5 rounded-lg bg-muted/30 border border-border/50 text-muted-foreground/70 text-xs font-medium">
{item}
</div>
))}
</div>
</div>
</div>
<!-- Interests -->
<div class="space-y-8">
<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')}
</h2>
<ul class="grid sm:grid-cols-2 gap-4">
{(t('about.interests.items') as unknown as any[]).map((item) => (
<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">
<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>
</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>
<!-- Contact -->
<div class="space-y-8 py-8">
<div class="px-2 space-y-4">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Mail className="w-6 h-6 text-primary" />
{t('about.contact.title')}
</h2>
<p class="text-muted-foreground leading-relaxed max-w-2xl">
{t('about.contact.warning')}
</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{(t('about.contact.methods') as unknown as any[]).map((method) => {
const Icon = IconMap[method.icon] || MessageSquare;
const content = (
<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 class="flex flex-col">
<span class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{method.label}</span>
<span class="text-sm font-medium break-all">{method.value}</span>
</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>
</Container>
</section>
<section class="page-content-main mt-6 page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '经验概览' : 'Experience'}</h2>
<ul class="mt-4 space-y-3 text-muted-foreground">
{experienceNotes.map((item) => (
<li class="flex gap-3"><span class="mt-2 h-1.5 w-1.5 rounded-full bg-primary"></span><span>{item}</span></li>
))}
</ul>
</section>
</Container>
</main>
<Footer client:load lang={lang} />
<Footer lang={lang} client:load />
</Layout>

View File

@@ -43,16 +43,16 @@ const sortedBlogPosts = sortPostsByDate(blogPosts);
---
<BlogLayout title="Blog - Joey Zhao" description="Thoughts on AI products, full-stack development, and building in public. Explore my latest posts below.">
<BlogLayout title="Writing - Joey Zhao" description="Engineering notes on architecture, delivery, and AI-assisted development workflows.">
<main class="min-h-screen">
<!-- Header Section -->
<Container className="pt-24 pb-12">
<div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-primary to-primary dark:from-foreground dark:via-blue-200 dark:to-orange-300 bg-clip-text text-transparent mb-6">
<span class="text-primary">Blog</span>
<span class="text-primary">Writing</span>
</h1>
<p class="text-xl text-muted-foreground page-content-main">
Thoughts on AI products, full-stack development, and building in public. Exploring the intersection of technology and product building.
Engineering notes on architecture, delivery, and AI-assisted development workflows.
</p>
</div>
</Container>

62
src/pages/contact.astro Normal file
View File

@@ -0,0 +1,62 @@
---
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { contactIntents, contactMethods } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
---
<Layout title={isZh ? '联系' : 'Contact'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '联系' : 'Contact'}</h1>
<p class="mt-4 text-lg text-muted-foreground">
{isZh
? '欢迎联系我沟通远程岗位或项目合作。默认优先响应远程岗位机会。'
: 'Open to remote role opportunities and project collaboration. Remote role discussions are prioritized.'}
</p>
</section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-2">
{contactIntents.map((intent) => (
<article id={intent.id} class="page-surface p-6">
<h2 class="text-xl font-bold">{intent.title[lang]}</h2>
<p class="mt-3 text-muted-foreground">{intent.description[lang]}</p>
</article>
))}
</section>
<section class="page-content-main mt-6 page-surface p-6">
<h2 class="text-xl font-bold">{isZh ? '联系方式' : 'Contact Methods'}</h2>
<ul class="mt-4 space-y-3 text-sm">
{contactMethods.map((method) => (
<li class="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between border-b border-border/70 pb-3">
<span class="font-semibold text-foreground">{method.label[lang]}</span>
{method.href ? (
<a href={method.href} target="_blank" rel="noopener noreferrer" class="text-primary hover:text-primary/80 break-all">{method.value}</a>
) : (
<span class="text-muted-foreground break-all">{method.value}</span>
)}
</li>
))}
</ul>
<p class="mt-5 text-xs text-muted-foreground">
{isZh
? '联系建议:请在邮件中注明岗位/项目背景、期望合作方式与时间窗口。'
: 'Suggestion: include role/project context, expected collaboration model, and timeline in your first message.'}
</p>
</section>
</Container>
</main>
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,375 +1,3 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import { useTranslations } from "@/i18n/utils";
import { Users, Wrench, Lightbulb, Handshake, CircleDollarSign, Clock, Target, Check, Calendar, Mail, Radio, Zap, Globe, Smartphone, ShoppingCart, Layout as LayoutIcon, ClipboardList } from "lucide-react";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const pageTitle = lang === 'zh' ? '合作' : 'Hire Me';
return Astro.redirect('/contact', 301);
---
<Layout title={pageTitle}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen">
<!-- Hire Page Hero -->
<section class="py-24 relative overflow-hidden">
<div class="page-hero-overlay"></div>
<Container className="relative z-10">
<div class="text-center mb-16">
<span class="inline-block px-4 py-1 bg-primary/20 text-primary dark:text-primary rounded-full text-sm font-medium mb-4">
{lang === 'zh' ? '专业合作' : 'Professional Collaboration'}
</span>
<h1 class="page-title-gradient text-5xl md:text-6xl font-bold mb-6">
{lang === 'zh' ? '合作' : 'Hire Me'}
</h1>
<p class="text-lg text-muted-foreground page-content-narrow">
{lang === 'zh'
? '构建优秀产品,从找到合适的技术合伙人开始'
: 'Building great products starts with finding the right technical partner'}
</p>
</div>
</Container>
</section>
<!-- Who I Work With -->
<section class="py-16 relative">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-primary/20 rounded-xl flex items-center justify-center">
<Users className="w-6 h-6 text-primary" />
</div>
<h2 class="text-3xl font-bold">
{lang === 'zh' ? '我与谁合作' : 'Who I Work With'}
</h2>
</div>
<div class="grid md:grid-cols-2 gap-6">
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
{lang === 'zh' ? '初创公司' : 'Startups'}
</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '从零到一构建产品的早期创业团队,需要快速迭代和灵活响应的技术方案。'
: 'Early-stage startup teams building products from scratch, needing fast iteration and flexible technical solutions.'}
</p>
</div>
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
{lang === 'zh' ? '独立创始人' : 'Indie Hackers'}
</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '独自构建产品的创业者,需要技术合伙人来实现产品愿景。'
: 'Solo founders building products who need a technical partner to realize their product vision.'}
</p>
</div>
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
{lang === 'zh' ? '传统企业' : 'Traditional Businesses'}
</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '希望数字化转型的传统企业,需要现代化的技术解决方案。'
: 'Traditional businesses looking to go digital and need modern technical solutions.'}
</p>
</div>
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
{lang === 'zh' ? '技术团队' : 'Technical Teams'}
</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '需要额外技术资源或特定技能集来推进项目的开发团队。'
: 'Development teams needing additional technical resources or specific skill sets to move projects forward.'}
</p>
</div>
</div>
</div>
</Container>
</section>
<!-- What I Build -->
<section class="py-16 relative page-section-soft">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-blue-500/20 rounded-xl flex items-center justify-center">
<Wrench className="w-6 h-6 text-blue-500" />
</div>
<h2 class="text-3xl font-bold">
{lang === 'zh' ? '我能构建什么' : 'What I Build'}
</h2>
</div>
<div class="space-y-6">
<div class="page-surface p-8">
<div class="flex items-start gap-4">
<div class="w-12 h-12 bg-gradient-to-br from-primary to-blue-600 rounded-xl flex items-center justify-center flex-shrink-0">
<Zap className="w-6 h-6 text-white" />
</div>
<div>
<h3 class="text-xl font-bold mb-2">AI 产品与应用</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '从 AI 助手到 Agent 系统,从 RAG 应用到 AI 驱动的 SaaS 产品。我可以帮助你将 AI 能力产品化。'
: 'From AI assistants to Agent systems, from RAG applications to AI-powered SaaS products. I can help you productize AI capabilities.'}
</p>
</div>
</div>
</div>
<div class="page-surface p-8">
<div class="flex items-start gap-4">
<div class="w-12 h-12 bg-gradient-to-br from-green-600 to-teal-600 rounded-xl flex items-center justify-center flex-shrink-0">
<Globe className="w-6 h-6 text-white" />
</div>
<div>
<h3 class="text-xl font-bold mb-2">Web 应用</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '现代 Web 应用、SaaS 平台、电商系统、内容管理系统等。使用 React、Next.js、Node.js 等技术栈。'
: 'Modern web applications, SaaS platforms, e-commerce systems, content management systems, etc. Using React, Next.js, Node.js and other tech stacks.'}
</p>
</div>
</div>
</div>
<div class="page-surface p-8">
<div class="flex items-start gap-4">
<div class="w-12 h-12 bg-gradient-to-br from-orange-600 to-red-600 rounded-xl flex items-center justify-center flex-shrink-0">
<Smartphone className="w-6 h-6 text-white" />
</div>
<div>
<h3 class="text-xl font-bold mb-2">全栈产品</h3>
<p class="text-muted-foreground">
{lang === 'zh'
? '从前端到后端,从数据库到部署,我提供完整的全栈开发能力,一个项目只需一个开发者。'
: 'From frontend to backend, from database to deployment, I provide complete full-stack development capabilities - one developer for the entire project.'}
</p>
</div>
</div>
</div>
</div>
</div>
</Container>
</section>
<!-- Engagement Models -->
<section class="py-16 relative">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-green-500/20 rounded-xl flex items-center justify-center">
<ClipboardList className="w-6 h-6 text-green-500" />
</div>
<h2 class="text-3xl font-bold">
{lang === 'zh' ? '合作模式' : 'Engagement Models'}
</h2>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div class="page-surface p-6 text-center">
<div class="w-12 h-12 bg-green-500/20 rounded-xl flex items-center justify-center mx-auto mb-4">
<Handshake className="w-6 h-6 text-green-600 dark:text-green-400" />
</div>
<h3 class="text-lg font-bold mb-2">
{lang === 'zh' ? '技术合伙人' : 'Technical Co-founder'}
</h3>
<p class="text-sm text-muted-foreground">
{lang === 'zh'
? '长期合作,股权合作,共同承担创业风险与回报'
: 'Long-term partnership, equity-based, sharing startup risks and rewards'}
</p>
</div>
<div class="page-surface p-6 text-center">
<div class="w-12 h-12 bg-blue-500/20 rounded-xl flex items-center justify-center mx-auto mb-4">
<CircleDollarSign className="w-6 h-6 text-blue-600 dark:text-blue-400" />
</div>
<h3 class="text-lg font-bold mb-2">
{lang === 'zh' ? '项目制' : 'Project-based'}
</h3>
<p class="text-sm text-muted-foreground">
{lang === 'zh'
? '按项目交付,固定价格或按阶段付款,适合明确需求的项目'
: 'Fixed-price or milestone-based, suitable for projects with clear requirements'}
</p>
</div>
<div class="page-surface p-6 text-center">
<div class="w-12 h-12 bg-primary/20 rounded-xl flex items-center justify-center mx-auto mb-4">
<Clock className="w-6 h-6 text-primary" />
</div>
<h3 class="text-lg font-bold mb-2">
{lang === 'zh' ? '咨询/顾问' : 'Consulting'}
</h3>
<p class="text-sm text-muted-foreground">
{lang === 'zh'
? '按小时咨询,帮助你做出技术决策,审查代码,指导团队'
: 'Hourly consulting, helping you make technical decisions, code reviews, team guidance'}
</p>
</div>
</div>
</div>
</Container>
</section>
<!-- Delivery Style -->
<section class="py-16 relative page-section-soft">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-yellow-500/20 rounded-xl flex items-center justify-center">
<Target className="w-6 h-6 text-yellow-600 dark:text-yellow-400" />
</div>
<h2 class="text-3xl font-bold">
{lang === 'zh' ? '工作方式' : 'Delivery Style'}
</h2>
</div>
<div class="page-surface p-8">
<ul class="space-y-4">
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">
{lang === 'zh' ? '敏捷迭代' : 'Agile Iteration'}
</strong>
<p class="text-muted-foreground text-sm">
{lang === 'zh'
? '2周一个迭代快速交付可用功能持续获取反馈'
: '2-week sprints, rapid delivery of usable features, continuous feedback'}
</p>
</div>
</li>
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">
{lang === 'zh' ? '透明沟通' : 'Transparent Communication'}
</strong>
<p class="text-muted-foreground text-sm">
{lang === 'zh'
? '定期同步进度,及时报告问题,保持信息对称'
: 'Regular progress updates, timely issue reporting, keeping information symmetric'}
</p>
</div>
</li>
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">
{lang === 'zh' ? '代码质量' : 'Code Quality'}
</strong>
<p class="text-muted-foreground text-sm">
{lang === 'zh'
? '完整的测试覆盖,清晰的文档注释,可维护的代码结构'
: 'Complete test coverage, clear documentation, maintainable code structure'}
</p>
</div>
</li>
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">
{lang === 'zh' ? '产品思维' : 'Product Thinking'}
</strong>
<p class="text-muted-foreground text-sm">
{lang === 'zh'
? '不只是写代码,还思考产品价值,用户体验 and 业务目标'
: 'Not just writing code, but also thinking about product value, user experience, and business goals'}
</p>
</div>
</li>
</ul>
</div>
</div>
</Container>
</section>
<!-- Availability -->
<section class="py-16 relative">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-red-500/20 rounded-xl flex items-center justify-center">
<Calendar className="w-6 h-6 text-red-500" />
</div>
<h2 class="text-3xl font-bold">
{lang === 'zh' ? '当前可用性' : 'Availability'}
</h2>
</div>
<div class="page-surface p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-4 h-4 bg-green-500 rounded-full animate-pulse"></div>
<span class="text-lg font-semibold">
{lang === 'zh' ? '目前可接受新项目' : 'Currently Available for New Projects'}
</span>
</div>
<p class="text-muted-foreground mb-6">
{lang === 'zh'
? '我目前可以接受 1-2 个新项目。偏好长期合作模式(技术合伙人或长期项目),但也会考虑短期项目。'
: 'I can currently take on 1-2 new projects. Prefer long-term partnership (technical co-founder or long-term projects), but also open to short-term projects.'}
</p>
<div class="flex flex-wrap gap-2">
<span class="px-3 py-1 bg-green-500/20 text-green-600 dark:text-green-400 rounded-full text-sm">
{lang === 'zh' ? '可立即开始' : 'Available immediately'}
</span>
<span class="px-3 py-1 bg-blue-500/20 text-blue-600 dark:text-blue-400 rounded-full text-sm">
{lang === 'zh' ? '远程工作' : 'Remote only'}
</span>
<span class="px-3 py-1 bg-primary/20 text-primary dark:text-primary rounded-full text-sm">
{lang === 'zh' ? '中英双语' : 'Bilingual EN/ZH'}
</span>
</div>
</div>
</div>
</Container>
</section>
<!-- Contact CTA -->
<section class="py-16 relative page-section-soft">
<Container>
<div class="page-content-main text-center">
<h2 class="text-3xl font-bold mb-6">
{lang === 'zh' ? '准备好一起构建了吗?' : 'Ready to build together?'}
</h2>
<p class="text-lg text-muted-foreground mb-8 page-content-narrow">
{lang === 'zh'
? '告诉我你的项目想法,让我们看看能否合作。'
: "Tell me about your project idea and let's see if we can work together."}
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="mailto:zhaoguiyang18@gmail.com"
class="bg-primary hover:bg-primary/90 text-white px-8 py-3 rounded-lg font-semibold transition-colors inline-flex items-center justify-center gap-2"
>
<Mail className="w-5 h-5" />
{lang === 'zh' ? '发送邮件' : 'Send Email'}
</a>
<a
href={lang === 'zh' ? '/zh/now' : '/now'}
class="border border-primary text-primary hover:bg-primary hover:text-white px-8 py-3 rounded-lg font-semibold transition-colors inline-flex items-center justify-center gap-2"
>
<Radio className="w-5 h-5" />
{lang === 'zh' ? '了解更多关于我' : 'Learn More About Me'}
</a>
</div>
</div>
</Container>
</section>
</main>
<Footer lang={lang} client:only="react" />
</Layout>

View File

@@ -1,239 +1,109 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import ProjectCard from "@/components/ProjectCard.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import { personalInfo, services, projects } from "@/lib/data/index";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { personalInfo, projects } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
import { sortPostsByDate } from '@/utils/blog-utils';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const t = useTranslations(lang);
const pageTitle = t("site.title");
const prefix = lang === "zh" ? "/zh" : "";
const isZh = lang === 'zh';
const prefix = isZh ? '/zh' : '';
const featuredProjects = projects[lang].filter((item) => item.featured).slice(0, 3);
const localizedServices = services[lang];
const featuredProjects = projects[lang].filter((project) => project.featured);
const proofItems = isZh
? ['8 年 Web 开发经验', '企业级复杂系统交付', '金融与区块链基础设施', '远程协作与稳定交付']
: ['8 years in web engineering', 'Enterprise-grade complex systems', 'Finance & blockchain infrastructure', 'Remote-first stable delivery'];
const careerMilestones = [
{
period: t("home.career.card1.period"),
title: t("home.career.card1.title"),
outcome: t("home.career.card1.outcome"),
},
{
period: t("home.career.card2.period"),
title: t("home.career.card2.title"),
outcome: t("home.career.card2.outcome"),
},
{
period: t("home.career.card3.period"),
title: t("home.career.card3.title"),
outcome: t("home.career.card3.outcome"),
},
];
const headline = isZh
? '资深前端工程师,构建复杂系统与 AI 协作产品'
: 'Senior Frontend Engineer building complex systems and AI-assisted products';
const keyFacts = [
t("home.trust.item1"),
t("home.trust.item3"),
t("home.trust.item4"),
];
const intro = personalInfo.description[lang];
const postModules = await import.meta.glob('./blog/posts/*.md', { eager: true });
const latestPosts = sortPostsByDate(
Object.values(postModules).map((post: any) => ({
title: post.frontmatter.title,
description: post.frontmatter.description || '',
slug: post.url?.split('/').filter(Boolean).pop() || '',
date: post.frontmatter.date || post.frontmatter.pubDate || '',
})),
).slice(0, 3);
---
<Layout title={pageTitle}>
<GlassHeader client:load transition:persist="header" lang={lang} />
<Layout title={isZh ? '首页' : 'Home'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen">
<div class="relative overflow-hidden">
<div class="absolute inset-0 -z-10">
<div class="absolute left-1/2 top-0 h-[600px] w-[800px] -translate-x-1/2 -translate-y-1/2 bg-primary/10 blur-[120px]"></div>
<div class="absolute right-0 top-1/4 h-[400px] w-[400px] bg-purple-500/5 blur-[100px]"></div>
<div class="absolute left-0 top-1/2 h-[400px] w-[400px] bg-orange-500/5 blur-[100px]"></div>
</div>
<section class="relative flex min-h-[80vh] items-center py-20 lg:py-28">
<Container className="relative z-10">
<div class="mx-auto max-w-5xl space-y-12">
<div class="space-y-8 text-center">
<div class="space-y-4">
<h1 class="text-5xl font-bold tracking-tight sm:text-7xl lg:text-8xl">
<span class="bg-gradient-to-b from-foreground to-foreground/70 bg-clip-text text-transparent">{personalInfo.name}</span>
</h1>
<p class="text-2xl font-medium text-foreground/80 sm:text-3xl">{personalInfo.position[lang]}</p>
</div>
<p class="mx-auto max-w-2xl text-lg leading-relaxed text-muted-foreground/90 sm:text-xl">{t("home.hero.summary")}</p>
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main space-y-8">
<p class="text-sm font-semibold uppercase tracking-[0.2em] text-primary">{isZh ? 'ENGINEERING PROFILE' : 'ENGINEERING PROFILE'}</p>
<h1 class="text-4xl font-bold tracking-tight text-foreground sm:text-5xl lg:text-6xl">{headline}</h1>
<p class="max-w-3xl text-lg leading-relaxed text-muted-foreground">{intro}</p>
<div class="flex flex-wrap items-center justify-center gap-4">
<a href={`${prefix}/about`} class="inline-flex h-12 items-center justify-center rounded-full bg-primary px-8 text-sm font-semibold text-primary-foreground shadow-lg shadow-primary/20 transition-all hover:translate-y-[-2px] hover:bg-primary/90 hover:shadow-xl hover:shadow-primary/30">
{t("home.hero.ctaPrimary")}
</a>
<a href={`${prefix}/hire`} class="inline-flex h-12 items-center justify-center rounded-full border border-border bg-background/50 px-8 text-sm font-semibold text-foreground backdrop-blur-sm transition-all hover:translate-y-[-2px] hover:bg-muted">
{t("home.hero.ctaSecondary")}
</a>
</div>
</div>
<div class="mx-auto max-w-3xl space-y-8">
<div class="flex flex-wrap items-center justify-center gap-3 text-sm">
{keyFacts.map((item) => (
<span class="inline-flex items-center rounded-full border border-primary/10 bg-primary/5 px-4 py-1.5 font-medium text-primary/80 backdrop-blur-sm">
<span class="mr-2 h-1 w-1 rounded-full bg-primary/50"></span>
{item}
</span>
))}
</div>
<div class="group relative">
<div class="absolute -inset-1 rounded-2xl bg-gradient-to-r from-primary/20 to-purple-500/20 opacity-50 blur transition duration-1000 group-hover:opacity-100 group-hover:duration-200"></div>
<div class="page-surface relative overflow-hidden rounded-2xl border bg-card/40 backdrop-blur-md">
<div class="flex items-center justify-between border-b border-border/50 bg-muted/20 px-5 py-3">
<div class="flex items-center gap-2">
<span class="h-3 w-3 rounded-full bg-red-400/80 shadow-[0_0_8px_rgba(248,113,113,0.4)]"></span>
<span class="h-3 w-3 rounded-full bg-yellow-400/80 shadow-[0_0_8px_rgba(250,204,21,0.4)]"></span>
<span class="h-3 w-3 rounded-full bg-green-400/80 shadow-[0_0_8px_rgba(74,222,128,0.4)]"></span>
</div>
<span class="font-mono text-xs font-medium text-muted-foreground/70 tracking-tight">{personalInfo.terminal.username}</span>
</div>
<div class="space-y-3 p-6 font-mono text-sm leading-relaxed text-foreground/90">
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">whoami</span> {personalInfo.name}</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">role</span> {personalInfo.position[lang]}</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">stack</span> TypeScript, React, Node.js, Astro</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">status</span> {t("home.hero.terminalStatus")}</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">contact</span> {personalInfo.github}</p>
</div>
</div>
</div>
</div>
</div>
<div class="flex flex-wrap gap-4 pt-2">
<a href={`${prefix}/contact`} class="inline-flex h-11 items-center rounded-lg bg-primary px-6 text-sm font-semibold text-primary-foreground hover:bg-primary/90">{isZh ? '远程岗位沟通' : 'Hire for Remote Role'}</a>
<a href={`${prefix}/contact#project-collaboration`} class="inline-flex h-11 items-center rounded-lg border border-border px-6 text-sm font-semibold text-foreground hover:bg-muted">{isZh ? '发起项目合作' : 'Start a Project'}</a>
</div>
</Container>
</section>
<div class="space-y-24 pb-24">
<section class="relative">
<div class="py-24 lg:py-32">
<Container>
<div class="mb-16 flex flex-col gap-6 md:flex-row md:items-end md:justify-between">
<div class="space-y-4">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">{t("home.services.title")}</h2>
<p class="max-w-2xl text-lg leading-relaxed text-muted-foreground/90">{t("home.services.description")}</p>
</div>
<a href={`${prefix}/services`} class="inline-flex items-center text-sm font-bold text-primary transition-colors hover:text-primary/70">
{t("services.viewAll")}
<svg class="ml-1 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/></svg>
</a>
</div>
<ul class="grid gap-3 sm:grid-cols-2 pt-4">
{proofItems.map((item) => (
<li class="page-surface p-4 text-sm font-medium text-foreground/90">{item}</li>
))}
</ul>
</section>
<div class="grid gap-10 md:grid-cols-2">
{localizedServices.map((service) => (
<article class="group relative rounded-2xl p-6 transition-all duration-500 hover:bg-card/50 hover:shadow-xl hover:shadow-primary/5">
<div class="mb-8 flex items-center gap-6">
<div class={`flex h-14 w-14 items-center justify-center rounded-2xl bg-gradient-to-br ${service.icon.gradient} text-white shadow-lg transition-transform duration-500 group-hover:scale-110 group-hover:rotate-3`}>
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<Fragment set:html={service.icon.svg} />
</svg>
</div>
<h3 class="text-2xl font-bold tracking-tight">{service.title}</h3>
</div>
<ul class="space-y-4">
{service.items.slice(0, 3).map((item) => (
<li class="flex items-start gap-3 text-muted-foreground group-hover:text-foreground/90 transition-colors">
<span class="mt-2.5 h-1 w-1 shrink-0 rounded-full bg-primary/30 group-hover:bg-primary transition-all"></span>
<span class="text-base leading-relaxed">{item}</span>
</li>
))}
</ul>
</article>
))}
</div>
</Container>
<section class="page-content-main mt-20">
<div class="mb-8 flex items-end justify-between gap-4">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">{isZh ? '精选工程案例' : 'Selected Engineering Cases'}</h2>
<a href={`${prefix}/projects`} class="text-sm font-semibold text-primary hover:text-primary/80">{isZh ? '查看全部案例' : 'View All Cases'}</a>
</div>
<div class="grid gap-6 lg:grid-cols-3">
{featuredProjects.map((project) => (
<article class="page-surface p-6">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{project.systemType}</p>
<h3 class="mt-2 text-lg font-bold">{project.title}</h3>
<p class="mt-3 text-sm leading-relaxed text-muted-foreground">{project.context}</p>
<p class="mt-4 text-xs font-semibold uppercase tracking-wide text-foreground/70">{isZh ? '结果' : 'Outcome'}</p>
<p class="mt-1 text-sm text-foreground/90">{project.outcomes?.[0] ?? project.impact}</p>
</article>
))}
</div>
</section>
<section class="relative">
<Container>
<div class="mb-16 space-y-3">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl">{t("home.career.title")}</h2>
<p class="max-w-xl text-lg text-muted-foreground">{t("home.career.description")}</p>
</div>
<section class="page-content-main mt-20">
<div class="mb-8 flex items-end justify-between gap-4">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">{isZh ? '最新写作' : 'Latest Writing'}</h2>
<a href={`${prefix}/blog`} class="text-sm font-semibold text-primary hover:text-primary/80">{isZh ? '查看全部文章' : 'View All Writing'}</a>
</div>
<div class="relative mx-auto max-w-4xl">
<div class="absolute left-0 top-0 h-full w-px bg-gradient-to-b from-primary/50 via-primary/10 to-transparent sm:left-1/2"></div>
<div class="space-y-12">
{careerMilestones.map((item, index) => (
<div class={`relative flex flex-col sm:flex-row ${index % 2 === 0 ? 'sm:flex-row-reverse' : ''}`}>
<div class="absolute -left-1.5 top-2 h-3 w-3 rounded-full border-2 border-primary bg-background sm:left-1/2 sm:-ml-1.5"></div>
<div class="w-full pl-8 sm:w-1/2 sm:px-12">
<article class="rounded-2xl p-4 transition-all hover:bg-card/40">
<span class="text-xs font-bold uppercase tracking-wider text-primary/60">{item.period}</span>
<h3 class="mt-2 text-xl font-bold leading-tight">{item.title}</h3>
<p class="mt-3 text-sm leading-relaxed text-muted-foreground/90">{item.outcome}</p>
</article>
</div>
</div>
))}
</div>
</div>
<div class="mt-16 text-center">
<a href={`${prefix}/about`} class="inline-flex h-12 items-center rounded-full border border-border bg-background px-8 text-sm font-semibold transition-all hover:bg-muted">
{t("home.career.cta")}
</a>
</div>
</Container>
</section>
<section class="relative">
<div class="py-24 lg:py-32">
<Container>
<div class="mb-12 space-y-3">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl">{t("home.featured.title")}</h2>
</div>
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{featuredProjects.map((project) => (
<ProjectCard project={project} lang={lang} />
))}
</div>
</Container>
<div class="grid gap-4 md:grid-cols-3">
{latestPosts.map((post) => (
<article class="page-surface p-5">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{post.date}</p>
<h3 class="mt-2 text-base font-bold leading-snug">
<a href={`${prefix}/blog/posts/${post.slug}`} class="hover:text-primary">{post.title}</a>
</h3>
<p class="mt-2 line-clamp-3 text-sm text-muted-foreground">{post.description}</p>
</article>
))}
</div>
</section>
<section class="relative">
<Container>
<div class="flex flex-col items-center text-center">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl mb-6">{t("home.final.title")}</h2>
<p class="text-lg leading-relaxed text-muted-foreground/90 sm:text-xl max-w-2xl mb-10">{t("home.final.description")}</p>
<div class="flex flex-wrap justify-center gap-4">
<a href={`${prefix}/about`} class="inline-flex h-12 items-center justify-center rounded-full bg-primary px-8 text-sm font-semibold text-primary-foreground transition-all hover:translate-y-[-2px] hover:bg-primary/90">
{t("home.final.ctaPrimary")}
</a>
<a href={`${prefix}/hire`} class="inline-flex h-12 items-center justify-center rounded-full border border-border px-8 text-sm font-semibold text-foreground transition-all hover:translate-y-[-2px] hover:bg-muted">
{t("home.final.ctaSecondary")}
</a>
</div>
</div>
</Container>
<section class="page-content-main mt-20 page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '下一步' : 'Next Step'}</h2>
<p class="mt-3 text-muted-foreground">{isZh ? '如果你正在招聘远程工程师,或希望推进复杂系统项目,我很乐意沟通。' : 'If you are hiring for a remote engineering role or need help shipping a complex system, I would love to connect.'}</p>
<div class="mt-6 flex flex-wrap gap-3">
<a href={`${prefix}/contact`} class="inline-flex h-10 items-center rounded-lg bg-primary px-5 text-sm font-semibold text-primary-foreground">{isZh ? '联系我' : 'Contact Me'}</a>
<a href={`${prefix}/about`} class="inline-flex h-10 items-center rounded-lg border border-border px-5 text-sm font-semibold hover:bg-muted">{isZh ? '了解更多' : 'About Me'}</a>
</div>
</section>
</div>
</div>
</main>
</Container>
</main>
<Footer lang={lang} client:only="react" />
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,228 +1,67 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import { useTranslations } from "@/i18n/utils";
import { Hammer, Zap, Telescope, Bot, Target, Rocket, Sparkles, MessageSquare, Handshake, MapPin } from "lucide-react";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const pageTitle = lang === 'zh' ? '现在' : 'Now';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
const doing = isZh
? ['推进工程化案例化的个人站升级', '优化远程协作下的交付流程与文档标准', '持续打磨 AI 协作开发实践']
: ['Upgrading this portfolio into an engineering case-study site', 'Improving remote-first delivery workflow and documentation quality', 'Refining practical AI-assisted development workflows'];
const exploring = isZh
? ['复杂权限系统的前端边界设计', '大规模业务表单与状态流管理', '更稳定的跨团队异步协作机制']
: ['Frontend boundary design for complex permission systems', 'Scalable state management for large business forms', 'More stable async collaboration practices across teams'];
const shipping = isZh
? ['工程案例库结构重构', '导航与路由转化路径优化', '双语文案统一与信息层级简化']
: ['Refactoring project pages into engineering case studies', 'Optimizing navigation and conversion routes', 'Unifying EN/ZH copy and simplifying information hierarchy'];
---
<Layout title={pageTitle}>
<Layout title={isZh ? '现在' : 'Now'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden">
<!-- 背景装饰 -->
<div class="absolute inset-0 -z-10">
<div class="absolute left-1/2 top-0 h-[800px] w-[1000px] -translate-x-1/2 -translate-y-1/2 bg-primary/10 blur-[120px]"></div>
<div class="absolute right-0 top-1/3 h-[500px] w-[500px] bg-blue-500/5 blur-[100px]"></div>
</div>
<!-- Now Page Hero -->
<section class="pt-32 pb-24 relative overflow-hidden">
<div class="page-hero-overlay" aria-hidden="true"></div>
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '现在' : 'Now'}</h1>
<p class="mt-4 text-lg text-muted-foreground">{isZh ? '我当前的工作重点与近期交付。' : 'What I am focusing on right now and what I am shipping recently.'}</p>
</section>
<Container className="relative z-10">
<div class="max-w-4xl mx-auto text-center">
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-bold uppercase tracking-wider mb-6 animate-fade-in">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
</span>
{lang === 'zh' ? '实时状态' : "Live Status"}
</div>
<h1 class="page-title-gradient text-6xl md:text-8xl font-bold mb-8 tracking-tight">
{lang === 'zh' ? '现在' : 'Now'}
</h1>
<p class="text-xl md:text-2xl text-muted-foreground leading-relaxed max-w-2xl mx-auto">
{lang === 'zh'
? '关于我现在正在关注的事、正在构建的产品以及我的生活状态。'
: 'What I am currently focusing on, the products I am building, and my life status.'}
</p>
</div>
</Container>
</section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-3">
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{isZh ? '在做什么' : 'Doing'}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{doing.map((item) => <li>• {item}</li>)}
</ul>
</article>
<!-- Main Content -->
<section class="pb-32 relative mt-12 md:mt-24">
<Container>
<div class="max-w-4xl mx-auto space-y-24">
<!-- Building Section -->
<div class="space-y-10">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-primary/10 rounded-xl flex items-center justify-center border border-primary/20">
<Hammer className="w-6 h-6 text-primary" />
</div>
<h2 class="text-3xl md:text-4xl font-bold tracking-tight">
{lang === 'zh' ? '正在构建' : 'Building'}
</h2>
</div>
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{isZh ? '在研究什么' : 'Exploring'}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{exploring.map((item) => <li>• {item}</li>)}
</ul>
</article>
<div class="group relative">
<div class="absolute -inset-1 rounded-[2rem] bg-gradient-to-r from-primary/30 to-blue-600/30 opacity-20 blur-xl transition duration-500 group-hover:opacity-40"></div>
<div class="page-surface relative p-8 md:p-12 overflow-hidden border-primary/10 rounded-[2rem]">
<div class="flex flex-col md:flex-row gap-10 items-start">
<div class="w-24 h-24 bg-gradient-to-br from-primary to-blue-600 rounded-2xl flex items-center justify-center flex-shrink-0 shadow-lg shadow-primary/20 group-hover:scale-105 transition-transform duration-500">
<Zap className="w-12 h-12 text-white" />
</div>
<div class="flex-1 space-y-6">
<div class="flex items-center justify-between">
<h3 class="text-3xl font-bold">Elynd</h3>
<span class="px-4 py-1.5 bg-green-500/10 text-green-600 dark:text-green-400 rounded-full text-xs font-bold border border-green-500/20 uppercase tracking-wider">Active</span>
</div>
<p class="text-xl text-muted-foreground leading-relaxed">
{lang === 'zh'
? '一个开放的 AI 工作空间,让构建者能够更智能地工作。从 AI 第一性原理出发,打造完全开放、可自托管的协作工具。'
: 'An open AI workspace for builders to work smarter. Built from first principles of AI, creating fully open, self-hostable collaboration tools.'}
</p>
<div class="flex flex-wrap gap-3 pt-2">
{['AI Product', 'TypeScript', 'Open Source', 'Astro'].map(tag => (
<span class="px-4 py-2 bg-secondary/50 text-secondary-foreground rounded-lg text-sm font-medium border border-border/50">{tag}</span>
))}
</div>
</div>
</div>
</div>
</div>
</div>
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{isZh ? '最近交付' : 'Shipping'}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{shipping.map((item) => <li>• {item}</li>)}
</ul>
</article>
</section>
<!-- Exploring Section -->
<div class="space-y-10">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-blue-500/10 rounded-xl flex items-center justify-center border border-blue-500/20">
<Telescope className="w-6 h-6 text-blue-500" />
</div>
<h2 class="text-3xl md:text-4xl font-bold tracking-tight">
{lang === 'zh' ? '正在探索' : 'Exploring'}
</h2>
</div>
<div class="grid gap-8 md:grid-cols-2">
{[
{
title: lang === 'zh' ? 'AI Agents 与工作流自动化' : 'AI Agents & Workflow Automation',
desc: lang === 'zh' ? '研究如何构建能够自主完成复杂任务的 AI Agent以及如何将 AI 能力融入日常工作流。' : 'Researching how to build AI Agents that can autonomously complete complex tasks, and how to integrate AI capabilities into daily workflows.',
icon: Bot
},
{
title: lang === 'zh' ? '产品导向的开发实践' : 'Product-Led Development Practices',
desc: lang === 'zh' ? '探索从产品角度思考开发,构建真正解决用户问题的产品,而不仅仅是技术实现。' : 'Exploring product thinking in development, building products that truly solve user problems, not just technical implementations.',
icon: Target
}
].map(item => (
<div class="page-surface p-8 rounded-3xl hover:translate-y-[-4px] transition-all duration-300 border-border/50 group">
<div class="w-12 h-12 bg-muted rounded-xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-300">
<item.icon className="w-6 h-6 text-foreground" />
</div>
<h3 class="text-2xl font-bold mb-4">{item.title}</h3>
<p class="text-muted-foreground text-base leading-relaxed">{item.desc}</p>
</div>
))}
</div>
</div>
<!-- Shipping Section -->
<div class="space-y-10">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-green-500/10 rounded-xl flex items-center justify-center border border-green-500/20">
<Rocket className="w-6 h-6 text-green-500" />
</div>
<h2 class="text-3xl md:text-4xl font-bold tracking-tight">
{lang === 'zh' ? '最近发布' : 'Shipping'}
</h2>
</div>
<div class="space-y-6">
{[
{
title: lang === 'zh' ? '个人网站全新改版' : 'Portfolio Redesign',
desc: lang === 'zh' ? '基于 Astro 5 和 Tailwind 4 的高性能双语站点。' : 'High-performance bilingual site built with Astro 5 & Tailwind 4.',
icon: Sparkles,
color: 'bg-green-500/10',
iconColor: 'text-green-500'
},
{
title: lang === 'zh' ? 'DeepSeek 满血版接入' : 'DeepSeek Full Access',
desc: lang === 'zh' ? '在本地工作流中深度整合 DeepSeek-V3 提升效率。' : 'Deep integration of DeepSeek-V3 in local workflows for efficiency.',
icon: MessageSquare,
color: 'bg-blue-500/10',
iconColor: 'text-blue-500'
}
].map(item => (
<div class="group relative flex items-center gap-6 p-4 rounded-2xl hover:bg-muted/50 transition-all duration-300">
<div class={`w-12 h-12 ${item.color} rounded-xl flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform`}>
<item.icon className={`w-6 h-6 ${item.iconColor}`} />
</div>
<div class="flex-1 min-w-0">
<h3 class="font-bold text-lg group-hover:text-primary transition-colors truncate">
{item.title}
</h3>
<p class="text-sm text-muted-foreground line-clamp-1">
{item.desc}
</p>
</div>
<div class="text-muted-foreground/30 group-hover:text-primary/50 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
</div>
</div>
))}
</div>
</div>
<!-- Bottom Grid: Collaboration & Meta -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 pt-8">
<!-- Collaboration Card -->
<div class="relative group h-full">
<div class="absolute -inset-1 rounded-[2.5rem] bg-gradient-to-br from-yellow-500/20 to-orange-500/20 blur opacity-75"></div>
<div class="page-surface relative p-10 border-yellow-500/10 bg-gradient-to-br from-card to-yellow-500/5 rounded-[2.5rem] h-full flex flex-col justify-between">
<div>
<div class="w-14 h-14 bg-yellow-500/10 rounded-2xl flex items-center justify-center mb-8">
<Handshake className="w-8 h-8 text-yellow-600 dark:text-yellow-400" />
</div>
<h3 class="text-3xl font-bold mb-4">{lang === 'zh' ? '开放合作' : 'Collaborate'}</h3>
<p class="text-lg text-muted-foreground mb-8 leading-relaxed">
{lang === 'zh'
? '始终对有趣的产品想法和技术咨询持开放态度。'
: "Always open to interesting product ideas and technical consulting."}
</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<a href={lang === 'zh' ? '/zh/hire' : '/hire'} class="flex items-center justify-center py-4 rounded-2xl bg-primary text-primary-foreground font-bold text-base hover:scale-[1.02] transition-transform">
{lang === 'zh' ? '合作方式' : 'View Options'}
</a>
<a href="mailto:zhaoguiyang18@gmail.com" class="flex items-center justify-center py-4 rounded-2xl border border-border bg-background/50 text-foreground font-bold text-base hover:bg-muted transition-colors">
{lang === 'zh' ? '发送邮件' : 'Email Me'}
</a>
</div>
</div>
</div>
<!-- Meta/Status Card -->
<div class="page-surface p-10 border-border/50 rounded-[2.5rem] flex flex-col items-center justify-center text-center space-y-6">
<div class="w-20 h-20 bg-muted rounded-full flex items-center justify-center text-3xl">
<MapPin className="w-10 h-10 text-primary" />
</div>
<div class="space-y-2">
<h3 class="text-2xl font-bold">{lang === 'zh' ? '当前位置' : 'Location'}</h3>
<p class="text-muted-foreground">{lang === 'zh' ? '中国 · 杭州' : 'Hangzhou, China'}</p>
</div>
<div class="pt-4 w-full">
<div class="inline-flex items-center gap-3 px-5 py-2.5 rounded-full bg-muted/50 border border-border/50 mx-auto">
<span class="text-xs text-muted-foreground uppercase font-bold tracking-widest border-r border-border/50 pr-3">
{lang === 'zh' ? '最后更新' : 'Updated'}
</span>
<span class="text-sm font-semibold">2025.03.14</span>
</div>
</div>
</div>
</div>
</div>
</Container>
</section>
<section class="page-content-main mt-8 page-surface p-6">
<p class="text-sm text-muted-foreground">
{isZh ? '最后更新2026-03-16' : 'Last updated: 2026-03-16'}
</p>
</section>
</Container>
</main>
<Footer lang={lang} client:only="react" />
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,114 +1,133 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import ProjectCard from "@/components/ProjectCard.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import { projects } from "@/lib/data/index";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { projects } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
// 使用Astro.currentLocale获取当前语言环境
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const pageTitle = t('projects.title');
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
const pageProjects = projects[lang];
// 根据当前语言获取项目数据
const currentProjects = projects[lang as keyof typeof projects] || projects.en;
const filterOptions = [
{ key: "all", label: t("project.filter.all") },
{ key: "product", label: t("project.type.product") },
{ key: "client", label: t("project.type.client") },
{ key: "experiment", label: t("project.type.experiment") },
const filters = [
{ key: 'all', label: isZh ? '全部' : 'All' },
{ key: 'product', label: isZh ? '产品系统' : 'Product Systems' },
{ key: 'client', label: isZh ? '企业项目' : 'Client Systems' },
{ key: 'experiment', label: isZh ? '实验项目' : 'Experiments' },
];
---
<Layout title={pageTitle}>
<Layout title={isZh ? '项目' : 'Projects'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden">
<div
aria-hidden="true"
class="page-hero-overlay"
></div>
<section class="relative z-10 py-24">
<Container>
<div class="text-center mb-8">
<h1 class="page-title-gradient text-5xl md:text-6xl font-bold mb-6">
{t('projects.title')}
</h1>
<p class="text-lg text-muted-foreground page-content-main mb-12 leading-relaxed">
{t('projects.slogan')} {t('projects.description')}
</p>
<main class="min-h-screen pt-24 pb-20" data-projects-root>
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '工程案例' : 'Engineering Case Studies'}</h1>
<p class="mt-4 text-lg leading-relaxed text-muted-foreground">
{isZh
? '围绕复杂系统建设的真实项目经验,重点展示技术挑战、职责边界和结果。'
: 'Real projects focused on complex system delivery, highlighting technical challenges, responsibilities, and outcomes.'}
</p>
</section>
<section class="page-content-main mt-8">
<div class="page-surface mb-8 flex flex-wrap gap-2 p-2">
{filters.map((filter, index) => (
<button
type="button"
data-filter={filter.key}
aria-pressed={index === 0 ? 'true' : 'false'}
class={`rounded-md px-4 py-2 text-sm font-semibold ${index === 0 ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground'}`}
>
{filter.label}
</button>
))}
</div>
</Container>
</section>
<section class="relative z-10 pb-20" data-projects-root>
<Container>
<div class="page-content-main">
<div class="page-surface flex flex-wrap gap-2 mb-8 p-1 rounded-xl">
{filterOptions.map((option, index) => (
<button
type="button"
data-filter={option.key}
aria-pressed={index === 0 ? "true" : "false"}
class={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
index === 0
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-muted"
}`}
>
{option.label}
</button>
))}
</div>
<div class="space-y-6">
{pageProjects.map((project) => (
<article data-project-card data-type={project.type} class="page-surface p-6 md:p-8">
<div class="grid gap-6 lg:grid-cols-[1.2fr_1fr]">
<div>
<p class="text-xs font-semibold uppercase tracking-wider text-primary">{project.systemType}</p>
<h2 class="mt-2 text-2xl font-bold tracking-tight">{project.title}</h2>
<p class="mt-3 text-muted-foreground">{project.context}</p>
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{currentProjects.map((project) => (
<ProjectCard project={project} lang={lang} showStatus={true} />
))}
</div>
<div class="mt-5 flex flex-wrap gap-2">
{project.tech.map((tech) => (
<span class="rounded-md border border-border bg-muted/50 px-2.5 py-1 text-xs font-medium">{tech}</span>
))}
</div>
</div>
<div class="space-y-4">
<div>
<h3 class="text-sm font-bold uppercase tracking-wider text-foreground/80">{isZh ? '技术挑战' : 'Technical Challenges'}</h3>
<ul class="mt-2 space-y-1.5 text-sm text-muted-foreground">
{project.challenges?.map((item) => <li>• {item}</li>)}
</ul>
</div>
<div>
<h3 class="text-sm font-bold uppercase tracking-wider text-foreground/80">{isZh ? '职责范围' : 'Responsibilities'}</h3>
<ul class="mt-2 space-y-1.5 text-sm text-muted-foreground">
{project.responsibilities?.map((item) => <li>• {item}</li>)}
</ul>
</div>
<div>
<h3 class="text-sm font-bold uppercase tracking-wider text-foreground/80">{isZh ? '结果' : 'Outcomes'}</h3>
<ul class="mt-2 space-y-1.5 text-sm text-foreground/90">
{project.outcomes?.map((item) => <li>• {item}</li>)}
</ul>
</div>
</div>
</div>
</article>
))}
</div>
</Container>
</section>
</section>
</Container>
</main>
<Footer lang={lang} client:load />
</Layout>
<script>
const projectsRoot = document.querySelector("[data-projects-root]");
if (projectsRoot) {
const filterButtons = Array.from(projectsRoot.querySelectorAll("[data-filter]"));
const projectCards = Array.from(projectsRoot.querySelectorAll("[data-project-card]"));
const root = document.querySelector('[data-projects-root]');
if (!root) {
// no-op
} else {
const buttons = Array.from(root.querySelectorAll('[data-filter]'));
const cards = Array.from(root.querySelectorAll('[data-project-card]'));
const applyFilter = (activeFilter: string | null) => {
projectCards.forEach((card) => {
const projectType = card.getAttribute("data-type");
const shouldShow = activeFilter === "all" || projectType === activeFilter;
card.classList.toggle("hidden", !shouldShow);
const apply = (activeFilter) => {
cards.forEach((card) => {
const cardType = card.getAttribute('data-type');
const visible = activeFilter === 'all' || activeFilter === cardType;
card.classList.toggle('hidden', !visible);
});
filterButtons.forEach((button) => {
const isActive = button.getAttribute("data-filter") === activeFilter;
button.setAttribute("aria-pressed", isActive ? "true" : "false");
button.classList.toggle("bg-primary", isActive);
button.classList.toggle("text-primary-foreground", isActive);
button.classList.toggle("text-muted-foreground", !isActive);
button.classList.toggle("hover:text-foreground", !isActive);
button.classList.toggle("hover:bg-muted", !isActive);
buttons.forEach((button) => {
const isActive = button.getAttribute('data-filter') === activeFilter;
button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
button.classList.toggle('bg-primary', isActive);
button.classList.toggle('text-primary-foreground', isActive);
button.classList.toggle('text-muted-foreground', !isActive);
button.classList.toggle('hover:bg-muted', !isActive);
button.classList.toggle('hover:text-foreground', !isActive);
});
};
filterButtons.forEach((button) => {
button.addEventListener("click", () => {
const selectedFilter = button.getAttribute("data-filter") ?? "all";
applyFilter(selectedFilter);
buttons.forEach((button) => {
button.addEventListener('click', () => {
apply(button.getAttribute('data-filter') ?? 'all');
});
});
applyFilter("all");
apply('all');
}
</script>

View File

@@ -1,42 +1,14 @@
---
title: "What I Do"
description: "Professional services focused on building AI products and technical excellence"
title: "Moved to Uses"
description: "This page has moved."
layout: "../layouts/AboutLayout.astro"
---
import HighlightBox from '../components/markdown/HighlightBox.astro';
# This page moved
# What I Do 🚀
The old **Services** page has been replaced by focused pages:
<HighlightBox type="tip">
Building AI-powered products and turning ambitious ideas into reality.
</HighlightBox>
- [Uses](/uses)
- [Contact](/contact)
## AI Product Development 🤖
- Building AI-powered products from concept to launch
- RAG applications, AI agents, and intelligent automation
- Full-stack development with modern tech stack (React, Next.js, Node.js)
- Product thinking - focus on solving real problems
- Rapid prototyping and iterative development
## Technical Consulting 📊
<HighlightBox type="info" title="How I Can Help">
- Technical architecture and stack decisions
- Code reviews and best practices implementation
- Team mentoring and knowledge transfer
- Performance optimization and scaling strategies
- Technical due diligence for investments
</HighlightBox>
# Let's Build Together 💼
<HighlightBox type="success" title="Get in Touch">
I'm always open to discussing new projects and opportunities. Whether you're looking for a technical co-founder, need help building an AI product, or want technical consulting - let's talk.
- Email: **zhaoguiyang18@gmail.com**
- Check out my [Hire Me](/hire) page for collaboration options
</HighlightBox>
If you are hiring for a remote role, please start from [Contact](/contact).

40
src/pages/uses.astro Normal file
View File

@@ -0,0 +1,40 @@
---
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { uses } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
---
<Layout title={isZh ? '工具' : 'Uses'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '工具与工作流' : 'Uses'}</h1>
<p class="mt-4 text-lg text-muted-foreground">
{isZh ? '我在日常研发中稳定使用的工具与协作方式。' : 'Tools and workflows I use for daily engineering work.'}
</p>
</section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-2">
{uses.map((group) => (
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{group.title[lang]}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{group.items.map((item) => <li>• {item}</li>)}
</ul>
</article>
))}
</section>
</Container>
</main>
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,220 +1,70 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import HighlightBox from "@/components/markdown/HighlightBox.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import {
Sparkles,
Heart,
Zap,
Mail,
MessageSquare,
Send,
Github,
Twitter,
Linkedin,
Globe
} from "lucide-react";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { personalInfo } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
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 isZh = lang === 'zh';
const lang = (Astro.currentLocale as Lang) || 'zh';
const t = useTranslations(lang);
const pageTitle = t("about.title");
const focusAreas = isZh
? ['前端架构设计与模块治理', '大型企业应用工程化交付', '金融与区块链系统前端建设', 'AI 协作开发流程实践']
: ['Frontend architecture and module governance', 'Large-scale enterprise application delivery', 'Financial and blockchain system engineering', 'AI-assisted development workflow practices'];
const experienceNotes = isZh
? [
'8 年专业开发经验,持续参与复杂业务系统建设。',
'参与多个政府与金融科技相关系统,包括交易平台、区块链基础设施、产业管理系统。',
'擅长跨角色协作与远程异步沟通,注重稳定交付与长期可维护性。',
]
: [
'8 years of professional development experience across complex business systems.',
'Contributed to government- and fintech-related systems, including trading platforms, blockchain infrastructure, and industrial management systems.',
'Strong in cross-functional collaboration and remote async execution with long-term maintainability in mind.',
];
---
<Layout title={pageTitle}>
<GlassHeader client:load transition:persist="header" lang={lang} />
<main class="min-h-screen relative overflow-hidden pt-16 sm:pt-20">
<!-- Background Decor -->
<div class="fixed inset-0 -z-10 h-full w-full bg-background">
<div class="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-primary/5 dark:from-primary/10 dark:via-transparent dark:to-primary/5"></div>
</div>
<Layout title={isZh ? '关于' : 'About'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<!-- Hero Section -->
<section class="relative z-10 py-16 md:py-24">
<Container>
<div class="max-w-4xl mx-auto">
<div class="flex flex-col md:flex-row items-center gap-12 mb-16">
<div class="relative group">
<div class="absolute -inset-1 rounded-full bg-gradient-to-r from-primary to-purple-600 opacity-75 blur transition duration-1000 group-hover:opacity-100 group-hover:duration-200"></div>
<div class="relative h-48 w-48 rounded-full border-4 border-background overflow-hidden bg-muted">
<img
src="/avatar.png"
alt="Joey Zhao"
class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-110"
onerror="this.src='https://ui-avatars.com/api/?name=Joy+Zhao&background=0D8ABC&color=fff&size=200'"
/>
</div>
</div>
<div class="text-center md:text-left space-y-6">
<h1 class="text-4xl md:text-6xl font-bold tracking-tight">
<span class="bg-gradient-to-r from-foreground to-foreground/70 bg-clip-text text-transparent">
{t('about.title')}
</span>
</h1>
<p class="text-xl text-muted-foreground leading-relaxed">
{t('about.description')}
</p>
</div>
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '关于我' : 'About'}</h1>
<p class="mt-6 text-lg leading-relaxed text-muted-foreground">{personalInfo.description[lang]}</p>
</section>
<section class="page-content-main mt-12 grid gap-6 lg:grid-cols-2">
<article class="page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '背景' : 'Background'}</h2>
<div class="mt-4 space-y-4 text-muted-foreground">
{personalInfo.about[lang].map((line) => <p>{line}</p>)}
</div>
</article>
<div class="grid gap-8">
<!-- Intro Box -->
<HighlightBox type="tip" title={t('about.intro.title')}>
<div class="space-y-4 py-2">
<p class="text-lg leading-relaxed whitespace-pre-line">{t('about.intro.content')}</p>
<div class="p-4 rounded-xl bg-primary/5 border border-primary/10 italic text-primary/80">
{t('about.intro.belief')}
</div>
</div>
</HighlightBox>
<article class="page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '技术焦点' : 'Technical Focus'}</h2>
<ul class="mt-4 space-y-3 text-muted-foreground">
{focusAreas.map((item) => (
<li class="flex gap-3"><span class="mt-2 h-1.5 w-1.5 rounded-full bg-primary"></span><span>{item}</span></li>
))}
</ul>
</article>
</section>
<!-- Self Intro -->
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Sparkles className="w-6 h-6 text-primary" />
{t('about.me.title')}
</h2>
<div class="prose dark:prose-invert max-w-none">
<p class="text-lg leading-relaxed text-muted-foreground whitespace-pre-line">
{t('about.me.content')}
</p>
</div>
</div>
<!-- Skills Grid -->
<div class="grid md:grid-cols-2 gap-8">
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Zap className="w-6 h-6 text-yellow-500" />
{t('about.skills.mastered.title')}
</h2>
<div class="flex flex-wrap gap-2">
{(t('about.skills.mastered.items') as unknown as string[]).map((item: string) => (
<div class="px-3 py-1.5 rounded-lg bg-primary/5 border border-primary/10 text-muted-foreground text-xs font-medium">
{item}
</div>
))}
</div>
</div>
<div class="page-surface p-8 rounded-2xl border bg-card/40 backdrop-blur-md space-y-6">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Heart className="w-6 h-6 text-red-500" />
{t('about.skills.learning.title')}
</h2>
<div class="flex flex-wrap gap-2">
{(t('about.skills.learning.items') as unknown as string[]).map((item: string) => (
<div class="px-3 py-1.5 rounded-lg bg-muted/30 border border-border/50 text-muted-foreground/70 text-xs font-medium">
{item}
</div>
))}
</div>
</div>
</div>
<!-- Interests -->
<div class="space-y-8">
<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')}
</h2>
<ul class="grid sm:grid-cols-2 gap-4">
{(t('about.interests.items') as unknown as any[]).map((item) => (
<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">
<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>
</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>
<!-- Contact -->
<div class="space-y-8 py-8">
<div class="px-2 space-y-4">
<h2 class="text-2xl font-bold flex items-center gap-3">
<Mail className="w-6 h-6 text-primary" />
{t('about.contact.title')}
</h2>
<p class="text-muted-foreground leading-relaxed max-w-2xl">
{t('about.contact.warning')}
</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
{(t('about.contact.methods') as unknown as any[]).map((method) => {
const Icon = IconMap[method.icon] || MessageSquare;
const content = (
<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 class="flex flex-col">
<span class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">{method.label}</span>
<span class="text-sm font-medium break-all">{method.value}</span>
</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>
</Container>
</section>
<section class="page-content-main mt-6 page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '经验概览' : 'Experience'}</h2>
<ul class="mt-4 space-y-3 text-muted-foreground">
{experienceNotes.map((item) => (
<li class="flex gap-3"><span class="mt-2 h-1.5 w-1.5 rounded-full bg-primary"></span><span>{item}</span></li>
))}
</ul>
</section>
</Container>
</main>
<Footer client:load lang={lang} />
<Footer lang={lang} client:load />
</Layout>

View File

@@ -55,16 +55,16 @@ const tags = extractTags(allPostsArray);
---
<BlogLayout title="博客 - Joey Zhao" description="关于 AI 产品、全栈开发和公开构建的思考。探索技术与产品构建的交汇点。">
<BlogLayout title="写作 - Joey Zhao" description="聚焦架构设计、工程交付与 AI 协作开发实践的技术写作。">
<main class="min-h-screen">
<!-- 头部区域 -->
<Container className="pt-24 pb-12">
<div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-primary to-primary dark:from-foreground dark:via-blue-200 dark:to-orange-300 bg-clip-text text-transparent mb-6">
<span class="text-primary">博客</span>
<span class="text-primary">写作</span>
</h1>
<p class="text-xl text-muted-foreground page-content-main">
关于 AI 产品、全栈开发和公开构建的思考。探索技术与产品构建的交汇点
聚焦架构设计、工程交付与 AI 协作开发实践的技术写作
</p>
</div>
</Container>

View File

@@ -0,0 +1,62 @@
---
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { contactIntents, contactMethods } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
---
<Layout title={isZh ? '联系' : 'Contact'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '联系' : 'Contact'}</h1>
<p class="mt-4 text-lg text-muted-foreground">
{isZh
? '欢迎联系我沟通远程岗位或项目合作。默认优先响应远程岗位机会。'
: 'Open to remote role opportunities and project collaboration. Remote role discussions are prioritized.'}
</p>
</section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-2">
{contactIntents.map((intent) => (
<article id={intent.id} class="page-surface p-6">
<h2 class="text-xl font-bold">{intent.title[lang]}</h2>
<p class="mt-3 text-muted-foreground">{intent.description[lang]}</p>
</article>
))}
</section>
<section class="page-content-main mt-6 page-surface p-6">
<h2 class="text-xl font-bold">{isZh ? '联系方式' : 'Contact Methods'}</h2>
<ul class="mt-4 space-y-3 text-sm">
{contactMethods.map((method) => (
<li class="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between border-b border-border/70 pb-3">
<span class="font-semibold text-foreground">{method.label[lang]}</span>
{method.href ? (
<a href={method.href} target="_blank" rel="noopener noreferrer" class="text-primary hover:text-primary/80 break-all">{method.value}</a>
) : (
<span class="text-muted-foreground break-all">{method.value}</span>
)}
</li>
))}
</ul>
<p class="mt-5 text-xs text-muted-foreground">
{isZh
? '联系建议:请在邮件中注明岗位/项目背景、期望合作方式与时间窗口。'
: 'Suggestion: include role/project context, expected collaboration model, and timeline in your first message.'}
</p>
</section>
</Container>
</main>
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,333 +1,3 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import { useTranslations } from "@/i18n/utils";
import { Users, Wrench, Lightbulb, Handshake, CircleDollarSign, Clock, Target, Check, Calendar, Mail, Radio, Zap, Globe, Smartphone, ShoppingCart, Layout as LayoutIcon, ClipboardList } from "lucide-react";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const pageTitle = lang === 'zh' ? '合作' : 'Hire Me';
return Astro.redirect('/zh/contact', 301);
---
<Layout title={pageTitle}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen">
<!-- Hire Page Hero -->
<section class="py-24 relative overflow-hidden">
<div class="page-hero-overlay"></div>
<Container className="relative z-10">
<div class="text-center mb-16">
<span class="inline-block px-4 py-1 bg-primary/20 text-primary dark:text-primary rounded-full text-sm font-medium mb-4">
专业合作
</span>
<h1 class="page-title-gradient text-5xl md:text-6xl font-bold mb-6">
合作
</h1>
<p class="text-lg text-muted-foreground page-content-narrow">
构建优秀产品,从找到合适的技术合伙人开始
</p>
</div>
</Container>
</section>
<!-- Who I Work With -->
<section class="py-16 relative">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-primary/20 rounded-xl flex items-center justify-center">
<Users className="w-6 h-6 text-primary" />
</div>
<h2 class="text-3xl font-bold">
我与谁合作
</h2>
</div>
<div class="grid md:grid-cols-2 gap-6">
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
初创公司
</h3>
<p class="text-muted-foreground">
从零到一构建产品的早期创业团队,需要快速迭代和灵活响应的技术方案。
</p>
</div>
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
独立创始人
</h3>
<p class="text-muted-foreground">
独自构建产品的创业者,需要技术合伙人来实现产品愿景。
</p>
</div>
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
传统企业
</h3>
<p class="text-muted-foreground">
希望数字化转型的传统企业,需要现代化的技术解决方案。
</p>
</div>
<div class="page-surface p-6">
<h3 class="text-lg font-bold mb-3">
技术团队
</h3>
<p class="text-muted-foreground">
需要额外技术资源或特定技能集来推进项目的开发团队。
</p>
</div>
</div>
</div>
</Container>
</section>
<!-- What I Build -->
<section class="py-16 relative page-section-soft">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-blue-500/20 rounded-xl flex items-center justify-center">
<Wrench className="w-6 h-6 text-blue-500" />
</div>
<h2 class="text-3xl font-bold">
我能构建什么
</h2>
</div>
<div class="space-y-6">
<div class="page-surface p-8">
<div class="flex items-start gap-4">
<div class="w-12 h-12 bg-gradient-to-br from-primary to-blue-600 rounded-xl flex items-center justify-center flex-shrink-0">
<Zap className="w-6 h-6 text-white" />
</div>
<div>
<h3 class="text-xl font-bold mb-2">AI 产品与应用</h3>
<p class="text-muted-foreground">
从 AI 助手到 Agent 系统,从 RAG 应用到 AI 驱动的 SaaS 产品。我可以帮助你将 AI 能力产品化。
</p>
</div>
</div>
</div>
<div class="page-surface p-8">
<div class="flex items-start gap-4">
<div class="w-12 h-12 bg-gradient-to-br from-green-600 to-teal-600 rounded-xl flex items-center justify-center flex-shrink-0">
<Globe className="w-6 h-6 text-white" />
</div>
<div>
<h3 class="text-xl font-bold mb-2">Web 应用</h3>
<p class="text-muted-foreground">
现代 Web 应用、SaaS 平台、电商系统、内容管理系统等。使用 React、Next.js、Node.js 等技术栈。
</p>
</div>
</div>
</div>
<div class="page-surface p-8">
<div class="flex items-start gap-4">
<div class="w-12 h-12 bg-gradient-to-br from-orange-600 to-red-600 rounded-xl flex items-center justify-center flex-shrink-0">
<Smartphone className="w-6 h-6 text-white" />
</div>
<div>
<h3 class="text-xl font-bold mb-2">全栈产品</h3>
<p class="text-muted-foreground">
从前端到后端,从数据库到部署,我提供完整的全栈开发能力,一个项目只需一个开发者。
</p>
</div>
</div>
</div>
</div>
</div>
</Container>
</section>
<!-- Engagement Models -->
<section class="py-16 relative">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-green-500/20 rounded-xl flex items-center justify-center">
<ClipboardList className="w-6 h-6 text-green-500" />
</div>
<h2 class="text-3xl font-bold">
合作模式
</h2>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div class="page-surface p-6 text-center">
<div class="w-12 h-12 bg-green-500/20 rounded-xl flex items-center justify-center mx-auto mb-4">
<Handshake className="w-6 h-6 text-green-600 dark:text-green-400" />
</div>
<h3 class="text-lg font-bold mb-2">
技术合伙人
</h3>
<p class="text-sm text-muted-foreground">
长期合作,股权合作,共同承担创业风险与回报
</p>
</div>
<div class="page-surface p-6 text-center">
<div class="w-12 h-12 bg-blue-500/20 rounded-xl flex items-center justify-center mx-auto mb-4">
<CircleDollarSign className="w-6 h-6 text-blue-600 dark:text-blue-400" />
</div>
<h3 class="text-lg font-bold mb-2">
项目制
</h3>
<p class="text-sm text-muted-foreground">
按项目交付,固定价格或按阶段付款,适合明确需求的项目
</p>
</div>
<div class="page-surface p-6 text-center">
<div class="w-12 h-12 bg-primary/20 rounded-xl flex items-center justify-center mx-auto mb-4">
<Clock className="w-6 h-6 text-primary" />
</div>
<h3 class="text-lg font-bold mb-2">
咨询/顾问
</h3>
<p class="text-sm text-muted-foreground">
按小时咨询,帮助你做出技术决策,审查代码,指导团队
</p>
</div>
</div>
</div>
</Container>
</section>
<!-- Delivery Style -->
<section class="py-16 relative page-section-soft">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-yellow-500/20 rounded-xl flex items-center justify-center">
<Target className="w-6 h-6 text-yellow-600 dark:text-yellow-400" />
</div>
<h2 class="text-3xl font-bold">
工作方式
</h2>
</div>
<div class="page-surface p-8">
<ul class="space-y-4">
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">敏捷迭代</strong>
<p class="text-muted-foreground text-sm">
2周一个迭代快速交付可用功能持续获取反馈
</p>
</div>
</li>
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">透明沟通</strong>
<p class="text-muted-foreground text-sm">
定期同步进度,及时报告问题,保持信息对称
</p>
</div>
</li>
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">代码质量</strong>
<p class="text-muted-foreground text-sm">
完整的测试覆盖,清晰的文档注释,可维护的代码结构
</p>
</div>
</li>
<li class="flex items-start gap-3">
<Check className="w-6 h-6 text-green-500 shrink-0 mt-0.5" />
<div>
<strong class="block mb-1">产品思维</strong>
<p class="text-muted-foreground text-sm">
不只是写代码,还思考产品价值,用户体验和业务目标
</p>
</div>
</li>
</ul>
</div>
</div>
</Container>
</section>
<!-- Availability -->
<section class="py-16 relative">
<Container>
<div class="page-content-main">
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 bg-red-500/20 rounded-xl flex items-center justify-center">
<Calendar className="w-6 h-6 text-red-500" />
</div>
<h2 class="text-3xl font-bold">
当前可用性
</h2>
</div>
<div class="page-surface p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-4 h-4 bg-green-500 rounded-full animate-pulse"></div>
<span class="text-lg font-semibold">
目前可接受新项目
</span>
</div>
<p class="text-muted-foreground mb-6">
我目前可以接受 1-2 个新项目。偏好长期合作模式(技术合伙人或长期项目),但也会考虑短期项目。
</p>
<div class="flex flex-wrap gap-2">
<span class="px-3 py-1 bg-green-500/20 text-green-600 dark:text-green-400 rounded-full text-sm">
可立即开始
</span>
<span class="px-3 py-1 bg-blue-500/20 text-blue-600 dark:text-blue-400 rounded-full text-sm">
远程工作
</span>
<span class="px-3 py-1 bg-primary/20 text-primary dark:text-primary rounded-full text-sm">
中英双语
</span>
</div>
</div>
</div>
</Container>
</section>
<!-- Contact CTA -->
<section class="py-16 relative page-section-soft">
<Container>
<div class="page-content-main text-center">
<h2 class="text-3xl font-bold mb-6">
准备好一起构建了吗?
</h2>
<p class="text-lg text-muted-foreground mb-8 page-content-narrow">
告诉我你的项目想法,让我们看看能否合作。
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="mailto:zhaoguiyang18@gmail.com"
class="bg-primary hover:bg-primary/90 text-white px-8 py-3 rounded-lg font-semibold transition-colors inline-flex items-center justify-center gap-2"
>
<Mail className="w-5 h-5" />
发送邮件
</a>
<a
href="/zh/now"
class="border border-primary text-primary hover:bg-primary hover:text-white px-8 py-3 rounded-lg font-semibold transition-colors inline-flex items-center justify-center gap-2"
>
<Radio className="w-5 h-5" />
了解更多关于我
</a>
</div>
</div>
</Container>
</section>
</main>
<Footer lang={lang} client:only="react" />
</Layout>

View File

@@ -1,282 +1,109 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import { personalInfo, services, projects } from "@/lib/data/index";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { personalInfo, projects } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
import { sortPostsByDate } from '@/utils/blog-utils';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const t = useTranslations(lang);
const pageTitle = t("site.title");
const prefix = lang === "zh" ? "/zh" : "";
const isZh = lang === 'zh';
const prefix = isZh ? '/zh' : '';
const featuredProjects = projects[lang].filter((item) => item.featured).slice(0, 3);
const localizedServices = services[lang];
const featuredProjects = projects[lang].filter((project) => project.featured);
const proofItems = isZh
? ['8 年 Web 开发经验', '企业级复杂系统交付', '金融与区块链基础设施', '远程协作与稳定交付']
: ['8 years in web engineering', 'Enterprise-grade complex systems', 'Finance & blockchain infrastructure', 'Remote-first stable delivery'];
const careerMilestones = [
{
period: t("home.career.card1.period"),
title: t("home.career.card1.title"),
outcome: t("home.career.card1.outcome"),
},
{
period: t("home.career.card2.period"),
title: t("home.career.card2.title"),
outcome: t("home.career.card2.outcome"),
},
{
period: t("home.career.card3.period"),
title: t("home.career.card3.title"),
outcome: t("home.career.card3.outcome"),
},
];
const headline = isZh
? '资深前端工程师,构建复杂系统与 AI 协作产品'
: 'Senior Frontend Engineer building complex systems and AI-assisted products';
const keyFacts = [
t("home.trust.item1"),
t("home.trust.item3"),
t("home.trust.item4"),
];
const intro = personalInfo.description[lang];
const postModules = await import.meta.glob('./blog/posts/*.md', { eager: true });
const latestPosts = sortPostsByDate(
Object.values(postModules).map((post: any) => ({
title: post.frontmatter.title,
description: post.frontmatter.description || '',
slug: post.url?.split('/').filter(Boolean).pop() || '',
date: post.frontmatter.date || post.frontmatter.pubDate || '',
})),
).slice(0, 3);
---
<Layout title={pageTitle}>
<GlassHeader client:load transition:persist="header" lang={lang} />
<Layout title={isZh ? '首页' : 'Home'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen">
<div class="relative overflow-hidden">
<div class="absolute inset-0 -z-10">
<div class="absolute left-1/2 top-0 h-[600px] w-[800px] -translate-x-1/2 -translate-y-1/2 bg-primary/10 blur-[120px]"></div>
<div class="absolute right-0 top-1/4 h-[400px] w-[400px] bg-purple-500/5 blur-[100px]"></div>
<div class="absolute left-0 top-1/2 h-[400px] w-[400px] bg-orange-500/5 blur-[100px]"></div>
</div>
<section class="relative flex min-h-[90vh] items-center py-24 lg:py-32">
<Container className="relative z-10">
<div class="mx-auto max-w-5xl space-y-16">
<div class="space-y-8 text-center">
<div class="space-y-4">
<h1 class="text-5xl font-bold tracking-tight sm:text-7xl lg:text-8xl">
<span class="bg-gradient-to-b from-foreground to-foreground/70 bg-clip-text text-transparent">{personalInfo.name}</span>
</h1>
<p class="text-2xl font-medium text-foreground/80 sm:text-3xl">{personalInfo.position[lang]}</p>
</div>
<p class="mx-auto max-w-2xl text-lg leading-relaxed text-muted-foreground/90 sm:text-xl">{t("home.hero.summary")}</p>
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main space-y-8">
<p class="text-sm font-semibold uppercase tracking-[0.2em] text-primary">{isZh ? 'ENGINEERING PROFILE' : 'ENGINEERING PROFILE'}</p>
<h1 class="text-4xl font-bold tracking-tight text-foreground sm:text-5xl lg:text-6xl">{headline}</h1>
<p class="max-w-3xl text-lg leading-relaxed text-muted-foreground">{intro}</p>
<div class="flex flex-wrap items-center justify-center gap-4">
<a href={`${prefix}/about`} class="inline-flex h-12 items-center justify-center rounded-full bg-primary px-8 text-sm font-semibold text-primary-foreground shadow-lg shadow-primary/20 transition-all hover:translate-y-[-2px] hover:bg-primary/90 hover:shadow-xl hover:shadow-primary/30">
{t("home.hero.ctaPrimary")}
</a>
<a href={`${prefix}/hire`} class="inline-flex h-12 items-center justify-center rounded-full border border-border bg-background/50 px-8 text-sm font-semibold text-foreground backdrop-blur-sm transition-all hover:translate-y-[-2px] hover:bg-muted">
{t("home.hero.ctaSecondary")}
</a>
</div>
<div class="flex flex-wrap items-center justify-center gap-3 text-sm">
{keyFacts.map((item) => (
<span class="inline-flex items-center rounded-full border border-primary/10 bg-primary/5 px-4 py-1.5 font-medium text-primary/80 backdrop-blur-sm">
<span class="mr-2 h-1 w-1 rounded-full bg-primary/50"></span>
{item}
</span>
))}
</div>
</div>
<div class="mx-auto max-w-3xl">
<div class="group relative">
<div class="absolute -inset-1 rounded-2xl bg-gradient-to-r from-primary/20 to-purple-500/20 opacity-50 blur transition duration-1000 group-hover:opacity-100 group-hover:duration-200"></div>
<div class="page-surface relative overflow-hidden rounded-2xl border bg-card/40 backdrop-blur-md">
<div class="flex items-center justify-between border-b border-border/50 bg-muted/20 px-5 py-3">
<div class="flex items-center gap-2">
<span class="h-3 w-3 rounded-full bg-red-400/80 shadow-[0_0_8px_rgba(248,113,113,0.4)]"></span>
<span class="h-3 w-3 rounded-full bg-yellow-400/80 shadow-[0_0_8px_rgba(250,204,21,0.4)]"></span>
<span class="h-3 w-3 rounded-full bg-green-400/80 shadow-[0_0_8px_rgba(74,222,128,0.4)]"></span>
</div>
<span class="font-mono text-xs font-medium text-muted-foreground/70 tracking-tight">{personalInfo.terminal.username}</span>
</div>
<div class="space-y-3 p-6 font-mono text-sm leading-relaxed text-foreground/90">
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">whoami</span> {personalInfo.name}</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">role</span> {personalInfo.position[lang]}</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">stack</span> TypeScript, React, Node.js, Astro</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">status</span> {t("home.hero.terminalStatus")}</p>
</div>
<div class="flex gap-3">
<span class="text-primary font-bold">~</span>
<p><span class="text-primary/70">contact</span> {personalInfo.github}</p>
</div>
</div>
</div>
</div>
</div>
<div class="flex flex-wrap gap-4 pt-2">
<a href={`${prefix}/contact`} class="inline-flex h-11 items-center rounded-lg bg-primary px-6 text-sm font-semibold text-primary-foreground hover:bg-primary/90">{isZh ? '远程岗位沟通' : 'Hire for Remote Role'}</a>
<a href={`${prefix}/contact#project-collaboration`} class="inline-flex h-11 items-center rounded-lg border border-border px-6 text-sm font-semibold text-foreground hover:bg-muted">{isZh ? '发起项目合作' : 'Start a Project'}</a>
</div>
</Container>
</section>
<div class="space-y-40 pb-40">
<section class="relative">
<div class="py-24 lg:py-32">
<Container>
<div class="mb-16 flex flex-col gap-6 md:flex-row md:items-end md:justify-between">
<div class="space-y-4">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">{t("home.services.title")}</h2>
<p class="max-w-2xl text-lg leading-relaxed text-muted-foreground/90">{t("home.services.description")}</p>
</div>
<a href={`${prefix}/services`} class="inline-flex items-center text-sm font-bold text-primary transition-colors hover:text-primary/70">
{t("services.viewAll")}
<svg class="ml-1 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/></svg>
</a>
</div>
<ul class="grid gap-3 sm:grid-cols-2 pt-4">
{proofItems.map((item) => (
<li class="page-surface p-4 text-sm font-medium text-foreground/90">{item}</li>
))}
</ul>
</section>
<div class="grid gap-10 md:grid-cols-2">
{localizedServices.map((service) => (
<article class="group relative rounded-3xl p-6 transition-all duration-500 hover:bg-card/50 hover:shadow-xl hover:shadow-primary/5">
<div class="mb-8 flex items-center gap-6">
<div class={`flex h-14 w-14 items-center justify-center rounded-2xl bg-gradient-to-br ${service.icon.gradient} text-white shadow-lg transition-transform duration-500 group-hover:scale-110 group-hover:rotate-3`}>
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<Fragment set:html={service.icon.svg} />
</svg>
</div>
<h3 class="text-2xl font-bold tracking-tight">{service.title}</h3>
</div>
<ul class="space-y-4">
{service.items.slice(0, 3).map((item) => (
<li class="flex items-start gap-3 text-muted-foreground group-hover:text-foreground/90 transition-colors">
<span class="mt-2.5 h-1 w-1 shrink-0 rounded-full bg-primary/30 group-hover:bg-primary transition-all"></span>
<span class="text-base leading-relaxed">{item}</span>
</li>
))}
</ul>
</article>
))}
</div>
</Container>
<section class="page-content-main mt-20">
<div class="mb-8 flex items-end justify-between gap-4">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">{isZh ? '精选工程案例' : 'Selected Engineering Cases'}</h2>
<a href={`${prefix}/projects`} class="text-sm font-semibold text-primary hover:text-primary/80">{isZh ? '查看全部案例' : 'View All Cases'}</a>
</div>
<div class="grid gap-6 lg:grid-cols-3">
{featuredProjects.map((project) => (
<article class="page-surface p-6">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{project.systemType}</p>
<h3 class="mt-2 text-lg font-bold">{project.title}</h3>
<p class="mt-3 text-sm leading-relaxed text-muted-foreground">{project.context}</p>
<p class="mt-4 text-xs font-semibold uppercase tracking-wide text-foreground/70">{isZh ? '结果' : 'Outcome'}</p>
<p class="mt-1 text-sm text-foreground/90">{project.outcomes?.[0] ?? project.impact}</p>
</article>
))}
</div>
</section>
<section class="relative">
<Container>
<div class="mb-16 space-y-3">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl">{t("home.career.title")}</h2>
<p class="max-w-xl text-lg text-muted-foreground">{t("home.career.description")}</p>
</div>
<section class="page-content-main mt-20">
<div class="mb-8 flex items-end justify-between gap-4">
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">{isZh ? '最新写作' : 'Latest Writing'}</h2>
<a href={`${prefix}/blog`} class="text-sm font-semibold text-primary hover:text-primary/80">{isZh ? '查看全部文章' : 'View All Writing'}</a>
</div>
<div class="relative mx-auto max-w-4xl">
<div class="absolute left-0 top-0 h-full w-px bg-gradient-to-b from-primary/50 via-primary/10 to-transparent sm:left-1/2"></div>
<div class="space-y-12">
{careerMilestones.map((item, index) => (
<div class={`relative flex flex-col sm:flex-row ${index % 2 === 0 ? 'sm:flex-row-reverse' : ''}`}>
<div class="absolute -left-1.5 top-2 h-3 w-3 rounded-full border-2 border-primary bg-background sm:left-1/2 sm:-ml-1.5"></div>
<div class="w-full pl-8 sm:w-1/2 sm:px-12">
<article class="rounded-2xl p-4 transition-all hover:bg-card/40">
<span class="text-xs font-bold uppercase tracking-wider text-primary/60">{item.period}</span>
<h3 class="mt-2 text-xl font-bold leading-tight">{item.title}</h3>
<p class="mt-3 text-sm leading-relaxed text-muted-foreground/90">{item.outcome}</p>
</article>
</div>
</div>
))}
</div>
</div>
<div class="mt-16 text-center">
<a href={`${prefix}/about`} class="inline-flex h-12 items-center rounded-full border border-border bg-background px-8 text-sm font-semibold transition-all hover:bg-muted">
{t("home.career.cta")}
</a>
</div>
</Container>
</section>
<section class="relative">
<div class="py-24 lg:py-32">
<Container>
<div class="mb-12 space-y-3">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl">{t("home.featured.title")}</h2>
</div>
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{featuredProjects.map((project) => (
<article class="group flex flex-col overflow-hidden rounded-3xl border border-border/50 bg-card/50 backdrop-blur-sm transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl hover:shadow-primary/5">
{/* 顶部封面图区域 */}
<div class="relative aspect-video overflow-hidden">
<div class={`absolute inset-0 bg-gradient-to-br ${project.image?.bg || 'from-primary/20 to-purple-500/20'} transition-transform duration-700 group-hover:scale-110`}></div>
<div class="absolute inset-0 flex items-center justify-center">
<span class="text-6xl transition-transform duration-500 group-hover:scale-110 group-hover:rotate-3">{project.icon}</span>
</div>
<div class="absolute top-4 right-4">
<span class="rounded-full bg-background/80 px-3 py-1 text-[10px] font-bold uppercase tracking-wider text-foreground backdrop-blur-md">
{project.type}
</span>
</div>
</div>
{/* 内容区域 */}
<div class="flex flex-1 flex-col p-6 lg:p-8">
<div class="flex-1 space-y-4">
<h3 class="text-2xl font-bold tracking-tight">{project.title}</h3>
<p class="line-clamp-2 text-sm leading-relaxed text-muted-foreground">
{project.impact}
</p>
<div class="flex flex-wrap gap-2">
{project.tech.map((tech) => (
<span class="rounded-md bg-primary/5 px-2 py-1 text-[10px] font-medium text-primary/80">
{tech}
</span>
))}
</div>
</div>
{/* 操作按钮 */}
<div class="mt-8 flex items-center justify-between gap-4">
<a href={`${prefix}/projects`} class="inline-flex h-10 items-center justify-center rounded-full bg-primary px-6 text-xs font-bold text-primary-foreground transition-all hover:bg-primary/90">
{t("home.featured.ctaPrimary")}
</a>
{project.links?.github && (
<a href={project.links.github} target="_blank" rel="noopener noreferrer" class="inline-flex h-10 w-10 items-center justify-center rounded-full border border-border bg-background/50 text-muted-foreground transition-all hover:bg-muted hover:text-foreground">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 4.125 9.642 9.807 11.53 0.6.111 0.799-0.26 0.799-0.577 0-0.285-0.011-1.04-0.017-2.042-3.338 0.727-4.042-1.61-4.042-1.61-0.546-1.387-1.333-1.756-1.333-1.756-1.089-0.745 0.083-0.729 0.083-0.729 1.205 0.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492 0.997 0.107-0.775 0.418-1.305 0.762-1.604-2.665-0.305-5.467-1.334-5.467-5.931 0-1.311 0.469-2.381 1.236-3.221-0.124-0.303-0.535-1.524 0.117-3.176 0 0 1.008-0.322 3.301 1.23 0.96-0.267 1.98-0.399 3-0.405 1.02 0.006 2.04 0.138 3 0.405 2.28-1.552 3.285-1.23 3.285-1.23 0.654 1.653 0.242 2.874 0.118 3.176 0.77 0.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921 0.43 0.372 0.823 1.102 0.823 2.222 0 1.606-0.014 2.898-0.014 3.293 0 0.319 0.192 0.694 0.801 0.576 5.687-1.889 9.812-6.228 9.812-11.53 0-6.627-5.373-12-12-12z"/></svg>
</a>
)}
</div>
</div>
</article>
))}
</div>
</Container>
<div class="grid gap-4 md:grid-cols-3">
{latestPosts.map((post) => (
<article class="page-surface p-5">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{post.date}</p>
<h3 class="mt-2 text-base font-bold leading-snug">
<a href={`${prefix}/blog/posts/${post.slug}`} class="hover:text-primary">{post.title}</a>
</h3>
<p class="mt-2 line-clamp-3 text-sm text-muted-foreground">{post.description}</p>
</article>
))}
</div>
</section>
<section class="relative">
<Container>
<div class="flex flex-col items-center text-center">
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl mb-6">{t("home.final.title")}</h2>
<p class="text-lg leading-relaxed text-muted-foreground/90 sm:text-xl max-w-2xl mb-10">{t("home.final.description")}</p>
<div class="flex flex-wrap justify-center gap-4">
<a href={`${prefix}/about`} class="inline-flex h-12 items-center justify-center rounded-full bg-primary px-8 text-sm font-semibold text-primary-foreground transition-all hover:translate-y-[-2px] hover:bg-primary/90">
{t("home.final.ctaPrimary")}
</a>
<a href={`${prefix}/hire`} class="inline-flex h-12 items-center justify-center rounded-full border border-border px-8 text-sm font-semibold text-foreground transition-all hover:translate-y-[-2px] hover:bg-muted">
{t("home.final.ctaSecondary")}
</a>
</div>
</div>
</Container>
<section class="page-content-main mt-20 page-surface p-8">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '下一步' : 'Next Step'}</h2>
<p class="mt-3 text-muted-foreground">{isZh ? '如果你正在招聘远程工程师,或希望推进复杂系统项目,我很乐意沟通。' : 'If you are hiring for a remote engineering role or need help shipping a complex system, I would love to connect.'}</p>
<div class="mt-6 flex flex-wrap gap-3">
<a href={`${prefix}/contact`} class="inline-flex h-10 items-center rounded-lg bg-primary px-5 text-sm font-semibold text-primary-foreground">{isZh ? '联系我' : 'Contact Me'}</a>
<a href={`${prefix}/about`} class="inline-flex h-10 items-center rounded-lg border border-border px-5 text-sm font-semibold hover:bg-muted">{isZh ? '了解更多' : 'About Me'}</a>
</div>
</section>
</div>
</div>
</main>
</Container>
</main>
<Footer lang={lang} client:only="react" />
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,228 +1,67 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import { useTranslations } from "@/i18n/utils";
import { Hammer, Zap, Telescope, Bot, Target, Rocket, Sparkles, MessageSquare, Handshake, MapPin } from "lucide-react";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const pageTitle = lang === 'zh' ? '现在' : 'Now';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
const doing = isZh
? ['推进工程化案例化的个人站升级', '优化远程协作下的交付流程与文档标准', '持续打磨 AI 协作开发实践']
: ['Upgrading this portfolio into an engineering case-study site', 'Improving remote-first delivery workflow and documentation quality', 'Refining practical AI-assisted development workflows'];
const exploring = isZh
? ['复杂权限系统的前端边界设计', '大规模业务表单与状态流管理', '更稳定的跨团队异步协作机制']
: ['Frontend boundary design for complex permission systems', 'Scalable state management for large business forms', 'More stable async collaboration practices across teams'];
const shipping = isZh
? ['工程案例库结构重构', '导航与路由转化路径优化', '双语文案统一与信息层级简化']
: ['Refactoring project pages into engineering case studies', 'Optimizing navigation and conversion routes', 'Unifying EN/ZH copy and simplifying information hierarchy'];
---
<Layout title={pageTitle}>
<Layout title={isZh ? '现在' : 'Now'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden">
<!-- 背景装饰 -->
<div class="absolute inset-0 -z-10">
<div class="absolute left-1/2 top-0 h-[800px] w-[1000px] -translate-x-1/2 -translate-y-1/2 bg-primary/10 blur-[120px]"></div>
<div class="absolute right-0 top-1/3 h-[500px] w-[500px] bg-blue-500/5 blur-[100px]"></div>
</div>
<!-- Now Page Hero -->
<section class="pt-32 pb-24 relative overflow-hidden">
<div class="page-hero-overlay" aria-hidden="true"></div>
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '现在' : 'Now'}</h1>
<p class="mt-4 text-lg text-muted-foreground">{isZh ? '我当前的工作重点与近期交付。' : 'What I am focusing on right now and what I am shipping recently.'}</p>
</section>
<Container className="relative z-10">
<div class="max-w-4xl mx-auto text-center">
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-bold uppercase tracking-wider mb-6 animate-fade-in">
<span class="relative flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
</span>
{lang === 'zh' ? '实时状态' : "Live Status"}
</div>
<h1 class="page-title-gradient text-6xl md:text-8xl font-bold mb-8 tracking-tight">
{lang === 'zh' ? '现在' : 'Now'}
</h1>
<p class="text-xl md:text-2xl text-muted-foreground leading-relaxed max-w-2xl mx-auto">
{lang === 'zh'
? '关于我现在正在关注的事、正在构建的产品以及我的生活状态。'
: 'What I am currently focusing on, the products I am building, and my life status.'}
</p>
</div>
</Container>
</section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-3">
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{isZh ? '在做什么' : 'Doing'}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{doing.map((item) => <li>• {item}</li>)}
</ul>
</article>
<!-- Main Content -->
<section class="pb-32 relative mt-12 md:mt-24">
<Container>
<div class="max-w-4xl mx-auto space-y-24">
<!-- Building Section -->
<div class="space-y-10">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-primary/10 rounded-xl flex items-center justify-center border border-primary/20">
<Hammer className="w-6 h-6 text-primary" />
</div>
<h2 class="text-3xl md:text-4xl font-bold tracking-tight">
{lang === 'zh' ? '正在构建' : 'Building'}
</h2>
</div>
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{isZh ? '在研究什么' : 'Exploring'}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{exploring.map((item) => <li>• {item}</li>)}
</ul>
</article>
<div class="group relative">
<div class="absolute -inset-1 rounded-[2rem] bg-gradient-to-r from-primary/30 to-blue-600/30 opacity-20 blur-xl transition duration-500 group-hover:opacity-40"></div>
<div class="page-surface relative p-8 md:p-12 overflow-hidden border-primary/10 rounded-[2rem]">
<div class="flex flex-col md:flex-row gap-10 items-start">
<div class="w-24 h-24 bg-gradient-to-br from-primary to-blue-600 rounded-2xl flex items-center justify-center flex-shrink-0 shadow-lg shadow-primary/20 group-hover:scale-105 transition-transform duration-500">
<Zap className="w-12 h-12 text-white" />
</div>
<div class="flex-1 space-y-6">
<div class="flex items-center justify-between">
<h3 class="text-3xl font-bold">Elynd</h3>
<span class="px-4 py-1.5 bg-green-500/10 text-green-600 dark:text-green-400 rounded-full text-xs font-bold border border-green-500/20 uppercase tracking-wider">Active</span>
</div>
<p class="text-xl text-muted-foreground leading-relaxed">
{lang === 'zh'
? '一个开放的 AI 工作空间,让构建者能够更智能地工作。从 AI 第一性原理出发,打造完全开放、可自托管的协作工具。'
: 'An open AI workspace for builders to work smarter. Built from first principles of AI, creating fully open, self-hostable collaboration tools.'}
</p>
<div class="flex flex-wrap gap-3 pt-2">
{['AI Product', 'TypeScript', 'Open Source', 'Astro'].map(tag => (
<span class="px-4 py-2 bg-secondary/50 text-secondary-foreground rounded-lg text-sm font-medium border border-border/50">{tag}</span>
))}
</div>
</div>
</div>
</div>
</div>
</div>
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{isZh ? '最近交付' : 'Shipping'}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{shipping.map((item) => <li>• {item}</li>)}
</ul>
</article>
</section>
<!-- Exploring Section -->
<div class="space-y-10">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-blue-500/10 rounded-xl flex items-center justify-center border border-blue-500/20">
<Telescope className="w-6 h-6 text-blue-500" />
</div>
<h2 class="text-3xl md:text-4xl font-bold tracking-tight">
{lang === 'zh' ? '正在探索' : 'Exploring'}
</h2>
</div>
<div class="grid gap-8 md:grid-cols-2">
{[
{
title: lang === 'zh' ? 'AI Agents 与工作流自动化' : 'AI Agents & Workflow Automation',
desc: lang === 'zh' ? '研究如何构建能够自主完成复杂任务的 AI Agent以及如何将 AI 能力融入日常工作流。' : 'Researching how to build AI Agents that can autonomously complete complex tasks, and how to integrate AI capabilities into daily workflows.',
icon: Bot
},
{
title: lang === 'zh' ? '产品导向的开发实践' : 'Product-Led Development Practices',
desc: lang === 'zh' ? '探索从产品角度思考开发,构建真正解决用户问题的产品,而不仅仅是技术实现。' : 'Exploring product thinking in development, building products that truly solve user problems, not just technical implementations.',
icon: Target
}
].map(item => (
<div class="page-surface p-8 rounded-3xl hover:translate-y-[-4px] transition-all duration-300 border-border/50 group">
<div class="w-12 h-12 bg-muted rounded-xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-300">
<item.icon className="w-6 h-6 text-foreground" />
</div>
<h3 class="text-2xl font-bold mb-4">{item.title}</h3>
<p class="text-muted-foreground text-base leading-relaxed">{item.desc}</p>
</div>
))}
</div>
</div>
<!-- Shipping Section -->
<div class="space-y-10">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-green-500/10 rounded-xl flex items-center justify-center border border-green-500/20">
<Rocket className="w-6 h-6 text-green-500" />
</div>
<h2 class="text-3xl md:text-4xl font-bold tracking-tight">
{lang === 'zh' ? '最近发布' : 'Shipping'}
</h2>
</div>
<div class="space-y-6">
{[
{
title: lang === 'zh' ? '个人网站全新改版' : 'Portfolio Redesign',
desc: lang === 'zh' ? '基于 Astro 5 和 Tailwind 4 的高性能双语站点。' : 'High-performance bilingual site built with Astro 5 & Tailwind 4.',
icon: Sparkles,
color: 'bg-green-500/10',
iconColor: 'text-green-500'
},
{
title: lang === 'zh' ? 'DeepSeek 满血版接入' : 'DeepSeek Full Access',
desc: lang === 'zh' ? '在本地工作流中深度整合 DeepSeek-V3 提升效率。' : 'Deep integration of DeepSeek-V3 in local workflows for efficiency.',
icon: MessageSquare,
color: 'bg-blue-500/10',
iconColor: 'text-blue-500'
}
].map(item => (
<div class="group relative flex items-center gap-6 p-4 rounded-2xl hover:bg-muted/50 transition-all duration-300">
<div class={`w-12 h-12 ${item.color} rounded-xl flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform`}>
<item.icon className={`w-6 h-6 ${item.iconColor}`} />
</div>
<div class="flex-1 min-w-0">
<h3 class="font-bold text-lg group-hover:text-primary transition-colors truncate">
{item.title}
</h3>
<p class="text-sm text-muted-foreground line-clamp-1">
{item.desc}
</p>
</div>
<div class="text-muted-foreground/30 group-hover:text-primary/50 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
</div>
</div>
))}
</div>
</div>
<!-- Bottom Grid: Collaboration & Meta -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 pt-8">
<!-- Collaboration Card -->
<div class="relative group h-full">
<div class="absolute -inset-1 rounded-[2.5rem] bg-gradient-to-br from-yellow-500/20 to-orange-500/20 blur opacity-75"></div>
<div class="page-surface relative p-10 border-yellow-500/10 bg-gradient-to-br from-card to-yellow-500/5 rounded-[2.5rem] h-full flex flex-col justify-between">
<div>
<div class="w-14 h-14 bg-yellow-500/10 rounded-2xl flex items-center justify-center mb-8">
<Handshake className="w-8 h-8 text-yellow-600 dark:text-yellow-400" />
</div>
<h3 class="text-3xl font-bold mb-4">{lang === 'zh' ? '开放合作' : 'Collaborate'}</h3>
<p class="text-lg text-muted-foreground mb-8 leading-relaxed">
{lang === 'zh'
? '始终对有趣的产品想法 and 技术咨询持开放态度。'
: "Always open to interesting product ideas and technical consulting."}
</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<a href={lang === 'zh' ? '/zh/hire' : '/hire'} class="flex items-center justify-center py-4 rounded-2xl bg-primary text-primary-foreground font-bold text-base hover:scale-[1.02] transition-transform">
{lang === 'zh' ? '合作方式' : 'View Options'}
</a>
<a href="mailto:zhaoguiyang18@gmail.com" class="flex items-center justify-center py-4 rounded-2xl border border-border bg-background/50 text-foreground font-bold text-base hover:bg-muted transition-colors">
{lang === 'zh' ? '发送邮件' : 'Email Me'}
</a>
</div>
</div>
</div>
<!-- Meta/Status Card -->
<div class="page-surface p-10 border-border/50 rounded-[2.5rem] flex flex-col items-center justify-center text-center space-y-6">
<div class="w-20 h-20 bg-muted rounded-full flex items-center justify-center text-3xl">
<MapPin className="w-10 h-10 text-primary" />
</div>
<div class="space-y-2">
<h3 class="text-2xl font-bold">{lang === 'zh' ? '当前位置' : 'Location'}</h3>
<p class="text-muted-foreground">{lang === 'zh' ? '中国 · 杭州' : 'Hangzhou, China'}</p>
</div>
<div class="pt-4 w-full">
<div class="inline-flex items-center gap-3 px-5 py-2.5 rounded-full bg-muted/50 border border-border/50 mx-auto">
<span class="text-xs text-muted-foreground uppercase font-bold tracking-widest border-r border-border/50 pr-3">
{lang === 'zh' ? '最后更新' : 'Updated'}
</span>
<span class="text-sm font-semibold">2025.03.14</span>
</div>
</div>
</div>
</div>
</div>
</Container>
</section>
<section class="page-content-main mt-8 page-surface p-6">
<p class="text-sm text-muted-foreground">
{isZh ? '最后更新2026-03-16' : 'Last updated: 2026-03-16'}
</p>
</section>
</Container>
</main>
<Footer lang={lang} client:only="react" />
<Footer lang={lang} client:load />
</Layout>

View File

@@ -1,114 +1,133 @@
---
import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import ProjectCard from "@/components/ProjectCard.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
import { projects } from "@/lib/data/index";
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { projects } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
// 使用Astro.currentLocale获取当前语言环境
const lang = Astro.currentLocale as Lang || defaultLang;
const t = useTranslations(lang);
const pageTitle = t('projects.title');
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
const pageProjects = projects[lang];
// 根据当前语言获取项目数据
const currentProjects = projects[lang as keyof typeof projects] || projects.en;
const filterOptions = [
{ key: "all", label: t("project.filter.all") },
{ key: "product", label: t("project.type.product") },
{ key: "client", label: t("project.type.client") },
{ key: "experiment", label: t("project.type.experiment") },
const filters = [
{ key: 'all', label: isZh ? '全部' : 'All' },
{ key: 'product', label: isZh ? '产品系统' : 'Product Systems' },
{ key: 'client', label: isZh ? '企业项目' : 'Client Systems' },
{ key: 'experiment', label: isZh ? '实验项目' : 'Experiments' },
];
---
<Layout title={pageTitle}>
<Layout title={isZh ? '项目' : 'Projects'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden">
<div
aria-hidden="true"
class="page-hero-overlay"
></div>
<section class="relative z-10 py-24">
<Container>
<div class="text-center mb-8">
<h1 class="page-title-gradient text-5xl md:text-6xl font-bold mb-6">
{t('projects.title')}
</h1>
<p class="text-lg text-muted-foreground page-content-main mb-12 leading-relaxed">
{t('projects.slogan')} {t('projects.description')}
</p>
<main class="min-h-screen pt-24 pb-20" data-projects-root>
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '工程案例' : 'Engineering Case Studies'}</h1>
<p class="mt-4 text-lg leading-relaxed text-muted-foreground">
{isZh
? '围绕复杂系统建设的真实项目经验,重点展示技术挑战、职责边界和结果。'
: 'Real projects focused on complex system delivery, highlighting technical challenges, responsibilities, and outcomes.'}
</p>
</section>
<section class="page-content-main mt-8">
<div class="page-surface mb-8 flex flex-wrap gap-2 p-2">
{filters.map((filter, index) => (
<button
type="button"
data-filter={filter.key}
aria-pressed={index === 0 ? 'true' : 'false'}
class={`rounded-md px-4 py-2 text-sm font-semibold ${index === 0 ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground'}`}
>
{filter.label}
</button>
))}
</div>
</Container>
</section>
<section class="relative z-10 pb-20" data-projects-root>
<Container>
<div class="page-content-main">
<div class="page-surface flex flex-wrap gap-2 mb-8 p-1 rounded-xl">
{filterOptions.map((option, index) => (
<button
type="button"
data-filter={option.key}
aria-pressed={index === 0 ? "true" : "false"}
class={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
index === 0
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-muted"
}`}
>
{option.label}
</button>
))}
</div>
<div class="space-y-6">
{pageProjects.map((project) => (
<article data-project-card data-type={project.type} class="page-surface p-6 md:p-8">
<div class="grid gap-6 lg:grid-cols-[1.2fr_1fr]">
<div>
<p class="text-xs font-semibold uppercase tracking-wider text-primary">{project.systemType}</p>
<h2 class="mt-2 text-2xl font-bold tracking-tight">{project.title}</h2>
<p class="mt-3 text-muted-foreground">{project.context}</p>
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{currentProjects.map((project) => (
<ProjectCard project={project} lang={lang} showStatus={true} />
))}
</div>
<div class="mt-5 flex flex-wrap gap-2">
{project.tech.map((tech) => (
<span class="rounded-md border border-border bg-muted/50 px-2.5 py-1 text-xs font-medium">{tech}</span>
))}
</div>
</div>
<div class="space-y-4">
<div>
<h3 class="text-sm font-bold uppercase tracking-wider text-foreground/80">{isZh ? '技术挑战' : 'Technical Challenges'}</h3>
<ul class="mt-2 space-y-1.5 text-sm text-muted-foreground">
{project.challenges?.map((item) => <li>• {item}</li>)}
</ul>
</div>
<div>
<h3 class="text-sm font-bold uppercase tracking-wider text-foreground/80">{isZh ? '职责范围' : 'Responsibilities'}</h3>
<ul class="mt-2 space-y-1.5 text-sm text-muted-foreground">
{project.responsibilities?.map((item) => <li>• {item}</li>)}
</ul>
</div>
<div>
<h3 class="text-sm font-bold uppercase tracking-wider text-foreground/80">{isZh ? '结果' : 'Outcomes'}</h3>
<ul class="mt-2 space-y-1.5 text-sm text-foreground/90">
{project.outcomes?.map((item) => <li>• {item}</li>)}
</ul>
</div>
</div>
</div>
</article>
))}
</div>
</Container>
</section>
</section>
</Container>
</main>
<Footer lang={lang} client:load />
</Layout>
<script>
const projectsRoot = document.querySelector("[data-projects-root]");
if (projectsRoot) {
const filterButtons = Array.from(projectsRoot.querySelectorAll("[data-filter]"));
const projectCards = Array.from(projectsRoot.querySelectorAll("[data-project-card]"));
const root = document.querySelector('[data-projects-root]');
if (!root) {
// no-op
} else {
const buttons = Array.from(root.querySelectorAll('[data-filter]'));
const cards = Array.from(root.querySelectorAll('[data-project-card]'));
const applyFilter = (activeFilter) => {
projectCards.forEach((card) => {
const projectType = card.getAttribute("data-type");
const shouldShow = activeFilter === "all" || projectType === activeFilter;
card.classList.toggle("hidden", !shouldShow);
const apply = (activeFilter) => {
cards.forEach((card) => {
const cardType = card.getAttribute('data-type');
const visible = activeFilter === 'all' || activeFilter === cardType;
card.classList.toggle('hidden', !visible);
});
filterButtons.forEach((button) => {
const isActive = button.getAttribute("data-filter") === activeFilter;
button.setAttribute("aria-pressed", isActive ? "true" : "false");
button.classList.toggle("bg-primary", isActive);
button.classList.toggle("text-primary-foreground", isActive);
button.classList.toggle("text-muted-foreground", !isActive);
button.classList.toggle("hover:text-foreground", !isActive);
button.classList.toggle("hover:bg-muted", !isActive);
buttons.forEach((button) => {
const isActive = button.getAttribute('data-filter') === activeFilter;
button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
button.classList.toggle('bg-primary', isActive);
button.classList.toggle('text-primary-foreground', isActive);
button.classList.toggle('text-muted-foreground', !isActive);
button.classList.toggle('hover:bg-muted', !isActive);
button.classList.toggle('hover:text-foreground', !isActive);
});
};
filterButtons.forEach((button) => {
button.addEventListener("click", () => {
const selectedFilter = button.getAttribute("data-filter") ?? "all";
applyFilter(selectedFilter);
buttons.forEach((button) => {
button.addEventListener('click', () => {
apply(button.getAttribute('data-filter') ?? 'all');
});
});
applyFilter("all");
apply('all');
}
</script>

View File

@@ -1,42 +1,14 @@
---
title: "我能做什么"
description: "专注于构建 AI 产品和技术卓越的专业服务"
title: "页面已迁移"
description: "该页面已迁移到新的结构。"
layout: "../../layouts/AboutLayout.astro"
---
import HighlightBox from '../../components/markdown/HighlightBox.astro';
# 页面已迁移
# 我能做什么 🚀
原 **服务** 页面已拆分为更清晰的页面:
<HighlightBox type="tip">
构建 AI 驱动产品,将雄心勃勃的想法变为现实。
</HighlightBox>
- [工具](/zh/uses)
- [联系](/zh/contact)
## AI 产品开发 🤖
- 从概念到上线构建 AI 驱动产品
- RAG 应用、AI Agent 和智能自动化
- 使用现代技术栈的全栈开发React、Next.js、Node.js
- 产品思维 - 专注于解决实际问题
- 快速原型和迭代开发
## 技术咨询 📊
<HighlightBox type="info" title="我可以如何帮助">
- 技术架构和技术栈决策
- 代码审查和最佳实践实施
- 团队指导和知识转移
- 性能优化和扩展策略
- 投资技术尽职调查
</HighlightBox>
# 一起构建 💼
<HighlightBox type="success" title="联系我">
我始终对讨论新项目和机会持开放态度。无论你是正在寻找技术合伙人、需要帮助构建 AI 产品,还是想要技术咨询 - 让我们聊聊。
- 邮箱:**zhaoguiyang18@gmail.com**
- 查看我的[合作](/zh/hire)页面了解合作方式
</HighlightBox>
如需沟通远程岗位,请优先前往 [联系](/zh/contact)。

40
src/pages/zh/uses.astro Normal file
View File

@@ -0,0 +1,40 @@
---
import Layout from '@/layouts/Layout.astro';
import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer';
import Container from '@/components/ui/Container.astro';
import { uses } from '@/lib/data';
import type { Lang } from '@/types/i18n';
import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
---
<Layout title={isZh ? '工具' : 'Uses'}>
<GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen pt-24 pb-20">
<Container>
<section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '工具与工作流' : 'Uses'}</h1>
<p class="mt-4 text-lg text-muted-foreground">
{isZh ? '我在日常研发中稳定使用的工具与协作方式。' : 'Tools and workflows I use for daily engineering work.'}
</p>
</section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-2">
{uses.map((group) => (
<article class="page-surface p-6">
<h2 class="text-lg font-bold">{group.title[lang]}</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground">
{group.items.map((item) => <li>• {item}</li>)}
</ul>
</article>
))}
</section>
</Container>
</main>
<Footer lang={lang} client:load />
</Layout>

View File

@@ -43,14 +43,28 @@ export interface ProjectImage {
export interface Project {
id: string;
tag: string;
tag?: string;
title: string;
icon: string;
type?: string;
status?: string;
role?: string;
impact?: string;
systemType?: string;
context?: string;
challenges?: string[];
responsibilities?: string[];
outcomes?: string[];
color: string;
image: ProjectImage;
description: string[];
tech: string[];
link: string;
featured?: boolean;
links?: {
github?: string;
demo?: string;
};
}
export interface ServiceIcon {
@@ -63,4 +77,21 @@ export interface Service {
icon: ServiceIcon;
items: string[];
color: string;
}
}
export interface UsesGroup {
title: LocalizedText;
items: string[];
}
export interface ContactIntent {
id: string;
title: LocalizedText;
description: LocalizedText;
}
export interface ContactMethod {
label: LocalizedText;
value: string;
href?: string;
}