An awesome blog system based on Next.js.
| Default | Nature |
|---|---|
- Rich MDX Support - GFM, KaTeX math, admonitions, emoji shortcodes, Shiki-based syntax highlighting, live code editor with Sandpack
- Modern UI/UX - Dark mode, smooth animations, command menu (⌘K), responsive design, progress indicators
- Advanced Navigation - Auto-generated TOC with active tracking, previous/next posts, tag filtering, search
- Social & Interactive - Giscus comments, share buttons, GitHub integration
- Bilingual (i18n) - Full English/Chinese support with locale-specific routing
- AI Agent Actions - One-click "Read with Claude" or "Read with ChatGPT" to open articles in AI assistants with context
- llms.txt API - Auto-generated structured feed for LLM consumption at
/llms.txt
- Modern Stack - Next.js App Router + Turbopack, React Compiler, TypeScript strict mode
- Comprehensive Testing - Vitest (unit), Playwright (E2E), Testing Library
- Code Quality - ESLint, Stylelint, Prettier, CI/CD with GitHub Actions
- Performance - Automatic code splitting, image optimization, Rust-based builds
- SEO Ready - Meta tags, sitemap, robots.txt, Open Graph, Twitter Cards
.yaml front matter + .mdx body:
---
layout: post
title: 'Your Post Title'
description: 'Your post description'
author: 'Your Name'
date: 2026-01-01
thumbnail: '/thumbnails/your-thumbnail.jpg'
tags:
- Your Tag 1
- Your Tag 2
- Your Tag 3
---
# Your Post Title
## Introduction
Your content here...
## Math Support
Inline math: $E = mc^2$
Block math:
$$
\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
$$
## Admonitions
:::note
This is a note admonition.
:::
:::tip
This is a tip admonition.
:::
:::warning
This is a warning admonition.
:::- Node.js 18.17 or later
- pnpm 10 or later
git clone https://github.com/sabertazimi/blog
cd blog
pnpm installpnpm devOpen the source code and start editing!
Your site is now running at http://localhost:3000!
# Build for production
pnpm build
# Start production server
pnpm serveBuild for production:
pnpm buildThe optimized production build will be in the .next folder.
Edit src/lib/site.ts to customize your blog:
export const site = {
author: 'Your Name',
url: 'https://yourblog.com',
// ... more settings
}Configure supported locales in src/i18n/routing.ts:
export const routing = defineRouting({
locales: ['en-US', 'zh-CN'],
defaultLocale: 'en-US',
localePrefix: 'always',
})Add translations in messages/[locale].json:
{
"site": {
"title": "Your Blog Title",
"description": "Your blog description"
},
"common": {
"loading": "Loading...",
"backToTop": "Back to top"
}
}Organize MDX posts by locale in content/[locale]/:
content/
├── en-US/
│ ├── my-first-post.mdx
│ └── ...
└── zh-CN/
├── my-first-post.mdx
└── ...The blog uses Tailwind CSS with custom CSS variables.
Edit src/app/globals.css to customize colors:
:root {
--background: oklch(100% 0 0deg);
--foreground: oklch(14.5% 0 0deg);
--primary: oklch(20.5% 0 0deg);
/* ... more colors */
}
.dark {
--background: oklch(14.5% 0 0deg);
--foreground: oklch(98.5% 0 0deg);
/* ... more colors */
}Nature theme:
pnpm dlx shadcn@latest add https://tweakcn.com/r/themes/nature.jsonClaude theme:
pnpm dlx shadcn@latest add https://tweakcn.com/r/themes/claude.jsonThe project includes multiple component registries in components.json:
- @animate-ui: https://animate-ui.com - Animated UI components
- @magicui: https://magicui.design - Magic UI components
- @shadcn-studio: https://shadcnstudio.com - Shadcn Studio components, blocks, and themes
You can add components from these registries:
pnpm dlx shadcn@latest add @magicui/morphing-text
pnpm dlx shadcn@latest add @animate-ui/gravity-starsCustomize MDX components in src/components/post-content.tsx:
const mdxComponents = {
aside: MDXAdmonition,
img: MDXImage,
pre: MDXCode,
Button,
Editor: MDXEditor,
// Add your custom components here
}.
├── node_modules/
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── [locale]/ # Locale-based routing
│ │ │ ├── about/ # About page
│ │ │ ├── post/[slug]/ # Dynamic post pages
│ │ │ ├── posts/ # All posts page
│ │ │ ├── tag/[tagName]/ # Tag filter pages
│ │ │ ├── layout.tsx # Locale layout
│ │ │ ├── page.tsx # Home page
│ │ │ └── not-found.tsx # 404 page
│ │ ├── globals.css # Global styles
│ │ ├── providers.tsx # Context providers
│ │ ├── robots.ts # robots.txt generation
│ │ └── sitemap.ts # Sitemap generation
│ ├── components/ # React components
│ │ ├── ui/ # Shadcn UI components
│ │ │ ├── button.tsx
│ │ │ ├── card.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── skeleton.tsx
│ │ │ └── ...
│ │ ├── language-switcher.tsx # Language switcher
│ │ ├── mdx-code.tsx # Code block with Shiki
│ │ ├── mdx-editor.tsx # Live code editor with Sandpack
│ │ ├── mdx-image.tsx # Optimized image component
│ │ ├── post-card.tsx # Post card component
│ │ ├── post-content.tsx # MDX content renderer
│ │ └── ...
│ ├── i18n/ # Internationalization
│ │ ├── routing.ts # i18n routing config
│ │ ├── request.ts # Request config
│ │ ├── navigation.ts # Navigation helpers
│ │ └── utils.ts # i18n utilities
│ ├── layouts/ # Layout components
│ │ └── default-layout.tsx
│ ├── lib/ # Utility functions
│ │ ├── get-posts-data.ts # MDX processing
│ │ ├── utils.ts # Helper functions
│ │ ├── get-routes.ts # Route generation
│ │ ├── seo.ts # SEO utilities
│ │ └── ...
│ ├── types/ # TypeScript type definitions
│ │ ├── index.d.ts
│ │ └── i18n.ts
│ └── proxy.ts # next-intl middleware
├── content/ # Blog posts (.mdx files)
│ ├── en-US/ # English posts
│ │ ├── post1.mdx
│ │ └── ...
│ └── zh-CN/ # Chinese posts
│ ├── post1.mdx
│ └── ...
├── messages/ # i18n translation files
│ ├── en-US.json
│ └── zh-CN.json
├── public/ # Static assets
│ ├── fonts/
│ ├── images/
│ ├── thumbnails/
│ └── ...
├── e2e/ # Playwright E2E tests
│ ├── home.spec.ts
│ ├── i18n.spec.ts
│ └── ...
├── .github/ # GitHub workflows
│ └── workflows/
│ ├── ci.yml
│ └── codeql-analysis.yml
├── .gitignore
├── .prettierrc.json
├── components.json # Shadcn UI config
├── eslint.config.mjs # ESLint Flat Config
├── next.config.ts # Next.js configuration
├── package.json
├── playwright.config.ts # Playwright configuration
├── postcss.config.mjs # PostCSS configuration
├── tsconfig.json # TypeScript configuration
├── vitest.config.mts # Vitest configuration
├── LICENSE
└── README.mdsrc/app/[locale]/: Locale-based Next.js App Router pages with i18n supportsrc/components/: Reusable React componentssrc/components/ui/: Shadcn UI base componentssrc/i18n/: Internationalization configuration and utilitiessrc/lib/: Utility functions and data fetching logicsrc/types/: TypeScript type definitionscontent/: Blog posts in MDX format (organized by locale)messages/: i18n translation JSON filespublic/: Static assets (images, fonts, etc.)e2e/: End-to-end tests with Playwright
- Next.js - React framework
- React - UI library
- TypeScript - Type safety
- Tailwind CSS - Utility-first CSS framework
- Shadcn UI - Component library
- Motion - Animation library
- Lucide React - Icon library
- Simple Icons - Brand icons
- next-mdx-remote - MDX support
- next-intl - Internationalization
- Shiki - Syntax highlighting
- Sandpack - Live code editor
- KaTeX - Math rendering
- remark - Markdown processing
- rehype - HTML processing
- Vitest - Unit testing
- Playwright - E2E testing
- Testing Library - React testing
importandexportstatements cannot be used inside MDX files due tonext-mdx-remotelimitations.- If you need custom components in MDX, add them to
src/components/post-content.tsx. - See explanation for details.