Back to Projects
Next.js Portfolio Framework
Stable
2024

Next.js Portfolio Framework

Production-ready portfolio framework with MDX content management and advanced theming

Project Tags

Framework
Portfolio
Content Management
Open Source
Year
2024
Reading Time
8 min read
Stars
234
Forks
45

A Modern Portfolio Framework for Developers & Designers

A comprehensive, production-ready portfolio framework built with Next.js 14+ that combines powerful content management, advanced theming, and performance optimization. Designed for developers and designers who want a sophisticated portfolio without starting from scratch.

Motivation

After building numerous custom portfolios for clients and myself, I noticed recurring patterns and requirements:

  • Content Management: Need for easy content updates without rebuilding
  • Performance: Must achieve excellent Lighthouse scores
  • Flexibility: Support for different industries and personal brands
  • Developer Experience: Smooth local development and deployment
  • Accessibility: WCAG AA compliance out of the box

Rather than reinventing the wheel each time, I created a framework that addresses these needs systematically.

Key Features

1. MDX-Powered Content Management

Seamless content authoring with MDX supporting custom components:

---
title: "My Latest Project"
date: "2024-01-15"
tags: ["React", "TypeScript", "AI"]
featured: true
---

# Project Overview

This project demonstrates advanced **AI integration** with React applications.

<TechStack items={["React", "TypeScript", "OpenAI", "Next.js"]} />

<Stats>
  <Stat label="Performance" value="98" suffix="/100" />
  <Stat label="Users" value="10K" suffix="+" />
</Stats>

<Callout type="success">
Successfully deployed to production with zero downtime!
</Callout>

2. Advanced Theming System

Dual theme support with extensive customization options:

// Theme configuration
export const themes = {
  professional: {
    colors: {
      primary: 'oklch(60% 0.15 240)', // Deep blue
      accent: 'oklch(75% 0.20 280)'   // Purple accent
    },
    fonts: {
      display: ['Inter', 'system-ui'],
      body: ['Inter', 'system-ui']
    },
    animations: {
      duration: 'normal', // 250ms
      easing: 'ease-out'
    }
  },
  creative: {
    colors: {
      primary: 'oklch(65% 0.20 280)', // Vibrant purple
      accent: 'oklch(70% 0.25 320)'   // Pink accent
    },
    fonts: {
      display: ['Clash Display', 'system-ui'],
      body: ['Inter', 'system-ui']
    },
    animations: {
      duration: 'slow', // 400ms
      easing: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)' // Bouncy
    }
  }
} as const

3. Performance-First Architecture

Built-in optimizations for superior performance:

// Automatic image optimization
import { OptimizedImage } from '@/components/OptimizedImage'

const ProjectCard = ({ project }: { project: Project }) => {
  return (
    <Card>
      <OptimizedImage
        src={project.coverImage}
        alt={project.title}
        width={400}
        height={240}
        priority={project.featured}
        placeholder="blur"
        blurDataURL={project.blurDataURL}
      />
      <CardContent>
        <h3>{project.title}</h3>
        <p>{project.description}</p>
      </CardContent>
    </Card>
  )
}

4. Accessibility-First Components

All components built with accessibility as a priority:

// Accessible navigation with keyboard support
const Navigation = () => {
  const [isOpen, setIsOpen] = useState(false)
  const trapFocusRef = useRef<HTMLDivElement>(null)

  useFocusTrap(trapFocusRef, isOpen)
  useEscapeKey(() => setIsOpen(false))

  return (
    <nav role="navigation" aria-label="Main navigation">
      <button
        type="button"
        aria-expanded={isOpen}
        aria-controls="navigation-menu"
        onClick={() => setIsOpen(!isOpen)}
      >
        <span className="sr-only">
          {isOpen ? 'Close navigation' : 'Open navigation'}
        </span>
        <MenuIcon />
      </button>

      <div
        ref={trapFocusRef}
        id="navigation-menu"
        className={cn(
          'navigation-menu',
          isOpen && 'navigation-menu--open'
        )}
      >
        {navigationItems.map((item) => (
          <NavigationLink
            key={item.href}
            href={item.href}
            onClick={() => setIsOpen(false)}
          >
            {item.label}
          </NavigationLink>
        ))}
      </div>
    </nav>
  )
}

Technical Architecture

Content Layer

Flexible content management supporting multiple content types:

// Content schema with Zod validation
export const ProjectSchema = z.object({
  title: z.string(),
  description: z.string(),
  year: z.number(),
  stack: z.array(z.string()),
  tags: z.array(z.string()),
  repo: z.string().url().optional(),
  demo: z.string().url().optional(),
  status: z.enum(['alpha', 'beta', 'stable', 'archived']),
  featured: z.boolean().default(false),
  published: z.boolean().default(true)
})

export type Project = z.infer<typeof ProjectSchema>

// Content loading with caching
export const getAllProjects = cache((): ProjectWithContent[] => {
  const projectFiles = fs.readdirSync(path.join(process.cwd(), 'content/projects'))

  return projectFiles
    .filter(file => file.endsWith('.mdx'))
    .map(file => {
      const slug = file.replace(/\.mdx$/, '')
      return parseProject(slug)
    })
    .filter(project => project.frontMatter.published)
    .sort((a, b) => b.frontMatter.year - a.frontMatter.year)
})

Component System

Modular component library with consistent APIs:

// Base card component with variants
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
  variant?: 'default' | 'elevated' | 'outlined'
  interactive?: boolean
  children: React.ReactNode
}

export const Card = forwardRef<HTMLDivElement, CardProps>(
  ({ className, variant = 'default', interactive = false, ...props }, ref) => {
    return (
      <div
        ref={ref}
        className={cn(
          'card',
          `card--${variant}`,
          interactive && 'card--interactive',
          className
        )}
        {...props}
      />
    )
  }
)

Build & Deployment Pipeline

Automated quality checks and deployment:

# GitHub Actions workflow
name: Build and Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  quality-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile
      - run: pnpm typecheck
      - run: pnpm lint
      - run: pnpm test
      - run: pnpm build

      - name: Lighthouse CI
        run: pnpm lighthouse-ci
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}

  deploy:
    needs: quality-checks
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.ORG_ID }}
          vercel-project-id: ${{ secrets.PROJECT_ID }}

Performance Optimization

Core Web Vitals Focus

Achieved excellent performance metrics through optimization:

98/100
Lighthouse Performance
0.8s
First Contentful Paint
1.2s
Largest Contentful Paint
0.01
Cumulative Layout Shift

Image Optimization Strategy

// Automatic next/image configuration
const nextConfig = {
  images: {
    domains: ['images.unsplash.com', 'avatars.githubusercontent.com'],
    formats: ['image/webp', 'image/avif'],
    sizes: '(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw',
  }
}

// Dynamic image loading with blur placeholders
export async function generateBlurDataURL(imageUrl: string): Promise<string> {
  const response = await fetch(imageUrl)
  const buffer = await response.arrayBuffer()
  const base64 = Buffer.from(buffer).toString('base64')
  return `data:image/jpeg;base64,${base64}`
}

Bundle Optimization

// Dynamic imports for code splitting
const LazyChart = dynamic(() => import('@/components/Chart'), {
  loading: () => <ChartSkeleton />,
  ssr: false
})

// Lazy loading of heavy components
const DragExploreGrid = dynamic(() => import('@/components/DragExploreGrid'), {
  loading: () => <GridSkeleton />,
  ssr: false
})

Developer Experience

Type Safety

Comprehensive TypeScript coverage with strict configuration:

// Strict tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "noUncheckedIndexedAccess": true
  }
}

// Type-safe content loading
export function getProject(slug: string): ProjectWithContent | null {
  try {
    const project = parseMarkdownFile('projects', slug, ProjectSchema)
    return project
  } catch (error) {
    console.error(`Failed to load project: ${slug}`, error)
    return null
  }
}

Development Tools

Comprehensive development setup:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "lint:fix": "next lint --fix",
    "typecheck": "tsc --noEmit",
    "test": "vitest",
    "test:coverage": "vitest --coverage",
    "test:e2e": "playwright test",
    "format": "prettier --write .",
    "validate-content": "tsx scripts/validate-content.ts"
  }
}

Community & Adoption

The framework has gained traction in the developer community:

GitHub Metrics

  • Stars: 234+
  • Forks: 45+
  • Contributors: 12
  • Issues Resolved: 89%

Community Contributions

  • Template variations for different industries
  • Additional theme presets
  • Custom component contributions
  • Documentation improvements
  • Translation support

User Testimonials

"Finally, a portfolio framework that doesn't compromise on performance or accessibility. The MDX integration is seamless." - Frontend Developer

"Used this as the foundation for my design portfolio. The theming system made customization effortless." - UI Designer

"The built-in accessibility features saved me weeks of work. Everything just works." - Accessibility Consultant

Future Roadmap

Planned Features

  • CMS Integration: Headless CMS adapters for non-technical users
  • Multi-language Support: i18n implementation with automatic routing
  • Analytics Dashboard: Built-in performance and visitor analytics
  • Component Marketplace: Shareable custom components
  • CLI Tool: Project scaffolding and content generation utilities

Community Requests

  • WordPress migration tool
  • Notion content sync
  • Advanced animation presets
  • E-commerce integration for selling digital products
  • Social media automation

Technical Innovation

1. Adaptive Theme System

Dynamic theme switching with CSS custom properties:

export function useTheme() {
  const [theme, setTheme] = useState<ThemeName>('professional')

  useEffect(() => {
    const root = document.documentElement
    const themeConfig = getTheme(theme)

    // Apply CSS custom properties
    Object.entries(generateCSSVariables(themeConfig)).forEach(([prop, value]) => {
      root.style.setProperty(prop, value)
    })

    // Set data attribute for theme-specific styling
    root.setAttribute('data-theme', theme)
  }, [theme])

  return { theme, setTheme }
}

2. Content Validation Pipeline

Automated content validation with detailed error reporting:

export async function validateAllContent(): Promise<ValidationReport> {
  const report = new ValidationReport()

  try {
    // Validate projects
    const projects = await getAllProjects()
    projects.forEach(project => {
      const result = ProjectSchema.safeParse(project.frontMatter)
      if (!result.success) {
        report.addError('projects', project.slug, result.error)
      }
    })

    // Validate images exist
    const imageValidation = await validateImages(projects)
    report.merge(imageValidation)

    // Validate external links
    const linkValidation = await validateExternalLinks(projects)
    report.merge(linkValidation)

  } catch (error) {
    report.addCriticalError(error as Error)
  }

  return report
}

3. Progressive Enhancement

Features that work without JavaScript:

// Server-side rendering with progressive enhancement
export default function ProjectsPage({ projects }: { projects: Project[] }) {
  return (
    <div>
      {/* Works without JavaScript */}
      <ProjectGrid projects={projects} />

      {/* Enhanced with JavaScript */}
      <ClientOnly>
        <ProjectFilters />
        <ProjectSearch />
      </ClientOnly>
    </div>
  )
}

Open Source Philosophy

This project embodies open source best practices:

  • Comprehensive Documentation: Detailed setup and customization guides
  • Clear Contributing Guidelines: Welcoming to contributors of all levels
  • Semantic Versioning: Predictable release cycles
  • Backwards Compatibility: Thoughtful breaking changes with migration guides
  • Community-Driven: Features prioritized based on community feedback

The framework is MIT licensed and available for both personal and commercial use. Contributions are welcome and encouraged!

Tech Stack

Next.js
TypeScript
Tailwind CSS
MDX
Framer Motion

Status

Stable

Production ready and actively maintained

Explore More Projects

Discover more open source tools, frameworks, and experiments that solve real-world problems with modern technologies.