Compare commits

..

6 Commits

Author SHA1 Message Date
zguiyang
45bdc497d8 refactor: naturalize English copy with developer voice
Remove AI-generated phrasing patterns and replace with conversational
developer language. Key changes:
- Replace "always-learning mindset" with authentic expressions
- Use "I built for myself" storytelling approach for projects
- Simplify complex phrases like "bridge comprehension breaks"
- Make method card descriptions more conversational
2026-03-17 15:12:14 +08:00
zguiyang
6327cf4d47 feat(hire): add payment terms (443) and remove mock labels
- Add payment terms section with 40% upfront, 40% mid-review, 20% completion
- Add payment FAQ entry
- Remove (Mock) labels from collaboration models and FAQ sections
2026-03-17 15:01:15 +08:00
zguiyang
8c7c6da03b refactor(now): restructure page with result-oriented content
- Replace Doing/Exploring/Shipping with Current Focus, Problems I'm Solving, Recent Outputs, Availability
- Focus on completed results rather than ongoing learning processes
- Add project status badges (Live/Coming Soon)
- Include abstract problem statements showing product thinking
- Add availability section with job preferences and project types
- Update date to auto-generate on each build
2026-03-17 13:37:58 +08:00
zguiyang
ff9dde98c7 feat(about): update narrative and capabilities with developer tone
Replaced formal descriptions with more natural developer voice for
about page narrative and core capabilities sections.
2026-03-17 12:42:43 +08:00
zguiyang
71d8af996a feat(projects): add cover images for Elynd and Linky with hover animation
- Added preview images for Elynd and Linky projects
- Added hover scale animation (scale-105) for cover images
2026-03-17 12:17:28 +08:00
zguiyang
014430e1b7 feat(projects): update Elynd details and add Linky project
- Revise Elynd from experimental AI workspace to AI English learning platform
- Add Linky as new indie project (self-hosted bookmark manager)
- Add status badges (completed/in-progress) to project cards
- Add Preview and GitHub action buttons to project cards
- Improve card layout with flexbox for better content alignment
2026-03-17 11:05:43 +08:00
8 changed files with 547 additions and 157 deletions

View File

@@ -44,7 +44,7 @@ export const heroPrinciples: LocalizedText[] = [
zh: '目前寻求远程工作机会,如你正在招聘,欢迎联系我。', zh: '目前寻求远程工作机会,如你正在招聘,欢迎联系我。',
}, },
{ {
en: 'Evolving from frontend toward full-stack, and building as an AI-era product engineer with an always-learning mindset.', en: 'Started as a frontend dev, now building full-stack skills while embracing AI as a productivity tool.',
zh: '我正在从前端走向全栈,持续进化为 AI 时代的产品工程师,不给自己设限。', zh: '我正在从前端走向全栈,持续进化为 AI 时代的产品工程师,不给自己设限。',
}, },
]; ];
@@ -90,15 +90,15 @@ export const brandProofPoints: LocalizedText[] = [
zh: '8 年企业级、金融科技、区块链系统经验', zh: '8 年企业级、金融科技、区块链系统经验',
}, },
{ {
en: 'Hands-on lead for architecture, core modules, and engineering workflows', en: 'Led architecture and core modules for multiple products',
zh: '可主导架构、核心模块和工程化流程落地', zh: '可主导架构、核心模块和工程化流程落地',
}, },
{ {
en: 'Strong in complex interactions, visual systems, and high-volume data workflows', en: 'Good at complex interactions, visual systems, and data-heavy workflows',
zh: '擅长复杂交互、可视化系统和大数据量业务流程', zh: '擅长复杂交互、可视化系统和大数据量业务流程',
}, },
{ {
en: 'Combines AI tooling with delivery to improve speed and clarity', en: 'Using AI tools to speed up development and understand codebases faster',
zh: '将 AI 工具用于研发提效、项目理解与文档沉淀', zh: '将 AI 工具用于研发提效、项目理解与文档沉淀',
}, },
]; ];
@@ -110,7 +110,7 @@ export const brandMethodCards: LocalizedCard[] = [
zh: '先定义问题', zh: '先定义问题',
}, },
description: { description: {
en: 'I align business context, technical boundaries, and delivery constraints before implementation.', en: 'I make sure we understand the problem before writing code — business context, technical limits, and timeline all need to be clear.',
zh: '编码之前先对齐业务上下文、技术边界和交付约束。', zh: '编码之前先对齐业务上下文、技术边界和交付约束。',
}, },
}, },
@@ -120,7 +120,7 @@ export const brandMethodCards: LocalizedCard[] = [
zh: '为迭代设计架构', zh: '为迭代设计架构',
}, },
description: { description: {
en: 'I build module boundaries and component conventions so systems can evolve safely.', en: 'I design module boundaries and component patterns so the system can grow without becoming a mess.',
zh: '通过模块边界与组件规范,确保系统能稳定演进。', zh: '通过模块边界与组件规范,确保系统能稳定演进。',
}, },
}, },
@@ -130,7 +130,7 @@ export const brandMethodCards: LocalizedCard[] = [
zh: '透明化执行', zh: '透明化执行',
}, },
description: { description: {
en: 'I keep progress visible via milestones, docs, and explicit decision records.', en: 'I share progress regularly — milestones, docs, and decisions are all visible to everyone involved.',
zh: '通过里程碑、文档和决策记录,让推进过程可视、可追踪。', zh: '通过里程碑、文档和决策记录,让推进过程可视、可追踪。',
}, },
}, },
@@ -267,35 +267,35 @@ export const brandTimeline: TimelineItem[] = [
export const aboutNarrative: LocalizedText[] = [ export const aboutNarrative: LocalizedText[] = [
{ {
en: 'I focus on complex business systems where architecture and long-term maintainability are critical.', en: '8 years of frontend experience, mostly working on complex business systems — fintech, enterprise tools, and products with heavy interactions. I care about code that survives the first release.',
zh: '我长期专注复杂业务系统,核心关注点是架构质量和长期可维护性。', zh: '做了 8 年前端,大部分时间在跟复杂业务系统打交道——金融、企业后台、交互密集型产品。代码要能经得起后续迭代,这是我关心的。',
}, },
{ {
en: 'My strengths combine frontend architecture, engineering processes, and cross-role collaboration.', en: 'Spent a lot of time building from scratch and extracting reusable patterns. Led frontend architecture for 3+ core products, set up internal component libraries, and pushed engineering standards across teams.',
zh: '我的优势在于前端架构能力、工程化推进能力和跨角色协作。', zh: '从 0 到 1 搭过不少项目,也从业务里抽过不少通用组件。带过 3+ 核心产品的前端架构,做过内部组件库,推过团队工程规范。',
}, },
{ {
en: 'This website is my long-term knowledge base for projects, methods, and practical lessons.', en: 'Recently started bringing AI into my workflow — not to chase trends, but because it genuinely helps me read code, analyze logic, and write docs faster.',
zh: '这个网站会持续沉淀项目案例、工作方法与可复用经验。', zh: '这两年在把 AI 融入日常开发流程,不是赶潮流,是真的拿它来帮忙读代码、分析逻辑、写文档。确实省时间。',
}, },
]; ];
export const aboutCapabilities: LocalizedText[] = [ export const aboutCapabilities: LocalizedText[] = [
{ {
en: 'Complex frontend system architecture and module governance', en: 'Frontend architecture & module design for complex products',
zh: '复杂前端系统架构与模块治理', zh: '复杂产品的模块设计与前端架构',
}, },
{ {
en: 'Data visualization and real-time interaction system implementation', en: 'Component libraries & engineering standardization (Vite / Webpack)',
zh: '数据可视化与实时交互系统开发', zh: '组件封装与工程化体系建设',
}, },
{ {
en: 'From-zero-to-one product frontend setup and engineering standardization', en: 'Complex interactions, data visualization, and real-time systems',
zh: '从 0 到 1 前端体系建设与工程规范落地', zh: '复杂交互、可视化与实时数据处理',
}, },
{ {
en: 'AI-assisted code understanding, documentation, and troubleshooting', en: 'AI-enhanced development workflow & cross-team collaboration',
zh: 'AI 辅助代码理解、文档沉淀与问题排查', zh: 'AI 提效开发与跨角色协作',
}, },
]; ];
@@ -382,6 +382,16 @@ export const collaborationProcess: LocalizedText[] = [
]; ];
export const collaborationFaq: QAItem[] = [ export const collaborationFaq: QAItem[] = [
{
question: {
en: 'Payment terms?',
zh: '付款方式?',
},
answer: {
en: '40% upfront, 40% at mid-point review, 20% upon completion.',
zh: '40% 预付款40% 中期验收20% 尾款。',
},
},
{ {
question: { question: {
en: 'Do you only do project-based work?', en: 'Do you only do project-based work?',

View File

@@ -159,32 +159,109 @@ const sharedCases: Project[] = [
}, },
{ {
id: 'elynd', id: 'elynd',
featured: false, featured: true,
type: 'experiment', type: 'product',
status: 'building', status: 'building',
role: 'Founder & Developer', role: 'Founder & Developer',
impact: 'Exploring AI-assisted development workflows in production-like scenarios', impact: 'Built an AI-powered English reading and learning platform for language learners',
systemType: 'AI-assisted workspace', systemType: 'AI-powered English reading & learning platform',
context: 'An open workspace product exploring practical AI collaboration in software development.', context: 'An AI-assisted English reading learning tool that combines reading, listening, word lookup, and AI Q&A to help users practice low-barrier language input.',
title: 'Elynd', title: 'Elynd - AI English Learning Platform',
icon: 'Zap', icon: 'BookOpen',
color: 'purple', color: 'purple',
image: { image: {
bg: 'from-purple-500/20 to-blue-500/20', bg: 'from-purple-500/20 to-blue-500/20',
hover: 'from-purple-500/30 to-blue-500/30', hover: 'from-purple-500/30 to-blue-500/30',
text: 'text-purple-500', text: 'text-purple-500',
}, },
challenges: ['Designing useful AI workflows without adding process burden'], challenges: [
responsibilities: ['Product exploration and end-to-end implementation'], 'Designing a smooth graded reading experience with content difficulty adaptation',
outcomes: ['Validated several practical AI-assisted development patterns'], 'Implementing real-time TTS audio playback with Azure Speech SDK',
description: [ 'Building an efficient word lookup system with instant definitions',
'An open AI workspace for builders.', 'Creating AI-powered Q&A that understands reading context',
'Used as an R&D track, not the primary professional narrative.',
], ],
coverImage: '', responsibilities: [
coverImageAlt: 'Elynd project cover', 'End-to-end product development from concept to launch',
tech: ['TypeScript', 'React', 'AI Workflow', 'Open Source'], 'Designed and implemented backend API with AdonisJS v6',
link: '#', 'Built frontend with Vue 3, TypeScript, and modern UI components',
'Integrated OpenAI SDK for AI conversation features',
'Implemented EPUB import and content parsing pipeline',
],
outcomes: [
'Launched a complete learning platform with 4 core features',
'Achieved smooth reading experience with progress tracking',
'Integrated Azure TTS for immersive listening practice',
'Enabled AI-powered interactive learning with context awareness',
],
description: [
'AI-powered English reading and learning platform.',
'Combines reading, listening, word lookup, and AI Q&A for comprehensive language learning.',
],
tech: [
'AdonisJS v6',
'PostgreSQL',
'Redis',
'Vue 3',
'TypeScript',
'Pinia',
'Reka UI',
'shadcn-vue',
'Tailwind CSS 4',
'OpenAI SDK',
'Azure Speech SDK',
'pnpm workspace',
],
link: 'https://github.com/zguiyang/elynd',
coverImage: 'https://cloud.zgyk.cc/f/VoFa/elynd-home.png',
coverImageAlt: 'Elynd Dashboard Preview',
links: {
github: 'https://github.com/zguiyang/elynd',
demo: 'https://elynd.zhaoguiyang.com/',
},
},
{
id: 'linky',
featured: true,
type: 'product',
status: 'completed',
role: 'Founder & Developer',
impact: 'Built a self-hosted knowledge management tool for bookmarks and notes',
systemType: 'Personal knowledge management system',
context: 'A simple, self-hosted tool for organizing bookmarks and writing notes with full user data control.',
title: 'Linky',
icon: 'Link',
color: 'cyan',
image: {
bg: 'from-cyan-500/20 to-blue-500/20',
hover: 'from-cyan-500/30 to-blue-500/30',
text: 'text-cyan-500',
},
challenges: [
'Designing intuitive bookmark organization with tags',
'Implementing AI-powered auto-tagging feature',
'Building self-hosted authentication system',
],
responsibilities: [
'End-to-end product development',
'Backend API design with AdonisJS',
'Frontend implementation with Nuxt',
],
outcomes: [
'Launched self-hosted version with full user data ownership',
'Integrated AI auto-tagging with OpenAI compatible APIs',
],
description: [
'A self-hosted bookmark manager and note-taking tool.',
'Focus on privacy, simplicity, and AI-assisted organization.',
],
tech: ['AdonisJS', 'Nuxt', 'PostgreSQL', 'Vue', 'Pinia', 'Tailwind CSS'],
link: 'https://github.com/zguiyang/linky',
coverImage: 'https://cloud.zgyk.cc/f/nYHM/linky-home.png',
coverImageAlt: 'Linky Dashboard Preview',
links: {
github: 'https://github.com/zguiyang/linky',
demo: 'https://linky.zhaoguiyang.com/',
},
}, },
]; ];
@@ -246,15 +323,74 @@ export const projects = {
{ {
...sharedCases[4], ...sharedCases[4],
role: '创始人 & 开发者', role: '创始人 & 开发者',
impact: '在真实场景中探索 AI 协作开发工作流', impact: '打造 AI 辅助英语阅读学习平台,帮助语言学习者提升阅读能力',
systemType: 'AI 协作工作空间', systemType: 'AI 驱动英语阅读学习平台',
context: '探索 AI 在软件工程中可落地协作方式的开放产品。', context: 'AI 辅助的英语阅读学习工具,通过「阅读 + 听读 + 查词 + AI 提问」四位一体帮助用户完成低门槛的语言输入练习。',
title: 'Elynd', title: 'Elynd - AI 英语学习平台',
challenges: ['在不增加流程负担前提下设计有效 AI 工作流'], challenges: [
responsibilities: ['产品探索与端到端实现'], '设计流畅的分级阅读体验,实现内容难度自适应',
outcomes: ['验证多种可实践的 AI 协作开发模式'], '集成 Azure Speech SDK 实现实时 TTS 音频播放',
description: ['一个面向构建者的开放 AI 工作空间。', '作为研发探索方向,不作为职业主叙事。'], '构建高效的即点查词系统,支持即时释义显示',
tech: ['TypeScript', 'React', 'AI 协作', '开源'], '打造理解阅读上下文的 AI 智能问答功能',
],
responsibilities: [
'从概念到上线的端到端产品开发',
'使用 AdonisJS v6 设计与实现后端 API',
'使用 Vue 3、TypeScript 和现代 UI 组件构建前端',
'集成 OpenAI SDK 实现 AI 对话功能',
'实现 EPUB 导入与内容解析流程',
],
outcomes: [
'上线具备 4 大核心功能的完整学习平台',
'实现流畅阅读体验与学习进度跟踪',
'集成 Azure TTS 实现沉浸式听读练习',
'支持上下文感知的 AI 智能交互学习',
],
description: [
'AI 驱动的英语阅读学习平台。',
'融合阅读、听读、查词、AI 问答,一站式语言学习体验。',
],
tech: [
'AdonisJS v6',
'PostgreSQL',
'Redis',
'Vue 3',
'TypeScript',
'Pinia',
'Reka UI',
'shadcn-vue',
'Tailwind CSS 4',
'OpenAI SDK',
'Azure Speech SDK',
'pnpm workspace',
],
},
{
...sharedCases[5],
role: '创始人 & 开发者',
impact: '打造自托管的书签管理与笔记工具,让用户完全掌控自己的数据',
systemType: '个人知识管理系统',
context: '简单、自托管的工具,用于组织书签和写笔记,数据完全由用户自己掌控。',
title: 'Linky',
challenges: [
'设计直观的书签组织系统,支持标签化管理',
'实现 AI 自动标签功能',
'构建自托管认证系统',
],
responsibilities: [
'端到端产品开发',
'使用 AdonisJS 设计后端 API',
'使用 Nuxt 实现前端',
],
outcomes: [
'上线自托管版本,用户完全拥有数据主权',
'集成 AI 自动标签功能,支持 OpenAI 兼容 API',
],
description: [
'自托管的书签管理器和笔记工具。',
'注重隐私、简洁和 AI 辅助整理。',
],
tech: ['AdonisJS', 'Nuxt', 'PostgreSQL', 'Vue', 'Pinia', 'Tailwind CSS'],
}, },
], ],
}; };

View File

@@ -32,7 +32,7 @@ const isZh = lang === 'zh';
</section> </section>
<section class="page-content-main mt-10"> <section class="page-content-main mt-10">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '合作模型Mock' : 'Collaboration Models (Mock)'}</h2> <h2 class="text-2xl font-bold tracking-tight">{isZh ? '合作模型' : 'Collaboration Models'}</h2>
<div class="mt-4 grid gap-4 md:grid-cols-3"> <div class="mt-4 grid gap-4 md:grid-cols-3">
{collaborationModels.map((model) => ( {collaborationModels.map((model) => (
<article class="page-surface p-5"> <article class="page-surface p-5">
@@ -69,7 +69,25 @@ const isZh = lang === 'zh';
</section> </section>
<section class="page-content-main mt-6 page-surface p-6"> <section class="page-content-main mt-6 page-surface p-6">
<h2 class="text-xl font-bold">{isZh ? '常见问题Mock' : 'FAQ (Mock)'}</h2> <h2 class="text-xl font-bold">{isZh ? '付款方式' : 'Payment Terms'}</h2>
<div class="mt-4 flex flex-wrap gap-3">
<div class="flex-1 min-w-[120px] rounded-lg border border-border/70 p-4 text-center">
<p class="text-2xl font-bold text-primary">40%</p>
<p class="text-sm text-muted-foreground">{isZh ? '预付款' : 'Upfront'}</p>
</div>
<div class="flex-1 min-w-[120px] rounded-lg border border-border/70 p-4 text-center">
<p class="text-2xl font-bold text-primary">40%</p>
<p class="text-sm text-muted-foreground">{isZh ? '中期验收' : 'Mid Review'}</p>
</div>
<div class="flex-1 min-w-[120px] rounded-lg border border-border/70 p-4 text-center">
<p class="text-2xl font-bold text-primary">20%</p>
<p class="text-sm text-muted-foreground">{isZh ? '尾款' : 'Completion'}</p>
</div>
</div>
</section>
<section class="page-content-main mt-6 page-surface p-6">
<h2 class="text-xl font-bold">{isZh ? '常见问题' : 'FAQ'}</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{collaborationFaq.map((item) => ( {collaborationFaq.map((item) => (
<div class="rounded-md border border-border/70 p-4"> <div class="rounded-md border border-border/70 p-4">

View File

@@ -9,55 +9,122 @@ import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang; const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh'; const isZh = lang === 'zh';
const doing = isZh const focuses = [
? ['推进工程化案例化的个人站升级', '优化远程协作下的交付流程与文档标准', '持续打磨 AI 协作开发实践'] {
: ['Upgrading this portfolio into an engineering case-study site', 'Improving remote-first delivery workflow and documentation quality', 'Refining practical AI-assisted development workflows']; title: 'Cloud Bookmark Tool',
status: 'Live',
desc: 'A self-hosted bookmark manager I built for myself — then realized others might want it too. Handles AI tagging, content extraction, and search.',
},
{
title: 'ELYND English Learning Tool',
status: 'Coming Soon',
desc: 'Reading English articles with synced audio, instant word lookup, and AI chat to ask questions about what I am reading.',
},
];
const exploring = isZh const problems = [
? ['复杂权限系统的前端边界设计', '大规模业务表单与状态流管理', '更稳定的跨团队异步协作机制'] {
: ['Frontend boundary design for complex permission systems', 'Scalable state management for large business forms', 'More stable async collaboration practices across teams']; title: 'The "Understanding Gap" in Language Learning',
desc: 'Vocabulary memorization lacks context, original texts are hard to understand, and there is no instant feedback when stuck.',
},
{
title: 'Productizing AI Capabilities',
desc: 'Making AI useful in real products, not just demos: tagging, text processing, and conversation that actually help.',
},
{
title: 'UX Design for AI-Powered Tools',
desc: 'Adding AI without making things complicated — keeping tools simple while powerful.',
},
];
const shipping = isZh const outputs = [
? ['工程案例库结构重构', '导航与路由转化路径优化', '双语文案统一与信息层级简化'] 'Cloud Bookmark Tool v1.0 launched',
: ['Refactoring project pages into engineering case studies', 'Optimizing navigation and conversion routes', 'Unifying EN/ZH copy and simplifying information hierarchy']; 'ELYND coming soon',
];
const availability = {
jobs: 'Remote / Full-stack / AI',
projects: 'Freelance / Subcontracting / Independent development',
preferences: 'Tool products / AI integration / Web applications',
};
const today = new Date().toISOString().split('T')[0];
--- ---
<Layout title={isZh ? '现在' : 'Now'}> <Layout title="Now">
<GlassHeader lang={lang} client:load transition:persist="header" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen pt-24 pb-20"> <main class="min-h-screen pt-24 pb-20">
<Container> <Container>
<section class="page-content-main"> <section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '现在' : 'Now'}</h1> <h1 class="text-4xl font-bold tracking-tight sm:text-5xl">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> <p class="mt-4 text-lg text-muted-foreground">What I am working on and what I have shipped.</p>
</section> </section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-3"> <!-- Current Focus -->
<article class="page-surface p-6"> <section class="page-content-main mt-10">
<h2 class="text-lg font-bold">{isZh ? '在做什么' : 'Doing'}</h2> <h2 class="text-xl font-bold">Current Focus</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground"> <div class="mt-4 space-y-4">
{doing.map((item) => <li>• {item}</li>)} {focuses.map((item) => (
</ul> <article class="page-surface p-5">
</article> <div class="flex items-center gap-3">
<h3 class="text-base font-bold">{item.title}</h3>
<article class="page-surface p-6"> <span class="rounded-full bg-primary/10 px-2.5 py-0.5 text-xs font-medium text-primary">{item.status}</span>
<h2 class="text-lg font-bold">{isZh ? '在研究什么' : 'Exploring'}</h2> </div>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground"> <p class="mt-2 text-sm text-muted-foreground">{item.desc}</p>
{exploring.map((item) => <li>• {item}</li>)} </article>
</ul> ))}
</article> </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> </section>
<section class="page-content-main mt-8 page-surface p-6"> <!-- Problems I'm Solving -->
<section class="page-content-main mt-8">
<h2 class="text-xl font-bold">Problems I'm Solving</h2>
<div class="mt-4 space-y-3">
{problems.map((item) => (
<article class="rounded-lg border border-border/70 p-4">
<h3 class="text-sm font-semibold">{item.title}</h3>
<p class="mt-1.5 text-sm text-muted-foreground">{item.desc}</p>
</article>
))}
</div>
</section>
<!-- Recent Outputs -->
<section class="page-content-main mt-8">
<h2 class="text-xl font-bold">Recent Outputs</h2>
<ul class="mt-4 space-y-2">
{outputs.map((item) => (
<li class="flex items-center gap-2 text-sm">
<span class="h-1.5 w-1.5 rounded-full bg-accent"></span>
{item}
</li>
))}
</ul>
</section>
<!-- Availability -->
<section class="page-content-main mt-8 page-surface p-5">
<h2 class="text-xl font-bold">Availability</h2>
<div class="mt-4 grid gap-3 text-sm md:grid-cols-3">
<div>
<span class="font-medium">Open to: </span>
<span class="text-muted-foreground">{availability.jobs}</span>
</div>
<div>
<span class="font-medium">Projects: </span>
<span class="text-muted-foreground">{availability.projects}</span>
</div>
<div>
<span class="font-medium">Preferred: </span>
<span class="text-muted-foreground">{availability.preferences}</span>
</div>
</div>
</section>
<section class="page-content-main mt-8 page-surface p-4">
<p class="text-sm text-muted-foreground"> <p class="text-sm text-muted-foreground">
{isZh ? '最后更新2026-03-16' : 'Last updated: 2026-03-16'} Last updated: {today}
</p> </p>
</section> </section>
</Container> </Container>

View File

@@ -11,7 +11,7 @@ const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh'; const isZh = lang === 'zh';
const pageProjects = projects[lang].map((project) => ({ const pageProjects = projects[lang].map((project) => ({
...project, ...project,
category: project.id === 'elynd' ? 'indie' : 'enterprise', category: project.id === 'elynd' || project.id === 'linky' ? 'indie' : 'enterprise',
})); }));
const enterpriseProjects = pageProjects.filter((project) => project.category === 'enterprise'); const enterpriseProjects = pageProjects.filter((project) => project.category === 'enterprise');
const indieProjects = pageProjects.filter((project) => project.category === 'indie'); const indieProjects = pageProjects.filter((project) => project.category === 'indie');
@@ -66,13 +66,13 @@ const indieProjects = pageProjects.filter((project) => project.category === 'ind
</div> </div>
<div class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3"> <div class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3">
{indieProjects.map((project) => ( {indieProjects.map((project) => (
<article class="page-surface overflow-hidden"> <article class="page-surface h-full overflow-hidden flex flex-col">
<div class="relative aspect-[16/9] overflow-hidden border-b border-border/70 bg-muted/30"> <div class="relative aspect-[16/9] overflow-hidden border-b border-border/70 bg-muted/30">
{project.coverImage ? ( {project.coverImage ? (
<img <img
src={project.coverImage} src={project.coverImage}
alt={project.coverImageAlt || project.title} alt={project.coverImageAlt || project.title}
class="h-full w-full object-cover" class="h-full w-full object-cover transition-transform duration-300 ease-out hover:scale-105"
loading="lazy" loading="lazy"
decoding="async" decoding="async"
/> />
@@ -83,22 +83,59 @@ const indieProjects = pageProjects.filter((project) => project.category === 'ind
<p class="mt-1 text-sm text-foreground/80">{project.systemType}</p> <p class="mt-1 text-sm text-foreground/80">{project.systemType}</p>
</div> </div>
)} )}
</div> {/* Status Badge */}
<div class="p-5"> <div class="absolute right-3 top-3">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{isZh ? '独立项目' : 'Independent'}</p> <span
<h3 class="mt-2 text-lg font-bold">{project.title}</h3> class={`inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium ${
<p class="text-sm text-muted-foreground">{project.context}</p> project.status === 'completed'
<div class="mt-4 flex flex-wrap gap-2"> ? 'bg-emerald-500/20 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30'
{project.tech.slice(0, 5).map((tech) => ( : 'bg-amber-500/20 text-amber-600 dark:text-amber-400 border border-amber-500/30'
<span class="rounded-md border border-border bg-muted/50 px-2.5 py-1 text-xs font-medium">{tech}</span> }`}
))} >
{project.status === 'completed' ? (isZh ? '已完成' : 'Completed') : (isZh ? '开发中' : 'In Progress')}
</span>
</div>
</div>
<div class="flex flex-1 flex-col p-5">
<div class="flex flex-1 flex-col pb-4">
<h3 class="text-lg font-bold">{project.title}</h3>
{project.context && <p class="mt-2 text-sm text-muted-foreground">{project.context}</p>}
<div class="mt-4 flex flex-wrap gap-2">
{project.tech.slice(0, 5).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>
{/* Action Buttons */}
<div class="mt-auto flex gap-3 border-t border-border/50 pt-5">
{project.links?.demo && (
<a
href={project.links.demo}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 rounded-md bg-primary px-3.5 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4">
<path d="M12.232 4.232a2.5 2.5 0 0 1 3.536 3.536l-1.225 1.224a.75.75 0 0 0 1.061 1.06l1.224-1.224a4 4 0 0 0-5.656-5.656l-3 3a4 4 0 0 0 .225 5.865.75.75 0 0 0 .977-1.139 2.5 2.5 0 0 1-.142-3.635l3-3Z" />
<path d="M11.603 7.963a.75.75 0 0 0-.977 1.139 2.5 2.5 0 0 1 .142 3.635l-3 3a4 4 0 0 0 5.656 5.656l1.224-1.224a.75.75 0 0 0-1.06-1.06l-1.224 1.224a2.5 2.5 0 0 1-3.536-3.536l1.225-1.224a.75.75 0 0 0-1.061-1.06l-1.224 1.224a4 4 0 0 0-5.656-5.656l-3 3a4 4 0 0 0-.225 5.865Z" />
</svg>
{isZh ? '预览' : 'Preview'}
</a>
)}
{project.links?.github && (
<a
href={project.links.github}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3.5 py-2 text-sm font-medium shadow-sm transition-colors hover:bg-muted"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="h-4 w-4">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
GitHub
</a>
)}
</div> </div>
<p class="mt-4 text-sm font-semibold text-foreground/90">{isZh ? '结果:' : 'Outcome:'} {project.outcomes?.[0] ?? project.impact}</p>
{project.link !== '#' && (
<a href={project.link} target="_blank" rel="noopener noreferrer" class="mt-3 inline-flex text-sm font-semibold text-primary hover:text-primary/80">
{isZh ? '查看项目' : 'Open Project'}
</a>
)}
</div> </div>
</article> </article>
))} ))}

View File

@@ -32,7 +32,7 @@ const isZh = lang === 'zh';
</section> </section>
<section class="page-content-main mt-10"> <section class="page-content-main mt-10">
<h2 class="text-2xl font-bold tracking-tight">{isZh ? '合作模型Mock' : 'Collaboration Models (Mock)'}</h2> <h2 class="text-2xl font-bold tracking-tight">{isZh ? '合作模型' : 'Collaboration Models'}</h2>
<div class="mt-4 grid gap-4 md:grid-cols-3"> <div class="mt-4 grid gap-4 md:grid-cols-3">
{collaborationModels.map((model) => ( {collaborationModels.map((model) => (
<article class="page-surface p-5"> <article class="page-surface p-5">
@@ -69,7 +69,25 @@ const isZh = lang === 'zh';
</section> </section>
<section class="page-content-main mt-6 page-surface p-6"> <section class="page-content-main mt-6 page-surface p-6">
<h2 class="text-xl font-bold">{isZh ? '常见问题Mock' : 'FAQ (Mock)'}</h2> <h2 class="text-xl font-bold">{isZh ? '付款方式' : 'Payment Terms'}</h2>
<div class="mt-4 flex flex-wrap gap-3">
<div class="flex-1 min-w-[120px] rounded-lg border border-border/70 p-4 text-center">
<p class="text-2xl font-bold text-primary">40%</p>
<p class="text-sm text-muted-foreground">{isZh ? '预付款' : 'Upfront'}</p>
</div>
<div class="flex-1 min-w-[120px] rounded-lg border border-border/70 p-4 text-center">
<p class="text-2xl font-bold text-primary">40%</p>
<p class="text-sm text-muted-foreground">{isZh ? '中期验收' : 'Mid Review'}</p>
</div>
<div class="flex-1 min-w-[120px] rounded-lg border border-border/70 p-4 text-center">
<p class="text-2xl font-bold text-primary">20%</p>
<p class="text-sm text-muted-foreground">{isZh ? '尾款' : 'Completion'}</p>
</div>
</div>
</section>
<section class="page-content-main mt-6 page-surface p-6">
<h2 class="text-xl font-bold">{isZh ? '常见问题' : 'FAQ'}</h2>
<div class="mt-4 space-y-4"> <div class="mt-4 space-y-4">
{collaborationFaq.map((item) => ( {collaborationFaq.map((item) => (
<div class="rounded-md border border-border/70 p-4"> <div class="rounded-md border border-border/70 p-4">

View File

@@ -9,55 +9,122 @@ import { defaultLang } from '@/i18n/ui';
const lang = (Astro.currentLocale as Lang) || defaultLang; const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh'; const isZh = lang === 'zh';
const doing = isZh const focuses = [
? ['推进工程化案例化的个人站升级', '优化远程协作下的交付流程与文档标准', '持续打磨 AI 协作开发实践'] {
: ['Upgrading this portfolio into an engineering case-study site', 'Improving remote-first delivery workflow and documentation quality', 'Refining practical AI-assisted development workflows']; title: '云端书签工具',
status: '已上线',
desc: '面向开发者与信息工作者的轻量级自部署工具,数据完全可控。支持 AI 自动标签、内容识别与语义搜索。',
},
{
title: 'ELYND 英语学习工具',
status: '即将上线',
desc: '基于阅读场景的英语学习产品,提供电子书与同步音频。支持点击单词/句子即时解释AI 对话辅助理解。',
},
];
const exploring = isZh const problems = [
? ['复杂权限系统的前端边界设计', '大规模业务表单与状态流管理', '更稳定的跨团队异步协作机制'] {
: ['Frontend boundary design for complex permission systems', 'Scalable state management for large business forms', 'More stable async collaboration practices across teams']; title: '英语学习中的「理解断点」问题',
desc: '背单词脱离语境、阅读原文有障碍、遇到问题缺乏即时反馈——想解决学习过程中的理解断裂。',
},
{
title: 'AI 能力的产品化落地',
desc: '不只是 Demo 层面的展示,而是在真实产品中接入 AI 标签、文本处理、对话能力。',
},
{
title: '工具型 AI 产品的用户体验',
desc: '如何在保持工具简洁性的同时,融入 AI 能力而不造成负担。',
},
];
const shipping = isZh const outputs = [
? ['工程案例库结构重构', '导航与路由转化路径优化', '双语文案统一与信息层级简化'] '云端书签工具 v1.0 上线',
: ['Refactoring project pages into engineering case studies', 'Optimizing navigation and conversion routes', 'Unifying EN/ZH copy and simplifying information hierarchy']; 'ELYND 即将发布',
];
const availability = {
jobs: '远程 / 全栈 / AI 方向',
projects: '外包 / 分包 / 独立项目开发',
preferences: '工具类产品 / AI 能力接入 / Web 应用',
};
const today = new Date().toISOString().split('T')[0];
--- ---
<Layout title={isZh ? '现在' : 'Now'}> <Layout title="现在">
<GlassHeader lang={lang} client:load transition:persist="header" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen pt-24 pb-20"> <main class="min-h-screen pt-24 pb-20">
<Container> <Container>
<section class="page-content-main"> <section class="page-content-main">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">{isZh ? '现在' : 'Now'}</h1> <h1 class="text-4xl font-bold tracking-tight sm:text-5xl">现在</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> <p class="mt-4 text-lg text-muted-foreground">我当前的工作状态与产出。</p>
</section> </section>
<section class="page-content-main mt-10 grid gap-6 md:grid-cols-3"> <!-- 当前主线 -->
<article class="page-surface p-6"> <section class="page-content-main mt-10">
<h2 class="text-lg font-bold">{isZh ? '在做什么' : 'Doing'}</h2> <h2 class="text-xl font-bold">当前主线</h2>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground"> <div class="mt-4 space-y-4">
{doing.map((item) => <li>• {item}</li>)} {focuses.map((item) => (
</ul> <article class="page-surface p-5">
</article> <div class="flex items-center gap-3">
<h3 class="text-base font-bold">{item.title}</h3>
<article class="page-surface p-6"> <span class="rounded-full bg-primary/10 px-2.5 py-0.5 text-xs font-medium text-primary">{item.status}</span>
<h2 class="text-lg font-bold">{isZh ? '在研究什么' : 'Exploring'}</h2> </div>
<ul class="mt-4 space-y-2 text-sm text-muted-foreground"> <p class="mt-2 text-sm text-muted-foreground">{item.desc}</p>
{exploring.map((item) => <li>• {item}</li>)} </article>
</ul> ))}
</article> </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> </section>
<section class="page-content-main mt-8 page-surface p-6"> <!-- 当前关注的问题 -->
<section class="page-content-main mt-8">
<h2 class="text-xl font-bold">当前关注的问题</h2>
<div class="mt-4 space-y-3">
{problems.map((item) => (
<article class="rounded-lg border border-border/70 p-4">
<h3 class="text-sm font-semibold">{item.title}</h3>
<p class="mt-1.5 text-sm text-muted-foreground">{item.desc}</p>
</article>
))}
</div>
</section>
<!-- 近期产出 -->
<section class="page-content-main mt-8">
<h2 class="text-xl font-bold">近期产出</h2>
<ul class="mt-4 space-y-2">
{outputs.map((item) => (
<li class="flex items-center gap-2 text-sm">
<span class="h-1.5 w-1.5 rounded-full bg-accent"></span>
{item}
</li>
))}
</ul>
</section>
<!-- 当前状态 -->
<section class="page-content-main mt-8 page-surface p-5">
<h2 class="text-xl font-bold">当前状态</h2>
<div class="mt-4 grid gap-3 text-sm md:grid-cols-3">
<div>
<span class="font-medium">求职:</span>
<span class="text-muted-foreground">{availability.jobs}</span>
</div>
<div>
<span class="font-medium">接单:</span>
<span class="text-muted-foreground">{availability.projects}</span>
</div>
<div>
<span class="font-medium">偏好:</span>
<span class="text-muted-foreground">{availability.preferences}</span>
</div>
</div>
</section>
<section class="page-content-main mt-8 page-surface p-4">
<p class="text-sm text-muted-foreground"> <p class="text-sm text-muted-foreground">
{isZh ? '最后更新2026-03-16' : 'Last updated: 2026-03-16'} 最后更新:{today}
</p> </p>
</section> </section>
</Container> </Container>

View File

@@ -11,7 +11,7 @@ const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh'; const isZh = lang === 'zh';
const pageProjects = projects[lang].map((project) => ({ const pageProjects = projects[lang].map((project) => ({
...project, ...project,
category: project.id === 'elynd' ? 'indie' : 'enterprise', category: project.id === 'elynd' || project.id === 'linky' ? 'indie' : 'enterprise',
})); }));
const enterpriseProjects = pageProjects.filter((project) => project.category === 'enterprise'); const enterpriseProjects = pageProjects.filter((project) => project.category === 'enterprise');
const indieProjects = pageProjects.filter((project) => project.category === 'indie'); const indieProjects = pageProjects.filter((project) => project.category === 'indie');
@@ -66,13 +66,13 @@ const indieProjects = pageProjects.filter((project) => project.category === 'ind
</div> </div>
<div class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3"> <div class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3">
{indieProjects.map((project) => ( {indieProjects.map((project) => (
<article class="page-surface overflow-hidden"> <article class="page-surface h-full overflow-hidden flex flex-col">
<div class="relative aspect-[16/9] overflow-hidden border-b border-border/70 bg-muted/30"> <div class="relative aspect-[16/9] overflow-hidden border-b border-border/70 bg-muted/30">
{project.coverImage ? ( {project.coverImage ? (
<img <img
src={project.coverImage} src={project.coverImage}
alt={project.coverImageAlt || project.title} alt={project.coverImageAlt || project.title}
class="h-full w-full object-cover" class="h-full w-full object-cover transition-transform duration-300 ease-out hover:scale-105"
loading="lazy" loading="lazy"
decoding="async" decoding="async"
/> />
@@ -83,22 +83,59 @@ const indieProjects = pageProjects.filter((project) => project.category === 'ind
<p class="mt-1 text-sm text-foreground/80">{project.systemType}</p> <p class="mt-1 text-sm text-foreground/80">{project.systemType}</p>
</div> </div>
)} )}
</div> {/* Status Badge */}
<div class="p-5"> <div class="absolute right-3 top-3">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{isZh ? '独立项目' : 'Independent'}</p> <span
<h3 class="mt-2 text-lg font-bold">{project.title}</h3> class={`inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium ${
<p class="text-sm text-muted-foreground">{project.context}</p> project.status === 'completed'
<div class="mt-4 flex flex-wrap gap-2"> ? 'bg-emerald-500/20 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30'
{project.tech.slice(0, 5).map((tech) => ( : 'bg-amber-500/20 text-amber-600 dark:text-amber-400 border border-amber-500/30'
<span class="rounded-md border border-border bg-muted/50 px-2.5 py-1 text-xs font-medium">{tech}</span> }`}
))} >
{project.status === 'completed' ? (isZh ? '已完成' : 'Completed') : (isZh ? '开发中' : 'In Progress')}
</span>
</div>
</div>
<div class="flex flex-1 flex-col p-5">
<div class="flex flex-1 flex-col pb-4">
<h3 class="text-lg font-bold">{project.title}</h3>
{project.context && <p class="mt-2 text-sm text-muted-foreground">{project.context}</p>}
<div class="mt-4 flex flex-wrap gap-2">
{project.tech.slice(0, 5).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>
{/* Action Buttons */}
<div class="mt-auto flex gap-3 border-t border-border/50 pt-5">
{project.links?.demo && (
<a
href={project.links.demo}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 rounded-md bg-primary px-3.5 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="h-4 w-4">
<path d="M12.232 4.232a2.5 2.5 0 0 1 3.536 3.536l-1.225 1.224a.75.75 0 0 0 1.061 1.06l1.224-1.224a4 4 0 0 0-5.656-5.656l-3 3a4 4 0 0 0 .225 5.865.75.75 0 0 0 .977-1.139 2.5 2.5 0 0 1-.142-3.635l3-3Z" />
<path d="M11.603 7.963a.75.75 0 0 0-.977 1.139 2.5 2.5 0 0 1 .142 3.635l-3 3a4 4 0 0 0 5.656 5.656l1.224-1.224a.75.75 0 0 0-1.06-1.06l-1.224 1.224a2.5 2.5 0 0 1-3.536-3.536l1.225-1.224a.75.75 0 0 0-1.061-1.06l-1.224 1.224a4 4 0 0 0-5.656-5.656l-3 3a4 4 0 0 0-.225 5.865Z" />
</svg>
{isZh ? '预览' : 'Preview'}
</a>
)}
{project.links?.github && (
<a
href={project.links.github}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3.5 py-2 text-sm font-medium shadow-sm transition-colors hover:bg-muted"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="h-4 w-4">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
GitHub
</a>
)}
</div> </div>
<p class="mt-4 text-sm font-semibold text-foreground/90">{isZh ? '结果:' : 'Outcome:'} {project.outcomes?.[0] ?? project.impact}</p>
{project.link !== '#' && (
<a href={project.link} target="_blank" rel="noopener noreferrer" class="mt-3 inline-flex text-sm font-semibold text-primary hover:text-primary/80">
{isZh ? '查看项目' : 'Open Project'}
</a>
)}
</div> </div>
</article> </article>
))} ))}