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: '目前寻求远程工作机会,如你正在招聘,欢迎联系我。',
},
{
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 时代的产品工程师,不给自己设限。',
},
];
@@ -90,15 +90,15 @@ export const brandProofPoints: LocalizedText[] = [
zh: '8 年企业级、金融科技、区块链系统经验',
},
{
en: 'Hands-on lead for architecture, core modules, and engineering workflows',
en: 'Led architecture and core modules for multiple products',
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: '擅长复杂交互、可视化系统和大数据量业务流程',
},
{
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 工具用于研发提效、项目理解与文档沉淀',
},
];
@@ -110,7 +110,7 @@ export const brandMethodCards: LocalizedCard[] = [
zh: '先定义问题',
},
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: '编码之前先对齐业务上下文、技术边界和交付约束。',
},
},
@@ -120,7 +120,7 @@ export const brandMethodCards: LocalizedCard[] = [
zh: '为迭代设计架构',
},
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: '通过模块边界与组件规范,确保系统能稳定演进。',
},
},
@@ -130,7 +130,7 @@ export const brandMethodCards: LocalizedCard[] = [
zh: '透明化执行',
},
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: '通过里程碑、文档和决策记录,让推进过程可视、可追踪。',
},
},
@@ -267,35 +267,35 @@ export const brandTimeline: TimelineItem[] = [
export const aboutNarrative: LocalizedText[] = [
{
en: 'I focus on complex business systems where architecture and long-term maintainability are critical.',
zh: '我长期专注复杂业务系统,核心关注点是架构质量和长期可维护性。',
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: '做了 8 年前端,大部分时间在跟复杂业务系统打交道——金融、企业后台、交互密集型产品。代码要能经得起后续迭代,这是我关心的。',
},
{
en: 'My strengths combine frontend architecture, engineering processes, and cross-role collaboration.',
zh: '我的优势在于前端架构能力、工程化推进能力和跨角色协作。',
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: '从 0 到 1 搭过不少项目,也从业务里抽过不少通用组件。带过 3+ 核心产品的前端架构,做过内部组件库,推过团队工程规范。',
},
{
en: 'This website is my long-term knowledge base for projects, methods, and practical lessons.',
zh: '这个网站会持续沉淀项目案例、工作方法与可复用经验。',
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: '这两年在把 AI 融入日常开发流程,不是赶潮流,是真的拿它来帮忙读代码、分析逻辑、写文档。确实省时间。',
},
];
export const aboutCapabilities: LocalizedText[] = [
{
en: 'Complex frontend system architecture and module governance',
zh: '复杂前端系统架构与模块治理',
en: 'Frontend architecture & module design for complex products',
zh: '复杂产品的模块设计与前端架构',
},
{
en: 'Data visualization and real-time interaction system implementation',
zh: '数据可视化与实时交互系统开发',
en: 'Component libraries & engineering standardization (Vite / Webpack)',
zh: '组件封装与工程化体系建设',
},
{
en: 'From-zero-to-one product frontend setup and engineering standardization',
zh: '从 0 到 1 前端体系建设与工程规范落地',
en: 'Complex interactions, data visualization, and real-time systems',
zh: '复杂交互、可视化与实时数据处理',
},
{
en: 'AI-assisted code understanding, documentation, and troubleshooting',
zh: 'AI 辅助代码理解、文档沉淀与问题排查',
en: 'AI-enhanced development workflow & cross-team collaboration',
zh: 'AI 提效开发与跨角色协作',
},
];
@@ -382,6 +382,16 @@ export const collaborationProcess: LocalizedText[] = [
];
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: {
en: 'Do you only do project-based work?',

View File

@@ -159,32 +159,109 @@ const sharedCases: Project[] = [
},
{
id: 'elynd',
featured: false,
type: 'experiment',
featured: true,
type: 'product',
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',
impact: 'Built an AI-powered English reading and learning platform for language learners',
systemType: 'AI-powered English reading & learning platform',
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 - AI English Learning Platform',
icon: 'BookOpen',
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.',
challenges: [
'Designing a smooth graded reading experience with content difficulty adaptation',
'Implementing real-time TTS audio playback with Azure Speech SDK',
'Building an efficient word lookup system with instant definitions',
'Creating AI-powered Q&A that understands reading context',
],
coverImage: '',
coverImageAlt: 'Elynd project cover',
tech: ['TypeScript', 'React', 'AI Workflow', 'Open Source'],
link: '#',
responsibilities: [
'End-to-end product development from concept to launch',
'Designed and implemented backend API with AdonisJS v6',
'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],
role: '创始人 & 开发者',
impact: '在真实场景中探索 AI 协作开发工作流',
systemType: 'AI 协作工作空间',
context: '探索 AI 在软件工程中可落地协作方式的开放产品。',
title: 'Elynd',
challenges: ['在不增加流程负担前提下设计有效 AI 工作流'],
responsibilities: ['产品探索与端到端实现'],
outcomes: ['验证多种可实践的 AI 协作开发模式'],
description: ['一个面向构建者的开放 AI 工作空间。', '作为研发探索方向,不作为职业主叙事。'],
tech: ['TypeScript', 'React', 'AI 协作', '开源'],
impact: '打造 AI 辅助英语阅读学习平台,帮助语言学习者提升阅读能力',
systemType: 'AI 驱动英语阅读学习平台',
context: 'AI 辅助的英语阅读学习工具,通过「阅读 + 听读 + 查词 + AI 提问」四位一体帮助用户完成低门槛的语言输入练习。',
title: 'Elynd - AI 英语学习平台',
challenges: [
'设计流畅的分级阅读体验,实现内容难度自适应',
'集成 Azure Speech SDK 实现实时 TTS 音频播放',
'构建高效的即点查词系统,支持即时释义显示',
'打造理解阅读上下文的 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 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">
{collaborationModels.map((model) => (
<article class="page-surface p-5">
@@ -69,7 +69,25 @@ const isZh = lang === 'zh';
</section>
<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">
{collaborationFaq.map((item) => (
<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 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 focuses = [
{
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
? ['复杂权限系统的前端边界设计', '大规模业务表单与状态流管理', '更稳定的跨团队异步协作机制']
: ['Frontend boundary design for complex permission systems', 'Scalable state management for large business forms', 'More stable async collaboration practices across teams'];
const problems = [
{
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
? ['工程案例库结构重构', '导航与路由转化路径优化', '双语文案统一与信息层级简化']
: ['Refactoring project pages into engineering case studies', 'Optimizing navigation and conversion routes', 'Unifying EN/ZH copy and simplifying information hierarchy'];
const outputs = [
'Cloud Bookmark Tool v1.0 launched',
'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" />
<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>
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">Now</h1>
<p class="mt-4 text-lg text-muted-foreground">What I am working on and what I have shipped.</p>
</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>
<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>
<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>
<!-- Current Focus -->
<section class="page-content-main mt-10">
<h2 class="text-xl font-bold">Current Focus</h2>
<div class="mt-4 space-y-4">
{focuses.map((item) => (
<article class="page-surface p-5">
<div class="flex items-center gap-3">
<h3 class="text-base font-bold">{item.title}</h3>
<span class="rounded-full bg-primary/10 px-2.5 py-0.5 text-xs font-medium text-primary">{item.status}</span>
</div>
<p class="mt-2 text-sm text-muted-foreground">{item.desc}</p>
</article>
))}
</div>
</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">
{isZh ? '最后更新2026-03-16' : 'Last updated: 2026-03-16'}
Last updated: {today}
</p>
</section>
</Container>

View File

@@ -11,7 +11,7 @@ const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
const pageProjects = projects[lang].map((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 indieProjects = pageProjects.filter((project) => project.category === 'indie');
@@ -66,13 +66,13 @@ const indieProjects = pageProjects.filter((project) => project.category === 'ind
</div>
<div class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3">
{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">
{project.coverImage ? (
<img
src={project.coverImage}
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"
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>
</div>
)}
</div>
<div class="p-5">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{isZh ? '独立项目' : 'Independent'}</p>
<h3 class="mt-2 text-lg font-bold">{project.title}</h3>
<p class="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>
))}
{/* Status Badge */}
<div class="absolute right-3 top-3">
<span
class={`inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium ${
project.status === 'completed'
? 'bg-emerald-500/20 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30'
: 'bg-amber-500/20 text-amber-600 dark:text-amber-400 border border-amber-500/30'
}`}
>
{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>
<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>
</article>
))}

View File

@@ -32,7 +32,7 @@ const isZh = lang === 'zh';
</section>
<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">
{collaborationModels.map((model) => (
<article class="page-surface p-5">
@@ -69,7 +69,25 @@ const isZh = lang === 'zh';
</section>
<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">
{collaborationFaq.map((item) => (
<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 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 focuses = [
{
title: '云端书签工具',
status: '已上线',
desc: '面向开发者与信息工作者的轻量级自部署工具,数据完全可控。支持 AI 自动标签、内容识别与语义搜索。',
},
{
title: 'ELYND 英语学习工具',
status: '即将上线',
desc: '基于阅读场景的英语学习产品,提供电子书与同步音频。支持点击单词/句子即时解释AI 对话辅助理解。',
},
];
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 problems = [
{
title: '英语学习中的「理解断点」问题',
desc: '背单词脱离语境、阅读原文有障碍、遇到问题缺乏即时反馈——想解决学习过程中的理解断裂。',
},
{
title: 'AI 能力的产品化落地',
desc: '不只是 Demo 层面的展示,而是在真实产品中接入 AI 标签、文本处理、对话能力。',
},
{
title: '工具型 AI 产品的用户体验',
desc: '如何在保持工具简洁性的同时,融入 AI 能力而不造成负担。',
},
];
const shipping = isZh
? ['工程案例库结构重构', '导航与路由转化路径优化', '双语文案统一与信息层级简化']
: ['Refactoring project pages into engineering case studies', 'Optimizing navigation and conversion routes', 'Unifying EN/ZH copy and simplifying information hierarchy'];
const outputs = [
'云端书签工具 v1.0 上线',
'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" />
<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>
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">现在</h1>
<p class="mt-4 text-lg text-muted-foreground">我当前的工作状态与产出。</p>
</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>
<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>
<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 class="page-content-main mt-10">
<h2 class="text-xl font-bold">当前主线</h2>
<div class="mt-4 space-y-4">
{focuses.map((item) => (
<article class="page-surface p-5">
<div class="flex items-center gap-3">
<h3 class="text-base font-bold">{item.title}</h3>
<span class="rounded-full bg-primary/10 px-2.5 py-0.5 text-xs font-medium text-primary">{item.status}</span>
</div>
<p class="mt-2 text-sm text-muted-foreground">{item.desc}</p>
</article>
))}
</div>
</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">
{isZh ? '最后更新2026-03-16' : 'Last updated: 2026-03-16'}
最后更新:{today}
</p>
</section>
</Container>

View File

@@ -11,7 +11,7 @@ const lang = (Astro.currentLocale as Lang) || defaultLang;
const isZh = lang === 'zh';
const pageProjects = projects[lang].map((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 indieProjects = pageProjects.filter((project) => project.category === 'indie');
@@ -66,13 +66,13 @@ const indieProjects = pageProjects.filter((project) => project.category === 'ind
</div>
<div class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3">
{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">
{project.coverImage ? (
<img
src={project.coverImage}
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"
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>
</div>
)}
</div>
<div class="p-5">
<p class="text-xs font-semibold uppercase tracking-wider text-primary/80">{isZh ? '独立项目' : 'Independent'}</p>
<h3 class="mt-2 text-lg font-bold">{project.title}</h3>
<p class="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>
))}
{/* Status Badge */}
<div class="absolute right-3 top-3">
<span
class={`inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium ${
project.status === 'completed'
? 'bg-emerald-500/20 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30'
: 'bg-amber-500/20 text-amber-600 dark:text-amber-400 border border-amber-500/30'
}`}
>
{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>
<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>
</article>
))}