Static website for portfolio, blog, and CV with dark mode support! 🌙
npm install
npm run devEdit site.config.js:
module.exports = {
name: "Your Name",
title: "My Portfolio",
description: "...",
// Profile picture (optional)
profileImage: "/images/profile.jpg", // or null to show initial letter
// Current role and affiliation
role: "PhD Student",
affiliation: "Stanford University",
// Research interests (with optional icons)
interests: [
{ name: "Machine Learning", icon: "Brain" },
{ name: "Web Development", icon: "Code" },
"Photography" // plain text works too
],
// Navigation items (with optional icons from Lucide React)
navigation: [
{ title: "Home", path: "/", icon: "Home" },
{ title: "CV", path: "/cv", icon: "FileText" },
{ title: "Blog", path: "/blog", icon: "BookOpen" }
],
social: {
github: "https://github.com/yourusername",
linkedin: "https://linkedin.com/in/yourusername",
email: "your.email@example.com"
}
}- Place your image in
public/images/folder (e.g.,public/images/profile.jpg) - Update
site.config.js:profileImage: "/images/profile.jpg" - Use
nullto show initial letter instead:profileImage: null
Tips:
- Use square images (recommended: 400x400px or larger)
- Supported formats: JPG, PNG, WebP
- Keep file size under 500KB
Make your site stand out with custom favicons and proper SEO metadata.
Favicon Setup:
-
Create your favicon files:
favicon.ico(32x32 or 16x16) - Standard faviconicon.png(512x512) - Modern browsers & PWAapple-icon.png(180x180) - Apple devices
-
Place them in the
public/folder:public/ ├── favicon.ico ├── icon.png └── apple-icon.png -
Update
site.config.js:favicon: "/favicon.ico", icon: "/icon.png", appleIcon: "/apple-icon.png",
SEO Settings:
Configure SEO metadata in site.config.js:
siteUrl: "https://yourdomain.com",
author: "Your Name",
keywords: ["portfolio", "blog", "your", "keywords"],What's Included:
- ✅ Open Graph metadata (Facebook, LinkedIn sharing)
- ✅ Twitter Card metadata (Twitter sharing)
- ✅ Proper favicon support (all devices)
- ✅ SEO-friendly meta tags
- ✅ Google indexing optimization
- ✅ Dynamic page titles with template
Tools to Create Favicons:
- Favicon.io - Generate from text, image, or emoji
- RealFaviconGenerator - All formats at once
- Design tools: Figma, Canva, Photoshop
Navigation items support optional icons from Lucide React.
How to Add Icons:
In site.config.js, add an icon field to any navigation item:
navigation: [
{ title: "Home", path: "/", icon: "Home" },
{ title: "CV", path: "/cv", icon: "FileText" },
{ title: "Blog", path: "/blog", icon: "BookOpen" },
{ title: "Projects", path: "/projects", icon: "Code" },
{ title: "Publications", path: "/publications", icon: "GraduationCap" }
]Available Icons:
Browse all available icons at lucide.dev/icons. Use the exact icon name (case-sensitive):
Home,User,Mail,PhoneFileText,Download,UploadBookOpen,Book,LibraryCode,Terminal,CpuGraduationCap,Award,Trophy- And 1000+ more!
Notes:
- Icons are optional - you can mix items with and without icons
- Icons work on both desktop and mobile navigation
- Invalid icon names will be ignored (no error shown)
Your site automatically supports dark mode with three themes: Light, Dark, and System (follows device preference).
How It Works:
- 🌙 Click the moon/sun icon in the header to toggle themes
- 🖥️ System theme (default) - follows your device's color scheme
- 💾 Theme preference is saved in browser localStorage
- 🎨 All components automatically adapt to the selected theme
Implementation Details:
Built using Tailwind CSS v4 with next-themes:
- Custom
@custom-variant darkin globals.css - Class-based dark mode strategy
- No FOUC (Flash of Unstyled Content) with
suppressHydrationWarning - Smooth transitions between themes
Customizing Dark Mode:
All dark mode colors are defined using Tailwind's dark: variant:
className="bg-white dark:bg-slate-950 text-gray-900 dark:text-white"To customize colors, edit the CSS classes in component files or update globals.css theme variables.
A powerful search feature is built-in to help users find content across all pages.
Features:
- Search across all blog posts, projects, publications, and custom pages
- Real-time search results as you type
- Search by title, description, tags, or category
- Beautiful modal interface with keyboard shortcuts
- Click the search icon in the header navigation to open
- Press
Escapeto close the search modal
How to Use:
- Click the 🔍 search icon in the header (after navigation items)
- Type your search query
- Click on any result to navigate to that page
- Results show the category, date, title, description, and tags
What Gets Searched:
- All markdown files in the
content/folder - Searches: title, description, tags, and category
- Results are sorted by date (newest first)
- Limited to 10 results for performance
Enable auto-generated navigation from content folders:
// site.config.js
useDynamicNavigation: true // Auto-generate nav from /content foldersOr use manual navigation (default):
useDynamicNavigation: false,
navigation: [
{ title: "Home", path: "/", icon: "Home" },
{ title: "CV", path: "/cv", icon: "FileText" },
{ title: "Blog", path: "/blog", icon: "BookOpen" }
]Configure CV page appearance in site.config.js:
cvConfig: {
showDownloadButton: false, // Show/hide download button
showPrintButton: false, // Show/hide print button
// Professional CV styling options
style: {
showBadge: true, // "Curriculum Vitae" badge
badgeColor: "gray", // "gray" | "blue" | "green" | "purple"
showDivider: true, // Divider line under header
contentPadding: "tight", // "tight" | "normal" | "relaxed"
}
}Option 1: PDF File
cvFile: "/cv/resume.pdf"Place PDF in public/cv/ folder
Option 2: Image File
cvFile: "/cv/cv.png"Place image in public/cv/ folder
Option 3: Markdown (Recommended for SEO)
cvFile: nullCreate content/cv/cv.md with this structure:
---
title: CV
---
## Education
**PhD in Computer Science** | Stanford University
*2020 - Present*
- Research focus: Machine Learning
- Advisor: Prof. Jane Doe
- GPA: 4.0/4.0
## Experience
**Research Assistant** | Stanford AI Lab
*September 2020 - Present*
- Developing novel neural network architectures
- Published 5 papers in top-tier conferencesFeatures:
- Timeline dots and accent lines
- Gradient section headers
- Custom bullet points
- Professional typography with kerning & ligatures
- Optimized for print
- Full dark mode support
- SEO-friendly
Everything is content-driven! No need to touch code in the app/ folder. Simply add markdown files to the content/ folder, and pages are automatically created.
This applies to all pages including blog, projects, and any custom collections you want to create.
1. Simple Pages (Single Markdown File)
Use Case: About page, Contact page, Terms of Service, etc.
How to Create:
- Create a file in
content/folder:content/about.md - Add frontmatter and content:
--- title: About Me description: Learn more about me --- # About Me Your content here...
- That's it! Page is automatically available at
/about
Example:
content/about.md→ Available at/aboutcontent/contact.md→ Available at/contactcontent/terms.md→ Available at/terms
2. Collection Pages (Folder with Multiple Items)
Use Case: Publications, Gallery, Courses, Tutorials, etc.
How to Create:
- Create a folder in
content/:content/publications/ - Add markdown files inside:
content/publications/ ├── paper-2024.md ├── paper-2023.md └── conference-talk.md - Each file has frontmatter:
--- title: My Research Paper date: 2024-01-15 description: A study on... tags: [research, AI] --- # My Research Paper Content here...
- That's it! Collection page is at
/publicationsand each item at/publications/paper-2024
Example:
content/publications/→ Collection at/publicationscontent/publications/paper-2024.md→ Item at/publications/paper-2024content/courses/→ Collection at/coursescontent/courses/ml-101.md→ Item at/courses/ml-101
By default, collection pages use a 3-column grid. To customize, edit site.config.js:
pages: {
projects: {
mode: "grid", // "grid" or "list"
itemsPerPage: 12,
columns: 2
},
blog: {
mode: "list",
itemsPerPage: 6,
columns: 4
},
// Add your new pages
publications: {
mode: "grid", // Cards in grid
itemsPerPage: 9,
columns: 3 // 3 columns
},
courses: {
mode: "list", // Large cards with thumbnails
itemsPerPage: 5,
columns: 1
}
}Edit site.config.js:
navigation: [
{ title: "Home", path: "/" },
{ title: "CV", path: "/cv" },
{ title: "Blog", path: "/blog" },
{ title: "Projects", path: "/projects" },
{ title: "Publications", path: "/publications" }, // New!
{ title: "About", path: "/about" } // New!
]Show latest items on home page by editing site.config.js:
homeSections: [
{
type: "blog",
title: "Latest Posts",
count: 1,
showViewAll: true,
viewAllText: "View All Posts",
viewAllLink: "/blog"
},
{
type: "projects",
title: "Featured Projects",
count: 2,
showViewAll: true,
viewAllText: "View All Projects",
viewAllLink: "/projects"
},
// Add your new section
{
type: "publications",
title: "Recent Publications",
count: 3,
showViewAll: true,
viewAllText: "View All Publications",
viewAllLink: "/publications"
}
]Step 1: Create folder and files
content/courses/
├── intro-to-ml.md
├── deep-learning.md
└── nlp-basics.md
Step 2: Add content to each file
---
title: Introduction to Machine Learning
date: 2024-01-10
description: Learn ML fundamentals
tags: [ML, beginner]
thumbnail: /images/ml-course.png
---
# Introduction to Machine Learning
Course content here...Step 3: Configure display in site.config.js
pages: {
// ... existing pages
courses: {
mode: "grid",
itemsPerPage: 9,
columns: 3
}
}Step 4: Add to navigation
navigation: [
// ... existing items
{ title: "Courses", path: "/courses" }
]Done! Your courses page is now live at /courses!
All pages support these fields:
---
title: Page Title # Required
date: 2024-01-15 # Optional (for sorting)
description: Short description # Optional
excerpt: Preview text # Optional
tags: [tag1, tag2] # Optional
thumbnail: /images/thumb.png # Optional (for cards)
tech: "React, Node.js" # Optional (for projects)
demo: https://demo.com # Optional (live demo link)
github: https://github.com/... # Optional (code link)
---To create a new page:
- Add folder or file to
content/ - Add to navigation in
site.config.js(optional) - Configure display in
pagessection (optional, for collections) - Add to home page in
homeSections(optional)
No code required! Just markdown files and config changes.
The site includes automatic dark/light mode switching:
- Toggle: Click the moon/sun icon in the header
- Persistence: Your preference is saved in browser localStorage
- Auto-styling: New pages automatically support dark mode through global CSS overrides
Adding custom pages? Dark mode works automatically for common Tailwind classes (text-gray-900, bg-white, etc.). For explicit control, add dark mode variants:
// Automatic (recommended)
<h1 className="text-gray-900">Title</h1>
// Explicit control (optional)
<h1 className="text-gray-900 dark:text-white">Title</h1>How it works:
- Global CSS automatically converts common gray colors to light colors in dark mode
- Only applies to elements WITHOUT explicit
dark:classes - Works for all new pages without extra configuration
If you want your site at https://username.github.io:
- Fork or clone this repository
- Rename the repository to
username.github.io(replaceusernamewith your GitHub username) - Update
next.config.mjs- Remove the basePath and assetPrefix:const nextConfig = { output: 'export', images: { unoptimized: true, }, };
- Enable GitHub Pages:
- Go to your repository on GitHub
- Click Settings (top menu)
- Click Pages (left sidebar)
- Under "Build and deployment":
- Source: Select "GitHub Actions" from the dropdown
- (NOT "Deploy from a branch" - make sure to select GitHub Actions!)
- Push your changes:
git add . git commit -m "Configure for GitHub Pages" git push
- Wait for deployment - The GitHub Action will automatically build and deploy
- Visit
https://username.github.io
If you want your site at https://username.github.io/my-portfolio:
- Fork or clone this repository
- Update
next.config.mjs- Change the basePath to match your repo name:const nextConfig = { output: 'export', basePath: process.env.NODE_ENV === 'production' ? '/my-portfolio' : '', assetPrefix: process.env.NODE_ENV === 'production' ? '/my-portfolio/' : '', images: { unoptimized: true, }, };
- Enable GitHub Pages:
- Go to your repository on GitHub
- Click Settings (top menu)
- Click Pages (left sidebar)
- Under "Build and deployment":
- Source: Select "GitHub Actions" from the dropdown
- (NOT "Deploy from a branch" - make sure to select GitHub Actions!)
- Push your changes:
git add . git commit -m "Configure for GitHub Pages" git push
- Wait for deployment - The GitHub Action will automatically build and deploy
- Visit
https://username.github.io/my-portfolio
If you prefer manual deployment:
# Build the site
npm run build
# The static files are in the 'out' folder
# Deploy the 'out' folder to any static hosting serviceThe repository includes a GitHub Actions workflow (.github/workflows/deploy.yml) that automatically:
- Builds your site when you push to
mainormasterbranch - Deploys to GitHub Pages
- No manual build commands needed!
Just edit your content, commit, and push:
git add .
git commit -m "Update content"
git push404 errors after deployment:
- Make sure the
basePathinnext.config.mjsmatches your repository name - For
username.github.io, remove the basePath entirely - For
username.github.io/repo-name, set basePath to/repo-name
GitHub Actions failing:
- Check Settings → Pages → Build and deployment → Source is set to "GitHub Actions" (not "Deploy from a branch")
- Verify you have write permissions for GitHub Pages in repository settings
- Check the Actions tab in your repository to see the build logs for any errors
Images not loading:
- Make sure images are in the
publicfolder - Use absolute paths:
/images/photo.jpgnot./images/photo.jpg