A blog by Linghao Zhang, built with Next.js 15 and modern web technologies.
- Framework: Next.js 15 (App Directory, Static Export)
- Language: TypeScript
- Styling: Tailwind CSS 4.0 beta
- Content: MDX for rich content
- Syntax Highlighting: Shiki
- Math: KaTeX
- Fonts: Inter Variable, Lora Italic Variable, Iosevka Fixed Curly
- Deployment: Cloudflare Pages
- CI/CD: GitHub Actions
- โจ Modern, clean design with smooth view transitions
- ๐ฑ Fully responsive layout
- ๐จ Custom typography with variable fonts
- ๐ Elegant color scheme (rurikon palette)
- ๐ MDX support for rich content
- ๐ Syntax highlighting for code blocks
- ๐งฎ Math rendering support
- ๐ท๏ธ Tag system with filtering
- ๐ธ Photography gallery with lightbox
- ๐ก Auto-generated RSS feed
- โก Optimized static site with CDN delivery
- ๐ Automated deployments
- Node.js 16 or later
- pnpm, yarn, or npm
# Install dependencies
pnpm install
# or
yarn install
# or
npm install# Run development server
pnpm dev
# or
yarn dev
# or
npm run devOpen http://localhost:3000 to view the blog.
# Build for production (includes RSS generation)
npm run buildThe build outputs to the dist/ directory and includes:
- Static HTML/CSS/JS files
- Auto-generated RSS feed at
/feed.xml - Optimized images and assets
# Generate RSS feed only
npm run rss
# Deploy to Cloudflare Pages (preview)
npm run deploy
# Deploy to Cloudflare Pages (production)
npm run deploy:prod
# Lint code
npm run lint.
โโโ app/ # Next.js app directory
โ โโโ _fonts/ # Custom font files
โ โโโ globals.css # Global styles
โ โโโ layout.tsx # Root layout
โ โโโ page.mdx # Home page
โ โโโ posts/ # Blog posts
โ โ โโโ page.tsx # Posts index
โ โ โโโ [slug]/ # Dynamic post pages
โ โ โโโ _articles/ # Post content (MDX)
โ โโโ notes/ # Reading notes
โ โ โโโ page.tsx # Notes index
โ โ โโโ [slug]/ # Dynamic note pages
โ โ โโโ _articles/ # Note content (MDX)
โ โโโ misc/ # Miscellaneous articles
โ โ โโโ page.tsx # Misc index
โ โ โโโ [slug]/ # Dynamic misc pages
โ โ โโโ _articles/ # Misc content (MDX)
โ โโโ gallery/ # Photography gallery
โ โ โโโ page.tsx # Gallery page
โ โ โโโ gallery-grid.tsx # Lightbox component
โ โ โโโ data.ts # Photo data
โ โโโ tags/ # Tag system
โ โโโ all/ # Tag filtering page
โโโ components/ # React components
โ โโโ navbar.tsx # Navigation
โ โโโ tag.tsx # Tag component
โ โโโ ... # Other components
โโโ lib/ # Utilities
โ โโโ tags.ts # Tag management
โโโ scripts/ # Build scripts
โ โโโ generate-rss.mjs # RSS generation
โโโ public/ # Static assets
โโโ dist/ # Build output
โโโ mdx-components.tsx # MDX component config
โโโ next.config.ts # Next.js config
โโโ wrangler.toml # Cloudflare config
โโโ .github/workflows/ # CI/CD pipelines
โโโ deploy.yml # Deployment workflow
All content is written in MDX format, combining Markdown with React components.
- Create a new
.mdxfile inapp/posts/_articles/ - Add metadata at the top:
export const metadata = {
title: 'Your Post Title',
description: 'A brief description',
date: '2025.01.01',
tags: ['Tag1', 'Tag2'],
}
Your content here...- The post will automatically:
- Appear in the posts index
- Be included in RSS feed
- Be filterable by tags
- Get a URL like
/posts/your-post-title
- Posts (
app/posts/_articles/) - Blog posts and articles - Notes (
app/notes/_articles/) - Reading notes and summaries - Misc (
app/misc/_articles/) - Miscellaneous content
All sections follow the same structure and metadata format.
The gallery feature displays a collection of photography. Photos are managed in app/gallery/data.ts.
To add a new photo:
- Upload the image to a hosting service (e.g., Cloudflare R2).
- Add a new object to the
photosarray inapp/gallery/data.ts:
{
id: 'unique-id',
src: 'https://your-image-url.jpg',
alt: 'Description for accessibility',
caption: 'Optional caption text',
metadata: {
'Location': 'Kyoto, Japan',
'Date': '2024-10-28',
'Camera': 'Sony ฮฑ7C II',
}
}MDX files can use React components:
<Card
image="https://example.com/image.jpg"
title="Card Title"
desc="Description"
link="https://example.com"
/>
<BlockSideTitle title="Side note text">
Main content here
</BlockSideTitle>The blog uses the "rurikon" color palette defined in app/globals.css. Customize colors by modifying the @theme section.
Custom fonts are loaded from app/_fonts/. To change fonts, replace the font files and update app/layout.tsx.
Edit components/navbar.tsx to modify navigation links.
The blog uses automated CI/CD with GitHub Actions and Cloudflare Pages.
# Deploy to preview
npm run deploy
# Deploy to production
npm run deploy:prod- Push to
v2branch โ Preview deployment - Push to
mainbranch โ Production deployment
See DEPLOYMENT.md for detailed setup instructions.
Add tags to any article's metadata:
export const metadata = {
title: 'My Post',
tags: ['JavaScript', 'React', 'Web Development'],
}- Browse all tags:
/tags/all - Filter by tags:
/tags/all?tag=JavaScript - Click tags on articles to filter
The RSS feed is automatically generated on every build:
- Feed URL:
https://linghao.io/feed.xml - Includes: All posts, notes, and misc articles
- Updates: Automatic on deployment
- Manual generation:
npm run rss
MIT
This blog is inspired by Shu Ding's blog.