norm-has-a-blog is a simple, static, and zero config blog built with SvelteKit. It’s designed for developers who want to save and share the stuff they’re discovering.(but can be used by anyone for anything)
Features
This blog comes packed with powerful features out of the box:
- Modern Stack: Built with SvelteKit 2.0 and Vite for blazing-fast performance
- Markdown Support: Write posts in Markdown(GFM is also supported) with MDSveX.
- Syntax Highlighting: Beautiful code blocks powered by Shiki.
- Math Equations: Full support for LaTeX/KaTeX mathematical expressions powered by MathJax.
- Static Site Generation: Deploy anywhere with zero runtime dependencies(and zero cost).
- Table of Contents: Interactive table of contents for easy navigation.
- Responsive Design: Looks great on all devices.
- Dark/Light Theme: Built-in theme support.
- SEO Friendly: RSS/Atom feeds, sitemap, OG tags and canonical URLs.
- Tags & Categories: Organize posts with hierarchical categories and tags.
- Featured Posts: Pin important posts to the homepage.
- Enhanced Footer: Customizable footer with projects, blogs, and social links.
- Archives: Browse posts by date.
Prerequisites
Before you begin, ensure you have the following installed on your system:
- Node.js (v18 or higher) - Download here
- npm or yarn or pnpm (or any other package manager)
- Git
- A code editor.
Installation
1. Clone the Repository
First, clone the repository to your local machine:
git clone https://github.com/ahampriyanshu/norm-has-a-blog.git
cd norm-has-a-blog2. Install Dependencies
Install all required npm packages:
npm installThis will install all dependencies including SvelteKit, MDSveX, Shiki, and other required packages.
3. Start the Development Server
Launch the development server to see your blog in action:
npm run devYour blog should now be running at http://localhost:5173. The development server supports hot module replacement (HMR), so any changes you make will be reflected instantly.
Project Structure
Understanding the project structure will help you customize and extend your blog:
norm-has-a-blog/
├── src/
│ ├── lib/
│ │ ├── components/ # Reusable Svelte components
│ │ ├── layouts/ # Page and post layouts
│ │ ├── styles/ # Global SCSS stylesheets
│ │ ├── utils/ # Utility functions
│ │ └── config.ts # Blog configuration
│ ├── blog/ # Your markdown articles
│ ├── routes/ # SvelteKit routes
│ │ ├── +page.svelte # Homepage
│ │ ├── blog/ # Blog post routes
│ │ ├── tags/ # Tag listing and filtering
│ │ ├── categories/ # Category pages
│ │ ├── archives/ # Archive page
│ │ └── api/ # API endpoints (RSS, sitemap)
│ └── app.html # HTML template
├── static/ # Static assets
│ ├── images/ # Images for blog posts
│ ├── user.jpg # Your profile image
│ ├── logo.png # Your logo for footer
│ └── assets/ # CSS, fonts, etc.
├── svelte.config.js # Svelte/Kit configuration
├── vite.config.ts # Vite configuration
└── package.json # Project dependenciesConfiguration
Basic Configuration
The main configuration file is located at src/lib/config.ts. This is where you’ll customize your blog:
export const siteConfig = {
title: 'Your Blog Title',
description: 'Your blog description',
author: 'Your Name',
designation: 'Your Role/Designation',
bio: [
'First paragraph of your bio...',
'Second paragraph...',
'Third paragraph...'
],
baseURL: 'https://yourdomain.com',
subPath: '', // Leave empty for root domain, or '/blog' for subdirectory
githubUsername: 'yourusername',
githubRepo: 'your-repo',
twitterHandle: 'yourhandle',
lang: 'en',
timezone: 'America/New_York',
theme: 'dark', // 'dark' or 'light'
contact: {
github: 'https://github.com/yourusername',
linkedin: 'https://linkedin.com/in/yourusername',
resume: 'https://yourresume.com',
twitter: 'https://twitter.com/yourhandle',
email: 'mailto:your@email.com'
},
footerLinks: {
projects: [
{ name: 'Project 1', url: 'https://github.com/...' }
],
blogs: [
{ name: 'Blog 1', url: 'https://...' }
],
personal: [
{ name: 'Bookshelf', url: 'https://...' }
]
}
// ... more configuration options
};Important Settings to Update
Personal Information
title: Your blog’s titleauthor: Your namedesignation: Your job title or rolebio: Array of paragraphs for the homepage bio sectiondescription: A brief description of your blog
URLs and Paths
baseURL: Your production domainsubPath: Subdirectory path if not deploying to root
Social Links
- Update
contactobject with your social media profiles (GitHub, LinkedIn, Resume, Twitter, Email) - Set your
githubUsernameandtwitterHandle
- Update
Footer Links
footerLinks.projects: Add your projects with name and URLfooterLinks.blogs: Link to other blogs you maintainfooterLinks.personal: Personal links like playlists, bookshelf, etc.
Navigation
- Customize
navItemsto add/remove navigation links
- Customize
Analytics (Optional)
- Add your Google Analytics tracking IDs
Customizing the Base Path
If you’re deploying to a subdirectory (like GitHub Pages at username.github.io/blog), update the basePath in svelte.config.js:
const basePath = '/your-subdirectory';And also update subPath in src/lib/config.ts to match.
Writing Your First Post
Create a new markdown file in the src/blog/ directory:
touch src/blog/my-first-post.mdAdd frontmatter and content:
---
title: My First Blog Post
description: This is my first post on my new blog
date: '2025-11-02'
tags:
- introduction
- first-post
categories:
- General
pin: true
---
## Hello World!
This is my first blog post. I'm excited to start writing!Tip: Set
pin: trueto feature this post on your homepage!
For a detailed guide on writing posts, see the Adding New Post guide.
Building for Production
When you’re ready to deploy your blog, create a production build:
npm run buildThis generates optimized static files in the build/ directory. The build process:
- Pre-renders all pages for optimal performance
- Optimizes and minifies JavaScript and CSS
- Generates sitemap, RSS, and Atom feeds
- Creates optimized images and assets
Preview the Build
Test your production build locally:
npm run previewDeployment
Your blog is a static site and can be deployed anywhere. Here are some popular options:
GitHub Pages (Recommended)
- Make sure githup pages is configured for your account.
- Push the changes to origin.
- Enable GitHub Pages in repository settings.
- The Deploy to GitHub Pages / build (push) workflow will automatically build and deploy your site to GitHub Pages.
Netlify
Connect Your Repository on Netlify dashboard
Configure Build Settings:
- Build command:
npm run build - Publish directory:
build
- Build command:
Deploy!
Cloudflare Pages
- Connect Your Repository on Cloudflare Pages
- Configure Build Settings:
- Build command:
npm run build - Build output directory:
build
- Build command:
Customizing Your Blog
Homepage
The homepage displays:
- Profile Image: Place your image at
static/user.jpg(displayed as a 200x250px rounded image) - Hero Section: Shows your bio from
config.ts - Featured Posts: Displays posts with
pin: truein their frontmatter
Footer
The footer is enhanced with:
- Profile Section: Shows your logo (
static/logo.png), name, and designation - Social Icons: Links to GitHub, LinkedIn, Resume, and Twitter
- Three Sections: Customizable links for Projects, Blogs, and Personal
- Subscribe Button: Links to your RSS feed
- Scroll to Top: Smooth scroll functionality
Styles
The blog uses SCSS for styling. Main styles are located in:
- Global Styles:
src/lib/styles/louie.scsscontains design tokens (colors, spacing, borders), CSS resets, and global prose styles
Key Design Tokens
// Colors (automatically switch between light/dark themes)
--color-text-primary // Primary text color
--color-text-secondary // Secondary/muted text
--color-background-primary // Page background
--color-surface-primary // Card/surface backgrounds
--color-surface-secondary // Hover states
--color-link // Link color
--color-border-primary // Border colors
--color-heading // Heading text colorTroubleshooting
Port Already in Use
If port 5173 is already in use:
npm run dev -- --port 3000Build Errors
- Clear the build cache:
rm -rf build .svelte-kit
npm run build- Reinstall dependencies:
rm -rf node_modules package-lock.json
npm installImage Paths Not Working
Ensure images are in the static/images/ directory and referenced with /images/ in markdown:
Advanced Customization
Reusable Components
The blog includes several reusable components you can leverage:
Icon.svelte: Consistent SVG icons throughout the site (arrow-right, search, copy, check, github, linkedin, x-twitter, rss, moon, sun, arrow-up, etc.)BlogList.svelte: Displays a list of blog posts with datesIndexList.svelte: Dotted list view used for tags and categories pagesCopyDropdown.svelte: Action dropdown with primary action and menu items
Adding New Icons
To add a new icon, edit src/lib/components/Icon.svelte:
const icons: Record<string, string> = {
'my-icon': 'M12 2L2 12h3v8h6v-6h2v6h6v-8h3L12 2z',
// ... other icons
};Then use it anywhere:
<Icon name="my-icon" size={16} />Next Steps
Now that you have your blog set up, here’s what to do next:
- Customize Your Configuration - Update
src/lib/config.tswith your information - Write Your First Post - See the Adding New Post guide
- Explore Markdown Features - Check out the Markdown Syntax Guide
Happy blogging! 🚀