A WordPress-inspired blog theme re-engineered with Astro 5 & React — fast, fully-featured, and ready to deploy.
- Astro 6 + React 19 — island architecture for optimal performance
- MDX support — mix Markdown with React components in your posts
- Dark mode — class-based toggle with smooth transitions
- Full-text search — powered by Pagefind, works without a backend
- Featured posts slideshow — auto-rotating carousel on the home page
- Sidebar widgets — categories, tags, archives, latest articles, search box
- Post navigation — previous/next links scoped to the same category
- Open Graph + JSON-LD — structured metadata for SEO and social sharing
- Sitemap & robots.txt — generated automatically at build time
- Reading time — calculated per post
- Bibliography support — custom rehype plugin for academic-style citations
- i18n-ready — all UI strings and the date locale are centralised in
src/consts.ts - Analytics — Cloudflare Web Analytics (optional)
- Static output — deploys to Netlify, Vercel, Cloudflare Pages, GitHub Pages, or any static host
| Layer | Technology |
|---|---|
| Framework | Astro 6 |
| UI | React 19 |
| Styling | Tailwind CSS 4 |
| Markdown | MDX, remark-gfm |
| Search | Pagefind |
| Icons | MDI + Phosphor via Iconify |
| Analytics | Cloudflare Web Analytics (optional) |
| Deployment | Any static host |
# Fork & Clone the repo
git clone https://github.com/your-username/astro-rift.git
cd astro-rift
# Install dependencies
yarn install
# Start the dev server
yarn devThe dev server runs at http://localhost:4321.
Edit src/consts.ts to configure the site title, description, navigation menu, and social links:
export const SITE_TITLE = 'AstroRift';
export const SITE_DESCRIPTION_PLAIN = 'A Wordpress Theme re-engineered with Astro & React';
export const menu: MenuItem[] = [
{ name: 'Home', url: '/' },
{ name: 'Categories', children: [
{ name: 'My Category', url: '/category/my-category' },
]},
];
export const social = [
{ name: 'instagram', url: 'https://www.instagram.com/yourhandle', icon: 'mdi:instagram' },
];src/consts.ts also contains two exports for localisation:
// BCP 47 locale tag — controls date formatting across the site
export const SITE_LOCALE = 'en-GB';
// All interface strings in one place — translate these to change the UI language
export const ui = {
nav: { toggleMenu: 'Toggle menu', ... },
sidebar: { categories: 'Categories', tags: 'Tags', ... },
post: { readingTime: 'Reading time', previousArticle: 'Previous article', ... },
pagination: { previous: 'Previous', next: 'Next', ... },
// ...
};To translate the interface, change SITE_LOCALE to the target BCP 47 tag (e.g. 'it-IT', 'fr-FR') and replace the string values in ui with your translations. Date formatting uses the native Intl.DateTimeFormat API and will follow the locale automatically.
Copy .env.example to .env and fill in the values you need:
cp .env.example .env| Variable | Purpose |
|---|---|
PUBLIC_CLOUDFLARE_ANALYTICS_TOKEN |
Cloudflare Web Analytics beacon (optional) |
All variables are optional.
Create a .md or .mdx file anywhere under src/content/blog/. Subdirectories are used for organisation only — they do not affect the URL slug.
---
title: My Post Title
category: How-To
pubDate: 2026-03-12
tags: astro, web dev, tutorial
heroImage: '@/assets/my-post/heroImage.png'
excerpt: Optional custom excerpt — auto-generated from content if omitted.
draft: false
featured: false
---
Your post content here...| Field | Type | Required | Notes |
|---|---|---|---|
title |
string | yes | |
category |
string | yes | Used for grouping and navigation |
pubDate |
date | yes | |
tags |
string or string[] | no | Comma-separated string or array |
heroImage |
image | no | Use @/assets/... path |
excerpt |
string | no | Auto-generated from first 30 words if omitted |
updatedDate |
date | no | Shown alongside publish date |
draft |
boolean | no | Defaults to false; drafts hidden in production |
featured |
boolean | no | Includes post in home page slideshow |
featuredRank |
number | no | Controls order in the featured slideshow |
src/
├── assets/ # Images referenced from content
├── components/
│ ├── blog/ # PostPreview, PostList, LatestPostsGrid, PostHeader, etc.
│ ├── home/ # FeaturedSlideshow
│ ├── nav/ # Header, Footer, Breadcrumbs, DarkModeToggle
│ ├── sidebar/ # Categories, Tags, Archives, LatestArticles, SearchBox
│ └── shared/ # Box, Pagination
├── content/
│ ├── blog/ # Blog posts (.md / .mdx)
│ └── pages/ # Static pages (.md / .mdx)
├── layouts/
│ └── BlogLayout.astro # Main layout with sidebar
├── pages/ # File-based routes
├── plugins/ # Custom rehype plugins
├── styles/
│ └── global.css # Tailwind theme + CSS variables
├── utils/ # posts, categories, tags, archives, images, excerpts
└── consts.ts # Site-wide configuration
| Command | Action |
|---|---|
yarn dev |
Start dev server at localhost:4321 |
yarn build |
Build production site to ./dist/ |
yarn preview |
Preview the production build locally |
yarn lint |
Run ESLint |
yarn lint:fix |
Run ESLint with auto-fix |
yarn format |
Format all files with Prettier |
yarn type-check |
Run Astro type checker |
yarn test:e2e |
Run Playwright end-to-end tests |
AstroRift outputs static HTML at build time (output: 'static') with no server-side adapter required. It deploys to any static host:
- Netlify — connect your repository and set build command
yarn build, publish directorydist - Vercel — same: build command
yarn build, output directorydist - Cloudflare Pages, GitHub Pages, or any CDN — same dist output works everywhere
See the Astro deployment docs for platform-specific guides.
The theme uses CSS custom properties mapped into Tailwind via @theme. Edit src/styles/global.css to change the palette.
| Variable | Light | Dark |
|---|---|---|
--primary |
#5b21b6 ![]() |
#f59e0b ![]() |
--accent |
#7537e1 ![]() |
#ffbf04 ![]() |
--background |
#faf7ff ![]() |
#0d0a15 ![]() |
--text |
#4a3f5c ![]() |
#e8e0f5 ![]() |








