A modern, statically-generated portfolio and technical blog built with Next.js 16, TypeScript, and Tailwind CSS. Deployed on GitHub Pages.
Production: jakea.net GitHub Pages: abendrothj.github.io/portfolio
- π Technical Blog: Markdown-based blog with syntax highlighting for code snippets
- π¨ Modern UI: Clean, minimalist design with dark mode support
- β‘ Static Export: Fully static site generated with Next.js SSG
- π SEO Optimized: Proper meta tags, OpenGraph, and semantic HTML
- π± Responsive: Mobile-first design that works on all devices
- π Fast: Optimized for performance with static HTML
- π― Type-Safe: Full TypeScript support
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS
- UI Components: Radix UI + shadcn/ui
- Icons: Lucide React
- Markdown: react-markdown + remark-gfm
- Deployment: GitHub Pages
- CI/CD: GitHub Actions
- Node.js 20+
- npm or yarn
-
Clone the repository:
git clone https://github.com/abendrothj/portfolio.git cd portfolio -
Install dependencies:
npm install --legacy-peer-deps
-
Run development server:
npm run dev
# Build static site
npm run build
# Output will be in ./out directory
# Test locally
npx serve outportfolio/
βββ app/ # Next.js app directory
β βββ about/ # About page
β βββ blog/ # Blog listing & posts
β β βββ [slug]/ # Dynamic blog post pages
β βββ layout.tsx # Root layout with navigation
β βββ page.tsx # Home page
β βββ globals.css # Global styles
βββ components/ # React components
β βββ ui/ # shadcn/ui components
β βββ nav.tsx # Navigation bar
β βββ footer.tsx # Footer
βββ lib/ # Utilities
β βββ blog.ts # Blog post parsing logic
βββ posts/ # Markdown blog posts
β βββ welcome.md
β βββ building-doppel.md
β βββ building-argus-file-integrity.md
β βββ ...
βββ public/ # Static assets
β βββ CNAME # Custom domain config
β βββ .nojekyll # Disable Jekyll on GitHub Pages
β βββ ...
βββ .github/
β βββ workflows/
β βββ deploy.yml # GitHub Actions deployment
βββ next.config.mjs # Next.js configuration
Blog posts are written in Markdown with frontmatter metadata.
-
Create a new
.mdfile in/posts/:touch posts/my-new-post.md
-
Add frontmatter and content:
--- title: "Your Post Title" date: "2025-12-27" excerpt: "A brief description of your post" tags: ["tag1", "tag2", "tag3"] --- # Your Post Title Your content here... ## Code Examples ```rust fn main() { println!("Hello, world!"); }
-
Rebuild the site:
npm run build
title: string # Post title (required)
date: string # Publication date in YYYY-MM-DD format (required)
excerpt: string # Short description for preview (required)
tags: string[] # Array of tags (required)- Syntax highlighting for code blocks (Rust, Python, JavaScript, etc.)
- GitHub Flavored Markdown (tables, task lists, strikethrough)
- Automatic metadata (reading time, timestamps)
- SEO optimization per post
This site deploys automatically to GitHub Pages via GitHub Actions.
-
Enable GitHub Pages:
- Go to repo Settings β Pages
- Set Source to GitHub Actions
-
Push to main branch:
git push origin main
-
GitHub Actions will:
- Build the static site
- Deploy to GitHub Pages
- Available at
https://abendrothj.github.io/portfolio
- Home page: Edit
app/page.tsx - About page: Edit
app/about/page.tsx - Navigation: Edit
components/nav.tsx - Footer: Edit
components/footer.tsx
The project uses Tailwind CSS with a custom theme:
- Theme colors:
tailwind.config.ts - Global styles:
app/globals.css - Component styles: Inline Tailwind classes
The site uses shadcn/ui components. To add new components:
npx shadcn-ui@latest add button
npx shadcn-ui@latest add cardTo add analytics:
-
Vercel Analytics (if re-deploying to Vercel):
import { Analytics } from '@vercel/analytics/react' // Already in dependencies
-
Google Analytics:
- Add tracking code to
app/layout.tsx - Use
next/scriptfor optimal loading
- Add tracking code to
-
Plausible or other privacy-friendly alternatives
This project doesn't require environment variables for basic functionality. Optional:
# .env.local (optional)
NEXT_PUBLIC_GA_ID=your-google-analytics-idKey settings in next.config.mjs:
{
output: 'export', // Static HTML export
images: {
unoptimized: true, // Required for static export
},
}# Clear cache and rebuild
rm -rf .next out
npm run build- Check for escaped backticks (
\```) instead of regular backticks - Ensure language is specified:
```rust
- Verify slug matches filename (without
.md) - Check frontmatter is valid YAML
- Rebuild after adding new posts
Contributions welcome! Feel free to:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is open source and available under the MIT License.
Jake Abendroth
- Website: jakea.net
- GitHub: @abendrothj
- Email: contact@jakea.net
- Built with Next.js
- UI components from shadcn/ui
- Deployed on GitHub Pages
- Inspired by the developer community
Made with π» and β by Jake Abendroth