Version 1.0 · Last updated: January 1, 2024
Introduction
Neutral is a minimal, fast, and fully-featured blog theme built with Astro, Tailwind CSS v4, and Alpine.js. It is designed for personal blogs, travel journals, and content-first websites.
What’s included
- Hero slider + category grid on the homepage
- Blog post pages with fullwidth and sidebar variants
- Category, tag, and author archive pages with pagination
- Search page with instant client-side filtering
- About, Contact, Privacy, Terms, and Cookie pages
- Reusable sidebar widgets (author, categories, tags, gallery)
- Footer with dynamic latest and featured posts
- Back-to-top button, social share, and related posts
Requirements
Before you begin, make sure you have the following installed:
- Node.js 18.17.1 or higher (LTS recommended) — nodejs.org
- npm 9+ or pnpm 8+ or yarn 1.22+
- A code editor — VS Code with the official Astro extension is recommended
Verify your Node version:
node -v
Installation
1. Clone or extract the theme
If you downloaded the theme as a ZIP file, extract it to your project folder:
cd my-blog
2. Install dependencies
npm install
This will install all required packages including:
astro— the core frameworktailwindcss+@tailwindcss/vite— styling@tailwindcss/typography— prose styling for blog contentalpinejs— lightweight interactivityastro-icon+@iconify-json/bi— Bootstrap Icons
3. Start the development server
npm run dev
Open http://localhost:4321 in your browser. The site hot-reloads automatically when you edit files.
Project Structure
neutral-astro/
├── public/
│ └── img/ # Static images (blog covers, avatar)
│ ├── blogs/
│ └── personal/
├── src/
│ ├── components/ # Reusable Astro components
│ ├── content/
│ │ ├── blog/ # Blog posts (.mdx)
│ │ └── pages/ # Static pages (.mdx)
│ ├── data/ # Site configuration data
│ │ ├── authorData.ts
│ │ ├── headerData.ts
│ │ ├── footerData.ts
│ │ ├── heroData.ts
│ │ └── aboutData.ts
│ ├── layouts/ # Page layout templates
│ ├── pages/ # Astro route pages
│ ├── styles/
│ │ └── style.css # Global styles + Tailwind entry
│ └── utils/
│ └── path.ts # URL helper
├── astro.config.mjs
├── content.config.ts # Content collection schemas
└── tsconfig.json
Writing Blog Posts
All blog posts live in src/content/blog/ as .mdx files.
Create a new post
Create a file: src/content/blog/my-first-post.mdx
---
title: "My First Post"
cover: "/img/blogs/my-cover.jpg"
date: "2024-06-01"
category: "Travel"
tags: ["travel", "tips", "adventure"]
readTime: 5
featured: false
trending: false
popular: false
authorId: "jesicca"
excerpt: "A short description shown in post cards and meta tags."
---
Your post content goes here. You can use **bold**, *italic*, and all standard Markdown.
## A Heading
Regular paragraph text.
> A blockquote looks like this.
- List item one
- List item two
Frontmatter fields
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✓ | Post title |
cover | string | ✓ | Cover image path from /public/ |
date | string | ✓ | ISO date: "2024-06-01" |
category | string | ✓ | Single category label |
tags | string[] | — | Array of tag strings |
readTime | number | ✓ | Estimated minutes to read |
featured | boolean | — | Shows in hero slider + featured widgets |
trending | boolean | — | Shows in gallery widgets |
popular | boolean | — | Shows in popular post widgets |
authorId | string | ✓ | Must match an id in authorData.ts |
excerpt | string | ✓ | Short description (150–200 chars) |
Post URL
The post URL is derived from the filename. my-first-post.mdx becomes /my-first-post.
Site Configuration
All site-wide data is stored in src/data/. Edit these files to customize the theme.
Header — headerData.ts
Controls the top bar links, navigation menu, social icons, and logo:
export const defaultHeaderData: HeaderData = {
topMenu: [
{ label: 'Home', href: '/' },
{ label: 'About', href: '/about' },
{ label: 'Contact', href: '/contact' },
],
logo: {
src: '/img/logo.png',
alt: 'My Blog',
width: 160,
},
navMenu: [
{ label: 'Home', href: '/' },
{ label: 'Travel', href: '/category/travel' },
{
label: 'Pages',
children: [
{ label: 'About', href: '/about' },
{ label: 'Contact', href: '/contact' },
],
},
],
socialLinks: [
{ icon: 'bi:instagram', href: 'https://instagram.com/yourhandle', label: 'Instagram' },
{ icon: 'bi:twitter-x', href: 'https://twitter.com/yourhandle', label: 'Twitter' },
],
copyright: 'Copyright 2024',
};
Footer — footerData.ts
Controls the about text, contact info, and copyright links:
export const defaultFooterData: FooterData = {
info: {
title: 'About Us',
description: 'Your blog description here.',
address: 'Your city, Country',
phone: '+(000) 000-0000',
email: 'hello@yourdomain.com',
},
copyright: {
links: [
{ label: 'Privacy', href: '/privacy' },
{ label: 'Terms', href: '/terms' },
],
text: 'Copyright 2024 Your Name',
},
};
Author — authorData.ts
Add or edit authors. The id must match the authorId in your MDX posts:
export const authors: AuthorData[] = [
{
id: 'your-id',
name: 'Your Name',
fullName: 'Your Full Name',
avatar: '/img/personal/avatar.jpg',
bio: 'Short bio shown in sidebar and author page.',
href: '/author/your-id',
website: 'https://yourwebsite.com',
socials: [
{ icon: 'bi:instagram', href: 'https://instagram.com/yourhandle', label: 'Instagram' },
],
},
];
About page — aboutData.ts
Edit stats, skills, timeline, and gallery for the /about page:
export const defaultAboutData: AboutData = {
name: 'Your Name',
tagline: 'Travel Blogger · Photographer',
avatar: '/img/personal/avatar.jpg',
intro: ['First paragraph...', 'Second paragraph...'],
stats: [{ value: '50+', label: 'Countries Visited' }],
skills: [{ name: 'Photography', percent: 90 }],
timeline: [
{ year: '2020', title: 'Started Blogging', description: '...' },
],
gallery: [
{ image: '/img/blogs/1.jpg', alt: 'Photo caption' },
],
};
Hero Section
The homepage hero has two parts: a slider and a category grid.
Slider
The slider automatically pulls the 3 most recent posts with featured: true. To change the number of slides:
<!-- src/pages/index.astro -->
<HeroSection sliderLimit={5} autoplayInterval={5000} />
Category grid
Edit the grid items in heroData.ts:
export const defaultHeroData: HeroData = {
grid: [
{ image: '/img/blogs/3.jpg', imageAlt: 'Travel', category: 'Travel', href: '/category/travel' },
{ image: '/img/blogs/6.jpg', imageAlt: 'Food', category: 'Food', href: '/category/food' },
{ image: '/img/blogs/8.jpg', imageAlt: 'Daily', category: 'Daily', href: '/category/daily' },
],
};
PostCard Variants
PostCard supports four layout variants:
<!-- Default: two-column, thumbnail left -->
<PostCard variant="default" ... />
<!-- Grid: thumbnail top, stacked layout -->
<PostCard variant="grid" ... />
<!-- Box: content overlapping thumbnail -->
<PostCard variant="box" ... />
<!-- List: compact thumbnail left (1/3), no button -->
<PostCard variant="list" ... />
Static Pages (MDX)
Pages in src/content/pages/ are used for /privacy, /terms, and /cookies. To add a new page:
1. Create src/content/pages/about-us.mdx:
---
title: "About Us"
label: "About Us"
icon: "bi:info-circle"
date: "2024-01-01"
description: "Learn more about our team."
---
Your page content here.
2. Create src/pages/about-us.astro:
---
import { getCollection, render } from 'astro:content';
import PageLayout from '@src/layouts/PageLayout.astro';
const pages = await getCollection('pages');
const page = pages.find((p) => p.id === 'about-us');
const { Content } = await render(page);
---
<PageLayout page={page} Content={Content} />
Adding Icons
This theme uses Bootstrap Icons via astro-icon. To add a new icon, first add it to astro.config.mjs:
icon({
include: {
bi: [
// existing icons...
'star', // ← add new icon name here
],
},
}),
Then use it in any component:
---
import { Icon } from 'astro-icon/components';
---
<Icon name="bi:star" class="size-4" />
Browse all Bootstrap Icons at icons.getbootstrap.com.
Sub-path Deployment
If your site is deployed to a sub-path (e.g. yourdomain.com/), set BASE_URL in your environment or update src/utils/path.ts:
const BASE = '/blog'; // your sub-path
All href and src attributes in this theme use the url() helper, so every link will automatically pick up the prefix.
Build & Deploy
Build for production
npm run build
Output is generated in dist/. Preview locally with:
npm run preview
Deploy to Netlify
npm install -g netlify-cli
netlify deploy --prod --dir=dist
Deploy to Vercel
npm install -g vercel
vercel --prod
Deploy to GitHub Pages
Add to astro.config.mjs:
export default defineConfig({
site: 'https://yourusername.github.io',
base: '/your-repo-name',
// ...
});
Then push to the gh-pages branch or use the official Astro GitHub Pages guide.
Support & License
For questions contact lightestcode@gmail.com.