Blogcraft
A minimalist bilingual blog built with Astro. Write in Markdown, statically generated, ready to go. Features built-in i18n (zh/en), dark/light theme, full-text search, and GitHub Discussions comments.
Features
- Bilingual — Chinese by default, with English at
/en/, automatic hreflang SEO, language switcher, and translation linking - Dark/Light mode — respects
prefers-color-schemewith manual toggle, persisted in localStorage, zero flash - Full-text search — powered by Pagefind, build-time indexing, zero external dependencies, works offline
- GitHub comments — Giscus integration using GitHub Discussions, no separate auth system needed
- SEO out of the box — auto-generated sitemap, Open Graph tags, robots.txt, semantic HTML
- Responsive — mobile-first, 900px max content width
- Fast by default — fully static generation, zero JS runtime
Tech Stack
| Layer | Choice |
|---|---|
| Framework | Astro v5 (static site generation) |
| Content | Markdown via Content Collections |
| Search | Pagefind (build-time indexing) |
| Comments | Giscus (GitHub Discussions) |
| Package manager | pnpm |
| Styling | Pure CSS with Custom Properties |
Prerequisites
# Install pnpm
npm install -g pnpm
Quick Start
# Clone the repository
git clone https://github.com/Alistairccc/BlogCraft.git
cd BlogCraft
# Install dependencies
pnpm install
# Start dev server (defaults to http://localhost:4321)
pnpm dev
Build for production
pnpm build
Output goes to dist/. Preview locally:
pnpm preview
Writing Blog Posts
Posts live in src/content/blog/ organized by language:
src/content/blog/
├── zh/ # Chinese posts (default language)
│ ├── hello-world.md
│ └── ...
└── en/ # English posts
├── hello-world.md
└── ...
Each post requires frontmatter:
---
title: "My First Post"
description: "A brief description for cards and SEO"
lang: zh
translationKey: "hello-world" # links zh/en versions of the same post
pubDate: 2026-05-27
draft: false
---
Linking translations: Posts with the same translationKey across languages are automatically linked — readers see a toggle button to switch language on the same article.
To draft a post: Set draft: true — it won’t appear on the homepage or in the sitemap.
Project Structure
BlogCraft/
├── public/
│ ├── favicon.ico
│ └── robots.txt
├── src/
│ ├── components/ # Reusable Astro components
│ │ ├── BlogCard.astro # Blog post card
│ │ ├── Footer.astro
│ │ ├── Giscus.astro # Giscus comments
│ │ ├── Header.astro
│ │ ├── LanguageSwitcher.astro
│ │ ├── SearchBar.astro
│ │ └── ThemeToggle.astro
│ ├── content/
│ │ ├── blog/en/ # English posts (Markdown)
│ │ ├── blog/zh/ # Chinese posts (Markdown)
│ │ └── config.ts # Content Collection schema
│ ├── i18n/
│ │ ├── ui.ts # Translation key-value pairs
│ │ └── utils.ts # i18n helper functions
│ ├── layouts/
│ │ └── BaseLayout.astro # HTML shell for all pages
│ ├── pages/
│ │ ├── index.astro # Homepage (zh)
│ │ ├── about.astro # About page (zh)
│ │ ├── blog/ # Blog-related pages
│ │ │ ├── index.astro # Blog listing (zh)
│ │ │ └── [...slug].astro # Blog post detail (zh)
│ │ ├── search.astro # Search page (zh)
│ │ └── en/ # English versions
│ │ ├── index.astro
│ │ ├── about.astro
│ │ ├── blog/
│ │ │ ├── index.astro
│ │ │ └── [...slug].astro
│ │ └── search.astro
│ └── styles/
│ ├── global.css # Design tokens, reset, layout
│ └── blog.css # Blog post typography
├── astro.config.mjs
├── package.json
└── README.md
Configuration
Site URL
Set your domain in astro.config.mjs:
export default defineConfig({
site: 'https://your-domain.com',
});
Also update public/robots.txt with the correct sitemap URL.
Giscus (Comments)
The blog uses Giscus to power comments via GitHub Discussions.
- Make sure your repository has GitHub Discussions enabled
- Install the Giscus app on your repo
- Open giscus.app, fill in your repo details, and copy the configuration
- Update
src/components/Giscus.astrowith yourdata-repo,data-repo-id,data-category,data-category-idvalues
Search
Search uses Pagefind and runs as a post-build step (pnpm build runs astro build && npx pagefind --site dist). No external service or API key needed.
Modifying Translations
Edit src/i18n/ui.ts to add or modify translation keys:
export const ui = {
zh: {
'nav.home': '首页',
'nav.blog': '文章',
},
en: {
'nav.home': 'Home',
'nav.blog': 'Blog',
},
};
Keys are strongly typed through the TranslationKey type in the same file.
Deployment
This is a fully static site — deploy to any static hosting platform (Cloudflare Pages, Vercel, Netlify, etc.). Build command:
pnpm build
Deploy the dist/ directory to your hosting platform.
Comments