Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

40 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation


Live React Vite Vercel License


Personal portfolio of Harsh Raj - a fast, fully-featured React SPA with dark/light theme, live GitHub data, animated custom cursor, and a canvas contribution heatmap.


✨ Features

πŸš€ SPA Navigation - zero full-page reloads
🎨 Dark / Light Theme - circular wipe via View Transition API
πŸ“‘ Live GitHub Projects - fetched, filtered & sorted by topics
πŸ”₯ GitHub Heatmap - canvas-rendered contribution graph
πŸ“¬ Contact Form - EmailJS + toast feedback + Ctrl+Enter

πŸ‘οΈ Scroll Reveal - IntersectionObserver fade-up animations
πŸ–±οΈ Custom Cursor - dual-ring, hover-expand (desktop only)
πŸ“Š Visit Counter - Upstash Redis via Vercel serverless
🧭 Persistent Layout - Nav, Footer, Cursor mount once
πŸ“± Fully Responsive - mobile-first, all breakpoints covered


πŸ› οΈ Tech Stack

Layer Choice
⚑ Build Tool Vite 6
βš›οΈ UI Framework React 19
πŸ”€ Routing React Router v7
πŸͺ– Meta / SEO react-helmet-async
🎨 Styling Single global CSS (src/index.css)
πŸ“‘ Data GitHub REST API + EmailJS
πŸ“Š Visit Counter Upstash Redis via Vercel serverless
πŸš€ Deployment Vercel

πŸ“„ Routes

URL Page
/ 🏠 Home - hero, about, journey preview, skills ticker, featured projects, GitHub heatmap
/projects πŸ—‚οΈ All Projects - search, filter (frontend / fullstack / AI), sort
/contact πŸ“¬ Contact - EmailJS form + social links
/journey πŸ—ΊοΈ Journey - experience & internship timeline
/certificates πŸ† Certificates & Achievements
* πŸ” 404 Not Found

πŸ“ File Structure

Portfolio/
β”œβ”€β”€ πŸ“„ index.html                  # SPA shell - single HTML entry point
β”œβ”€β”€ βš™οΈ  vite.config.js
β”œβ”€β”€ πŸš€ vercel.json                 # SPA rewrites + /api route
β”œβ”€β”€ πŸ“¦ package.json
β”œβ”€β”€ πŸ“‹ Resume.pdf                  # Served from /Resume.pdf
β”‚
└── src/
    β”œβ”€β”€ πŸš€ main.jsx                # BrowserRouter + HelmetProvider + ThemeProvider
    β”œβ”€β”€ πŸ—ΊοΈ  App.jsx                # Route definitions + AppShell wrapper
    β”œβ”€β”€ 🎨 index.css               # Full design system + all component styles
    β”‚
    β”œβ”€β”€ layouts/
    β”‚   └── πŸ—οΈ  AppShell.jsx       # Persistent shell - Nav, Footer, Cursor, Glows
    β”‚
    β”œβ”€β”€ router/
    β”‚   β”œβ”€β”€ πŸ”€ routes.jsx          # Lazy imports for all pages
    β”‚   └── ⬆️  ScrollToTop.jsx    # Scrolls to top on every route change
    β”‚
    β”œβ”€β”€ context/
    β”‚   └── πŸŒ— ThemeContext.jsx    # Theme state + View Transition toggle
    β”‚
    β”œβ”€β”€ hooks/
    β”‚   β”œβ”€β”€ πŸ“‘ useProjects.js      # GitHub projects fetch + cache + auto-refresh
    β”‚   β”œβ”€β”€ πŸ—‚οΈ  useGistContent.js  # Gist CMS hook - experiences, internships, certs
    β”‚   β”œβ”€β”€ πŸ‘οΈ  useReveal.js       # IntersectionObserver scroll reveal
    β”‚   └── πŸŒ— useTheme.js         # Re-export of useTheme from context
    β”‚
    β”œβ”€β”€ services/
    β”‚   β”œβ”€β”€ πŸ™ githubProjects.js        # Fetch + normalise portfolio repos
    β”‚   β”œβ”€β”€ πŸ”₯ githubContributions.js   # Fetch contribution heatmap data
    β”‚   └── πŸ“ gistContent.js           # Gist CMS - fetch + fallback for content
    β”‚
    β”œβ”€β”€ components/
    β”‚   β”œβ”€β”€ layout/
    β”‚   β”‚   β”œβ”€β”€ 🧭 Navbar.jsx          # Pill nav - tabs, GitHub icon, theme toggle
    β”‚   β”‚   β”œβ”€β”€ 🦢 Footer.jsx          # Footer + visit counter
    β”‚   β”‚   β”œβ”€β”€ πŸ–±οΈ  CustomCursor.jsx   # Dual-ring cursor (desktop only)
    β”‚   β”‚   └── πŸ“Š ScrollProgress.jsx  # Top gradient progress bar
    β”‚   β”‚
    β”‚   └── home/
    β”‚       β”œβ”€β”€ 🦸 Hero.jsx            # Hero section
    β”‚       β”œβ”€β”€ πŸ‘€ About.jsx           # About section
    β”‚       β”œβ”€β”€ πŸ—ΊοΈ  JourneyPreview.jsx # Journey + Certificates card links
    β”‚       β”œβ”€β”€ πŸ› οΈ  Skills.jsx         # Ticker marquee tech stack
    β”‚       β”œβ”€β”€ πŸ—‚οΈ  FeaturedProjects.jsx # Top 2 projects from GitHub
    β”‚       β”œβ”€β”€ πŸ”₯ GitHubHeatmap.jsx   # Canvas contribution heatmap
    β”‚       └── πŸ“± BottomNav.jsx       # Floating pill nav (home page only)
    β”‚
    └── pages/
        β”œβ”€β”€ 🏠 Home.jsx
        β”œβ”€β”€ πŸ—‚οΈ  Projects.jsx        # Full grid - search, filter, sort, pagination
        β”œβ”€β”€ πŸ“¬ Contact.jsx         # EmailJS form + toast
        β”œβ”€β”€ πŸ—ΊοΈ  Journey.jsx         # Timeline - data from Gist CMS
        β”œβ”€β”€ πŸ† Certificates.jsx    # Certificate cards - data from Gist CMS
        └── πŸ” NotFound.jsx        # 404

⚑ Quick Start

Requirements: Node.js 18+

# Clone the repository
git clone https://github.com/RajHarsh03/Portfolio
cd Portfolio

# Install dependencies
npm install

# Start dev server
npm run dev

Dev server runs at http://localhost:5173


πŸ” Environment Variables

No .env file is needed to run or deploy this project.

Variable Where Notes
KV_REST_API_URL Vercel Dashboard β†’ Storage Auto-injected by Vercel when Upstash Redis is connected
KV_REST_API_TOKEN Vercel Dashboard β†’ Storage Auto-injected by Vercel when Upstash Redis is connected

πŸ“Œ EmailJS keys are public client-side keys (hardcoded intentionally). Security is handled via domain whitelisting in the EmailJS dashboard. Ensure only harshx.in is listed under Account β†’ Security.


πŸ“¦ Build & Preview

npm run build      # β†’ outputs production bundle to dist/
npm run preview    # β†’ preview the production build locally

πŸš€ Deployment (Vercel)

  1. Push to GitHub
  2. Import the repo on vercel.com
  3. Set the following options:
Setting Value
Framework Preset Vite
Root Directory /
Build Command npm run build
Output Directory dist
  1. Connect Upstash Redis from Vercel Dashboard β†’ Storage (auto-injects env vars)
  2. Deploy πŸŽ‰

The vercel.json handles SPA routing - all URLs serve index.html and React Router takes over client-side.


πŸ™ GitHub Projects Setup

To show a repo on the portfolio, add these topics to it on GitHub:

Topic Effect
portfolio βœ… Required - makes it appear on the portfolio
rank-1, rank-2, … πŸ“Š Controls display order (lower = higher priority)
completed 🟒 Shows green "Completed" badge
frontend / fullstack / ai πŸ” Sets the filter category
personal / client / open-source / hackathon 🏷️ Sets the type pill label

Tech icon topics (auto-mapped to devicons): react, nodejs, python, typescript, mongodb, tailwindcss, and more.


πŸ—‚οΈ Gist CMS - Experiences, Internships & Certificates

Content for the Journey and Certificates pages is managed via a GitHub Gist β€” no code push needed to add or edit cards.

How it works

The app fetches a single JSON file from a private Gist at runtime. If the Gist is unreachable, it automatically falls back to hardcoded data so the site never breaks.

Gist URL β†’ fetched on every page visit (cached 5 min)
         ↓ fails?
Fallback data in gistContent.js (always shown instantly)

Adding or editing a card

  1. Go to your Gist: https://gist.github.com/
  2. Click Add Gist
  3. Add the JSON structure for (experiences, internships, or certificates)
  4. Click Create secret gist
  5. Click Raw after creating the gist
  6. Copy the raw url after clicking Raw
  7. Replace the copied url in the src/services/gistContent.js with the Replace with your URL - changes are live within 5 minutes, no deploy needed
  8. For any changes just addd/modify the present gist, dont create a new one

JSON structure

Experience / Internship card:

{
  "label": "INTERNSHIP",
  "type": "INTERNSHIP",
  "typeColor": "badge-purple",
  "company": "Company Name",
  "role": "Your Role Title",
  "date": "JAN 2025 - PRESENT",
  "bullets": [
    "First bullet point about what you did.",
    "Second bullet point with an achievement."
  ]
}

Certificate card:

{
  "label": "COURSE",
  "type": "CERTIFICATE",
  "typeColor": "badge-teal",
  "title": "Certificate Title",
  "issuer": "ISSUING BODY",
  "date": "JAN 2025",
  "desc": "Short description of what this certificate covers.",
  "link": "https://drive.google.com/..."
}

typeColor options: badge-blue | badge-purple | badge-teal

Permanent updates

To update the fallback (shown before Gist loads), also edit FALLBACK_DATA in src/services/gistContent.js and push.


πŸ“Š Visit Counter

Uses a Vercel serverless function at /api/visits:

POST /api/visits  β†’  Records unique daily visit (hashed IP + UA + date), returns total
GET  /api/visits  β†’  Returns total count without incrementing

Backed by Upstash Redis (Vercel KV). In local dev it reads from the live production endpoint so the counter is always visible.


πŸ“œ License

MIT License - feel free to use as a reference or template.
A credit link back to harshx.in is appreciated but not required.

Made by Harsh Raj

About

Personal portfolio built with React 19 + Vite SPA - live GitHub projects, contribution heatmap, EmailJS contact, dark/light theme & visit counter.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages