A modern, SEO-optimized blog frontend built with Next.js 16, React 19, and Tailwind CSS v4. Features internationalization (English/Vietnamese), server-side rendering, and a clean responsive design.
- Blog Pages — Homepage with featured post, paginated grid, post detail with 3-column layout
- Search — Keyword-based search with paginated results
- Categories & Tags — Filtered listing pages with pagination
- About Page — Profile hero with gradient background, social links, and markdown content
- Internationalization — Full i18n support (EN/VI) via
next-intl - Markdown Rendering — GFM tables, scrollable code blocks, custom link styling
- SEO — Per-page metadata, Open Graph tags, canonical URLs, sitemap support
- Google Analytics — Optional GA4 integration
- On-Demand Revalidation — Cache invalidation via API with secret token
- Sitemap — Auto-generated sitemap with all posts, categories, tags, and static pages
- Responsive Design — Mobile-first with sticky header, drawer menu, and adaptive layouts
- Custom 404 — Branded not-found page with illustration
| Category | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI | React 19 |
| Styling | Tailwind CSS v4 + @tailwindcss/typography |
| Language | TypeScript 5 |
| i18n | next-intl |
| Search Params | nuqs |
| Markdown | react-markdown + remark-gfm |
| Analytics | @next/third-parties (Google Analytics) |
| Font | Google Sans (via CDN) |
app/
├── [locale]/
│ ├── page.tsx # Homepage (featured + paginated posts)
│ ├── layout.tsx # Locale layout (header, footer, SEO)
│ ├── about/page.tsx # About page
│ ├── posts/[slug]/page.tsx # Post detail
│ ├── categories/[slug]/ # Posts by category
│ ├── tags/[slug]/ # Posts by tag
│ └── search/page.tsx # Search results
├── not-found.tsx # Custom 404 page
├── sitemap.ts # Auto-generated sitemap
├── layout.tsx # Root layout (fonts, analytics)
└── globals.css # Tailwind config + design tokens
components/
├── home/ # FeaturedPost, PostCard, Pagination
├── layout/ # Header, Footer
├── post/ # ShareSidebar
├── empty-state.tsx # Reusable empty/no-data state
└── markdown-renderer.tsx # Markdown with prose styling
libs/
├── api/public.ts # API client (getPosts, getPostBySlug, etc.)
├── types/api.ts # TypeScript interfaces
├── routes.ts # Centralized route definitions
├── constants.ts # Site-wide constants from env vars
└── utils.ts # cn(), getLocalizedValue()
- Node.js 20+
- Yarn or npm
- Backend API server running (see vietduc-blog-server)
# Clone the repository
git clone https://github.com/duc30012001/vietduc-blog-client-v2.git
cd vietduc-blog-client-v2
# Install dependencies
yarn install
# Copy environment file
cp .env.example .env| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_API_URL |
Backend API base URL | http://localhost:8080/v1 |
NEXT_PUBLIC_SITE_URL |
Public-facing site URL | http://localhost:3000 |
NEXT_PUBLIC_SITE_NAME |
Site name for meta tags | Duck Blog |
NEXT_PUBLIC_SITE_KEYWORDS |
SEO keywords (comma-separated) | blog, technology... |
NEXT_PUBLIC_GA_ID |
Google Analytics ID (optional) | — |
REVALIDATION_SECRET |
Cache revalidation secret token | — |
yarn devOpen http://localhost:3000.
yarn build
yarn start| Method | Route | Description |
|---|---|---|
POST |
/api/revalidate |
On-demand cache revalidation (requires REVALIDATION_SECRET) |
- English (
/en/...) - Vietnamese (
/vi/...)
Translation files are located in messages/en.json and messages/vi.json.
Private project.