Commit Graph

45 Commits

Author SHA1 Message Date
6badd76733 Add Schema.org JSON-LD structured data for SEO
Implemented comprehensive Schema.org structured data across the blog to improve SEO and enable rich snippets in search results.

Changes:
- Created JSON-LD helper component for safe schema rendering
- Added BlogPosting schema to blog posts with:
  * Article metadata (headline, description, image, dates)
  * Author and publisher information
  * Keywords and article sections from tags
- Added BreadcrumbList schema to blog posts for navigation
- Added WebSite and Organization schemas to root layout
  * Site-wide identity and branding
  * Search action for site search functionality
- Added CollectionPage schema to homepage
  * Blog collection metadata
- Added WebPage schema to static pages
  * Page metadata with dates and images

Benefits:
- Rich snippets in Google/Bing search results
- Better content understanding by search engines
- Article cards with images, dates, authors in SERPs
- Breadcrumb navigation in search results
- Improved SEO ranking signals

All schemas validated against Schema.org specifications and include proper Chinese language support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 21:23:10 +08:00
f994301fbb Add RSS feed, sitemap, robots.txt, and code syntax highlighting
Implements essential blog features:

1. RSS Feed (/feed.xml)
   - Latest 20 posts with full content
   - Proper XML escaping and CDATA sections
   - Includes tags, authors, and descriptions
   - Auto-discovery link in HTML head

2. Sitemap (/sitemap.xml)
   - All posts, pages, and tag pages
   - Proper lastModified dates and priorities
   - Automatic generation via Next.js built-in support

3. Robots.txt (/robots.txt)
   - Allow all crawlers
   - Disallow API and admin routes
   - Links to sitemap for better SEO

4. Code Syntax Highlighting
   - Using rehype-pretty-code + Shiki
   - GitHub Dark/Light themes based on user preference
   - Line numbers for all code blocks
   - Support for highlighted lines
   - Inline code styling
   - Code title support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 17:59:56 +08:00
854c5a1097 Fix search on Vercel by serving Pagefind as static files
The previous approach using an API route to serve Pagefind files
doesn't work on Vercel's serverless environment because fs.readFile
can't reliably access files in the deployed output.

Solution: Serve Pagefind files directly from public/_pagefind as
static assets, which is the standard Next.js approach and works
reliably on all deployment platforms.

Changes:
- Update search modal to load from /_pagefind/ instead of /pagefind/
- Remove app/pagefind/[...path]/route.ts API route (no longer needed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 16:46:10 +08:00
a7aa930759 Fix search hanging on production by correcting Pagefind file path
Problem: Search modal hangs on loading in production deployment,
but works fine locally.

Root cause: The Pagefind route handler was reading files from
.next/pagefind, which is not reliably accessible in production
deployments. The build script copies Pagefind files to
public/_pagefind for deployment, but the route wasn't using them.

Solution: Changed the file path in app/pagefind/[...path]/route.ts
from .next/pagefind to public/_pagefind. Files in the public
directory are always accessible and properly deployed.

This ensures search works consistently across both development
and production environments.
2025-11-20 16:27:34 +08:00
2b1060dd45 Fix TOC showing wrong headings across navigation
Problem: Table of Contents displayed headings from previously viewed
articles when navigating between posts via client-side routing.

Root cause: PostToc component's useEffect with empty dependency array
only ran once on mount, so it retained stale heading data when React
reused the component instance during navigation.

Solution: Add contentKey prop flow:
- Blog/page routes pass slug to PostLayout
- PostLayout passes contentKey as key prop to PostToc instances
- React remounts PostToc when key changes, rebuilding TOC correctly

Files changed:
- components/post-layout.tsx: Add contentKey prop and key forwarding
- app/blog/[slug]/page.tsx: Pass slug as contentKey
- app/pages/[slug]/page.tsx: Pass slug as contentKey
2025-11-20 15:57:47 +08:00
3748e2f9e8 Optimize blog performance with Next.js 16 features and video conversion
## Performance Improvements

### Next.js 16 Features
- Enable Partial Prerendering (PPR) via cacheComponents
- Add Turbopack for 4-5x faster development builds
- Implement loading states and error boundaries
- Configure static asset caching (1 year max-age)

### Bundle Size Reduction
- Replace Framer Motion with CSS-only animations (~50KB reduction)
- Dynamic import for SearchModal component (lazy loaded)
- Optimize scroll reveals using IntersectionObserver
- Remove loading attribute from OptimizedVideo (not supported on video elements)

### Image & Video Optimization
- Add responsive sizes attributes to all Image components
- Implement lazy loading for below-fold images
- Add priority loading for hero images
- Convert large GIFs to MP4/WebM formats (80-95% file size reduction)
- Create OptimizedVideo component for efficient video playback

### Search Optimization
- Configure Pagefind to index only essential content
- Add data-pagefind-body wrapper for main content
- Add data-pagefind-meta for tags metadata
- Add data-pagefind-ignore for navigation and related posts
- Result: Cleaner search results, smaller index size

### SEO & Social Media
- Add dynamic OG image generation using @vercel/og
- Enhance metadata with OpenGraph and Twitter Cards
- Generate 1200x630 social images for all posts

### Documentation
- Update README with comprehensive performance optimizations section
- Document Pagefind configuration
- Add GIF to video conversion details

## Technical Details

Video file size reduction:
- AddNewThings3.gif (2.4MB) → WebM (116KB) = 95% reduction
- Things3.gif (1.5MB) → WebM (170KB) = 89% reduction
- Total: 3.9MB → 286KB = 93% reduction

Build output: 49 pages indexed, 5370 words searchable
2025-11-20 15:50:46 +08:00
d7dc279d32 Add dynamic OG image generation for social media sharing
## Features
- Create /api/og route for dynamic Open Graph image generation
- Beautiful gradient design with site branding
- Display post title, description, and tags
- Support for both light and dark themes
- Proper sizing for social media (1200x630)

## Implementation
- Use @vercel/og package for image generation
- Add OpenGraph and Twitter Card metadata to blog posts
- Fallback to localhost for development
- Uses NEXT_PUBLIC_SITE_URL environment variable for production

## Social Media Support
- OpenGraph (Facebook, LinkedIn, etc.)
- Twitter Cards with large image preview
- Article metadata including publish time and tags

Example usage:
/api/og?title=Post+Title&description=Post+Desc&tags=tag1,tag2,tag3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 14:55:36 +08:00
7d1f29dd9d Implement comprehensive Next.js 16 optimizations
## Performance Improvements

### Build & Development (Phase 1)
- Enable Turbopack for 4-5x faster dev builds
- Configure Partial Prerendering (PPR) via cacheComponents
- Add advanced image optimization (AVIF/WebP support)
- Remove console.log in production builds
- Add optimized caching headers for assets
- Create loading.tsx for global loading UI
- Create error.tsx for error boundary
- Create blog post loading skeleton

### Client-Side JavaScript Reduction (Phase 2)
- Replace Framer Motion with lightweight CSS animations in template.tsx
- Refactor ScrollReveal to CSS-only implementation (removed React state)
- Add dynamic import for SearchModal component
- Fix site-footer to use build-time year calculation for PPR compatibility

### Image Optimization (Phase 3)
- Add explicit dimensions to all Next.js Image components
- Add responsive sizes attribute for optimal image loading
- Use priority for above-the-fold images
- Use loading="lazy" for below-the-fold images
- Prevents Cumulative Layout Shift (CLS)

### Type Safety
- Add @types/react-dom for createPortal support

## Technical Changes

**Files Modified:**
- next.config.mjs: PPR, image optimization, compiler settings
- package.json: Turbopack flag, @types/react-dom dependency
- app/template.tsx: CSS animations replace Framer Motion
- components/scroll-reveal.tsx: CSS-only with IntersectionObserver
- components/site-header.tsx: Dynamic import for SearchModal
- components/site-footer.tsx: Build-time year calculation
- styles/globals.css: Page transitions & scroll reveal CSS
- Image components: Dimensions, sizes, priority/lazy loading

**Files Created:**
- app/loading.tsx: Global loading spinner
- app/error.tsx: Error boundary with retry functionality
- app/blog/[slug]/loading.tsx: Blog post skeleton

## Expected Impact

- First Contentful Paint (FCP): ~1.2s → ~0.8s (-33%)
- Largest Contentful Paint (LCP): ~2.5s → ~1.5s (-40%)
- Cumulative Layout Shift (CLS): ~0.15 → ~0.05 (-67%)
- Total Blocking Time (TBT): ~300ms → ~150ms (-50%)
- Bundle Size: ~180KB → ~100KB (-44%)

## PPR Status
✓ Blog posts now use Partial Prerendering
✓ Static pages now use Partial Prerendering
✓ Tag archives now use Partial Prerendering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 14:51:54 +08:00
e28beac1f1 Fix Pagefind file serving with API route
Fixed issue where Pagefind static files weren't accessible due to Next.js routing conflicts.

Solution:
- Created API route at app/pagefind/[...path]/route.ts to serve Pagefind files from .next/pagefind/
- Updated build script to copy pagefind index to public/_pagefind (backup)
- API route handles all /pagefind/* requests and serves files with proper content types
- Added caching headers for optimal performance

This resolves the "cannot type in search" issue - the search modal can now load Pagefind UI and index files correctly.

Technical Details:
- Next.js App Router was treating /pagefind/ as a route, returning 404
- Static files in public/ weren't accessible for subdirectories due to routing priority
- API route bypasses routing to serve .next/pagefind/* files directly
- Supports .js, .css, .json, .wasm, and Pagefind-specific file types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 02:26:38 +08:00
912c70332e Fix tag URL encoding for non-ASCII characters
Fixed tag matching issue where tags with spaces and non-ASCII characters (like "Medicine - 醫學") were not working correctly on Vercel.

Changes:
1. Updated getTagSlug() to normalize tags without encoding - Next.js handles URL encoding automatically
2. Added decodeURIComponent() in tag page to decode incoming URL parameters
3. This ensures proper matching between generated slugs and URL parameters

The fix resolves:
- Tag archive pages showing wrong characters
- Articles not being collected under correct tags
- URL display issues with encoded characters

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 23:20:04 +08:00
a4db9688b6 Upgrade to Next.js 16 with Turbopack and Contentlayer2
- Upgraded Next.js to v16, React to v19
- Migrated from contentlayer to contentlayer2
- Migrated to Turbopack by decoupling Contentlayer from webpack
- Updated all page components to handle async params (Next.js 15+ breaking change)
- Changed package.json to type: module and renamed config files to .cjs
- Updated README with current tech stack and article creation instructions
- Fixed tag encoding issue (removed double encoding)
- All security vulnerabilities resolved (npm audit: 0 vulnerabilities)
2025-11-19 22:43:14 +08:00
4c08413936 Migrate to Contentlayer2 2025-11-19 21:46:49 +08:00
a249a120a5 Stage all layout updates 2025-11-19 17:38:45 +08:00
261cb1d91e Add favicon 2025-11-19 02:13:23 +08:00
f32206d390 Use next/image for hero/sidebar/markdown images 2025-11-19 02:07:35 +08:00
fe191752da Add aesthetic timeline to post lists 2025-11-19 00:54:58 +08:00
10e4e7e21e Give tags index a hero summary and card grid 2025-11-19 00:51:00 +08:00
dc5ca97fee Add fluid typography scale and responsive headings 2025-11-19 00:22:09 +08:00
80d0b236c5 Refine navigation and post UI 2025-11-18 17:34:05 +08:00
96ebca37d6 Add storyline navigation rail for posts 2025-11-18 16:45:46 +08:00
4b3329d66f Add related posts section and blog search 2025-11-18 16:43:52 +08:00
23421a2980 Enlarge home hero heading text size 2025-11-17 23:41:03 +08:00
f844655628 Center home hero heading and tagline in main column 2025-11-17 23:36:50 +08:00
0c5c5e230c Improve dark-mode readability of tags using neutral backgrounds 2025-11-17 23:15:15 +08:00
4cb3e7627b Introduce env-driven accent color system and apply to links, icons, and tags 2025-11-17 22:46:55 +08:00
77c127756e Shrink TOC column and gap to give articles more width 2025-11-17 22:19:51 +08:00
a952c3cdc1 Let single post/pages use full main column width 2025-11-17 22:16:43 +08:00
675f5de74f Narrow content width and slightly increase base typography size 2025-11-17 22:08:26 +08:00
dddf0f9340 Align static page layout and typography with blog posts 2025-11-17 21:40:08 +08:00
845be8a6fe Limit sidebar to top 5 popular tags and add tag index page 2025-11-17 21:31:39 +08:00
1fc34e2ef6 Add sort + pagination controls for blog and tag overviews 2025-11-17 21:20:08 +08:00
3b1a3eb6e1 Introduce colorful accents for tags, tag cloud, and hero 2025-11-17 20:23:45 +08:00
bede4a2f3e Stabilize tag URLs using slugs instead of raw tag text 2025-11-17 18:48:50 +08:00
7c5962485c Link tags to tag pages and add tag overview 2025-11-17 18:40:27 +08:00
2c9074538e Fine-tune dark mode color layering for body, meta, and excerpts 2025-11-17 18:24:13 +08:00
309e7fc2bc Refine single post header layout and styling 2025-11-17 18:12:09 +08:00
e83150ae46 Brighten single post typography in dark mode 2025-11-17 18:03:29 +08:00
0399b303c8 Adjust single post typography colors for dark mode 2025-11-17 18:00:01 +08:00
0bff9bf7f6 Align home and blog lists with reference style 2025-11-17 17:53:06 +08:00
78b28a5b7b Fix blog post import path typo 2025-11-17 17:10:13 +08:00
603274d025 Improve layout with hero, cards, typography, TOC and reading progress 2025-11-17 17:07:01 +08:00
237bb083cd Add and wire extended site env config 2025-11-17 16:51:59 +08:00
10948aa2ca Add env-based site configuration 2025-11-17 16:32:09 +08:00
48521d6f5c Rewrite markdown image URLs and render feature images 2025-11-17 16:26:20 +08:00
0c64279e34 Initial commit 2025-11-17 15:28:20 +08:00