Built with Astro β’ Powered by Cloudflare Workers β’ Deployed on GitHub Pages
π Live Demo β’ π Documentation β’ π Report Bug β’ β¨ Request Feature
- Project Overview
- Architecture
- System Flowcharts
- Features
- Tech Stack
- Project Structure
- Installation
- Configuration
- Usage
- Deployment
- Troubleshooting
- Future Enhancements
- Contributing
- License
- Author
- Acknowledgments
This portfolio website serves as a comprehensive professional showcase, designed specifically for software engineers, data scientists, and ML practitioners. It automatically fetches and displays project READMEs from GitHub repositories, manages multiple resume versions, and provides an innovative contact form system using GitHub Issues as a backend.
| Goal | Description |
|---|---|
| π― Recruiter-Friendly | Streamlined UX designed for hiring managers and technical recruiters |
| π Data-Driven Content | Projects, experience, and skills managed through configuration files and markdown |
| π¨ Modern Aesthetic | Dark theme with neon cyan accents, glass-morphism effects, and scroll-reveal animations |
| π° Zero-Cost Infrastructure | Static site deployment with serverless contact form via Cloudflare Workers |
| π Automated Updates | CI/CD pipeline rebuilds site automatically when content changes |
| π Privacy-First Contact | Contact form creates GitHub Issues - no database, no third-party services |
- β 100% Static - No server-side runtime required
- β Lighthouse Score 95+ - Optimized performance out of the box
- β Mobile-First - Fully responsive design
- β SEO Optimized - Proper meta tags, sitemap, and semantic HTML
- β Accessible - Keyboard navigation and screen reader support
- β Customizable - Single config file for all personalization
The portfolio follows a static-first architecture using Astro's build-time rendering capabilities combined with serverless functions for dynamic features.
graph TB
subgraph "Content Sources"
A[π config.json] --> B[Astro Build]
C[π Markdown Files] --> B
D[π CSV Data] --> B
E[π GitHub READMEs] --> B
end
subgraph "Build Process"
B --> F[Static HTML/CSS/JS]
end
subgraph "Hosting"
F --> G[GitHub Pages CDN]
end
subgraph "Runtime Services"
H[π§ Contact Form] --> I[Cloudflare Worker]
I --> J[GitHub API]
J --> K[GitHub Actions]
K --> L[GitHub Issues]
end
subgraph "User"
M[π Browser] --> G
M --> H
end
graph LR
subgraph "Pages Layer"
P1[index.astro]
P2[projects.astro]
P3[resume.astro]
P4[about.astro]
P5[contact.astro]
P6[projects/slug.astro]
end
subgraph "Components Layer"
C1[Header]
C2[Footer]
C3[ProjectCard]
C4[ExperienceTimeline]
C5[ResumeViewer]
C6[ScrollRevealWrapper]
C7[CursorLight]
C8[MarkdownRenderer]
end
subgraph "Library Layer"
L1[config.json]
L2[readmeFetcher.js]
L3[markdown.js]
L4[csvParser.js]
L5[sr.js]
L6[githubForm.js]
end
subgraph "Layout Layer"
B1[BaseLayout.astro]
end
P1 --> B1
P2 --> B1
P3 --> B1
P4 --> B1
P5 --> B1
P6 --> B1
B1 --> C1
B1 --> C2
B1 --> C7
P1 --> C3
P1 --> C4
P2 --> C3
P6 --> C8
C3 --> L1
C3 --> L2
C8 --> L3
P4 --> L4
flowchart LR
subgraph "Build Time"
direction TB
GH[GitHub API] -->|fetch README| RF[readmeFetcher.js]
RF --> MD[markdown.js]
MD -->|sanitize & transform| HTML[HTML Output]
CSV[skills.csv] --> CP[csvParser.js]
CP --> SKILLS[Skills Data]
EXP[experience.md] --> MD
ABOUT[about.md] --> MD
end
subgraph "Static Assets"
HTML --> DIST[dist/]
SKILLS --> DIST
IMG[images/] --> DIST
PDF[resumes/] --> DIST
end
subgraph "CDN"
DIST --> GHP[GitHub Pages]
end
For environments that don't support Mermaid:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PORTFOLIO SITE ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββββββ β
β β CONTENT LAYER β β BUILD LAYER β β HOSTING LAYER β β
β βββββββββββββββββββ€ ββββββββββββββββββββ€ βββββββββββββββββββββββ€ β
β β β β β β β β
β β β’ config.json ββββββΆβ Astro SSG ββββββΆβ GitHub Pages β β
β β β’ about.md β β βββββββββββββ β β ββββββββββββββ β β
β β β’ experience.md β β β’ Parse MD β β β’ Global CDN β β
β β β’ skills.csv β β β’ Fetch READMEs β β β’ HTTPS β β
β β β’ GitHub APIs β β β’ Process CSS β β β’ Custom Domain β β
β β β β β’ Bundle JS β β β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CONTACT FORM FLOW β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
β β β β
β β ββββββββββ ββββββββββββββ βββββββββββ βββββββββββ β β
β β β Form βββββββΆβ Cloudflare βββββββΆβ GitHub βββββββΆβ GitHub β β β
β β β Submit β β Worker β β Actions β β Issue β β β
β β ββββββββββ ββββββββββββββ βββββββββββ βββββββββββ β β
β β β β β
β β βΌ β β
β β ββββββββββββββ β β
β β β Fallback: β β β
β β β Direct GH β β β
β β β Issue Link β β β
β β ββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
This flowchart shows how content is processed during npm run build:
flowchart TD
START([npm run build]) --> A[Load config.json]
A --> B{For each project in config}
B --> C[Fetch README from GitHub]
C --> D[Parse Markdown to AST]
D --> E[Transform image URLs to absolute paths]
E --> F[Sanitize HTML for security]
F --> G[Generate HTML output]
G --> B
B --> H[Parse content/about.md]
H --> I[Parse content/experience.md]
I --> J[Parse content/skills.csv]
J --> K[Generate Astro pages]
K --> L[Bundle CSS/JS assets]
L --> M[Optimize images]
M --> N[Generate sitemap.xml]
N --> O[Output to dist/ folder]
O --> END([Build Complete])
This flowchart shows the complete journey of a contact form submission:
flowchart TD
START([User fills form]) --> A{Form valid?}
A -->|No| B[Show validation error]
B --> START
A -->|Yes| C[Show loading spinner]
C --> D[POST to Cloudflare Worker]
D --> E{Worker response?}
E -->|Success| F[Worker validates payload]
F --> G[Worker calls GitHub API]
G --> H{GitHub API response?}
H -->|Success| I[Trigger repository_dispatch]
I --> J[GitHub Actions workflow starts]
J --> K[Create GitHub Issue]
K --> L[Email notification sent]
L --> M[Show success message]
M --> N[Reset form]
N --> END([Complete])
H -->|Error 401| O[Invalid GitHub token]
O --> P[Show error message]
E -->|Error/Timeout| Q{Fallback enabled?}
Q -->|Yes| R[Show fallback message]
R --> S[Redirect to GitHub Issues]
S --> END
Q -->|No| P
P --> END
flowchart LR
subgraph "Navigation"
HOME[π Home] --> PROJ[π Projects]
PROJ --> DETAIL[π Project Detail]
HOME --> ABOUT[π€ About]
HOME --> RESUME[π Resume]
HOME --> CONTACT[π§ Contact]
end
subgraph "Project Detail"
DETAIL --> README[Rendered README]
DETAIL --> LINKS[GitHub/Demo Links]
DETAIL --> TECH[Tech Stack Tags]
end
flowchart LR
A[Raw Markdown] --> B[remark-parse]
B --> C[AST Tree]
C --> D[remark-rehype]
D --> E[HTML AST]
E --> F[rehype-sanitize]
F --> G[Safe HTML AST]
G --> H[Image URL Transform]
H --> I[rehype-stringify]
I --> J[Final HTML]
flowchart TD
LOAD([Page Load]) --> A[Initialize CursorLight]
A --> B[Initialize ScrollReveal]
B --> C{Is touch device?}
C -->|Yes| D[Disable cursor effects]
C -->|No| E[Enable cursor tracking]
E --> F[Add mousemove listener]
F --> G[Update gradient position]
B --> H[Register scroll observers]
H --> I{Element in viewport?}
I -->|Yes| J[Play reveal animation]
I -->|No| K[Wait for scroll]
K --> I
- Automatic README Fetching: Pulls project documentation directly from GitHub repositories at build time
- Glass-Card Design: Projects displayed in modern glass-morphism cards with hover effects
- Lazy Image Loading: Project thumbnails optimized for performance
- Technical Details: Automatically extracts and displays tech stack, features, and project descriptions
How it works: The fetchReadme() function in src/lib/readmeFetcher.js makes build-time requests to raw.githubusercontent.com to fetch README.md files from public repositories listed in config.json. The markdown is then sanitized and rendered using the remark and rehype processing pipeline.
- Version Switching: Store and toggle between different resume variants (general, data engineer, ML engineer, etc.)
- Inline PDF Viewer: View resumes directly in the browser without downloading
- Direct Download: One-click download for any resume version
- Responsive Display: Mobile-optimized PDF viewing experience
Implementation: Resume PDFs are stored in /public/resumes/ and managed through the ResumeViewer.astro component. The viewer is implemented using PDF.js and provides a robust in-browser experience with several user-friendly features and graceful fallbacks.
- Source:
public/resumes/(add new PDF files here). The active resume link is configured insrc/lib/config.jsonvia theresume.displayLinkproperty. - Rendering: Uses PDF.js (CDN) and a canvas-based renderer for crisp, cross-browser output with HiDPI (devicePixelRatio) support.
- Navigation: Previous/Next page buttons with a current/total page indicator.
- Zoom modes:
Fit Page(default),Fit Width, and preset percentages (50%, 75%, 100%, 125%, 150%, 200%). - Scrolling: "Fit Page" shows a single full page without scrolling. Selecting a zoom > Fit Page or
Fit Widthenables scrolling so users can pan horizontally/vertically. - Mobile: On small screens the component simplifies the chrome (card background removed) and centers the PDF viewport to occupy ~90% width for better legibility.
- Print: The Print button opens the raw PDF in a new tab and triggers the browser print dialog so only the PDF is printed (avoids printing the surrounding page chrome).
- Download: The Download button opens the PDF in a new tab for direct downloading.
- Errors: Load/render errors display an in-app toast notification instead of an inline error block.
- Component file:
src/components/ResumeViewer.astroβ contains the viewer logic, controls, and the small inline toast helper used for error messages. - Styling:
src/styles/global.csscontains the layout, responsive behavior, and toast styles. Mobile-specific rules hide the heavy card chrome and center the PDF viewport. - Adding a new resume: Place the PDF in
public/resumes/and updatesrc/lib/config.jsonβresume.displayLinkto the new relative path (e.g./resumes/my-resume.pdf). - CORS/Serving: Ensure the resume files are served as static assets (they live under
public/) and are accessible at build/deploy time.
- If the viewer shows a toast like "Unable to load resume in browser", check that the file exists under
public/resumes/and thatresume.displayLinkis set correctly insrc/lib/config.json. - If the browser blocks popups, the Print button may not open a new tab automatically β the viewer will show an informational toast asking the user to print from the opened PDF tab.
- For blurry rendering on Retina devices, PDF.js uses
devicePixelRatioto render canvases at higher resolution; ensurewindow.devicePixelRatioisn't being overridden by browser extensions.
The viewer is designed to be robust on both desktop and mobile; if you want the PDF to always render as a continuous scroll of pages (instead of single-page view by default), see src/components/ResumeViewer.astro and the renderPage logic for easy customization.
- Serverless Backend: Uses Cloudflare Workers to proxy form submissions
- Repository Dispatch: Triggers GitHub Actions workflow to create issues
- Spam Protection: Server-side validation and rate limiting
- Fallback Mechanism: Automatic redirect to GitHub Issues if Worker fails
- No Database Required: All contact requests stored as GitHub Issues with proper labeling
Technical Flow:
Form Submit β Cloudflare Worker β GitHub API (repository_dispatch)
β
GitHub Actions listens for dispatch event
β
Creates issue with contact details and label
β
Email notification sent to repository owner- Dual View Variants:
compactmode for homepage (company + short summary + project highlights) anddetailedmode for about page (full descriptions, tenure, location) - Company-Project Hierarchy: Experience organized by company with nested projects, supporting complex career histories
- Markdown Support in JSON: Descriptions support bold, italic, and bullet lists rendered from JSON config
- Chronological Sorting: Projects automatically sorted by date (most recent first)
- Configurable Accent Colors: Company name accent color configurable in settings
- Scroll Animations: Smooth reveal animations as user scrolls
Data Source: Content managed in src/lib/config/experience.config.json with company-level and project-level details.
Component Usage:
<!-- Homepage: Compact view -->
<ExperienceTimeline variant="compact" />
<!-- About page: Detailed view -->
<ExperienceTimeline variant="detailed" />- Accordion UI: Left panel shows expanded category with icon and full skill list; right panel shows collapsed category buttons
- Click to Swap: Click any collapsed category to expand it (previous collapses automatically)
- Category Icons: Each skill category has a unique SVG icon (GenAI, ML, Backend, Data Engineering)
- JSON-Driven: Skills managed in
src/lib/config/about.config.jsonfor easy updates - Category Ordering: Skills ordered by complexity (GenAI first, Data Engineering last)
- Responsive Design: Stacks on mobile, 2-column collapsed grid on tablet
- Dynamic Styling: Uses
:global()CSS for JavaScript-inserted content
Skill Categories:
- GenAI / LLM Systems
- NLP, Embeddings & Retrieval
- Neural Networks & Deep Learning
- Machine Learning
- Backend, Architecture & Performance
- Data Engineering & Analytics
- Programming & Core Languages
- Progressive Disclosure: Content fades in as user scrolls
- Performance Optimized: Uses Intersection Observer API
- Customizable Delays: Staggered animations for list items
- Configurable Duration: Fine-tune animation timing per component
Library: ScrollReveal.js (4.0.9) wrapped in Astro component for SSR compatibility.
- Interactive Light: Radial gradient follows cursor position
- GPU Accelerated: Uses CSS transforms for smooth 60fps performance
- Responsive: Automatically disabled on touch devices
- Customizable: Gradient colors and blur radius configurable in CSS
- Sticky Header: Transparent nav with backdrop blur effect
- Mobile Menu: Hamburger menu for small screens
- Active State: Current page highlighted in navigation
- Smooth Transitions: Page transitions with fade effects
- Meta Tags: Comprehensive Open Graph and Twitter Card support
- Sitemap Generation: Automatic sitemap.xml creation
- Asset Optimization: Image compression and lazy loading
- Lighthouse Score: 95+ performance on all pages
- Semantic HTML: Proper heading hierarchy and ARIA labels
- Split Config Files: Monolithic
config.jsonreplaced with modular files:site.config.json: Hero content, social links, navigation, resume settingsabout.config.json: Profile, skills, competencies, projects, education, certificationsexperience.config.json: Company/project hierarchy with settingsprojects.config.json: Portfolio project definitions
- Re-export Layer:
config.jsprovides backward compatibility and flattened exports - Type-Safe Imports: Clean imports from
../lib/config.js - Hot Reload: Development server updates instantly on config changes
Import Example:
import { site, about, experience, projects } from '../lib/config.js';- Glassmorphism Cards: Certifications displayed as modern glass-effect cards with hover animations
- Certification Icon: Each card displays a medal/ribbon icon in teal accent
- Golden Star: Recognition star with glow effect for visual appeal
- Conditional Link Button: "View Credential" button only appears when
linkPresent: true - Responsive Grid: Auto-fit grid that stacks on mobile
JSON Structure:
{
"title": "Certification Name",
"organisation": "Issuing Organization",
"date": "Month Year",
"linkPresent": true,
"link": "https://credential-url.com"
}- Centered Hero Section: Name, title, contact icons, and tag badges
- Full-Width Summary: Justified text without left accent bar
- Interactive Skills Accordion: See Feature #5
- Core Competencies Grid: Card-based layout for key competencies
- Featured Projects Section: Domain tags and highlight bullets
- Education & Certifications: Clean typography with card layouts
- Green Accent Theme: All headings use
#1fb6a0accent color
- Astro 5.16.4 - Static Site Generator
- Why: Zero-JS by default, excellent DX, fast builds, MDX support, built-in asset optimization
- Features Used: File-based routing, component islands, build-time data fetching
- Tailwind CSS 3.x - Utility-First CSS Framework
- Why: Rapid prototyping, consistent design system, purged CSS for minimal bundle size
- Custom CSS Variables (
vars.css) - Theme management - Glass-morphism Effects - Modern UI aesthetics with backdrop filters
- Remark - Markdown Processor
remark-parse: Markdown β ASTremark-rehype: AST β HTML AST
- Rehype - HTML Processor
rehype-sanitize: XSS protectionrehype-stringify: HTML generation
- Unified - Pipeline orchestration
- ScrollReveal.js 4.0.9 - Scroll animations
- Why: Lightweight (3kb gzipped), no dependencies, Intersection Observer based
- Custom Cursor Light - Vanilla JavaScript with CSS transform
- Cloudflare Workers - Serverless functions
- Why: Free tier, global edge network, zero cold starts, 100k requests/day
- Usage: Contact form proxy and validation
- GitHub Actions - CI/CD
- Automated builds on push
- Deploys to GitHub Pages
- Creates issues from contact form dispatches
- GitHub Pages - Static hosting
- Why: Free, HTTPS included, custom domain support, integrated with GitHub
- GitHub API - Project metadata and README fetching
- Modular JSON Configs - Site, about, experience, projects configuration (v2.0)
- Markdown Files - About page content
- JSON - Skills, certifications, competencies
{
"astro": "^5.16.4", // SSG framework
"react": "^18.0.0", // Component library (optional islands)
"react-dom": "^18.0.0", // React DOM renderer
"scrollreveal": "^4.0.9", // Scroll animations
"rehype-sanitize": "^5.0.1", // Security (XSS prevention)
"remark": "^14.0.0", // Markdown processing
"unified": "^10.1.2" // Content pipeline
}portfolio-site/
β
βββ π public/ # Static assets (served as-is)
β βββ π resumes/ # PDF resume files
β β βββ resume_latest.pdf # Default resume
β β βββ resume_data_engineer.pdf # Specialized resume variant
β βββ π images/ # Images and graphics
β β βββ π projects/ # Project thumbnails
β βββ π og/ # Open Graph images for social sharing
β
βββ π src/ # Source code
β βββ π pages/ # Astro pages (file-based routing)
β β βββ index.astro # Homepage (hero, projects, timeline)
β β βββ projects.astro # Projects listing page
β β βββ projects_new.astro # Experimental projects view
β β βββ resume.astro # Resume viewer page
β β βββ about.astro # About/bio page
β β βββ contact.astro # Contact form page
β β
β βββ π components/ # Reusable Astro/React components
β β βββ Header.astro # Site navigation header
β β βββ Footer.astro # Site footer with links
β β βββ ProjectCard.astro # Individual project card UI
β β βββ ProjectDetail.astro # Expanded project view with README
β β βββ ProjectsTimeline.astro # Timeline-style project display
β β βββ ExperienceTimeline.astro # Work experience timeline
β β βββ Timeline.astro # Generic timeline component
β β βββ MarkdownRenderer.astro # Renders markdown with sanitization
β β βββ ResumeViewer.astro # PDF viewer with download option
β β βββ ScrollRevealWrapper.astro # HOC for scroll animations
β β βββ CursorLight.astro # Interactive cursor spotlight effect
β β
β βββ π layouts/ # Page layout templates
β β βββ BaseLayout.astro # Base HTML structure, meta tags, global styles
β β
β βββ π lib/ # Utility functions and configuration
β β βββ config.js # Re-export layer for modular configs
β β βββ π config/ # Modular configuration files (v2.0)
β β β βββ site.config.json # Hero, social links, nav, resume settings
β β β βββ about.config.json # Profile, skills, competencies, education, certs
β β β βββ experience.config.json # Company/project hierarchy with settings
β β β βββ projects.config.json # Portfolio project definitions
β β βββ readmeFetcher.js # Fetches README from GitHub (public repos)
β β βββ csvParser.js # Parses CSV files (skills data)
β β βββ markdown.js # Markdown-to-HTML processing pipeline
β β βββ githubForm.js # Client-side form submission logic
β β βββ sr.js # ScrollReveal initialization
β β
β βββ π styles/ # Global styles
β βββ global.css # Main stylesheet (layout, components)
β βββ vars.css # CSS custom properties (theme colors, fonts)
β
βββ π content/ # Markdown and data files
β βββ about.md # About page content
β βββ experience.md # Work experience entries
β βββ skills.csv # Skills list (parsed at build time)
β
βββ π cloudflare-worker/ # Serverless backend
β βββ contact-proxy.js # Cloudflare Worker for contact form
β βββ README.md # Worker deployment instructions
β
βββ π .github/ # GitHub automation
β βββ π workflows/ # CI/CD workflows
β β βββ build_and_deploy.yml # Build site and deploy to GitHub Pages
β β βββ contact_issue_from_dispatch.yml # Creates issues from contact form
β βββ π scripts/ # Helper scripts
β
βββ π astro.config.mjs # Astro configuration
βββ π package.json # Dependencies and scripts
βββ π tsconfig.json # TypeScript configuration
βββ π README.md # This file
| File | Purpose |
|---|---|
src/lib/config.js |
Re-export layer for modular configs, provides backward compatibility |
src/lib/config/site.config.json |
Hero content, social links, navigation, resume settings |
src/lib/config/about.config.json |
Profile, skills (accordion), competencies, education, certifications |
src/lib/config/experience.config.json |
Company/project hierarchy with shortSummary and detailed descriptions |
src/lib/config/projects.config.json |
Portfolio project definitions |
src/lib/readmeFetcher.js |
Fetches README.md from GitHub repos at build time using raw.githubusercontent.com |
src/lib/markdown.js |
Processes markdown content using remark/rehype pipeline with sanitization |
src/components/ExperienceTimeline.astro |
Work experience with compact and detailed variants |
src/components/ScrollRevealWrapper.astro |
Wraps components with scroll-reveal animations |
cloudflare-worker/contact-proxy.js |
Serverless function that proxies contact form to GitHub API |
.github/workflows/build_and_deploy.yml |
Builds Astro site and deploys to GitHub Pages |
.github/workflows/contact_issue_from_dispatch.yml |
Listens for repository_dispatch and creates GitHub Issue |
Ensure you have the following installed on your system:
- Node.js: Version 18.x or higher (Download)
- npm: Version 9.x or higher (comes with Node.js)
- Git: For cloning the repository (Download)
- GitHub Account: For deployment and contact form integration
- Cloudflare Account (Optional): For contact form worker deployment
-
Clone the Repository
git clone https://github.com/manideepsp/Portfolio-ManideepSP.git cd Portfolio-ManideepSP
-
Install Dependencies
npm install
This installs all packages listed in
package.json, including:- Astro framework
- Remark/Rehype markdown processors
- ScrollReveal for animations
- Tailwind CSS and PostCSS
-
Verify Installation
node --version # Should show v18.x or higher npm --version # Should show v9.x or higher
-
Initial Build Test
npm run build
This creates a
dist/folder with static HTML files. If successful, you'll see:β Built in XXXms
This is the central configuration file for your portfolio. Edit this file to customize your site:
{
"name": "Manideep SP", // Your display name
"title": "Software Engineer β’ Data & ML", // Tagline/title
"githubUsername": "manideepsp", // Your GitHub username
"resume": "resume_latest.pdf", // Default resume filename
"projectsRepoList": [ // GitHub repos to showcase
"manideepsp/project-1",
"manideepsp/project-2"
],
"customDomain": "", // Optional: yourdomain.com
"contactWorkerUrl": "", // Cloudflare Worker URL (see below)
"contactFallback": {
"autoRedirect": true, // Auto-redirect to GitHub Issues if worker fails
"delayMs": 5000, // Delay before redirect
"showFallbackButton": true // Show manual fallback button
},
"experience": {
"showMonth": true, // Show months in timeline dates
"defaultMonth": "Jan" // Default month if not specified
}
}For local development with private GitHub repositories or API access:
Create a .env file in the root directory (this file is gitignored):
# GitHub Personal Access Token (for private repo README fetching)
GH_README_TOKEN=ghp_your_token_here
# Cloudflare Worker URL (for contact form)
PUBLIC_CONTACT_WORKER_URL=https://contact-proxy.your-subdomain.workers.dev.env file or expose your GitHub token in client-side code.
export default {
site: 'https://your-portfolio-url.com', // Your site URL (for sitemap)
base: '/', // Base path (use '/repo-name' for GitHub Pages)
buildOptions: {
outDir: 'dist', // Build output directory
},
markdown: {
shikiConfig: {
theme: 'nord', // Code syntax highlighting theme
},
},
vite: {
server: {
port: 3000, // Development server port
},
},
};Add your GitHub repositories to the projectsRepoList array:
"projectsRepoList": [
"manideepsp/repo-name-1",
"manideepsp/repo-name-2"
]The site will automatically fetch README.md from each repository at build time.
Place your PDF resumes in this directory:
resume_latest.pdf- Your default resumeresume_data_engineer.pdf- Specialized variantresume_ml_engineer.pdf- Another variant
Update config.json to set the default:
"resume": "resume_latest.pdf"Write your bio in markdown format:
I'm a software engineer specializing in data infrastructure and machine learning systems.
I build scalable backend services and production ML pipelines...Format your work history:
## Software Engineer | Company Name
**Jan 2023 - Present**
- Built distributed data processing pipelines handling 10M+ events/day
- Designed and deployed ML models for real-time fraud detection
- Technologies: Python, Spark, Kubernetes, TensorFlowCreate a CSV file with your skills:
category,skill,level
Languages,Python,Expert
Languages,JavaScript,Advanced
Frameworks,React,Advanced
Tools,Docker,Expertcd cloudflare-worker
wrangler publishIn Cloudflare dashboard or via CLI:
wrangler secret put GLOBAL_GITHUB_TOKEN
# Paste your GitHub Personal Access Token (PAT)Creating a GitHub PAT:
- Go to GitHub Settings β Developer Settings β Personal Access Tokens β Tokens (classic)
- Click "Generate new token (classic)"
- Select scopes:
repo(full control of private repositories) - Copy the token (you won't see it again!)
Add the worker URL to src/lib/config.json:
"contactWorkerUrl": "https://contact-proxy.your-subdomain.workers.dev"For automated deployments, add these secrets in your repository settings:
- Go to:
Settings β Secrets and variables β Actions - Add the following secrets:
| Secret Name | Value | Purpose |
|---|---|---|
GH_README_TOKEN |
GitHub PAT | Fetch private repo READMEs during build |
GITHUB_TOKEN |
Auto-provided | Deploy to GitHub Pages (no action needed) |
Start the local development server with hot reload:
npm run dev- URL: http://localhost:3000
- Features: Hot module replacement, instant updates on file changes
- Console: Shows build errors and warnings
Create an optimized production build:
npm run build- Output:
dist/folder with static HTML, CSS, JS - Optimizations: Minification, asset bundling, image optimization
- Validation: Checks for broken links and missing assets
Test the production build locally:
npm run preview- URL: http://localhost:4321 (different port than dev)
- Purpose: Verify production build works correctly before deployment
# Clean install (removes node_modules and reinstalls)
Remove-Item -Recurse -Force node_modules; npm install
# Build and preview in sequence
npm run build; npm run preview
# Check for outdated packages
npm outdated
# Update dependencies
npm updateThis is a static site with no traditional API endpoints. However, the contact form interacts with:
Cloudflare Worker Endpoint:
POST https://contact-proxy.your-subdomain.workers.dev
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com",
"position": "Software Engineer",
"message": "I'd like to discuss an opportunity...",
"title": "Contact from Portfolio Site"
}
Response:
{
"ok": true
}Input (config.json):
"projectsRepoList": ["manideepsp/awesome-project"]Build-time Fetch:
const readme = await fetchReadme("manideepsp/awesome-project");
// Fetches from: https://raw.githubusercontent.com/manideepsp/awesome-project/main/README.mdOutput (rendered on page):
<article class="project-card">
<h3>awesome-project</h3>
<p>A comprehensive data pipeline for real-time analytics...</p>
<a href="https://github.com/manideepsp/awesome-project">View Project β</a>
</article>Input (content/skills.csv):
category,skill,level
Languages,Python,ExpertParsing:
import { parseCSV } from './lib/csvParser.js';
const skills = parseCSV(csvText);
// Result: [{ category: "Languages", skill: "Python", level: "Expert" }]For testing on your local network:
npm run build
npm run previewAccess from other devices on your network: http://YOUR_LOCAL_IP:4321
- GitHub repository
- GitHub Actions enabled
GH_README_TOKENsecret configured (optional, for private repos)
-
Enable GitHub Pages
- Go to repository
Settings β Pages - Source:
GitHub Actions
- Go to repository
-
Configure Base Path (if not using custom domain)
Edit
astro.config.mjs:export default { site: 'https://manideepsp.github.io', base: '/Portfolio-ManideepSP', // Your repo name };
-
Push to Main Branch
git add . git commit -m "Deploy portfolio site" git push origin main
-
Automatic Build
GitHub Actions will automatically:
- Install dependencies
- Fetch project READMEs
- Build static site
- Deploy to GitHub Pages
-
Verify Deployment
- Check Actions tab for build status
- Visit:
https://manideepsp.github.io/Portfolio-ManideepSP
-
Add CNAME File
Create
public/CNAME:yourdomain.com -
Configure DNS
Add DNS records with your domain provider:
Type: A Name: @ Value: 185.199.108.153 Type: A Name: @ Value: 185.199.109.153 Type: A Name: @ Value: 185.199.110.153 Type: A Name: @ Value: 185.199.111.153 Type: CNAME Name: www Value: manideepsp.github.io -
Enable HTTPS
In GitHub Pages settings, check "Enforce HTTPS"
Deploy the contact form proxy:
cd cloudflare-worker
wrangler login
wrangler publishSet the GitHub token secret:
wrangler secret put GLOBAL_GITHUB_TOKENThe .github/workflows/build_and_deploy.yml workflow runs on:
- Push to
mainbranch - Pull requests to
mainbranch
Workflow Steps:
- Checkout code
- Setup Node.js 18
- Install dependencies
- Build Astro site
- Deploy to
gh-pagesbranch - Update GitHub Pages
Environment Variables in CI:
GITHUB_TOKEN: Auto-provided by GitHub ActionsGH_README_TOKEN: Manual secret for private repos
Before deploying to production:
- Update
config.jsonwith real data - Add actual resume PDFs to
public/resumes/ - Write
content/about.mdandcontent/experience.md - Configure
astro.config.mjswith correct site URL - Test contact form with Cloudflare Worker
- Verify all project READMEs load correctly
- Check mobile responsiveness
- Run Lighthouse audit (aim for 90+ scores)
- Set up custom domain (optional)
- Configure GitHub Pages settings
- Test all navigation links
Symptom: Build succeeds but projects show "README not available"
Causes:
- Repository is private (raw.githubusercontent.com doesn't work with private repos)
- Repository doesn't have README.md in root
- Branch name is not
main(might bemaster)
Solutions:
// In src/lib/readmeFetcher.js, try different branch
const readme = await fetchReadme('user/repo', 'master');
// Or add error handling
const readme = await fetchReadme('user/repo').catch(err => {
console.error(`Failed to fetch ${repo}:`, err);
return '# Project\n\nNo README available.';
});For private repos, use GitHub Actions with GH_README_TOKEN:
# .github/workflows/build_and_deploy.yml
env:
GH_README_TOKEN: ${{ secrets.GH_README_TOKEN }}Symptom: Form submission fails with "Method Not Allowed"
Cause: Worker URL is incorrect or worker isn't deployed
Solutions:
-
Verify worker is deployed:
cd cloudflare-worker wrangler whoami # Check you're logged in wrangler publish
-
Check
config.jsonhas correct URL:"contactWorkerUrl": "https://contact-proxy.YOUR-SUBDOMAIN.workers.dev"
-
Test worker directly:
curl -X POST https://contact-proxy.YOUR-SUBDOMAIN.workers.dev ` -H "Content-Type: application/json" ` -d '{"name":"Test","email":"test@example.com","message":"Test"}'
Symptom: Actions tab shows red X on workflow run
Common Errors:
| Error | Cause | Solution |
|---|---|---|
npm ERR! 404 Not Found |
Dependency version doesn't exist | Check package.json, run npm install locally first |
Error: No such file or directory |
File path issue | Verify file exists, check case sensitivity |
Permission denied |
GitHub token lacks permissions | Check GITHUB_TOKEN has contents: write permission |
Failed to fetch README |
Private repo without token | Add GH_README_TOKEN secret |
Debug Steps:
- Check Actions logs for exact error message
- Run the same commands locally:
npm ci # Clean install (same as CI) npm run build - Verify secrets are set in repo settings
Symptom: Site works locally but looks unstyled on GitHub Pages
Cause: Incorrect base path in config
Solution:
// astro.config.mjs
export default {
base: '/portfolio-site', // Must match repo name
};Or set base: '/' if using custom domain.
Symptom: No animations on scroll
Causes:
- JavaScript not loading
- ScrollReveal not initialized
- Elements missing
data-srattribute
Solutions:
-
Check browser console for errors
-
Verify ScrollReveal is imported:
--- import ScrollRevealWrapper from '../components/ScrollRevealWrapper.astro'; --- <ScrollRevealWrapper> <div>Content</div> </ScrollRevealWrapper>
-
Check
src/lib/sr.jsis being called
Symptom: Resume page shows broken embed or download doesn't work
Causes:
- PDF file not in
/public/resumes/ - Incorrect filename in
config.json - Browser blocking PDF embed
Solutions:
-
Verify file exists:
ls public/resumes/
-
Check filename matches config:
"resume": "resume_latest.pdf" // Must match actual filename
-
Test direct URL:
http://localhost:3000/resumes/resume_latest.pdf
-
Private Repository READMEs: Cannot fetch at build time using
raw.githubusercontent.com. Must use GitHub Actions with API token. -
Contact Form Rate Limiting: Cloudflare Workers free tier has 100,000 requests/day limit. For higher traffic, upgrade to paid tier.
-
Build Time: Fetching multiple READMEs can slow builds. Consider caching or using GitHub API with pagination.
-
Image Optimization: Astro's image optimization requires additional setup for remote images (e.g., GitHub avatars).
-
Browser Support: CSS features like
backdrop-filter(glass effect) not supported in older browsers. Provide fallbacks:.glass-card { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); /* Fallback for unsupported browsers */ @supports not (backdrop-filter: blur(10px)) { background: rgba(255, 255, 255, 0.2); } }
If you encounter issues not covered here:
- Check Astro Docs: docs.astro.build
- GitHub Issues: Search existing issues in this repository
- Cloudflare Docs: developers.cloudflare.com/workers
- Browser DevTools: Check Console and Network tabs for errors
- Blog Section: Markdown-based blog with RSS feed
- Dark/Light Theme Toggle: User preference with localStorage persistence
- Advanced Project Filtering: Filter by tech stack, date, or category
- Search Functionality: Fuzzy search across projects and blog posts
- Analytics Integration: Privacy-friendly analytics (Plausible or Fathom)
- View Counter: Track project page views using Cloudflare KV
- Commenting System: Utterances or Giscus for blog comments
- Multi-language Support: i18n for international audience
- Performance Monitoring: Real User Monitoring (RUM) with Cloudflare
- Automated Testing: E2E tests with Playwright
- Image Optimization: Implement Astro's
<Image>component for responsive images - Service Worker: Offline support with workbox
- Incremental Static Regeneration: Rebuild only changed pages
- GraphQL API: Unified data layer for content
- TypeScript Migration: Full TypeScript for type safety
- Component Library: Storybook for component development
- Accessibility Audit: WCAG 2.1 AAA compliance
- SEO Enhancements: Schema.org structured data
- Project Demos: Embedded demos or video walkthroughs
- Case Studies: In-depth project breakdowns
- Testimonials: Client/colleague recommendations
- Certifications: Display badges and credentials
- Publications: Link to papers or articles
- Open Source Contributions: GitHub contribution graph
- Page Transitions: Smooth transitions between routes
- Loading States: Skeleton screens for better perceived performance
- Toast Notifications: User feedback for form submissions
- Keyboard Navigation: Full keyboard accessibility
- Print Styles: Optimized print layout for resume page
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated!
-
Fork the Project
# Click the Fork button on GitHub, then clone your fork git clone https://github.com/YOUR-USERNAME/Portfolio-ManideepSP.git cd Portfolio-ManideepSP
-
Create your Feature Branch
git checkout -b feature/AmazingFeature
-
Make your Changes
- Follow existing code style and conventions
- Test your changes locally with
npm run dev - Ensure build passes with
npm run build
-
Commit your Changes
git commit -m 'Add some AmazingFeature'
-
Push to the Branch
git push origin feature/AmazingFeature -
Open a Pull Request
- Go to the original repository
- Click "New Pull Request"
- Select your fork and branch
- Describe your changes in detail
| Type | Description |
|---|---|
| π Bug Reports | Open an issue with detailed reproduction steps |
| β¨ Feature Requests | Open an issue describing the feature and use case |
| π Documentation | Improvements to README, comments, or code docs |
| π¨ Design | UI/UX improvements, accessibility enhancements |
| π§ Code | Bug fixes, new features, performance improvements |
Please be respectful and constructive in all interactions. We follow the Contributor Covenant code of conduct.
This project is licensed under the MIT License - you are free to use, modify, and distribute this code for personal or commercial purposes.
MIT License
Copyright (c) 2025 Manideep SP
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
When using this project as a template or base for your own portfolio:
Please include attribution to the original project by:
- Keeping a link to this repository in your README, OR
- Adding a comment in your source code referencing this project, OR
- Mentioning this project in your portfolio's footer or about section
Example attribution:
<!-- Based on Portfolio Site by Manideep SP -->
<!-- https://github.com/manideepsp/Portfolio-ManideepSP -->β
Use this as a template for your personal portfolio
β
Modify and customize for your needs
β
Use commercially (freelance, business, etc.)
β
Distribute your modified version
β
Use in private projects
π Include attribution to the original project
π Keep the MIT license notice in your copy
π Star the repo if you find it useful β
π Consider contributing improvements back
- Astro - The web framework for content-driven websites
- Tailwind CSS - A utility-first CSS framework
- ScrollReveal - Easy scroll animations
- Cloudflare Workers - Serverless functions at the edge
- GitHub Actions - Automation and CI/CD
- GitHub Pages - Free static site hosting
- Remark & Rehype - Markdown processing
- All the amazing open-source contributors who make projects like this possible! β€οΈ
Built with β€οΈ using Astro, Tailwind CSS, and Cloudflare Workers
If you found this project helpful, please consider giving it a βοΈ!
Report Bug β’ Request Feature β’ Fork Project