This document provides comprehensive technical information for developers working on the Yibin (Leon) Liu Academic Personal Website project.
- Project Overview
- Architecture
- Development Environment Setup
- Project Structure
- Configuration System
- Component Development
- Styling Guidelines
- Build System
- Deployment
- Testing
- Performance Optimization
- SEO Implementation
- Troubleshooting
This is a modern academic personal website built as a single-page application (SPA) using React 19, TypeScript, and Vite. The site is deployed as a static website on GitHub Pages with automated CI/CD.
Core Framework:
- React 19.1.1 - Latest React with concurrent features
- TypeScript 5.9.3 - Type safety and developer experience
- Vite 7.2.2 - Fast build tool and development server
Styling:
- Tailwind CSS 4.1.14 - Utility-first CSS framework
- @tailwindcss/vite - Vite plugin for Tailwind CSS 4
- Radix UI - Accessible component primitives
- Framer Motion 12.23.22 - Animation library
Routing:
- Wouter 3.7.1 - Lightweight client-side router (3.3kb)
UI Components:
- shadcn/ui components built on Radix UI
- Lucide React - Icon library
- Embla Carousel - Carousel functionality
Form Handling:
- React Hook Form 7.64.0 - Performant form validation
Data Fetching:
- @tanstack/react-query 5.90.2 - Server state management
Utilities:
- date-fns 4.1.0 - Date manipulation
- zod 4.1.12 - Schema validation
- nanoid 5.1.5 - Unique ID generation
The application uses client-side routing with Wouter. All routing is handled in the browser without server-side rendering.
Routing Structure:
/ - Home page
/blog - Blog listing page
/cv - Opens CV PDF in new tab
/showcase - Component showcase (development)
* - 404 Not Found page
- React Context - Global theme and UI state
- React Query - Server state and data fetching
- Local State - Component-level state with hooks
Components follow a composition pattern with:
- Presentational components in
client/src/components/ - Page components in
client/src/pages/ - Reusable UI components in
client/src/components/ui/ - Configuration-driven content
Required:
- Node.js 18.x or higher
- pnpm 10.x (recommended) or npm 8.x+
Optional:
- VS Code with recommended extensions
- Git for version control
- Clone the repository:
git clone https://github.com/10-OASIS-01/10-OASIS-01.github.io.git
cd 10-OASIS-01.github.io- Install dependencies:
pnpm install- Start development server:
pnpm devThe development server will start at http://localhost:5173 (or next available port).
# Development
pnpm dev # Start dev server with hot reload
pnpm preview # Preview production build locally
# Build
pnpm build # Build for production
pnpm check # TypeScript type checking
# Code Quality
pnpm format # Format code with Prettier
pnpm test # Run tests with VitestCreate a .env file in the root directory for environment-specific configuration:
VITE_APP_TITLE=Yibin (Leon) Liu - Academic Homepage
VITE_APP_LOGO=/favicon.ico.
├── client/ # Frontend application
│ ├── public/ # Static assets
│ │ ├── assets/ # Images, PDFs, etc.
│ │ ├── sitemap.xml # SEO sitemap
│ │ └── robots.txt # Search engine crawler config
│ ├── src/
│ │ ├── components/ # React components
│ │ │ ├── ui/ # Reusable UI components
│ │ │ ├── Navigation.tsx # Main navigation
│ │ │ ├── HeroSection.tsx # Hero banner
│ │ │ ├── SidebarProfile.tsx # Profile sidebar
│ │ │ └── ...
│ │ ├── config/ # Configuration files
│ │ │ ├── siteConfig.ts # Main site configuration
│ │ │ ├── blogConfig.ts # Blog posts data
│ │ │ └── themeConfig.ts # Theme settings
│ │ ├── contexts/ # React contexts
│ │ ├── hooks/ # Custom React hooks
│ │ ├── lib/ # Utility functions
│ │ ├── pages/ # Page components
│ │ │ ├── Home.tsx # Home page
│ │ │ ├── Blog.tsx # Blog page
│ │ │ └── NotFound.tsx # 404 page
│ │ ├── App.tsx # Main app component
│ │ ├── main.tsx # React entry point
│ │ └── index.css # Global styles
│ └── index.html # HTML template
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions CI/CD
├── dist/ # Build output (generated)
│ └── public/ # Deployable files
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
└── vitest.config.ts # Vitest test configuration
This is the main configuration file that controls all content on the website.
Personal Information:
export const personalInfo = {
name: "Your Name",
chineseName: "中文名",
pronouns: "he/him",
title: "Your Title",
university: "Your University",
location: "City, Country",
email: "your.email@example.com",
// ... more fields
};Social Links:
export const socialLinks = {
googleScholar: "https://scholar.google.com/...",
github: "https://github.com/...",
linkedin: "https://linkedin.com/in/...",
bluesky: "https://bsky.app/...",
email: "mailto:...",
};Navigation:
export const navigationMenu = [
{ label: "Home", href: "/" },
{ label: "Publications", href: "/#publications" },
{ label: "CV", href: "/cv.pdf", external: true },
];Publications:
export const publications = [
{
id: 1,
title: "Paper Title",
authors: "Author 1, Author 2, Author 3",
venue: "Conference/Journal Name",
year: 2024,
links: {
paper: "https://arxiv.org/...",
project: "https://project-page.com",
code: "https://github.com/...",
},
note: "Best Paper Award", // Optional
},
];Awards:
export const awards = [
{
id: 1,
title: "Award Name",
year: "2024",
description: "Description of the award and its significance.",
},
];export const blogPosts = [
{
id: 1,
title: "Blog Post Title",
excerpt: "Brief description...",
date: "2025-01-15",
readTime: "5 min read",
tags: ["AI", "Research"],
slug: "blog-post-slug",
},
];
export const blogConfig = {
title: "Blog",
description: "Thoughts on AI research and technology",
comingSoonMessage: "More posts coming soon...",
};- Create component file in
client/src/components/:
// components/MyComponent.tsx
import React from 'react';
interface MyComponentProps {
title: string;
description?: string;
}
export function MyComponent({ title, description }: MyComponentProps) {
return (
<div className="p-4">
<h2 className="text-2xl font-bold">{title}</h2>
{description && <p className="text-gray-600">{description}</p>}
</div>
);
}- Export from index if creating a UI component library
- Import and use in page components
The project uses shadcn/ui components. To add a new component:
- Check available components in
client/src/components/ui/ - Use existing components or create new ones following the same pattern
- All UI components should support className prop for customization
- Use TypeScript interfaces for props
- Implement proper accessibility (ARIA labels, keyboard navigation)
- Support dark mode through theme context
- Keep components focused and single-purpose
- Use composition over inheritance
The project uses Tailwind CSS 4 with the Vite plugin. All styling should use Tailwind utility classes.
Common Patterns:
// Layout
<div className="container mx-auto px-4">
// Responsive
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
// Spacing
<div className="space-y-4">
// Typography
<h1 className="text-4xl font-bold tracking-tight">
// Colors
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">Global styles are in client/src/index.css. Add custom CSS only when Tailwind utilities are insufficient.
Customize colors, fonts, and other design tokens in tailwind.config.js.
The build system is configured in vite.config.ts:
export default defineConfig({
plugins: [
react(),
tailwindcss(),
jsxLocPlugin()
],
resolve: {
alias: {
"@": path.resolve(__dirname, "client", "src"),
},
},
build: {
outDir: path.resolve(__dirname, "dist/public"),
emptyOutDir: true,
rollupOptions: {
output: {
manualChunks: {
'radix-ui': [/* Radix UI components */],
'vendor': ['react', 'react-dom', 'wouter']
}
}
}
}
});The build system uses manual chunk splitting to optimize loading:
- vendor chunk: React core libraries (4KB gzipped)
- radix-ui chunk: UI component library (57KB gzipped)
- main chunk: Application code (315KB gzipped)
Production builds are output to dist/public/:
dist/public/
├── index.html
├── assets/
│ ├── index-[hash].js
│ ├── vendor-[hash].js
│ ├── radix-ui-[hash].js
│ └── index-[hash].css
├── sitemap.xml
└── robots.txt
TypeScript path aliases are configured:
// Use @ to reference src directory
import { Component } from "@/components/Component";The site automatically deploys to GitHub Pages when changes are pushed to the master branch.
GitHub Actions Workflow (.github/workflows/deploy.yml):
name: Deploy to GitHub Pages
on:
push:
branches: [master]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm install -g pnpm
- run: pnpm install
- run: pnpm build
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist/public- Build the project:
pnpm build- Deploy the
dist/public/directory to your hosting provider
For deployment to subdirectories, update vite.config.ts:
export default defineConfig({
base: '/subdirectory/',
// ... rest of config
});The project uses Vitest for testing:
pnpm test # Run tests once
pnpm test:watch # Run tests in watch modeExample Test:
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { MyComponent } from './MyComponent';
describe('MyComponent', () => {
it('renders title correctly', () => {
render(<MyComponent title="Test" />);
expect(screen.getByText('Test')).toBeInTheDocument();
});
});Run TypeScript compiler in check mode:
pnpm check- Code Splitting: Separate vendor and UI library chunks
- Tree Shaking: Unused code is removed during build
- Asset Optimization: Images and static assets are optimized
- Lazy Loading: Routes and components can be lazy loaded
- Use React.memo() for expensive components
- Implement virtualization for long lists
- Optimize images (WebP format, proper sizing)
- Minimize bundle size by auditing dependencies
- Use Lighthouse to measure performance
Analyze bundle size:
pnpm build
npx vite-bundle-visualizerSEO meta tags are configured in client/index.html:
- Basic meta tags (description, keywords, author)
- Open Graph tags for social media
- Twitter Card tags
- Academic citation meta tags
- Canonical URL
JSON-LD structured data is included for:
- Person schema (academic profile)
- Social media links
- Affiliations
The sitemap is located at client/public/sitemap.xml and includes:
- Homepage (priority 1.0)
- CV page (priority 0.8)
- Blog page (priority 0.7)
Update the sitemap when adding new pages.
The client/public/robots.txt file configures crawler behavior:
- Allows all crawlers
- References sitemap.xml
- Sets crawl delay for politeness
Issue: Build fails with TypeScript errors
# Check TypeScript configuration
pnpm check
# Fix type errors or add type assertionsIssue: Development server won't start
# Clear cache and reinstall
rm -rf node_modules pnpm-lock.yaml
pnpm installIssue: Styles not applying
# Ensure Tailwind is configured correctly
# Check tailwind.config.js and postcss.config.js
# Restart dev serverIssue: Components not rendering
- Check browser console for errors
- Verify import paths are correct
- Ensure all dependencies are installed
Enable verbose logging:
# Development with debug info
DEBUG=* pnpm dev
# Vite specific debugging
VITE_LOG_LEVEL=info pnpm dev- Check existing issues on GitHub
- Review documentation in this file
- Contact maintainers via email or GitHub issues
When contributing to this project:
- Follow the existing code style
- Add TypeScript types for all new code
- Test changes locally before committing
- Update documentation for new features
- Keep commits focused and atomic
- Write clear commit messages
- Use 2 spaces for indentation
- Use semicolons
- Use double quotes for strings
- Use trailing commas in objects/arrays
- Run
pnpm formatbefore committing
Follow conventional commits:
feat: add new publication section
fix: correct navigation link
docs: update development documentation
style: format code with prettier
refactor: reorganize component structure
This project is licensed under the MIT License. See the LICENSE file for details.
Yibin (Leon) Liu
- Email: kevin.lau.stu@gmail.com
- GitHub: @10-OASIS-01
- LinkedIn: yibin-leon-liu