Personal portfolio and blog of a Junior Embedded Systems Engineer & Software Developer. Built with Next.js, TypeScript, Tailwind CSS, and a love for clean, minimal design.
- Overview
- Tech Stack
- Features
- Project Structure
- Architecture
- Getting Started
- Configuration
- Content Guide
- Comments & Social
- Deployment
- Roadmap
- License
mitaa.dev is a statically-generated portfolio website showcasing projects, technical blog posts, and GitHub activity. It is designed with a minimalist aesthetic, smooth scroll animations, and a focus on readability and performance.
The site is fully static — no database, no server runtime, no dynamic API routes at deploy time. Everything is pre-rendered at build time, making it perfect for hosting on GitHub Pages, Vercel, or any static CDN. voor
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 |
| UI Primitives | shadcn/ui |
| Animations | GSAP + Motion |
| Smooth Scroll | Lenis |
| Markdown | Remark + Rehype |
| Syntax Highlighting | highlight.js |
| Icons | Lucide React |
| Font | Inter (Google Fonts) |
| Build Output | Static Export (output: "export") |
- ⚡ Fully static — zero runtime dependencies, instant page loads
- 🎨 Minimalist light theme — clean whites, subtle grays, green accents
- 📱 Responsive — optimized for mobile, tablet, and desktop
- 🔤 Inter font — crisp, modern typography with tight tracking
- ✨ Scroll animations — blur, fade, and slide effects via
animate-uiprimitives - 📊 Scroll progress bar — subtle indicator at the top of the viewport
- 🧭 Sticky table of contents — auto-highlighting active section on blog posts
- Bio section with staggered fade-in paragraphs
- Latest blog posts list with date and primary tag
- Curated projects from
content/projects/projects.json - Dynamically fetched public GitHub repos (deduplicated against curated projects)
- Category filter tabs (Embedded, Web, ML, Open Source, etc.)
- Live search by title, description, or tech stack
- Star/fork counts for GitHub-sourced projects
- Detail pages with rich markdown content, tech stack, features, and context
- Markdown-driven blog posts with frontmatter
- Auto-generated table of contents from
h2/h3headings - Syntax-highlighted code blocks with language labels
- Auto-numbered figure captions for images
- GitHub-flavored Markdown (tables, task lists, strikethrough)
- SEO-friendly metadata per post
- Contribution calendar heatmap (via GitHub GraphQL API)
- Public repo listing with metadata (stars, forks, language, topics)
mitaa.dev/
├── content/ # All content source files
│ ├── blog/
│ │ ├── posts.json # Blog post registry (metadata)
│ │ └── *.md # Individual blog posts
│ └── projects/
│ ├── projects.json # Curated project registry
│ └── *.md # Project detail content
├── public/ # Static assets
│ └── data/ # Pre-fetched GitHub data (generated at build time)
│ ├── github-contributions.json
│ └── github-repos.json
├── scripts/
│ └── fetch-github-data.mjs # Pre-build script to fetch GitHub data
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── blog/ # Blog list & post pages
│ │ ├── projects/ # Project list & detail pages
│ │ ├── layout.tsx # Root layout (font, footer)
│ │ ├── page.tsx # Home page
│ │ └── globals.css # Global styles + prose-blog
│ ├── components/ # React components
│ │ ├── animate-ui/ # Animation primitives (Blur, Fade, Slide, etc.)
│ │ ├── DiscussOnX.tsx # Link to X/Twitter discussion
│ │ ├── Footer.tsx
│ │ ├── GitHubContributions.tsx
│ │ ├── Navbar.tsx
│ │ ├── ScrollProgressBar.tsx
│ │ ├── TableOfContents.tsx
│ │ └── icons.tsx # Custom SVG icons
│ ├── data/ # Static data (skills, legacy project data)
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Utility libraries
│ │ ├── blog.ts # Blog parsing & rendering
│ │ ├── github.ts # GitHub API helpers + JSON readers
│ │ ├── projects.ts # Project parsing & rendering
│ │ └── utils.ts # cn() helper
│ └── ...
├── components.json # shadcn/ui config
├── next.config.ts # Next.js config (static export)
├── postcss.config.mjs # PostCSS config
└── tsconfig.json # TypeScript config
All content lives in the content/ directory as plain files (JSON + Markdown). There is no CMS, no database, and no API for content. This makes the site:
- Version-controlled — content changes are Git commits
- Portable — move the folder, the content moves with it
- Fast — content is read at build time, never fetched at runtime
The blog uses a registry + file pattern:
-
content/blog/posts.json— a JSON array where each entry defines:slug— URL segment (e.g.,"building-rtos-from-scratch")title— display titledate— ISO date string ("2026-01-15")excerpt— short description for list viewstags— array of stringsreadTime— human-readable string (e.g.,"12 min read")
-
content/blog/{slug}.md— the Markdown content for that post.
At build time, lib/blog.ts:
- Reads
posts.jsonfor metadata - Reads the corresponding
.mdfile for content - Processes Markdown through Remark → Rehype → HTML
- Applies custom transforms:
- Code block language labels
- Image →
<figure>with auto-numbered captions - Heading IDs for anchor links
- Table of Contents extraction
Similar to the blog, projects use:
-
content/projects/projects.json— curated project metadata:slug,title,description,category,techStack[]github,demo,featuredcontext,role,goal,features[]
-
content/projects/{slug}.md— optional rich markdown content (Overview section).
Curated projects and GitHub-sourced projects are merged and deduplicated on the projects list page.
Because the site uses static export (output: "export"), it cannot use API routes at runtime. Instead, GitHub data is fetched at build time by a pre-build script and written to JSON files in public/data/:
| File | Purpose |
|---|---|
public/data/github-contributions.json |
Contribution calendar data (last 52 weeks) |
public/data/github-repos.json |
Public repositories (name, description, stars, forks, language, topics) |
The script scripts/fetch-github-data.mjs runs automatically before every build (npm run prebuild). It reads the GitHub GraphQL API for contributions and the REST API for repos. The site then reads these JSON files at build time (server-side for repos, client-side for contributions).
# Clone the repository
git clone https://github.com/MITCHEL-Development/mitaa.dev.git
cd mitaa.dev
# Install dependencies
npm install# Start the development server
npm run devOpen http://localhost:3000 in your browser.
# Build for production (static export)
npm run buildThis generates a static out/ folder ready for deployment to any static host.
Create a .env.local file in the project root:
# Required for pre-build GitHub data fetching
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxTo create a token:
- Go to GitHub Settings → Developer Settings → Personal Access Tokens
- Generate a new token (classic) with no scopes required for public data, or
read:userfor private contributions - Copy the token into
.env.local
The token is only used at build time by
scripts/fetch-github-data.mjs. It is never exposed to the client bundle. Without it, contributions data will be skipped (repos are public and will still be fetched).
-
Create a new Markdown file in
content/blog/:touch content/blog/my-new-post.md
-
Add the post metadata to
content/blog/posts.json:{ "slug": "my-new-post", "title": "My New Post", "date": "2026-04-23", "excerpt": "A short description of this post.", "tags": ["Web", "Tutorial"], "readTime": "5 min read" } -
Write your content in
content/blog/my-new-post.md:## Introduction Your content here... ```typescript const example = "code blocks are highlighted";
-
Rebuild the site:
npm run build
- Add project metadata to
content/projects/projects.json - (Optional) Create
content/projects/{slug}.mdfor a detailed overview - Rebuild
This website does not host its own comment system. Instead, blog post discussions happen externally on X (formerly Twitter).
- Each blog post published on
mitaa.devis also shared as a post on X - Readers can reply, quote, or discuss the post directly on that platform
- This keeps the website lightweight and static while still enabling community interaction
- X / Twitter: Follow @MITCHEL_Dev for new posts and updates (replace with your actual handle)
- GitHub: Star and fork the repo at github.com/MITCHEL-Development/mitaa.dev
Want to self-host comments instead? The site is built to be extended. You can integrate Disqus, Cusdis, or a custom Supabase backend by adding a client-side comment component to
src/app/blog/[slug]/page.tsx.
For selling digital products (such as software applications) and issuing license keys directly on the website, this project is integrated with Lemon Squeezy.
Using Lemon Squeezy as a Merchant of Record (MoR) is highly recommended for static Next.js sites because:
- Global Tax/VAT Handling: They automatically calculate, collect, and remit global software taxes so you don't have to worry about complex tax administration.
- Built-in Licensing: It provides out-of-the-box software licensing (generating, validating, and managing license keys).
- No Customer Data Handling: They safely store customer data (emails, billing info) and are fully GDPR/PCI compliant. You don't need to build or secure your own database.
- No Backend Required: You don't need a custom server or complex webhooks just to generate a license key.
- Products: Add a
BuyButtoncomponent linking to a Lemon Squeezy checkout overlay or hosted checkout page. - Delivery: After a successful payment, Lemon Squeezy automatically emails the customer their download link and generated license key.
- Validation: Inside your sold application (e.g., a desktop app in Rust, C#, or Electron), implement a check against the Lemon Squeezy License API to verify the entered key.
This site is configured for static export with trailingSlash: true, which is compatible with GitHub Pages:
npm run build
# Deploy the `out/` folder to the `gh-pages` branchVercel is the recommended host for Next.js projects. Simply connect your GitHub repo and Vercel will handle builds automatically.
Make sure to add
GITHUB_TOKENas an environment variable in your Vercel project settings so the pre-build script can fetch contribution data.
Any host that can serve static HTML works: Netlify, Cloudflare Pages, AWS S3, etc. Just upload the contents of the out/ folder.
- Dark mode toggle
- RSS feed for blog posts
- Sitemap.xml generation
- Open Graph image generation
- Project image gallery
- Tag-based blog filtering
- Estimated reading time calculation (auto)
- Update
xPostUrlfields incontent/blog/posts.jsonwith real tweet URLs
This project is open source and available under the MIT License.
Feel free to fork, clone, or use this as a template for your own portfolio. If you do, a shoutout or star on GitHub is always appreciated ⭐
Built with ❤️ by mitaa.dev
