Skip to content

omarafify7/omarafify.com

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

86 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

omarafify.com

Modern Portfolio Engine with Custom MDX Pipeline & Edge Analytics

Next.js TypeScript React Tailwind CSS Vercel

A high-performance portfolio platform built with Next.js 13 App Router, featuring a custom MDX content pipeline, privacy-preserving edge analytics, and interactive UI components.

Live Demo โ€ข View Projects


๐Ÿ“‹ Table of Contents


๐ŸŽฏ Overview

This portfolio platform is designed to showcase engineering projects and technical skills through an optimized, modern web experience. Built on Next.js 13's App Router with React Server Components, it combines:

  • Custom MDX Content Pipeline using Contentlayer with semantic processing
  • Edge-based Analytics with Upstash Redis for privacy-preserving view tracking
  • Interactive Visualizations including Mermaid diagrams and particle animations
  • End-to-end Type Safety via TypeScript and validated content schemas

The platform prioritizes performance, privacy, and developer experience while maintaining a visually stunning interface.


๐Ÿ—๏ธ Architecture

System Architecture

graph TB
    subgraph "Content Layer"
        MDX[MDX Files<br/>content/projects/*.mdx]
        FM[Frontmatter YAML]
        Content[Markdown Content]
    end

    subgraph "Build Time - Contentlayer"
        CL[Contentlayer Engine]
        Schema[Schema Validation]
        Remark[Remark Plugins<br/>remark-gfm]
        Rehype[Rehype Plugins<br/>rehype-slug<br/>rehype-mermaid<br/>rehype-pretty-code<br/>rehype-autolink-headings]
        JSON[Generated JSON + Types]
    end

    subgraph "Next.js App Router"
        SSR[Server Components]
        CSR[Client Components]
        Pages["Pages<br/>/projects/[slug]"]
        Layouts[Layouts]
    end

    subgraph "Edge Runtime"
        API[API Routes<br/>/api/incr]
        Redis[(Upstash Redis)]
    end

    subgraph "Client Browser"
        UI[Interactive UI]
        Particles[Particle System]
        Mermaid[Mermaid.js Renderer]
        Analytics[Analytics Component]
    end

    MDX --> FM
    MDX --> Content
    FM --> CL
    Content --> CL
    CL --> Schema
    Schema --> Remark
    Remark --> Rehype
    Rehype --> JSON
    JSON --> SSR
    SSR --> Pages
    SSR --> Layouts
    Pages --> CSR
    CSR --> UI
    CSR --> Particles
    CSR --> Mermaid
    CSR --> Analytics
    Analytics --> API
    API --> Redis

    style MDX fill:#f9f,stroke:#333,stroke-width:2px
    style CL fill:#bbf,stroke:#333,stroke-width:2px
    style SSR fill:#bfb,stroke:#333,stroke-width:2px
    style API fill:#fbb,stroke:#333,stroke-width:2px
    style Redis fill:#fab,stroke:#333,stroke-width:3px
Loading

Content Processing Pipeline

flowchart LR
    subgraph Input
        A[MDX File] --> B{Parse}
        B --> C[Frontmatter<br/>YAML]
        B --> D[Markdown<br/>Content]
    end

    subgraph Contentlayer
        C --> E[Schema Validation]
        E --> F{Valid?}
        F -->|Yes| G[Type Generation]
        F -->|No| H[Build Error]
        D --> I[Remark Processing]
    end

    subgraph "Markdown โ†’ HTML"
        I --> J[remark-gfm<br/>GFM Support]
        J --> K[rehype-slug<br/>Add IDs]
        K --> L[rehype-mermaid<br/>Detect Diagrams]
        L --> M{Mermaid<br/>Block?}
        M -->|Yes| N[Create Custom<br/>div with data-mermaid]
        M -->|No| O[rehype-pretty-code<br/>Syntax Highlighting]
        N --> P[rehype-autolink-headings<br/>Link Headings]
        O --> P
        P --> Q[HTML Output]
    end

    subgraph Output
        G --> R[Typed JSON]
        Q --> R
        R --> S[.contentlayer/<br/>generated/]
        S --> T[Import in<br/>React Components]
    end

    style A fill:#f9f,stroke:#333,stroke-width:2px
    style E fill:#bbf,stroke:#333,stroke-width:2px
    style L fill:#bfb,stroke:#333,stroke-width:2px
    style R fill:#fbb,stroke:#333,stroke-width:2px
Loading

Analytics Pipeline

sequenceDiagram
    participant User
    participant Browser
    participant ReportView as ReportView Component
    participant EdgeAPI as Edge API<br/>/api/incr
    participant Redis as Upstash Redis

    User->>Browser: Visit /projects/[slug]
    Browser->>ReportView: Component Mounts
    ReportView->>ReportView: Check hasReported ref
    
    alt First Mount
        ReportView->>EdgeAPI: POST /api/incr<br/>{slug: "project-name"}
        EdgeAPI->>EdgeAPI: Extract IP Address
        EdgeAPI->>EdgeAPI: SHA-256 Hash IP
        
        EdgeAPI->>Redis: SET deduplicate:{hash}:{slug}<br/>NX EX 86400
        
        alt New Visitor (24h)
            Redis-->>EdgeAPI: OK (Key Created)
            EdgeAPI->>Redis: INCR pageviews:projects:{slug}
            Redis-->>EdgeAPI: New Count
            EdgeAPI-->>ReportView: 202 Accepted
        else Seen Before
            Redis-->>EdgeAPI: NULL (Key Exists)
            EdgeAPI-->>ReportView: 202 Accepted<br/>(No Increment)
        end
    else Already Reported
        ReportView->>ReportView: Skip (React Strict Mode)
    end

    Note over EdgeAPI,Redis: Privacy: Only hashed IPs stored<br/>Deduplication: 24-hour window<br/>No PII or tracking cookies
Loading

Component Architecture

graph TD
    subgraph "Server Components"
        Root[layout.tsx<br/>Root Layout]
        Home[page.tsx<br/>Home Page]
        ProjectLayout[projects/layout.tsx]
        ProjectPage["projects/[slug]/page.tsx"]
        Header["projects/[slug]/header.tsx"]
        Article[projects/article.tsx]
    end

    subgraph "Client Components"
        Particles[particles.tsx<br/>Canvas Animation]
        Nav[nav.tsx<br/>Navigation]
        Card[card.tsx<br/>Project Cards]
        SpotlightBtn[spotlight-button.tsx<br/>Interactive Button]
        SkillIcon[skill-icon.tsx<br/>Tech Icons]
        Mermaid[mermaid.tsx<br/>Diagram Renderer]
        TOC[table-of-contents.tsx<br/>Page Navigation]
        ReportView[view.tsx<br/>Analytics Reporter]
        MDX[mdx.tsx<br/>MDX Components]
    end

    subgraph "Shared Utilities"
        Mouse[util/mouse.ts<br/>Mouse Tracking]
        Analytics[components/analytics.tsx<br/>Vercel Analytics]
    end

    Root --> Home
    Root --> ProjectLayout
    ProjectLayout --> ProjectPage
    ProjectPage --> Header
    ProjectPage --> Article
    ProjectPage --> ReportView

    Home --> Particles
    Home --> Nav
    Home --> SpotlightBtn
    Home --> SkillIcon

    Article --> MDX
    Article --> TOC

    MDX --> Mermaid

    SpotlightBtn --> Mouse
    Particles --> Mouse

    ProjectPage --> Analytics

    style Root fill:#bfb,stroke:#333,stroke-width:2px
    style Particles fill:#bbf,stroke:#333,stroke-width:2px
    style Mermaid fill:#fbb,stroke:#333,stroke-width:2px
    style ReportView fill:#fab,stroke:#333,stroke-width:2px
Loading

โœจ Key Features

๐Ÿš€ Next.js 13 App Router

Full utilization of React Server Components for optimal initial load performance and automatic code splitting.

๐Ÿ“ Custom MDX Engine

Semantic content processing with extensible plugin architecture:

  • Syntax Highlighting: rehype-pretty-code with GitHub Dark theme
  • Auto-linked Headings: Automatic anchor generation with rehype-slug and rehype-autolink-headings
  • GFM Support: Tables, task lists, and strikethrough via remark-gfm
  • Custom Mermaid Plugin: lib/rehype-mermaid.js intercepts diagram code blocks before syntax highlighting

๐Ÿ“Š Edge Analytics

Privacy-preserving view tracking system:

  • Edge Runtime: Runs on Vercel Edge Network for global low-latency
  • IP Hashing: SHA-256 hashing ensures no PII storage (pages/api/incr.ts)
  • Deduplication: 24-hour Redis key expiration prevents double-counting
  • Atomic Operations: Redis INCR ensures accurate concurrent updates

๐ŸŽจ Interactive Diagrams

Integrated Mermaid.js support with zoom/pan controls:

  • Diagrams defined in markdown code blocks
  • Client-side rendering with mermaid.tsx
  • Powered by react-zoom-pan-pinch for interactive exploration

๐ŸŒˆ Dynamic UI

Premium visual experience:

  • Particle System: WebGL-accelerated canvas with mouse magnetism (particles.tsx)
  • Spotlight Buttons: Proximity-based hover effects (spotlight-button.tsx)
  • Smooth Animations: Framer Motion for declarative transitions
  • Responsive Design: Tailwind CSS with mobile-first approach

๐Ÿ”’ Type Safety

End-to-end type safety for content:

  • Schema Validation: Contentlayer validates frontmatter against TypeScript schemas
  • Generated Types: Automatic type generation for content files
  • TypeScript Strict Mode: Prevents runtime errors during development

๐Ÿ› ๏ธ Tech Stack

Core Framework

Content Management

Data & Infrastructure

Styling & UI

Visualization


๐Ÿš€ Quick Start

Prerequisites

Installation

  1. Clone the repository:

    git clone https://github.com/omarafify/omarafify.com.git
    cd omarafify.com
  2. Install dependencies:

    pnpm install
  3. Configure environment variables:

    Create a .env file in the root directory:

    UPSTASH_REDIS_REST_URL=your-upstash-url
    UPSTASH_REDIS_REST_TOKEN=your-upstash-token
    NEXT_PUBLIC_BEAM_TOKEN=optional-analytics-token

    Note: Get free Upstash Redis credentials at console.upstash.com

  4. Run the development server:

    pnpm dev

    Open http://localhost:3000 in your browser.

  5. Build for production:

    pnpm build
    pnpm start

๐Ÿ’ป Development

Project Structure

omarafify.com/
โ”œโ”€โ”€ app/                      # Next.js App Router
โ”‚   โ”œโ”€โ”€ components/           # React components
โ”‚   โ”‚   โ”œโ”€โ”€ particles.tsx    # Canvas particle system
โ”‚   โ”‚   โ”œโ”€โ”€ mermaid.tsx      # Mermaid diagram renderer
โ”‚   โ”‚   โ”œโ”€โ”€ mdx.tsx          # MDX component mappings
โ”‚   โ”‚   โ””โ”€โ”€ ...
โ”‚   โ”œโ”€โ”€ projects/            # Projects section
โ”‚   โ”‚   โ”œโ”€โ”€ [slug]/          # Dynamic project pages
โ”‚   โ”‚   โ””โ”€โ”€ page.tsx         # Projects listing
โ”‚   โ”œโ”€โ”€ layout.tsx           # Root layout
โ”‚   โ””โ”€โ”€ page.tsx             # Home page
โ”œโ”€โ”€ content/                 # MDX content files
โ”‚   โ””โ”€โ”€ projects/            # Project markdown files
โ”œโ”€โ”€ lib/                     # Utilities and plugins
โ”‚   โ””โ”€โ”€ rehype-mermaid.js   # Custom rehype plugin
โ”œโ”€โ”€ pages/api/               # API routes
โ”‚   โ””โ”€โ”€ incr.ts             # Analytics endpoint
โ”œโ”€โ”€ public/                  # Static assets
โ”œโ”€โ”€ util/                    # Helper functions
โ”œโ”€โ”€ contentlayer.config.js  # Content schema & config
โ””โ”€โ”€ tailwind.config.js      # Tailwind configuration

Adding New Projects

  1. Create an MDX file in content/projects/:

    ---
    title: "Your Project Title"
    description: "Brief description"
    date: "2024-01-01"
    published: true
    tier: "A"
    category: ["ml", "backend"]
    techStack: ["Python", "AWS", "Docker"]
    repository: "https://github.com/username/repo"
    ---
    
    Your project content here...
  2. Contentlayer will automatically:

    • Validate the frontmatter schema
    • Generate TypeScript types
    • Process the MDX content
    • Make it available in your components

Custom MDX Components

Extend app/components/mdx.tsx to add custom components:

const components = {
  h1: (props: any) => <h1 className="custom-h1" {...props} />,
  YourComponent: CustomComponent,
};

Formatting

The project uses Rome for formatting:

pnpm fmt

๐Ÿ“š What I Learned

Edge Computing Constraints

Adapting API routes to the Vercel Edge Runtime required fundamental changes:

  • No Node.js APIs: Switched from native crypto to Web Crypto API
  • No TCP Connections: Used Upstash's REST API instead of Redis protocol
  • Stateless Functions: Designed for instant cold starts and global distribution

AST Transformations

Building the custom Mermaid plugin (lib/rehype-mermaid.js) taught me:

  • How markdown parsers create Abstract Syntax Trees (ASTs)
  • Plugin execution order matters (must run before syntax highlighting)
  • Transforming nodes while preserving document structure

React Server Components

Learned the new paradigm of data fetching and rendering:

  • Server Components: Fetch data, access databases, render static content
  • Client Components: Handle interactivity, use hooks, access browser APIs
  • Boundaries: Strategic "use client" directives for minimal client JavaScript

๐Ÿ”ฎ Future Improvements

Migration from Contentlayer

Contentlayer is deprecated. Plan to migrate to:

  • Option 1: Next.js built-in MDX support with custom loader
  • Option 2: Velite as a direct replacement
  • Option 3: Custom build-time processor

Search Functionality

Implement client-side fuzzy search:

  • Index project metadata (title, description, tech stack)
  • Use Fuse.js for fuzzy matching
  • Filter and sort projects dynamically

Testing Suite

Add comprehensive testing:

  • Unit Tests: Jest for utilities and components
  • Integration Tests: Test MDX pipeline and content processing
  • E2E Tests: Playwright for user flows and analytics verification

Performance Optimizations

  • Implement incremental static regeneration (ISR) for projects
  • Add image optimization with Next.js Image component
  • Optimize particle system with WebGL shaders

Built with โค๏ธ by Omar Afify

About

Personal portfolio website

Resources

License

Stars

Watchers

Forks

Languages

  • TypeScript 52.9%
  • MDX 41.3%
  • JavaScript 5.0%
  • CSS 0.8%