Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

302 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Synthesist in the Shell

A blog by Linghao Zhang, built with Next.js 15 and modern web technologies.

Tech Stack

  • Framework: Next.js 15 (App Directory, Static Export)
  • Language: TypeScript
  • Styling: Tailwind CSS 4
  • Content: MDX for rich content
  • Syntax Highlighting: Shiki
  • Math: KaTeX
  • Fonts: Inter Variable, Lora Italic Variable, Iosevka Fixed Curly
  • Deployment: Cloudflare Pages

Features

  • โœจ Modern, clean design with smooth view transitions
  • ๐Ÿ“ฑ Fully responsive layout
  • ๐ŸŽจ Custom typography with variable fonts
  • ๐ŸŒˆ Flexoki-inspired color scheme (warm cream, near-black text, teal accents)
  • ๐Ÿ“ MDX support for rich content
  • ๐Ÿ” Syntax highlighting for code blocks
  • ๐Ÿงฎ Math rendering support
  • ๐Ÿท๏ธ Tag system with filtering
  • ๐Ÿงฉ Projects page with SVG logos
  • ๐Ÿ“ธ Photography gallery with lightbox
  • ๐Ÿ“ก Auto-generated RSS feed
  • ๐Ÿ—‚๏ธ Toggleable table of contents sidebar for long posts
  • โš“ Anchor links on all headings
  • ๐ŸŒ Multilingual article support with language switcher
  • โšก Optimized static site with CDN delivery

Getting Started

Prerequisites

  • Node.js 18.18 or later
  • npm

Installation

npm install

Development

npm run dev

Open http://localhost:3000 to view the blog.

Build

npm run build

The build outputs to the dist/ directory and includes:

  • Static HTML/CSS/JS files
  • Auto-generated RSS feed at /feed.xml

Additional Commands

# 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

Project Structure

.
โ”œโ”€โ”€ 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/              # Legacy URL compatibility routes (redirect/alias to posts)
โ”‚   โ”‚   โ”œโ”€โ”€ page.tsx        # Legacy notes index
โ”‚   โ”‚   โ””โ”€โ”€ [slug]/         # Legacy note URLs
โ”‚   โ”œโ”€โ”€ 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
โ”‚   โ”œโ”€โ”€ lists/              # Curation lists
โ”‚   โ”‚   โ”œโ”€โ”€ page.tsx        # Lists hub
โ”‚   โ”‚   โ””โ”€โ”€ [slug]/         # Individual list pages
โ”‚   โ”œโ”€โ”€ projects/           # Projects page
โ”‚   โ”‚   โ”œโ”€โ”€ page.tsx        # Projects page
โ”‚   โ”‚   โ”œโ”€โ”€ data.tsx        # Project metadata
โ”‚   โ”‚   โ””โ”€โ”€ logos.tsx       # Project SVG logos
โ”‚   โ”œโ”€โ”€ resume/             # Public resume at /resume
โ”‚   โ”‚   โ”œโ”€โ”€ source.ts       # Resume content source of truth
โ”‚   โ”‚   โ””โ”€โ”€ page.tsx        # Resume HTML renderer
โ”‚   โ””โ”€โ”€ tags/               # Tag system
โ”‚       โ””โ”€โ”€ all/            # Tag filtering page
โ”œโ”€โ”€ components/             # React components
โ”‚   โ”œโ”€โ”€ navbar.tsx          # Navigation
โ”‚   โ”œโ”€โ”€ tag.tsx             # Tag component
โ”‚   โ”œโ”€โ”€ toc-sidebar.tsx     # Table of contents sidebar
โ”‚   โ””โ”€โ”€ ...                 # Other components
โ”œโ”€โ”€ lib/                    # Utilities
โ”‚   โ”œโ”€โ”€ articles.ts         # Content loading
โ”‚   โ”œโ”€โ”€ seo.ts              # OG/social image resolution
โ”‚   โ””โ”€โ”€ 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

Content Management

Adding a New Post

  1. Create a new .mdx file in app/posts/_articles/
  2. Add metadata at the top:
export const metadata = {
  title: 'Your Post Title',
  description: 'A brief description',
  date: '2025.01.01',
  tags: ['Tag1', 'Tag2'],

  // Optional: show a table of contents sidebar (default open)
  toc: true,

  // Optional: OG/social card image (hosted on Cloudflare R2 or any public URL)
  image: 'https://r2.linghao.io/blog-assets/your-image.png',
  imageWidth: 1200,
  imageHeight: 630,

  // Optional: multilingual linking (see Multilingual Support below)
  language: 'en',
  translationId: 'shared-slug',
  canonical: true,
}

Your content here...
  1. 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
    • Have anchor links on all headings (#heading-slug)

Table of Contents

Any post with two or more headings gets a toggleable TOC sidebar. A small icon button appears on the right side of the viewport; clicking it opens a panel listing all headings (h2โ€“h4) with hierarchical numbering and active-heading highlighting as you scroll.

By default the sidebar is closed. Set toc: true in the article metadata to have it open automatically โ€” useful for long reference posts.

Multilingual Support

Articles sharing a translationId are grouped as translations of each other. The article page shows a language switcher between them. Only the canonical: true version appears in index pages and tag pages.

export const metadata = {
  title: 'My Post',
  language: 'en',
  translationId: 'my-post',
  canonical: true,
}

Content Sections

  • Posts (app/posts/_articles/) - Blog posts and reading notes
  • Misc (app/misc/_articles/) - Miscellaneous content

Legacy /notes/* URLs are still supported for backward compatibility, but new content should be added under posts.

Resume Page

The public resume is available at /resume. Its content source is app/resume/source.ts, and the rendered HTML page is app/resume/page.tsx. Update content in source.ts; only edit page.tsx for layout/styling changes. See docs/resume.md for the full update workflow.

Gallery

The gallery feature displays a collection of photography. Photos are managed in app/gallery/data.ts.

To add a new photo:

  1. Upload the image to a hosting service (e.g., Cloudflare R2).
  2. Add a new object to the photos array in app/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',
  }
}

Using Components

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>

Customization

Colors

The blog uses the "rurikon" color palette defined in app/globals.css, mapped to Flexoki values. Customize colors by modifying the @theme section. See docs/visual-style.md for the full palette reference.

Fonts

Fonts are loaded locally via next/font/local in app/layout.tsx and exposed as CSS variables:

  • --sans: Inter Variable (body text, headings, UI elements โ€” used everywhere)
  • --serif: Lora Italic Variable (navigation elements via global nav {} rule)
  • --mono: Iosevka Fixed Curly (code blocks and inline code)

Navigation

Edit components/navbar.tsx to modify navigation links.

Deployment

# Deploy to preview
npm run deploy

# Deploy to production
npm run deploy:prod

See DEPLOYMENT.md for detailed setup instructions.

Tag System

Using Tags

Add tags to any article's metadata:

export const metadata = {
  title: 'My Post',
  tags: ['JavaScript', 'React', 'Web Development'],
}

Viewing Tags

  • Browse all tags: /tags/all
  • Filter by tags: /tags/all?tag=JavaScript
  • Click tags on articles to filter

RSS Feed

The RSS feed is automatically generated on every build:

  • Feed URL: https://linghao.io/feed.xml
  • Includes: All posts and misc articles
  • Updates: Automatic on deployment
  • Manual generation: npm run rss

License

MIT

Acknowledgments

This blog is inspired by Shu Ding's blog.

About

Personal blog built with Next.js and MDX

Resources

Stars

21 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages