A minimal, fast, and bilingual personal blog built with Next.js App Router, Tailwind CSS, shadcn/ui, and MDX.
BitLog is designed for developers who want a clean writing experience with a lightweight CMS that runs locally. Write posts in Markdown/MDX, manage them through the admin panel, and deploy a fully static site.
- Static Site Generation — Pre-rendered pages for performance and SEO.
- Local Admin CMS — Write, edit, publish, and delete posts from
/admin. - MDX Content — Rich Markdown with syntax-highlighted code blocks, tables, and frontmatter.
- Bilingual — Built-in English / 中文 support with language switching.
- Dark Mode — System-aware light/dark theme toggle.
- Giscus Comments — GitHub Discussions-powered comments (optional).
- Auto-generated SEO — Sitemap, RSS feed, Open Graph, and Twitter cards.
- Tag-based Navigation — Browse posts by tags.
- Reading Stats — Word count and estimated reading time for every post.
- Framework: Next.js 16 (App Router)
- Styling: Tailwind CSS 4 + shadcn/ui components
- UI Primitives: @base-ui/react
- Content: MDX via
next-mdx-remote,gray-matter,rehype-pretty-code - Auth: JWT (
jose) + bcryptjs - Charts: Recharts
- Icons: Lucide React
- Package Manager: pnpm
- Node.js 20+
- pnpm 9+
pnpm installCopy the example file and update the values:
cp .env.local.example .env.localRequired variables:
| Variable | Description |
|---|---|
ADMIN_USERNAME |
Username for the admin panel |
ADMIN_PASSWORD_HASH |
Base64-encoded bcrypt hash of the admin password |
SESSION_SECRET |
Random secret for signing JWT tokens |
NEXT_PUBLIC_SITE_URL |
Public URL of the site |
Generate a password hash:
node -e "const bcrypt = require('bcryptjs'); bcrypt.hash('your-password', 10).then(h => console.log(Buffer.from(h).toString('base64')))"Optional Giscus variables for comments:
| Variable | Description |
|---|---|
NEXT_PUBLIC_GISCUS_REPO |
owner/repo |
NEXT_PUBLIC_GISCUS_REPO_ID |
From giscus.app |
NEXT_PUBLIC_GISCUS_CATEGORY |
Discussion category name |
NEXT_PUBLIC_GISCUS_CATEGORY_ID |
From giscus.app |
pnpm devOpen http://localhost:3000 for the blog and http://localhost:3000/admin/login for the CMS.
- Log in with the credentials configured in
.env.local. - Create and edit posts in Markdown/MDX.
- Save drafts with
Ctrl/Cmd + S. - Publish/unpublish posts or delete them from the post list.
- Upload images via the media library (
/admin/media).
Posts live in content/posts/ as .mdx files. Drafts are stored in content/drafts/.
Example frontmatter:
---
title: "My First Post"
slug: "my-first-post"
date: "2026-07-19"
tags: ["nextjs", "blog"]
description: "A short description for SEO and previews."
draft: false
---Code blocks support syntax highlighting and a copy button:
```typescript
const greeting = "Hello, BitLog!"
```This project includes a GitHub Actions workflow (.github/workflows/deploy.yml) that automatically builds and deploys to GitHub Pages on every push to main.
Setup steps:
- Fork or push this repo to your GitHub account.
- In your target GitHub Pages repo, go to Settings → Secrets and variables → Actions and add:
GH_PAT: A personal access token withreposcope.
- Update
.github/workflows/deploy.yml:- Change
external_repositorytoyour-username/your-username.github.io.
- Change
- Set the
NEXT_PUBLIC_SITE_URLenv var in the workflow to your Pages URL. - Optionally configure
NEXT_PUBLIC_GISCUS_*vars in the workflow for comments. - Push to
main— the workflow builds and deploys automatically.
Manual static export:
pnpm exportThis generates a static site in out/ that you can deploy to any static host.
- Import the repo into Vercel.
- Set the Build Command to
pnpm build(NOTpnpm export). - Set the Output Directory to
.next(Vercel default). - Add environment variables in Vercel's project settings:
ADMIN_USERNAME/ADMIN_PASSWORD_HASH/SESSION_SECRETfor admin auth.NEXT_PUBLIC_SITE_URL— your Vercel domain.NEXT_PUBLIC_GISCUS_*— if using Giscus comments.
- Deploy. The admin panel at
/admin/loginwill work on Vercel since it runs a Node server.
Note: Static export (
pnpm export) strips the admin API — use it only for GitHub Pages. Vercel/Node hosting preserves the full admin CMS.
bitlog/
├── content/ # MDX posts and drafts
├── public/ # Static assets
├── scripts/ # Build helpers
├── src/
│ ├── app/ # Next.js App Router pages
│ ├── components/ # React components
│ │ ├── admin/ # Admin UI components
│ │ ├── blog/ # Blog rendering components
│ │ ├── layout/ # Header, theme, i18n
│ │ └── ui/ # shadcn/ui components
│ ├── lib/ # Utilities, auth, content API
│ └── types/ # TypeScript types
├── .env.local.example # Environment variable template
├── next.config.ts
├── package.json
└── README.md
| Script | Description |
|---|---|
pnpm dev |
Start development server |
pnpm build |
Build for production |
pnpm export |
Build static export |
pnpm start |
Start production server |
pnpm lint |
Run ESLint |
- Edit
src/lib/site-config.tsto change site name, author, and social links. - Update
src/lib/i18n.tsto add or modify translations. - Adjust
src/app/globals.cssfor theme colors and scrollbar styles.
MIT