Version 1.1.0 · Last updated: June 26, 2026
Introduction
Portal 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
portall-astro/
├── public/
│ └── img/ # Static images (blog covers, avatar)
│ ├── news/
│ └── 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: "2026-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: "2026-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 2026',
};
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: '[email protected]',
},
copyright: {
links: [
{ label: 'Privacy', href: '/privacy' },
{ label: 'Terms', href: '/terms' },
],
text: 'Copyright 2026 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' },
],
},
];
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: "2026-01-01"
description: "Learn more about our team."
---
Your page content here.
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 [email protected].